The RAG pipeline in detail

Last updated: June 26, 2026

What RAG actually means

RAG -- Retrieval-Augmented Generation -- is the pattern that makes modern AI assistants factually grounded. Instead of asking the language model to recall rules from training data (it was never trained on your game rulebook), I retrieve the relevant text at query time and hand it to the model as context.

The critical benefit: the model can only cite what I give it. It cannot hallucinate rules that are not in the chunks.

Loading diagram...

Each node in this diagram is a real function call. There is no magic -- just a well-engineered sequence.

Query expansion

Before embedding the question, I run it through the corpus-analyzer service. This uses BERTopic topic models built on the actual content of community forums to expand the query with related terms. A question like "can I take back a move" gets expanded with related phrases from the game domain vocabulary, improving recall. Query expansion uses Claude Haiku 4.5.

Question categories

The extraction step classifies every question into one of 7 categories, which determines which synthesis template is used:

CategoryDescriptionExample
YES_NOPermissibility and legality questions"Can I attack on my first turn?"
RULE_EXPLANATIONHow a rule works"How does flanking work?"
PROCEDURALStep-by-step actions"How do I set up the game?"
OVERVIEWHigh-level summaries"How does the combat system work overall?"
EDGE_CASEAmbiguous or interaction rules"What happens if both players run out of cards?"
MULTI_QUESTIONMultiple distinct questions"Can I move through walls, and can I carry items?"
COUNT_ENUMERATIONTotals and complete listings"How many growth cards are there?"

COUNT_ENUMERATION was added specifically to handle questions that ask for a quantity or a complete list of a discrete game element. These route to a dedicated synthesis template that states the total first, then enumerates from the relevant table or list. A component list or table that contains the answer is treated as a found answer — not a "no result" just because the answer is structured data rather than prose.

Context assembly

Retrieval matches on small passages — precise targets for a specific rule. After ranking, I assemble context from the surrounding sections those passages belong to, not just the passages themselves. This means the language model sees each matched rule in its natural context rather than as an isolated fragment.

Context is assembled from two pools:

  • Prose sections: up to 8 parent sections, ordered by best child passage score
  • Table sections: up to 4 table sections (component lists, card tables) with their own budget, not competing against prose sections

This two-budget approach means a large component table doesn't crowd out the prose rules that govern how those components are used — and a relevant table isn't dropped just because highly-scored prose sections consumed the cap first.

I cap context at roughly 3,000 tokens — enough to cover the passages and their parent sections for 3–6 distinct rules. If the question explicitly spans multiple rules sections, I use the multi-question synthesis template which handles longer context differently.

Hybrid retrieval and reranking

Retrieval is not purely vector-based. Each search combines cosine similarity with BM25 keyword matching. A per-PDF BM25-floor reservation ensures a strongly-matched source is never dropped even if its cosine score sits slightly below the cutoff — so a game with a single highly relevant section won't be edged out by a game with more but weaker matches.

After the hybrid search returns candidates, a deterministic LLM reranker (Claude Haiku 4.5) scores each passage against the original question. This step catches mismatches that cosine similarity alone would miss — for example, a passage that uses similar vocabulary but discusses a different game mechanic.

Tier 1 vs Tier 2 comparison

DimensionTier 1Tier 2
Source materialOfficial rulebook onlyRulebook + community threads
Context size~3,000 tokens~6,000-10,000 tokens
Synthesis modelGemini 3 FlashGemini 3 Flash (deeper reasoning prompt)
Latency5-7s7-35s
Use caseClear rules questionsEdge cases, interpretation, exceptions
Citation types[PDF][PDF] + [T] community threads

The corpus analyzer

The corpus-analyzer service (port 3481) runs BERTopic and CADA to:

  1. Classify the question into one of the 7 categories above
  2. Expand the query with domain-specific synonyms
  3. Detect ambiguous terms that need disambiguation

The category drives which synthesis YAML template I use — count/enumeration questions get a different prompt than yes/no questions, and edge-case questions get a different prompt than procedural ones.