Dayward AI
Week 1 · D1About 4 hours

Why Retrieve at All: Hallucination, Knowledge Cutoffs, and the Cost of Long Context; a Minimal Keyword-Only RAG

First get clear on the three specific problems Retrieval-Augmented Generation actually solves for a model, weigh it against fine-tuning and very long context on cost and fit, then write your first working question-answering system with BM25 scoring, without touching a single vector.

Today's goals 0/3

Sign in to tick these off and save your progress.

Today's Goals

  1. State in one sentence that Retrieval-Augmented Generation solves knowledge freshness, factual attribution, and context cost, and give one scenario where it shouldn't be used
  2. Draw the five stages of Retrieval-Augmented Generation — chunking, indexing, retrieval, context assembly, generation — and explain how each stage can fail
  3. Hand-write a BM25 scoring function and explain what term-frequency saturation and document-length normalization each guard against

Today installs no vector store, calls no embedding endpoint, and pulls in no framework: about three hundred lines of code get a complete question-answering path running. Once you have read this and finished the lab, scroll back to the top and tick off the three goals.

Plain-Language Walkthrough

Why an open-book exam beats memorizing, and costs less

Picture two exams. The first is closed-book: you memorize the whole textbook and answer from memory. However well you memorized, three problems remain — the textbook was revised last year and you did not know; where your memory is fuzzy you instinctively smooth out an answer that looks plausible; and asked by the marker which page supports that, you cannot say. The second is open-book: you memorize nothing and practice one thing only — hearing the question, quickly judging which page to turn to, reading that page properly, writing the answer from it, and marking the page number after it.

This course is about doing well in the second kind of exam from beginning to end. Its formal name is Retrieval-Augmented Generation (RAG): when a user asks, first fetch the most relevant passages from an external library of material, hand them to the model with the question, and have the model answer strictly from those passages. The model is still the same model; what changed is what it has at hand while answering.

Where does open-book win? In three very concrete things. Change one line in the library and the next question reflects it immediately, with nothing retrained; an answer can be traced to a specific passage, so a problem can be investigated; and each question carries only the relevant passages to the desk rather than the entire library, which differs by an order of magnitude on the token bill. Those three are knowledge freshness, factual attribution, and context cost — the first judgment to build today, and every day of the next thirteen is about making those three solid.

This analogy runs through the whole course, so map the words now: the corpus is the collection, chunking is cutting whole books into entries, the index is the card catalog, retrieval is fetching a book from the shelf by the catalog, reranking is the librarian picking again from the armful you fetched, a citation is a reference at the end of a paper, and refusal is saying "I could not find it" after searching the catalog rather than inventing an entry.

The model's three ailments are exactly three bills

Break the vague claim that a model is not enough into three verifiable phenomena.

The first ailment is the knowledge cutoff. A model's knowledge comes from its training data and it knows nothing that happened after training ended. Ask about the expense policy your company revised last week and it can only answer from the old version, in the same confident tone it uses for everything else. That is not the model being dim; it simply has no channel through which to know.

The second ailment is hallucination. A model works by predicting the most likely next word, and most likely and true are two different things. When it is unsure, what comes out is not "I do not know" but a passage that looks very much like a correct answer — right format, right terminology, confident tone, and invented content. That is far more dangerous than the first: a knowledge cutoff is a definite boundary and hallucination has none.

The third ailment is the absence of attribution. Even when it answers correctly this time, you do not know on what basis, and cannot point the answer back to source material you could check. For personal use that is merely inconvenient; for an enterprise knowledge base, support, or legal work, where the evidence is often matters more than whether the answer is right — a correct answer with no evidence cannot be used in a process.

Those three ailments correspond to three bills: the bill for updating knowledge, the bill for errors, and the bill for tokens. Every technical choice from today on gets settled against those three.

Three roads: retrieval, fine-tuning, and stuffing the whole book in

Making a model know something it originally did not has three engineering roads, each with its own cost curve.

The first is fine-tuning: continue training the model on your data, welding the knowledge into the parameters. It is good at teaching a model a style or a format — writing weekly reports in the company's voice, emitting fields in a fixed schema. It is bad at instilling facts: any change means retraining on a timescale of days, and even after training there is still no attribution.

