{"title":"语义搜索（向量嵌入）","slug":"semantic-search","category":"concepts","summary":"使用向量嵌入进行概念性记忆搜索 — 按意义查找，而非仅按关键词。","audience":["human","llm"],"tags":["concept","semantic","embeddings","vector-search"],"difficulty":"advanced","updated":"2026-06-27","word_count":221,"read_minutes":1,"lang":"zh","translated":true,"requested_lang":"zh","content_markdown":"\n# 语义搜索（向量嵌入）\n\nSynapse 支持基于向量嵌入的语义搜索。与 FTS5（关键词匹配）不同，语义搜索按**意义**查找记忆 — 即使没有关键词匹配也能找到。\n\n## 工作原理\n\n```\n1. 记忆存储 → 生成嵌入 → 存储向量\n2. 搜索查询 → 生成嵌入 → 比较向量\n3. 余弦相似度 → 返回前 N 个结果\n```\n\n### 什么是嵌入？\n\n嵌入是文本的数值向量表示。意义相近的文本有相近的向量。Synapse 为每条记忆的内容生成一个向量（例如 1536 维）。\n\n### 余弦相似度\n\n为找到语义相似的记忆，Synapse 计算查询向量与每条记忆向量之间的余弦相似度。相似度越高 = 越相关。\n\n## 何时使用语义搜索\n\n### 在以下场景使用语义搜索：\n\n- 想要“关于 X 的记忆”，而 X 与存储时的描述不同\n- FTS5 返回零结果（无关键词匹配）\n- 想要概念聚合（例如所有“部署”相关记忆，即使有些写的是“发布”）\n- 查询是一个问题：“我们如何处理认证？”\n\n### 在以下场景使用 FTS5：\n\n- 已知精确关键词\n- 需要布尔逻辑（AND、OR、NOT）\n- 需要亚毫秒级响应\n- 想要短语匹配\n\n## 端点\n\n### GET /memory/semantic-search\n\n```bash\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     \"https://synapse.schaefer.zone/memory/semantic-search?q=container+orchestration\"\n```\n\n响应：\n\n```json\n{\n  \"results\": [\n    {\n      \"id\": \"mem_001\",\n      \"category\": \"project\",\n      \"key\": \"project_synapse_deployment\",\n      \"content\": \"Synapse deployed using Docker Swarm on vps1...\",\n      \"tags\": [\"docker\", \"swarm\", \"deployment\"],\n      \"similarity\": 0.89\n    },\n    {\n      \"id\": \"mem_042\",\n      \"category\": \"fact\",\n      \"key\": \"kubernetes_cluster\",\n      \"content\": \"We use Kubernetes for production orchestration...\",\n      \"tags\": [\"kubernetes\", \"orchestration\"],\n      \"similarity\": 0.84\n    }\n  ]\n}\n```\n\n## 示例\n\n### 查找部署相关记忆\n\n```bash\n# FTS5 可能遗漏部分 — 语义搜索能全部捕获\ncurl .../memory/semantic-search?q=deployment+process\n```\n\n返回关于 \"deployment\"、\"release\"、\"publishing\"、\"rolling out\" 等的记忆。\n\n### 查找认证模式\n\n```bash\ncurl .../memory/semantic-search?q=how+do+users+log+in\n```\n\n返回关于 login、auth、JWT、session 管理、OAuth 等的记忆。\n\n### 查找相似记忆\n\n```bash\n# 查找与某条记忆相似的记忆\ncurl .../memory/related/mem_001\n```\n\n使用语义相似度（基于共享标签 + 嵌入向量）。\n\n## 嵌入生成\n\n### 何时生成嵌入？\n\n- **存储记忆时** — 若配置了嵌入服务，则同步生成嵌入\n- **批量生成** — `POST /memory/embed-batch` 为缺失嵌入的记忆生成\n- **异步更新** — 内容更新时重新生成嵌入\n\n### 嵌入提供方\n\nSynapse 支持可配置的嵌入提供方：\n\n- **OpenAI**（`text-embedding-3-small`、`text-embedding-3-large`）\n- **本地模型**（通过 Ollama 等）\n- **自定义**（实现 embeddings 接口）\n\n通过环境变量配置：\n\n```bash\nEMBEDDINGS_PROVIDER=openai\nEMBEDDINGS_API_KEY=sk-...\nEMBEDDINGS_MODEL=text-embedding-3-small\n```\n\n### 批量生成\n\n对于很多记忆缺少嵌入的 Mind：\n\n```bash\n# 为最多 100 条记忆生成嵌入\ncurl -X POST https://synapse.schaefer.zone/memory/embed-batch \\\n  -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"limit\": 100}'\n\n# 检查进度\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     https://synapse.schaefer.zone/memory/embed-batch-status\n```\n\n## 性能\n\n| 操作 | 延迟 |\n|-----------|---------|\n| 生成嵌入（OpenAI） | 100-200ms |\n| 语义搜索（1k 条记忆） | 50-100ms |\n| 语义搜索（10k 条记忆） | 200-500ms |\n| 批量生成（100 条记忆） | 10-20s |\n\n> [!NOTE]\n> 由于向量计算，语义搜索比 FTS5 慢。已知关键词时用 FTS5，概念查询用语义搜索。\n\n## 局限性\n\n### 嵌入成本\n\n若使用 OpenAI，生成嵌入需要付费（text-embedding-3-small 约 $0.02 / 1M tokens）。对于平均每条 100 tokens 的 10,000 条记忆，约 $0.02 — 可忽略不计。\n\n### 冷启动\n\n在配置嵌入之前存储的记忆没有嵌入。请运行 `POST /memory/embed-batch` 补齐。\n\n### 提供方依赖\n\n如果嵌入提供方宕机，语义搜索会优雅降级（返回空结果或错误）。FTS5 仍可正常工作。\n\n## 当嵌入不可用时\n\n如果未配置嵌入服务：\n\n- `GET /memory/semantic-search` 返回 503 Service Unavailable\n- `POST /memory` 仍可正常工作（只是不生成嵌入）\n- FTS5 搜索仍可正常工作\n\n## 最佳实践\n\n> [!TIP]\n> - **概念查询用语义搜索** — \"我们如何处理 X？\"\n> - **具体术语用 FTS5** — \"docker swarm\"\n> - **定期补齐嵌入** — `POST /memory/embed-batch`\n> - **监控提供方健康** — 语义搜索依赖它\n> - **与标签结合** — 语义 + 标签过滤缩小结果范围\n\n## 下一步\n\n- [FTS5 搜索](/docs/concepts/fts5-search)\n- [Memory API](/docs/api/memory)\n- [架构](/docs/concepts/architecture)\n","content_html":"<h1>语义搜索（向量嵌入）</h1>\n<p>Synapse 支持基于向量嵌入的语义搜索。与 FTS5（关键词匹配）不同，语义搜索按<strong>意义</strong>查找记忆 — 即使没有关键词匹配也能找到。</p>\n<h2>工作原理</h2>\n<pre><code class=\"hljs language-plaintext\">1. 记忆存储 → 生成嵌入 → 存储向量\n2. 搜索查询 → 生成嵌入 → 比较向量\n3. 余弦相似度 → 返回前 N 个结果</code></pre><h3>什么是嵌入？</h3>\n<p>嵌入是文本的数值向量表示。意义相近的文本有相近的向量。Synapse 为每条记忆的内容生成一个向量（例如 1536 维）。</p>\n<h3>余弦相似度</h3>\n<p>为找到语义相似的记忆，Synapse 计算查询向量与每条记忆向量之间的余弦相似度。相似度越高 = 越相关。</p>\n<h2>何时使用语义搜索</h2>\n<h3>在以下场景使用语义搜索：</h3>\n<ul>\n<li>想要“关于 X 的记忆”，而 X 与存储时的描述不同</li>\n<li>FTS5 返回零结果（无关键词匹配）</li>\n<li>想要概念聚合（例如所有“部署”相关记忆，即使有些写的是“发布”）</li>\n<li>查询是一个问题：“我们如何处理认证？”</li>\n</ul>\n<h3>在以下场景使用 FTS5：</h3>\n<ul>\n<li>已知精确关键词</li>\n<li>需要布尔逻辑（AND、OR、NOT）</li>\n<li>需要亚毫秒级响应</li>\n<li>想要短语匹配</li>\n</ul>\n<h2>端点</h2>\n<h3>GET /memory/semantic-search</h3>\n<pre><code class=\"hljs language-bash\">curl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     <span class=\"hljs-string\">&quot;https://synapse.schaefer.zone/memory/semantic-search?q=container+orchestration&quot;</span></code></pre><p>响应：</p>\n<pre><code class=\"hljs language-json\"><span class=\"hljs-punctuation\">{</span>\n  <span class=\"hljs-attr\">&quot;results&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-punctuation\">[</span>\n    <span class=\"hljs-punctuation\">{</span>\n      <span class=\"hljs-attr\">&quot;id&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;mem_001&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;category&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;project&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;key&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;project_synapse_deployment&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;content&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;Synapse deployed using Docker Swarm on vps1...&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;tags&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-punctuation\">[</span><span class=\"hljs-string\">&quot;docker&quot;</span><span class=\"hljs-punctuation\">,</span> <span class=\"hljs-string\">&quot;swarm&quot;</span><span class=\"hljs-punctuation\">,</span> <span class=\"hljs-string\">&quot;deployment&quot;</span><span class=\"hljs-punctuation\">]</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;similarity&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-number\">0.89</span>\n    <span class=\"hljs-punctuation\">}</span><span class=\"hljs-punctuation\">,</span>\n    <span class=\"hljs-punctuation\">{</span>\n      <span class=\"hljs-attr\">&quot;id&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;mem_042&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;category&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;fact&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;key&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;kubernetes_cluster&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;content&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;We use Kubernetes for production orchestration...&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;tags&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-punctuation\">[</span><span class=\"hljs-string\">&quot;kubernetes&quot;</span><span class=\"hljs-punctuation\">,</span> <span class=\"hljs-string\">&quot;orchestration&quot;</span><span class=\"hljs-punctuation\">]</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;similarity&quot;</span><span class=\"hljs-punctuation\">:</span> <span class=\"hljs-number\">0.84</span>\n    <span class=\"hljs-punctuation\">}</span>\n  <span class=\"hljs-punctuation\">]</span>\n<span class=\"hljs-punctuation\">}</span></code></pre><h2>示例</h2>\n<h3>查找部署相关记忆</h3>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># FTS5 可能遗漏部分 — 语义搜索能全部捕获</span>\ncurl .../memory/semantic-search?q=deployment+process</code></pre><p>返回关于 &quot;deployment&quot;、&quot;release&quot;、&quot;publishing&quot;、&quot;rolling out&quot; 等的记忆。</p>\n<h3>查找认证模式</h3>\n<pre><code class=\"hljs language-bash\">curl .../memory/semantic-search?q=how+<span class=\"hljs-keyword\">do</span>+<span class=\"hljs-built_in\">users</span>+<span class=\"hljs-built_in\">log</span>+<span class=\"hljs-keyword\">in</span></code></pre><p>返回关于 login、auth、JWT、session 管理、OAuth 等的记忆。</p>\n<h3>查找相似记忆</h3>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># 查找与某条记忆相似的记忆</span>\ncurl .../memory/related/mem_001</code></pre><p>使用语义相似度（基于共享标签 + 嵌入向量）。</p>\n<h2>嵌入生成</h2>\n<h3>何时生成嵌入？</h3>\n<ul>\n<li><strong>存储记忆时</strong> — 若配置了嵌入服务，则同步生成嵌入</li>\n<li><strong>批量生成</strong> — <code>POST /memory/embed-batch</code> 为缺失嵌入的记忆生成</li>\n<li><strong>异步更新</strong> — 内容更新时重新生成嵌入</li>\n</ul>\n<h3>嵌入提供方</h3>\n<p>Synapse 支持可配置的嵌入提供方：</p>\n<ul>\n<li><strong>OpenAI</strong>（<code>text-embedding-3-small</code>、<code>text-embedding-3-large</code>）</li>\n<li><strong>本地模型</strong>（通过 Ollama 等）</li>\n<li><strong>自定义</strong>（实现 embeddings 接口）</li>\n</ul>\n<p>通过环境变量配置：</p>\n<pre><code class=\"hljs language-bash\">EMBEDDINGS_PROVIDER=openai\nEMBEDDINGS_API_KEY=sk-...\nEMBEDDINGS_MODEL=text-embedding-3-small</code></pre><h3>批量生成</h3>\n<p>对于很多记忆缺少嵌入的 Mind：</p>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># 为最多 100 条记忆生成嵌入</span>\ncurl -X POST https://synapse.schaefer.zone/memory/embed-batch \\\n  -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n  -H <span class=\"hljs-string\">&quot;Content-Type: application/json&quot;</span> \\\n  -d <span class=\"hljs-string\">&#x27;{&quot;limit&quot;: 100}&#x27;</span>\n\n<span class=\"hljs-comment\"># 检查进度</span>\ncurl -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n     https://synapse.schaefer.zone/memory/embed-batch-status</code></pre><h2>性能</h2>\n<table>\n<thead>\n<tr>\n<th>操作</th>\n<th>延迟</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>生成嵌入（OpenAI）</td>\n<td>100-200ms</td>\n</tr>\n<tr>\n<td>语义搜索（1k 条记忆）</td>\n<td>50-100ms</td>\n</tr>\n<tr>\n<td>语义搜索（10k 条记忆）</td>\n<td>200-500ms</td>\n</tr>\n<tr>\n<td>批量生成（100 条记忆）</td>\n<td>10-20s</td>\n</tr>\n</tbody></table>\n<div class=\"callout callout-note\">由于向量计算，语义搜索比 FTS5 慢。已知关键词时用 FTS5，概念查询用语义搜索。</div><h2>局限性</h2>\n<h3>嵌入成本</h3>\n<p>若使用 OpenAI，生成嵌入需要付费（text-embedding-3-small 约 $0.02 / 1M tokens）。对于平均每条 100 tokens 的 10,000 条记忆，约 $0.02 — 可忽略不计。</p>\n<h3>冷启动</h3>\n<p>在配置嵌入之前存储的记忆没有嵌入。请运行 <code>POST /memory/embed-batch</code> 补齐。</p>\n<h3>提供方依赖</h3>\n<p>如果嵌入提供方宕机，语义搜索会优雅降级（返回空结果或错误）。FTS5 仍可正常工作。</p>\n<h2>当嵌入不可用时</h2>\n<p>如果未配置嵌入服务：</p>\n<ul>\n<li><code>GET /memory/semantic-search</code> 返回 503 Service Unavailable</li>\n<li><code>POST /memory</code> 仍可正常工作（只是不生成嵌入）</li>\n<li>FTS5 搜索仍可正常工作</li>\n</ul>\n<h2>最佳实践</h2>\n<div class=\"callout callout-ok\"></div><h2>下一步</h2>\n<ul>\n<li><a href=\"/docs/concepts/fts5-search\">FTS5 搜索</a></li>\n<li><a href=\"/docs/api/memory\">Memory API</a></li>\n<li><a href=\"/docs/concepts/architecture\">架构</a></li>\n</ul>\n","urls":{"html":"/docs/concepts/semantic-search","text":"/docs/concepts/semantic-search?format=text","json":"/docs/concepts/semantic-search?format=json","llm":"/docs/concepts/semantic-search?format=llm"},"translations_available":["en","zh","hi","es","fr","ar","pt","ru","ja","de","it","ko","nl","pl","tr","sv","vi","th","id","uk"]}