{"title":"Semantic Search (Embeddings)","slug":"semantic-search","category":"concepts","summary":"Conceptual memory search using vector embeddings — find by meaning, not just keywords.","audience":["human","llm"],"tags":["concept","semantic","embeddings","vector-search"],"difficulty":"advanced","updated":"2026-06-27","word_count":513,"read_minutes":3,"lang":"en","translated":true,"requested_lang":"en","content_markdown":"\n# Semantic Search (Embeddings)\n\nSynapse supports semantic search using vector embeddings. Unlike FTS5 (keyword\nmatching), semantic search finds memories by **meaning** — even if no keywords\nmatch.\n\n## How It Works\n\n```\n1. Memory stored → embedding generated → vector stored\n2. Search query → embedding generated → vector compared\n3. Cosine similarity → top N results returned\n```\n\n### What are embeddings?\n\nEmbeddings are numerical vector representations of text. Text with similar\nmeaning has similar vectors. Synapse generates a vector (e.g. 1536 dimensions)\nfor each memory's content.\n\n### Cosine similarity\n\nTo find semantically similar memories, Synapse computes the cosine similarity\nbetween the query vector and each memory vector. Higher similarity = more\nrelevant.\n\n## When to Use Semantic Search\n\n### Use semantic search when:\n\n- You want \"memories about X\" where X is described differently than stored\n- FTS5 returns no results (no keyword match)\n- You want conceptual grouping (e.g. all \"deployment\" memories, even if some say \"release\")\n- Query is a question: \"how do we handle authentication?\"\n\n### Use FTS5 when:\n\n- You know exact keywords\n- You need boolean logic (AND, OR, NOT)\n- You need sub-millisecond response\n- You want phrase matching\n\n## Endpoint\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\nResponse:\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## Examples\n\n### Find deployment memories\n\n```bash\n# FTS5 might miss some — semantic catches all\ncurl .../memory/semantic-search?q=deployment+process\n```\n\nReturns memories about \"deployment\", \"release\", \"publishing\", \"rolling out\",\netc.\n\n### Find authentication patterns\n\n```bash\ncurl .../memory/semantic-search?q=how+do+users+log+in\n```\n\nReturns memories about login, auth, JWT, session management, OAuth, etc.\n\n### Find similar memories\n\n```bash\n# Find memories similar to a specific one\ncurl .../memory/related/mem_001\n```\n\nUses semantic similarity (via shared tags AND embedding vectors).\n\n## Embedding Generation\n\n### When are embeddings generated?\n\n- **On memory store** — if embeddings service is configured, embedding is generated synchronously\n- **Batch generation** — `POST /memory/embed-batch` generates embeddings for memories missing them\n- **Async updates** — when content is updated, embedding is regenerated\n\n### Embedding providers\n\nSynapse supports configurable embedding providers:\n\n- **OpenAI** (`text-embedding-3-small`, `text-embedding-3-large`)\n- **Local models** (via Ollama or similar)\n- **Custom** (implement the embeddings interface)\n\nConfigure via environment variables:\n\n```bash\nEMBEDDINGS_PROVIDER=openai\nEMBEDDINGS_API_KEY=sk-...\nEMBEDDINGS_MODEL=text-embedding-3-small\n```\n\n### Batch generation\n\nFor minds with many memories missing embeddings:\n\n```bash\n# Generate embeddings for up to 100 memories\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# Check progress\ncurl -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n     https://synapse.schaefer.zone/memory/embed-batch-status\n```\n\n## Performance\n\n| Operation | Latency |\n|-----------|---------|\n| Generate embedding (OpenAI) | 100-200ms |\n| Semantic search (1k memories) | 50-100ms |\n| Semantic search (10k memories) | 200-500ms |\n| Batch generation (100 memories) | 10-20s |\n\n> [!NOTE]\n> Semantic search is slower than FTS5 due to vector computation. Use FTS5\n> for known keywords, semantic for conceptual queries.\n\n## Limitations\n\n### Embeddings cost\n\nIf using OpenAI, generating embeddings costs money (~$0.02 per 1M tokens\nfor text-embedding-3-small). For 10,000 memories averaging 100 tokens each,\nthat's ~$0.02 — negligible.\n\n### Cold start\n\nMemories stored before embeddings were configured won't have embeddings. Run\n`POST /memory/embed-batch` to backfill.\n\n### Provider dependency\n\nIf the embeddings provider is down, semantic search fails gracefully (returns\nempty results or error). FTS5 still works.\n\n## When Embeddings Aren't Available\n\nIf embeddings service is not configured:\n\n- `GET /memory/semantic-search` returns 503 Service Unavailable\n- `POST /memory` still works (just no embedding generated)\n- FTS5 search still works\n\n## Best Practices\n\n> [!TIP]\n> - **Use semantic for conceptual queries** — \"how do we handle X?\"\n> - **Use FTS5 for specific terms** — \"docker swarm\"\n> - **Backfill embeddings regularly** — `POST /memory/embed-batch`\n> - **Monitor provider health** — semantic search depends on it\n> - **Combine with tags** — semantic + tag filter narrows results\n\n## Next Steps\n\n- [FTS5 Search](/docs/concepts/fts5-search)\n- [Memory API](/docs/api/memory)\n- [Architecture](/docs/concepts/architecture)\n","content_html":"<h1>Semantic Search (Embeddings)</h1>\n<p>Synapse supports semantic search using vector embeddings. Unlike FTS5 (keyword\nmatching), semantic search finds memories by <strong>meaning</strong> — even if no keywords\nmatch.</p>\n<h2>How It Works</h2>\n<pre><code class=\"hljs language-plaintext\">1. Memory stored → embedding generated → vector stored\n2. Search query → embedding generated → vector compared\n3. Cosine similarity → top N results returned</code></pre><h3>What are embeddings?</h3>\n<p>Embeddings are numerical vector representations of text. Text with similar\nmeaning has similar vectors. Synapse generates a vector (e.g. 1536 dimensions)\nfor each memory&#39;s content.</p>\n<h3>Cosine similarity</h3>\n<p>To find semantically similar memories, Synapse computes the cosine similarity\nbetween the query vector and each memory vector. Higher similarity = more\nrelevant.</p>\n<h2>When to Use Semantic Search</h2>\n<h3>Use semantic search when:</h3>\n<ul>\n<li>You want &quot;memories about X&quot; where X is described differently than stored</li>\n<li>FTS5 returns no results (no keyword match)</li>\n<li>You want conceptual grouping (e.g. all &quot;deployment&quot; memories, even if some say &quot;release&quot;)</li>\n<li>Query is a question: &quot;how do we handle authentication?&quot;</li>\n</ul>\n<h3>Use FTS5 when:</h3>\n<ul>\n<li>You know exact keywords</li>\n<li>You need boolean logic (AND, OR, NOT)</li>\n<li>You need sub-millisecond response</li>\n<li>You want phrase matching</li>\n</ul>\n<h2>Endpoint</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>Response:</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>Examples</h2>\n<h3>Find deployment memories</h3>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># FTS5 might miss some — semantic catches all</span>\ncurl .../memory/semantic-search?q=deployment+process</code></pre><p>Returns memories about &quot;deployment&quot;, &quot;release&quot;, &quot;publishing&quot;, &quot;rolling out&quot;,\netc.</p>\n<h3>Find authentication patterns</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>Returns memories about login, auth, JWT, session management, OAuth, etc.</p>\n<h3>Find similar memories</h3>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># Find memories similar to a specific one</span>\ncurl .../memory/related/mem_001</code></pre><p>Uses semantic similarity (via shared tags AND embedding vectors).</p>\n<h2>Embedding Generation</h2>\n<h3>When are embeddings generated?</h3>\n<ul>\n<li><strong>On memory store</strong> — if embeddings service is configured, embedding is generated synchronously</li>\n<li><strong>Batch generation</strong> — <code>POST /memory/embed-batch</code> generates embeddings for memories missing them</li>\n<li><strong>Async updates</strong> — when content is updated, embedding is regenerated</li>\n</ul>\n<h3>Embedding providers</h3>\n<p>Synapse supports configurable embedding providers:</p>\n<ul>\n<li><strong>OpenAI</strong> (<code>text-embedding-3-small</code>, <code>text-embedding-3-large</code>)</li>\n<li><strong>Local models</strong> (via Ollama or similar)</li>\n<li><strong>Custom</strong> (implement the embeddings interface)</li>\n</ul>\n<p>Configure via environment variables:</p>\n<pre><code class=\"hljs language-bash\">EMBEDDINGS_PROVIDER=openai\nEMBEDDINGS_API_KEY=sk-...\nEMBEDDINGS_MODEL=text-embedding-3-small</code></pre><h3>Batch generation</h3>\n<p>For minds with many memories missing embeddings:</p>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># Generate embeddings for up to 100 memories</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\"># Check progress</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>Performance</h2>\n<table>\n<thead>\n<tr>\n<th>Operation</th>\n<th>Latency</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>Generate embedding (OpenAI)</td>\n<td>100-200ms</td>\n</tr>\n<tr>\n<td>Semantic search (1k memories)</td>\n<td>50-100ms</td>\n</tr>\n<tr>\n<td>Semantic search (10k memories)</td>\n<td>200-500ms</td>\n</tr>\n<tr>\n<td>Batch generation (100 memories)</td>\n<td>10-20s</td>\n</tr>\n</tbody></table>\n<div class=\"callout callout-note\">Semantic search is slower than FTS5 due to vector computation. Use FTS5\nfor known keywords, semantic for conceptual queries.</div><h2>Limitations</h2>\n<h3>Embeddings cost</h3>\n<p>If using OpenAI, generating embeddings costs money (~$0.02 per 1M tokens\nfor text-embedding-3-small). For 10,000 memories averaging 100 tokens each,\nthat&#39;s ~$0.02 — negligible.</p>\n<h3>Cold start</h3>\n<p>Memories stored before embeddings were configured won&#39;t have embeddings. Run\n<code>POST /memory/embed-batch</code> to backfill.</p>\n<h3>Provider dependency</h3>\n<p>If the embeddings provider is down, semantic search fails gracefully (returns\nempty results or error). FTS5 still works.</p>\n<h2>When Embeddings Aren&#39;t Available</h2>\n<p>If embeddings service is not configured:</p>\n<ul>\n<li><code>GET /memory/semantic-search</code> returns 503 Service Unavailable</li>\n<li><code>POST /memory</code> still works (just no embedding generated)</li>\n<li>FTS5 search still works</li>\n</ul>\n<h2>Best Practices</h2>\n<div class=\"callout callout-ok\"></div><h2>Next Steps</h2>\n<ul>\n<li><a href=\"/docs/concepts/fts5-search\">FTS5 Search</a></li>\n<li><a href=\"/docs/api/memory\">Memory API</a></li>\n<li><a href=\"/docs/concepts/architecture\">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"]}