The second is stuffing the whole book into the context: with windows now running to hundreds of thousands of tokens, a small knowledge base genuinely can go in whole. The upside is almost no engineering; the downside is paying for all the material on every single question, with latency rising with input length. Worse, as material grows, a model's reliability at locating key information in a long context declines — you will see it read without reading.

The third is retrieval: material lives outside and only the relevant passages are fetched each time. Changing material means changing a file, effective immediately; cost depends only on the passages fetched rather than the library's total size; and every passage carries an id so the answer can cite. The price is building a retrieval system yourself, and that system will itself make mistakes — the next thirteen days are mostly about that.

Choosing is not one of three but a question of what you lack. Lacking how to say something, fine-tune; lacking what to know, retrieve; and the two are frequently used together. As for when not to retrieve: if your task does not depend on external facts at all — rewriting a passage more concisely, converting code from one style to another — forcing retrieval in only adds noise, latency, and cost. The criterion is one sentence: would this task's answer change if a document changed? If not, you do not need retrieval.

Five stages, five ways to break

A retrieval-augmented generation system has only five stages, strung left to right:

TextText
Source documents → 1 chunking → 2 indexing → 3 retrieval → 4 context assembly → 5 generation → a cited answer

The beginner's most common error is treating that chain as a black box and, when something goes wrong, saying only that the model answered badly. In fact each stage has its own typical failure with very different symptoms:

  • Chunking broke: a complete rule was cut in half, the first clause in one chunk and the second in the next. Retrieval hit one of them, and that one alone is incomplete or even misleading. The symptom is a half-right answer.
  • Indexing broke: parsing was not clean, table rows crossed, headers and footers mixed into the body. The symptom is obviously irrelevant material in the retrieval results.
  • Retrieval broke: the correct answer never entered the candidates. This is the most fatal, because no later stage can help — what is not in the material, the model can only invent. The symptom is an off-topic answer or confident nonsense.
  • Context assembly broke: the material was right but the prompt's ordering got scrambled, it got truncated, or "answer only from the material below" was left out. The symptom is the model ignoring the material and answering from prior knowledge.
  • Generation broke: material complete, instructions clear, and the model still missed a line or attributed one passage's number to another. The symptom is citation ids that do not match their content.

The way to use that table: investigate right to left, fix left to right. Right to left because the generated result is what you see first; left to right because errors on the left get amplified on the right, and no prompt rescues what retrieval failed to fetch. Day 8 turns this into quantifiable metrics; today, build the habit of attributing by stage.

Getting keyword retrieval solid: BM25 term by term

Now build stage 3. No vectors at all today — instead an algorithm settled in the 1990s and still standard in every retrieval system: BM25.

Start from the plainest idea: the more often a question's words appear in a document, the more likely it is relevant. That is term frequency. But frequency alone has a large hole — words like "the," "we," and "company" are everywhere and their counts say nothing about relevance. So each term needs a weight measuring how rare it is, which is inverse document frequency: a word appearing in only 2 documents is highly informative when it hits, and one appearing in 28 says essentially nothing.

Tokenize first. Chinese has no spaces and cannot be split on whitespace as English can. In a dependency-free setting the most economical approach is bigrams: cut a CJK run into overlapping two-character tokens, cut the same word in the query the same way, and they match without a dictionary. The price is roughly one token per character and an index twice the size — entirely irrelevant for thirty documents.

tokenize.js
// CJK runs are cut into bigrams; letters and digits are cut into words; punctuation and whitespace separate
const SEGMENT = /[\u4e00-\u9fff]+|[a-z0-9]+/gu
const CJK = /^[\u4e00-\u9fff]+$/u
 
export function tokenize(text) {
  const tokens = []
  const segments = text.toLowerCase().match(SEGMENT) ?? []
  for (const seg of segments) {
    if (CJK.test(seg)) {
      if (seg.length === 1) {
        tokens.push(seg)
        continue
      }
      for (let i = 0; i + 1 < seg.length; i += 1) tokens.push(seg.slice(i, i + 2))
    } else if (seg.length > 1) {
      // A single letter or digit has almost no discriminating power; dropping them saves a lot of index
      tokens.push(seg)
    }
  }
  return tokens
}

