· 12 min read 🍿

Where the answers come from

Part 5 of a series from six weeks building AI systems by hand: an operator going beneath the abstractions, on purpose. These posts carry more machinery than executive writing usually does. That’s deliberate.

In week three I asked a system I had built a counting question: how many of Project Orion’s weekly status updates flagged it At Risk. It answered three. Three was correct. I refused to score it a pass.

Part 3 ended on a finding and promised it a post of its own: the quality of an answer is set less by the model than by what the evidence layers feed it. This is that post, told through the corpus builds, where the finding cut deepest. The failures worth writing about were invisible from the answers: the trouble lived underneath, in what was searched for and what came back, and the answer never once told me.

The setting was week three’s build: retrieval-augmented generation, RAG — a corpus embedded so the system can search it by meaning and hand the best passages to the model as evidence. Mine was the internal documentation of a fictional infrastructure company: 450 documents of the messy, shared-drive kind, seeded with lookalike decoys, chunked to 2,616 passages, each embedded as a vector so that a query retrieves its nearest semantic neighbours. The test questions came with answer keys naming the exact documents that hold each answer: the gold documents. The index was wrapped as a tool, search_redwood_docs, that the agent loop from part 3 could call as often as it judged necessary. And one line of my config sets the window everything else must fit through: SEARCH_K = 5, five chunks per search — chosen deliberately, on the reasoning that an agent can always search again. Five, and no more.

The lucky answer

The Orion question needed six documents: six weekly updates, three of which flag At Risk. The search came back with every one of its five slots filled with gold documents. Perfect precision, and arithmetic that cannot work: six documents do not fit through a five-slot window. The agent read the five it had, counted three At-Risk weeks, and answered. It never noticed the series was incomplete. It searched once, and never went back. Nothing in five weekly updates says how many weeks exist.

The sixth week happened to be On Track. A sixth At-Risk week sitting outside the window would have made the same confident “Three” wrong. The process could not have told the difference, because nothing it retrieved said the series went on. So the verdict I logged that evening was lucky: right answer, broken process. My own answer key had been wrong first — I had written “gold: three docs” in my notes when the label listed six. The labeller has to count what the agent must see, not what the answer says.

WHY “THREE” WAS LUCKY · THE k=5 WINDOW weekly 01-16 · At Risk weekly 01-23 · At Risk weekly 02-06 · At Risk ranks 1–3 — the query says “At Risk”, and risk-saturated updates rank first weekly · On Track weekly · On Track ranks 4–5 k=5 — retrieval stops here weekly 02-13 · On Track below the cut — never seen; happened to agree recall 5 of 6  ·  answer “Three” matches gold  ·  verdict LUCKY

The query said At Risk, so the three At-Risk weeks ranked highest — those documents are saturated with risk language — and the same mechanism pushed the one upbeat week out of the window. Helpful luck, and luck all the same.

The operating consequence: spot-checking answers cannot catch this class of failure, and spot-checking answers is how most AI deployments get checked. Retrieval needs its own score — which gold documents did the system actually see — with lucky as a verdict distinct from correct. The stakes are structural: the engineering course’s claim, which my sprint kept illustrating, is that some 80% of RAG failures are retrieval failures. Retrieval sets a ceiling the generator cannot rescue.

Four searches, wrong shelf

The hardest question of the sprint had no answer key at all: the normal condition in a real company, where labelled questions are the luxury. Which team received the most follow-up actions across the corpus’s twenty-five incident postmortems? The agent searched four times, retrieved seven documents, and refused to answer. Every one of the seven was a document about the postmortem process: templates, playbooks, ownership guides. Zero of the twenty-five actual postmortems. The first query, verbatim from the trace, shows why:

search_redwood_docs · call #1 of 4 · the agent's own query, from the trace
team with most follow-up actions across incident postmortems follow-up actions per team postmortem follow-ups 'follow-up actions' 'incident postmortems' 'most'
Four searches in this register returned seven process documents between them — and zero of the twenty-five postmortems that held the answer.

