← chapter

Vector store and retrieval

Chapter 10 · the search loop, given a home

The hour

Why not just a loop?

Two things break at scale:

A vector store fixes both.

add() + search()

class VectorStore:
    def add(self, docs):
        vecs = self._embed([d["text"] for d in docs])
        for d, v in zip(docs, vecs):
            self._items.append({**d, "vec": v})

    def search(self, query, k=3, where=None):
        qv = self._embed([query])[0]
        pool = [it for it in self._items
                if not where or matches(it, where)]
        return top_k_by_cosine(qv, pool, k)

Two design choices

"Like this query, but only billing, only this customer, only since March."

Where the toy ends

Still a linear scan. A real database (pgvector, Qdrant, Pinecone) adds:

Same add / search interface.

Put it to work — three views

One shared store.py; only the corpus + query differ.

The rule that grows teeth

The embedding model is part of your schema.

Change it → every stored vector is meaningless → re-embed the whole corpus. Version it.

Takeaway

A vector store is add() + search() with vectors kept beside the text. You now have RAG's retrieval half. Next: hand the passages to a model and answer from them, with citations.