With tokens comes the inverted index: not which words a document contains but the reverse — which documents each word appears in, and how often. Retrieval then only has to score the candidate documents for the query's few terms rather than scanning the whole library. That is the value of a card catalog.

Then BM25 itself. The full formula looks like this:

TextText
score(D, Q) = Σ  idf(t) · ( f(t,D) · (k1 + 1) ) / ( f(t,D) + k1 · (1 - b + b · |D| / avgdl) )
             t∈Q
 
idf(t) = ln( 1 + (N - n(t) + 0.5) / (n(t) + 0.5) )

Intimidating, and it is only three parts.

The first part is the inverse document frequency, idf. N is the total document count and n(t) is how many contain this term. The rarer the term, the larger the numerator and the higher the weight. The ln around it compresses the magnitude, and the added 1 keeps the score from going negative when n(t) exceeds half the documents. This term brings stop-word behavior for free: with no stop-word list, a word like "the" pushes itself to near zero.

The second part is term-frequency saturation, controlled by k1. Note that f appears in both numerator and denominator, so the fraction approaches an upper bound as f grows rather than growing without limit. What does it guard against? Against an article writing "recycle bin" fifty times to dominate the ranking. Fifty times really is more relevant than five, and it should never be ten times as relevant. A smaller k1 saturates faster; at 0.2, appearing twice and appearing twenty times score almost the same.

The third part is length normalization, controlled by b. Long documents hit keywords by chance more easily — treat a whole book as one document and it can match almost any query. This term divides the document's length by the average to scale over-long documents back proportionally. At b of 0, length is ignored entirely; at 1, it is fully penalized; and 0.75 is the compromise long practice settled on and the default in nearly every implementation.

bm25.js
// idf: the fewer documents a term appears in, the more persuasive a hit on it is
export function idf(index, term) {
  const n = index.postings.get(term)?.size ?? 0
  return Math.log(1 + (index.docCount - n + 0.5) / (n + 0.5))
}
 
export function scoreDoc(index, docId, queryTerms, { k1 = 1.2, b = 0.75 } = {}) {
  const len = index.lengths.get(docId) ?? 0
  const norm = 1 - b + (b * len) / index.avgLength // the length term does not depend on the word; compute it once
  let score = 0
  for (const term of queryTerms) {
    const f = index.postings.get(term)?.get(docId) ?? 0
    if (f === 0) continue
    score += (idf(index, term) * (f * (k1 + 1))) / (f + k1 * norm)
  }
  return score
}

The last stage is context assembly. Having fetched the top three passages, three things must happen while composing the prompt, and omitting any one produces the corresponding failure in today's lab: give each passage a citable id, write the citation rule into the instruction, and explicitly permit refusal. The third is the most often forgotten and is precisely the main gate against hallucination.

prompt.js
export function buildPrompt(question, passages) {
  const system = [
    'You are the knowledge base assistant for Skyladder Technologies. Answer only from the material below.',
    'When the material contains no answer, reply with exactly: The material contains nothing that supports an answer.',
    'Mark every conclusion with the source it came from in square brackets, in the form [doc-006].',
    'If two passages contradict each other, list both claims with their update dates rather than picking one.',
  ].join('\n')
 
  const context = passages
    .map((p) => `[${p.id}] (updated ${p.updated}) ${p.title}\n${p.body}`)
    .join('\n\n---\n\n')
 
  return { system, user: `Material:\n\n${context || '(none)'}\n\nQuestion: ${question}` }
}

Why the first version uses no vectors

You may be asking: the world talks about nothing but vector search, so why does day one write an algorithm from thirty years ago?

Three reasons. First, it is explainable. Every point of a BM25 score decomposes into which term contributed how much, so when the ranking is wrong you can see on the spot whether it is a frequency problem or a rarity problem. Vector search hands you a similarity of 0.83 and no idea where to start when it goes wrong. Second, zero dependencies: no embedding endpoint, no vector store, no GPU, running in two minutes and reproducible on a laptop with no network. Third, and most importantly — it is the baseline.

