{"slug": "vectorai-db-doesn-t-embed-your-text-and-that-s-the-point", "title": "VectorAI DB Doesn't Embed Your Text, and That's the Point", "summary": "A developer built a local knowledge base on Actian VectorAI DB, emphasizing that the database does not embed text but stores vectors and runs nearest-neighbor searches. The project separates concerns: an embedding model handles language understanding, VectorAI DB stores vectors and payloads, n8n acts as a trigger, and an optional LLM answers questions using retrieved excerpts. The developer tested the system with six notes, including a distractor, and demonstrated that semantic search correctly ranks relevant results.", "body_md": "**Building a small local knowledge base on top of Actian VectorAI DB, the actual challenge wasn't the database. It was easy to accidentally fake semantic search, and just as easy to reach for automation tools, or an LLM, in the wrong place. Here's the split that fixed it, plus the grounded answer step I added on top of search. The full build is on GitHub.**\n\nThe first pass at this stored a single note and searched for that same note. It \"worked,\" in the sense that the top result was always right. That doesn't prove anything about semantic search: with one point in the database, of course it wins.\n\nThe other early version chained four n8n HTTP Request nodes straight into the database. That's not using n8n for anything; it's a `curl`\n\ncommand dressed up as a workflow.\n\nBoth come from the same mistake: not being clear on what each tool is actually for.\n\n| Layer | Job | Not its job |\n|---|---|---|\nEmbedding model (`all-MiniLM-L6-v2` ) |\nTurn text into a 384-number vector | Storage, search, answering |\n| Actian VectorAI DB | Store vectors + payload, run nearest-neighbor search | Embed text, call an LLM, talk to Slack |\n| n8n | Trigger a search from Slack, a form, a webhook | Own the vectors |\n| Optional LLM | Answer a question using only the retrieved excerpt text | See vectors, talk to VectorAI directly |\n\nOnce that's the frame, the fix is straightforward: give the embedding model a real corpus, let VectorAI DB just be the store, and only bring n8n in as a trigger.\n\nSix notes: five on-topic, one deliberate distractor about campus cafe hours. If a search demo can't tell \"how do I start the database\" from \"what does the cafe serve,\" it isn't doing much. Real queries against the running container:\n\n| Query | Expected top result | Score |\n|---|---|---|\n| How do I start the database with Docker? | Start VectorAI DB | 0.466 |\n| What's the prize track at PEC Hacks? | PEC Hacks 4.0 track | 0.668 |\n| How many vectors can I store for free? | Community Edition limits | 0.481 |\n| Does VectorAI embed text for me? | Embeddings are your job | 0.619 |\n| What does the campus cafe serve? | Campus cafe hours | 0.582 |\n\nNo cafe question beat a Docker or pricing question. These scores are cosine similarity, not percentages: treat 0.466 as \"clearly the best match among the options,\" not \"47% confident.\"\n\nA brand-new note, added through the UI and searched for right away, also came back correctly. VectorAI DB's upsert blocks until the point is indexed by default, so that's a real upsert-then-retrieve, not a cached result.\n\n**The embedding model does the language understanding, not the database.** VectorAI DB never sees a search string; every insert and every search is a float array, and its length has to match whatever size the collection was created with:\n\n```\nPUT /collections/kb\nContent-Type: application/json\n\n{\"vectors\":{\"size\":384,\"distance\":\"Cosine\"}}\n```\n\nGet the dimension wrong and it says so plainly:\n\n```\nUpsert failed: Dimension mismatch for vector '': expected 1536, got 3\n```\n\nThat error shows up fast if you swap embedding models without recreating the collection.\n\n**The payload holds the human-readable text.** Each vector carries a `title`\n\nand `text`\n\nalongside it, so a search result comes back readable, not just an ID and a score to look up elsewhere.\n\n**n8n only makes sense as a trigger.** What's actually built is three nodes: a webhook, an HTTP call to the app's `/api/search`\n\n, and a response back. On its own, that's not doing much more than `curl`\n\n.\n\nThe value shows up when the trigger changes and nothing else does. Swap the webhook for a Slack trigger or a form submission, and the same search logic still runs; only the front door changes. The Slack version isn't built for this demo, so there's nothing to show running yet, but that's the actual case for n8n here: it makes adding a second or third way to trigger the same search cheap.\n\nRanked hits are still excerpts, and most people want a sentence, not a list. `/api/answer`\n\nreuses the exact same search, then hands the top few excerpts to an LLM with one rule: answer only from what search returned, and say the knowledge base doesn't cover it rather than guess.\n\nWorth being precise about what this is and isn't. VectorAI DB still only ever sees float vectors; it has no idea an LLM exists. The app calls search, gets back `title`\n\n/`text`\n\npayloads, and only those payloads go into the prompt, never the vectors, never anything outside them. Without an API key, the endpoint doesn't error; it returns the same ranked hits with `\"answer\": null`\n\n, so the base demo has zero dependency on an LLM being available.\n\nThe check that mattered: asking something the seeded notes don't cover, or a cafe question when the answer should come from the database, and confirming the model says it can't find that rather than inventing something plausible-sounding. If retrieval is wrong or the corpus doesn't have the answer, generation shouldn't be able to paper over that.\n\nThe six-note demo is a stand-in. Swapping in a different corpus doesn't touch the plumbing:\n\n`/api/answer`\n\nalready does this for the six-note demo, and the same prompt-and-refuse pattern carries over.Different corpus, sometimes a different trigger. Same architecture.\n\nEach point's ID is a hash of the note's text, so re-saving a note with the same wording overwrites the same point. Edit the wording, even slightly, and it's treated as a new point: the old version doesn't get cleaned up, it just sits there, still searchable, still a possible top result. Decide early whether edits should replace or version, and delete the stale point explicitly if you want replace.\n\nThis is small and local on purpose. It hasn't been pushed anywhere near the 5,000-vector ceiling on Community Edition, and there's no auth or TLS in front of it, so it's not production-ready as-is. [Fork the repo](https://github.com/gerimate/vectorai-n8n-demo), swap the corpus, pick a trigger, and the pattern holds.", "url": "https://wpnews.pro/news/vectorai-db-doesn-t-embed-your-text-and-that-s-the-point", "canonical_source": "https://dev.to/gerimate/vectorai-db-doesnt-embed-your-text-and-thats-the-point-3n34", "published_at": "2026-08-27 16:04:36+00:00", "updated_at": "2026-08-27 16:18:45.272079+00:00", "lang": "en", "topics": ["artificial-intelligence", "machine-learning", "developer-tools", "ai-infrastructure"], "entities": ["Actian VectorAI DB", "n8n", "all-MiniLM-L6-v2", "PEC Hacks", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/vectorai-db-doesn-t-embed-your-text-and-that-s-the-point", "markdown": "https://wpnews.pro/news/vectorai-db-doesn-t-embed-your-text-and-that-s-the-point.md", "text": "https://wpnews.pro/news/vectorai-db-doesn-t-embed-your-text-and-that-s-the-point.txt", "jsonld": "https://wpnews.pro/news/vectorai-db-doesn-t-embed-your-text-and-that-s-the-point.jsonld"}}