What we're building

A function that chunks a document (Lesson 4), embeds every chunk (Lesson 2), and holds the results in one Python list. That list is this lesson's vector store, deliberately the simplest possible one: nothing gets saved to disk, and there's no library involved beyond the embedding call itself.

A vector store is simpler than the name suggests

"Vector store" and "vector database" sound like specialized infrastructure, and at scale, they are (this repo's pgvector course covers a real one). But at its core, a vector store is just a collection of records, each one pairing a piece of text with its embedding:

[{"text": chunk, "embedding": vector}, ...]

That's genuinely it. Everything a real vector database adds on top (persisting to disk, indexing for fast search over millions of records, metadata filtering) is optimization layered on top of this same idea, not a fundamentally different one. Building the plain-list version first means Lesson 20's jump to chromadb later in this course will feel like a natural next step, not a black box.

The code, piece by piece

response = client.models.embed_content(
model=EMBEDDING_MODEL,
contents=texts,
...
)

Lesson 2 passed a single string wrapped in a one-item list to contents. Here, texts is already a list of every chunk, embedded in one network call instead of one call per chunk. This matters for two reasons: it's faster (one round trip instead of five), and it uses up far less of the free tier's requests-per-minute quota, which counts calls, not chunks. From here on, this course always embeds in batches like this wherever more than one piece of text needs embedding.

return [{"text": chunk, "embedding": vector} for chunk, vector in zip(chunks, vectors)]

zip pairs up the original chunks list with the vectors list the embedding call returned, position by position (the first chunk with the first vector, and so on, since embed_content preserves input order). The result is the list-of-dicts vector store described above.

Checkpoint

  • vector store: a collection of {text, embedding} records, nothing more at its core, no matter how much infrastructure sits on top of that idea in a real system.
  • batch embedding: passing every chunk to embed_content in one call (contents=texts) instead of one call per chunk, faster and much friendlier to rate limits.
  • This in-memory list is what Lesson 6 searches over, and what Lesson 20 eventually replaces with chromadb.

If anything here still feels unclear, ask before moving to Lesson 6.