A baseline is not the version you make do with; a baseline is a ruler. Over the next thirteen days you will add vectors, hybrid search, reranking, and query rewriting, each of which costs money, adds latency, and adds a failure point. What justifies any of it? Only one answer: against the baseline, how much did the metric rise, how much did latency rise, and how much did the money rise. Three bills, and missing one means it does not count.

BM25 also does something vectors cannot: exact matching. Document ids, error codes, personal names, model numbers — vectors often "understand" these into something semantically nearby, while BM25 goes by the letter. That is why on day 9, when we cover hybrid search, the keyword path is not dropped but run alongside the vector path and fused — what you write today lives all the way to the last day.

Today's lab shows the baseline's two real shortcomings: when an answer is split across two documents, BM25 fetches only one of them (the multi-hop problem, handled on day 12); and when two documents give different conclusions about the same thing, it takes both without knowing which to believe (the conflicting material problem, handled on day 6). Seeing the shortcomings is today's takeaway, because each of the following days patches one of them.

Source Reading

Hands-On Lab

🧪 D1 lab: a minimal question-answering script using BM25 retrieval and citing its sources, with no vector store

Code location: labs/rag-14days/day-01-bm25-mini-rag

Acceptance criteria:

  1. Running offline prints the top three for all 9 baseline questions, each line carrying a score, document id, title, and department, and writes baseline.json at the end.
  2. For b01 (the maximum size of a single upload) the top two are both doc-024 and doc-006, with both ids appearing in the answer — you have seen two passages contradict each other with your own eyes.
  3. For b03 (who approves a failover) doc-019 is hit, but the answer stops at "the platform team lead" and doc-014 never enters the top three — the live scene of pure keyword retrieval failing a multi-hop question.
  4. For b08 (the team outing budget) it reaches a refusal, while b09 (expensing a phone bill) still assembles a stretch of irrelevant content — showing the score threshold blocks one class of question and not the other.
  5. Change K1 from the default 1.2 to 5 and rerun: b04's third place changes from doc-022 to doc-014; change it to 0.2 and rerun: b07's second and third swap.

The lab directory already holds a fictional corpus of thirty documents — the product manual, internal policies, technical documentation, support Q&A, and meeting notes of a company called Skyladder Technologies. The same corpus is used for all thirteen remaining days, so it is worth five minutes of browsing, especially doc-005 with its mangled table and doc-024 whose support answer disagrees with the product manual; they were left there deliberately.

starter/ has four exercise points cut out: tokenization, inverse document frequency, BM25 scoring, and score threshold filtering. Run as-is, every question shows not one term matched — because the default tokenizer splits on whitespace, which is useless for Chinese, and that is your first task. No API key is needed to finish it all offline; offline mode replaces only the final generation with template assembly, and the first four stages genuinely run.

  1. Read three to five documents in corpus/ first and make sure you know what the corpus does and does not contain, since that determines what questions you can ask.
  2. Complete the tokenizer and the inverted index, run again, and watch retrieval go from not one term matched to a scored top three.
  3. Switch scoring to full BM25, compose the top three into the prompt, and complete one question-answer round, seeing an id such as [doc-006] in the answer.
  4. Ask b08 and b09, two questions with no answer in the corpus, and watch one blocked by the score threshold while the other invents regardless; work out which layer is responsible for each.
  5. Adjust K1 and B once each and rerun the baseline, comparing the changes in the top three, then keep the default-parameter baseline.json as the reference for the next thirteen days.

Interview Questions

Today's 4 questions are in the question bank below, weighted toward retrieval-augmented generation versus fine-tuning and the limits of long context, the meaning of the BM25 formula, and the failure modes of each stage in the minimal system. Expand each one and read the analysis before the key points — practicing the derivation beats memorizing bullets. The high-frequency labels for the domestic and overseas markets are there so you can pick by target market.

Checklist and Tomorrow

  • State in one sentence that Retrieval-Augmented Generation solves knowledge freshness, factual attribution, and context cost, and give one scenario where it shouldn't be used
  • Draw the five stages of Retrieval-Augmented Generation — chunking, indexing, retrieval, context assembly, generation — and explain how each stage can fail
  • Hand-write a BM25 scoring function and explain what term-frequency saturation and document-length normalization each guard against
  • Explain why investigation runs right to left and fixes run left to right, and use it on one real wrong answer
  • All 5 acceptance criteria of the lab pass, with baseline.json generated and kept
  • Answer at least 3 of the 4 interview questions without looking at the key points