Embedding search retrieves by proximity: it finds what sounds like the question. That is its power, and this query is its failure surface. Every word comes from the question’s own aggregate register, and no postmortem is written in that register: each one describes a single incident and never says “follow-up actions across”. The quoted phrases are keyword tactics on a semantic engine, which reads the quote marks as just more characters. Nothing had ever told the model what kind of search sat behind its tool, so it used the grammar it knew. The cheapest repair in the whole incident is a sentence in the tool’s description: name the engine, and say queries should read like the passages you want back. On the third search the agent did the sophisticated thing and reused vocabulary from its earlier results. The borrowed words came from the wrong shelf, so the reformulation dug further into the same trap. Bad first results poison the escape route, and retrying is not diversity: different phrasings of the same register land in the same neighbourhood.

THE GENRE TRAP · EMBEDDING SPACE, SCHEMATIC documents about the process templates · playbooks · ownership guides × q1 × q2 × q3 × q4 all four searches land here — the reformulations borrowed this cluster’s own vocabulary semantic distance the 25 postmortems “streaming stalls” · “latency spike” each about one incident, in its own vocabulary holds the answer · never retrieved

Beneath the queries sits a harder truth: perfect search could not have answered this. Ninety-six follow-up items spread across twenty-five documents do not flow through a top-k pipe, however the question is phrased. Aggregation over a corpus is a query — enumerate and tally, in code — not a retrieval. Orion was the small dose of the same disease, six documents nearly fitting through k=5, the failure invisible and the answer lucky; this was the full dose, and the failure undeniable. And the refusal was the discipline holding: the agent had process documents in hand and declined to name a team from them. A worse-behaved system answers confidently here, and nobody ever knows.

Then I tallied the real answer myself, agent-assisted, with the counting rule fixed before I started. A tie, twenty-five each for two teams, and a fragile one: seven items name people rather than teams, and merging one sub-team into its parent, or not, changes the winner. The question sounds like it has one answer. It has one per rulebook, and someone has to own the rulebook.

The answer was in there the whole time, and so was everything else the suite missed that week. A credentials question dropped three of six gold documents: one at rank seven, just outside the k=5 window, two filed under vocabulary nobody asking the question would use. The knowledge existed, in a corpus I controlled.

Your AI doesn’t have a knowledge problem. It has a filing problem, and the filing is the part you own.

Where knowledge should live

Each failure above has a fix, and the prices span from a config edit to a standing engineering programme:

THE FIXES  ·  CHEAPEST FIRST
The near miss
a gold document at rank 7 — raise k from five to eight
ONE INTEGER
The vocabulary miss
hybrid search — semantic plus keyword, so exact names still match — and a corpus filed under the words people ask with
CORPUS WORK
The aggregation
enumerate and tally in code — a query, not a search
CODE
Facts in the weights
keep facts in the corpus, not the model — a fine-tuned fact is stale the day its source changes
LAST RESORT

Two rules govern the spend. Raising k is not free depth: more context is noise, not knowledge, and even the brute-force end of that road fails. Models start degrading at 60–70% of their stated context window, long before “just give it everything” runs out of room. And training facts into the model, the fix that surfaces first on most roadmaps, is the most expensive dial on the panel and the wrong one for facts: the model cannot tell you where it learned something, and updating it means owning a model lifecycle forever. I order the fixes cheapest first, and touching the model comes last, usually never. The model is rented intelligence; the corpus is owned knowledge. In most organisations nobody owns it, and the retrieval failures land on whoever trusted the answer.

The artefacts to ask for

Three things I now ask of any system that claims to answer from evidence, mine or a vendor’s. The retrieval score, separate from the answer score: which gold documents did it see, and does the grading have a verdict for lucky. The query log: not which sources the report cites, but what was asked in order to find them. And behind any aggregate number, the rulebook that makes the answer singular, with the name of the person who set it.

What changed for me is the reading order. The answer used to be the artefact. Now it is the last thing I read, because the answer is the one part of the pipeline that cannot tell you when the evidence failed. I start where the answers come from.

COO in energy, previously Twitter and Stripe. I build what I write about.

Comments