Everyone will tell you that building a RAG (Retrieval-Augmented Generation) assistant means signing up for Pinecone, Weaviate, or spinning up pgvector. I want to show you the counter-example I run in production: the AI assistant on my robotics platform, roboturfs.ca, answers customer questions every day with no vector database at all—just MariaDB, Gemini embeddings, and a cosine-similarity function that fits in ten lines of PHP.
This isn't a toy. It retrieves knowledge, quotes live inventory and prices, captures leads, and books appointments. Here's how it works, why I built it this way, and honestly when you should not copy me.
What RAG actually requires (less than you think)
Strip away the hype and RAG needs exactly four things:
- Chunks of your content (knowledge-base entries, docs, FAQs)
- An embedding per chunk—a list of numbers that captures its meaning
- A way to find the nearest chunks by meaning when a question arrives
- A prompt that pastes those chunks in and tells the model to answer only from them
Notice what's missing: nothing in that list says "dedicated vector database." A vector DB is a scaling optimization, not a requirement of the pattern.
My setup
-
Embeddings: Google's
gemini-embeddingat 256 dimensions. One API call per chunk. -
Storage: each chunk lives in a plain MariaDB table (
kb_chunks (id, title, content, embedding)) with the embedding cached as JSON in a column. - Lazy embedding: chunks are embedded on first use, then cached forever. Add a new knowledge chunk to the table today, the assistant knows it today—no reindexing pipeline, no deploy.
- Retrieval: brute-force cosine similarity over every chunk, in PHP, at request time. Top 4 chunks win.
- Corpus size: a few hundred chunks.
The entire "vector search engine"
This is the actual production code:
php
function cosine(array $a, array $b): float {$dot = $na =$nb = 0.0;
$n = min(count($a), count($b));
for ($i = 0; $i <$n; $i++) {$dot += $a[$i] * $b[$i];
$na +=$a[$i] *$a[$i];$nb += $b[$i] * $b[$i];
}
return ($na && $nb) ?$dot / (sqrt($na) * sqrt($nb)) : 0.0;
}
Top comments (0)