Tomorrow (D2) we give the system its other eye: embeddings and vector search. Today's BM25 goes by the letter, so rephrasing the same question leaves it stumped; vectors turn similar in meaning into near in coordinates, which covers exactly that gap. Learning keywords before vectors is deliberate — start with vectors and you come to believe retrieval simply is computing similarity, never again remembering that exact matching exists; whereas with a baseline in hand, every improvement tomorrow can be measured on the spot.

Interview questions

  • When should you use retrieval-augmented generation, when should you fine-tune, and when is stuffing the documents into the context window good enough?什么时候该用检索增强生成,什么时候该微调,什么时候直接把文档塞进上下文就够了?
    Common in ChinaCommon overseasBasic#rag-basics#fine-tuning#long-context

    How to reason about it · think before answering

    1. This question shows up in almost every loop. The differentiator is not reciting three definitions, it is offering a decision rule the interviewer can reuse.
    2. Lead with the rule: is the model missing knowledge, or missing a way of speaking? Missing knowledge means retrieval; missing style or output shape means fine-tuning. That single cut covers most cases.
    3. Then line up the three options against three costs: cost of updating knowledge, cost per request, and whether the answer can be traced back to a source. Retrieval updates by editing a file, fine-tuning takes a retraining cycle, and long-context pays for the whole corpus on every call.
    4. Give long-context its fair case: when the corpus is small, changes rarely, and request volume is low, stuffing it in is the cheapest engineering decision you can make. It stops being cheap once the corpus grows or the same material is queried thousands of times a day.
    5. Close by naming when none of this applies: if the answer does not depend on any external document (rewriting, translating, reformatting), retrieval only adds noise, latency and cost.
    6. Expected follow-up: can you do both? Yes, and it is common. Fine-tuning controls format and refusal behavior, retrieval supplies the facts.

    分析过程 · 先想清楚再作答

    1. 这题几乎每场都问,区分度不在能不能背出三条定义,而在你会不会给一条判据。只说「RAG 适合动态知识、微调适合特定风格」的人一抓一大把,面试官等的是下一句。
    2. 先给一条能当场套用的判据:模型缺的是「知道什么」还是「怎么说」。缺知识走检索,缺风格与输出格式走微调,这一刀切下去能分掉八成场景。
    3. 再拿三笔账把三条路排开:知识更新的代价(改文件立刻生效 / 重训以天计 / 改文件立刻生效)、单次成本(只付取回的几段 / 只付推理 / 每次都付全量材料)、能不能归因(能 / 不能 / 能但材料一多定位会飘)。
    4. 把上下文直塞的适用边界说清楚:材料总量小、更新不频繁、对单次成本不敏感的场景它最划算,因为工程量近乎为零。一旦材料涨到几百篇,或者同一批材料每天要被问上万次,成本曲线立刻反超。
    5. 最后主动补一句「什么时候都不该用检索」——任务的答案不依赖任何外部文档时(改写、翻译、格式转换),加检索只会引入噪声、延迟和成本。能主动划出不该用的边界,比会背适用场景更能证明你做过。
    6. 可预期的追问:能不能既微调又检索?答案是可以,而且常见——微调管输出格式与拒答口径,检索管事实,两者解决的不是同一个问题。

    Key points

    • One rule: retrieval for missing knowledge, fine-tuning for a missing way of speaking.
    • Retrieval updates instantly by editing files, supports citation, and costs scale with the retrieved passages rather than the corpus.
    • Fine-tuning is good at locking in style and output schema, poor at loading facts, and offers no traceability.
    • Long-context stuffing wins when the corpus is small, stable and queried infrequently; it loses on cost and on locating facts once the corpus grows.
    • If the answer does not depend on any document, use none of them.

    答题要点

    • 一条判据:缺「知道什么」用检索,缺「怎么说」用微调。
    • 检索改文件即时生效、可归因、成本只跟取回的几段有关,代价是要自己建一套会出错的检索系统。
    • 微调擅长固化风格与输出格式,不擅长灌事实:数据一变就要重训,而且没法归因。
    • 长上下文直塞在小型、低频、少变的语料上最划算,材料变多或调用量变大之后成本与定位稳定性都会恶化。
    • 任务答案不依赖外部文档时三条路都不该用,直接调模型。
  • In BM25, what problems do term-frequency saturation and document length normalization each solve? What happens if you set both k1 and b to zero?BM25 里的词频饱和与文档长度归一化分别在解决什么问题?把 k1 和 b 都设成 0 会发生什么?
    Common in ChinaCommon overseasIntermediate#bm25#ranking#information-retrieval

    How to reason about it · think before answering

    1. This checks whether you have actually read the formula rather than merely called a library. The test is whether you can map k1 and b onto specific terms and name the failure each one prevents.
    2. Start with the two holes in raw term frequency: keyword stuffing lets one document dominate by repeating a word, and long documents win by accident because they contain more words overall.
    3. k1 closes the first hole. Term frequency appears in both numerator and denominator, so the ratio approaches a ceiling instead of growing linearly. Fifty mentions are more relevant than five, but not ten times more relevant. A smaller k1 saturates sooner.
    4. b closes the second. The normalization factor is one minus b plus b times document length over average length: at b equal to zero length is ignored entirely, at one it is fully penalized, and 0.75 is the conventional compromise.
    5. Now the trap in the question: k1 equal to zero collapses the ratio to a constant, so one occurrence scores the same as a hundred and matching becomes boolean. b equal to zero removes length entirely. Set both to zero and BM25 degenerates into a plain sum of inverse document frequencies.
    6. Expected follow-up: can you drop the IDF term? No. Without it, ubiquitous words drown everything else, and it is precisely IDF that lets BM25 work without a stopword list.

    分析过程 · 先想清楚再作答

    1. 这题考的是你有没有真的读过公式,而不是有没有调过库。判据很明确:能不能把 k1 和 b 各自对应到公式里的哪一项,并说出去掉之后会被什么样的文档钻空子。
    2. 先说朴素词频的两个漏洞:一是重复刷词,一篇文章把关键词写五十遍就能霸榜;二是长文占便宜,文档越长越容易蒙中查询里的词。这两个漏洞正好对应两个修正。
    3. k1 管第一个漏洞。分子分母里都有词频 f,所以词频涨上去之后整个分式趋近一个上界而不是线性增长——写五十遍确实比写五遍相关,但绝不该相关十倍。k1 越小饱和越快。
    4. b 管第二个漏洞。归一化项是 1 减 b 加上 b 乘以本文长度除以平均长度,b 等于 0 时完全不看长度,b 等于 1 时完全按长度比例惩罚,0.75 是长期折中的默认值。
    5. 回到题干那个陷阱:k1 设成 0 会让分式退化成常数,词出现一次和一百次得分完全一样,等于只剩「有没有出现过」的布尔匹配;b 设成 0 则长度信息彻底消失。两个一起设成 0,BM25 就退化成对逆文档频率求和,跟词频再无关系。
    6. 可预期的追问:那逆文档频率去掉行不行?答案是不行,去掉之后「的」「我们」这类高频词会淹没一切——而且要顺带说明 BM25 因此天然不需要停用词表,这一句最能体现你读懂了公式。

    Key points

    • k1 controls saturation and prevents keyword stuffing: the score approaches a ceiling rather than growing linearly with frequency.
    • b controls length normalization and stops long documents from winning by sheer word count.
    • Setting k1 to zero degenerates the scorer into boolean matching; one occurrence scores the same as a hundred.
    • Setting b to zero removes document length from the equation entirely; both at zero leaves only a sum of IDF terms.
    • IDF is the third component: it up-weights rare terms and removes the need for a stopword list.

    答题要点

    • 词频饱和由 k1 控制,防的是重复刷词:词频涨大后得分趋近上界而非线性增长。
    • 长度归一化由 b 控制,防的是长文档靠词多蒙中查询,用本文长度比平均长度把它压回去。
    • k1 设 0 会退化成布尔匹配,词出现一次和一百次同分;b 设 0 则完全不考虑文档长度。
    • 两者都设 0 时 BM25 只剩逆文档频率求和,等于放弃了词频信息。
    • 逆文档频率是第三块,让稀有词权重更高,也让 BM25 天然不需要停用词表。
  • A retrieval-augmented generation system gave a wrong answer. How do you determine whether retrieval or generation is at fault?一个检索增强生成系统答错了,你怎么定位是检索的锅还是生成的锅?
    Common in ChinaCommon overseasIntermediate#debugging#failure-modes#evaluation

    How to reason about it · think before answering

    1. The question asks how you localize the fault, not what the possible causes are. Listing causes loses; the interviewer wants an ordered procedure that ends in concrete actions.
    2. Give the cheapest first step: print the retrieved passages verbatim and read them. If the correct answer is not in there, retrieval is at fault. If it is in there and the model ignored it, generation is at fault. Thirty seconds, and it removes most of the guesswork.
    3. Then lay out the five stages — chunking, indexing, retrieval, context assembly, generation — with the rule: diagnose right to left, fix left to right. You see the generated answer first, but an error on the left is amplified by everything to its right.
    4. Add symptoms that pin down a stage: half-correct answers usually mean a rule was split across chunks; obviously irrelevant hits usually mean dirty parsing; the model ignoring the supplied material usually means the prompt never said it must; citation numbers that do not match their content point at generation.
    5. Land it in engineering terms: to run this procedure repeatedly you must log the retrieved hits, the passages that entered the context, and the final answer together, otherwise production issues are unreproducible. At scale this becomes a fixed question set with metrics rather than case-by-case reading.
    6. Expected follow-up: if retrieval missed the document, will prompt tuning help? No. Nothing in the prompt can conjure material that was never supplied.

    分析过程 · 先想清楚再作答

    1. 题眼在「怎么定位」,不在「有哪些原因」。答成一串可能原因的罗列就输了,面试官想听的是一个有先后顺序、能落到具体动作的排查流程。
    2. 先给最省时间的第一步:把这次检索出来的几段原文原样打印出来,自己读一遍。正确答案不在里面就是检索的锅,在里面而模型没用上才是生成的锅。这一步三十秒,能省掉大半天的瞎猜。
    3. 然后把链路展开成五个环节——切块、建索引、检索、组装上下文、生成——并给出「排查从右往左、修复从左往右」这条口径:从右往左是因为你最先看到的是生成结果,从左往右是因为左边的错会被右边放大。
    4. 补充几个能把环节钉死的症状:答案「半对」多半是切块把一条完整规则切断了;检索结果里混着一眼不相干的东西多半是解析没做干净;模型无视材料用先验知识作答,通常是提示词里少了「只能依据资料回答」;引用编号和内容对不上,那是生成侧漏读或串了行。
    5. 最后落到工程做法:这套排查要能重复做,就必须把每次请求的检索结果、进上下文的段落、最终回答一起记下来,否则线上出问题时你根本复现不了。到了要批量做的时候,就得换成一批固定问题加指标,而不是一条条人工看。
    6. 可预期的追问:如果检索确实没捞到,改提示词有没有用?答案是没用——材料里没有的东西,再好的指令也只能换一种编法。这句话最能证明你分清了两层。

    Key points

    • Always start by printing the retrieved passages and checking whether the correct answer is present at all.
    • Split the pipeline into chunking, indexing, retrieval, context assembly and generation; diagnose right to left, fix left to right.
    • Use symptoms to pin the stage: half-correct answers point at chunking, irrelevant hits at parsing, ignored material at the prompt, mismatched citations at generation.
    • If retrieval missed the document, prompt changes cannot help; the material simply is not there.
    • Log retrieved hits, the passages that entered the context, and the final answer together, or production failures are unreproducible.

    答题要点

    • 第一步永远是把检索出来的原文打印出来读一遍,判断正确答案在不在里面。
    • 把链路拆成切块、建索引、检索、组装上下文、生成五个环节,排查从右往左、修复从左往右。
    • 用症状钉环节:半对多半是切块问题,混入无关结果多半是解析问题,无视材料多半是提示词缺约束,引用与内容对不上是生成问题。
    • 检索没捞到时改提示词没有意义,材料里没有的东西模型只能编。
    • 要能重复排查就必须把检索结果、进上下文的段落和最终回答一起记录下来。
  • Context windows are now in the millions of tokens. Does that make the retrieval step obsolete?上下文窗口已经做到上百万 token 了,检索这一步会被淘汰吗?
    Common in ChinaCommon overseasDeep dive#long-context#cost#system-design

    How to reason about it · think before answering

    1. This is a position question and it is easy to answer as a binary. The signal is whether you separate what fits technically from what is worth paying for on every request.
    2. Concede the valid half first: bigger windows genuinely absorb part of the use case. For an internal tool over a few dozen stable documents with low traffic, stuffing everything in is the right call and building a retrieval stack would be over-engineering.
    3. Then give three reasons it does not absorb the rest. Cost is the first: context is billed per request, so the same corpus is paid for on every one of ten thousand queries, whereas retrieval only pays for the passages it returns. Prompt caching softens this but does not remove it.
    4. Scale is the second: enterprise corpora run to hundreds of thousands of documents and no window holds them. Attribution and access control are the third: pointing an answer at a specific passage, and showing each user only what they are permitted to see, both have to happen before the material reaches the model.
    5. Add the empirical point: as the supplied material grows, models become less reliable at locating the one relevant fact inside it. More context is not automatically better; fewer and more precise passages often win.
    6. Expected follow-up: does retrieval change shape? Yes. Larger windows allow bigger chunks and more of them, which relieves pressure on reranking and compression. Retrieval gets coarser, it does not disappear.

    分析过程 · 先想清楚再作答

    1. 这是一道立场题,容易答成非黑即白。判断你有没有做过的地方在于:会不会区分「技术上能不能塞进去」和「工程上该不该每次都塞」,只谈前者的答案一听就是纸上谈兵。
    2. 先承认对方有道理的部分:窗口变大确实吃掉了检索的一部分场景。几十篇文档、更新不频繁、调用量不大的内部工具,直接全塞是最省事的选择,为它建一套检索系统是过度设计。
    3. 再给三条它吃不掉的理由。第一是成本:材料是按次计费的,同一份材料被问一万次就要付一万次,而检索只付取回的那几段;预填充缓存能缓解但不能消除,缓存也有有效期和命中率。
    4. 第二是规模:企业知识库动辄几十万篇,再大的窗口也塞不下,检索是唯一的入口。第三是归因与权限:答案要指回具体某一段,以及不同的人只能看到自己有权访问的材料——这两件事必须在把材料喂给模型之前完成,窗口再大也不解决。
    5. 还要补一条经验事实:材料变多之后,模型在长上下文里定位关键信息的稳定性会下降,出现「读了但没读到」。所以「全塞」并不总是等于「效果更好」,很多时候少而准反而更好。
    6. 可预期的追问:那检索的形态会不会变?会——窗口变大之后,取回的块可以更大、条数可以更多,重排与压缩的压力变小,检索从「精挑几句」变成「粗筛一批」。趋势是检索的粒度变粗,不是检索消失。

    Key points

    • Separate whether it fits from whether it is worth paying for on every request.
    • Small, stable, low-traffic corpora can legitimately be stuffed whole; building retrieval for them is over-engineering.
    • Three reasons retrieval survives: per-request cost, corpora too large for any window, and attribution plus access control that must happen before the model sees the material.
    • More supplied context reduces the reliability of locating a single fact, so stuffing everything is not automatically better.
    • The trend is coarser retrieval — bigger chunks, more of them, less reranking pressure — not the removal of retrieval.

    答题要点

    • 先区分「能不能塞进去」和「该不该每次都塞」,前者是技术问题,后者是成本问题。
    • 小规模、低频、少变的语料确实可以直接全塞,为它建检索系统是过度设计。
    • 检索不会被淘汰的三个理由:按次计费的成本、几十万篇塞不下的规模、必须在喂给模型之前完成的归因与权限过滤。
    • 材料越多,模型定位关键信息的稳定性越差,全塞不等于效果更好。
    • 趋势是检索粒度变粗——块更大、条数更多、重排压力变小,而不是检索消失。

Comments