JJoeven

Projects/RAG Customer Support Agent/Part 2

Chunk the Handbook

Split a small handbook into overlapping chunks with stable ids, headings carried into the chunk text, and no empty slices.

Chunking is the unglamorous half of RAG quality. Embeddings cannot retrieve a fact that you split in half or buried in a 4,000-token blob. This part writes a deterministic chunker for a tiny handbook: split on headings, then pack sentences into windows with overlap.

What a chunk must contain

  • Stable id chunk-01, chunk-02, … zero-padded so lexicographic sort matches order.
  • text used for embedding and for citation display.
  • heading copied into the text prefix so "Refunds" context is not lost when a sentence is generic ("within 14 days").
  • start/end character offsets into the original handbook (debugging).

Do not use a random uuid. Ids must be stable across runs for evals.

Strategy for a tiny doc

  1. Split on lines matching # Heading.
  2. Inside each section, split into sentences on . .
  3. Pack sentences until len(text) >= 180 or the section ends.
  4. Overlap: last sentence of chunk N starts chunk N+1 when the section is long enough.

For Joeven's handbook, each heading may already be one chunk. That is OK. Still write the packer so a longer FAQ later does not become one vector.

What not to do

  • Chunk by raw text[i:i+200] through the middle of a word — unless you also overlap a lot. Sentence boundaries are cheaper.
  • One chunk for the whole handbook — cosine still "works" but citations are useless and distractors pollute.
  • Drop headings. Isolated sentences like "Burst above that returns HTTP 429" need the rate-limit heading.
Live Pythonpython
Output
Run to execute this in your browser. Nothing is sent to a server.

Step-by-step quality checks

  1. Print every chunk. Read them. If a refund sentence sits in the mug chunk, fix the splitter.
  2. Assert no empty text.
  3. Assert ids unique and sequential.
  4. Assert each heading appears in at least one chunk.
  5. Keep chunk count small (5–12). If you have 80 chunks on a 1-page doc, your target length is too small.

Overlap tradeoff

Overlap helps questions whose answer straddles a boundary. Too much overlap duplicates vectors and can crowd top-k with the same section. For a handbook, heading-based sections + light overlap is the sweet spot.

Versioning

When the handbook changes, rebuild the index and bump a doc_version integer stored next to chunks. Answers should cite version in traces. You will not build a diff indexer here; just store DOC_VERSION = 1.

Note:Character offsets are optional in the Try it box but useful when you later highlight the source in a UI.

Exercise

Add a sentence to Refunds that is long enough to force two chunks in that section (target=80). Confirm overlap kept the connecting sentence. Confirm mug refunds did not merge into API refunds.

Check your understanding

Why copy the section heading into each chunk's text?