Dayward AI
Week 2 · D11About 5 hours

Advanced Indexing: Parent-Child Documents, Summary Indexes, Contextual Retrieval, and the Trade-Offs of Tree Aggregation vs. Graph Retrieval

The same set of documents can support several index structures. Today implement parent-child and summary indexes, land contextual retrieval — a technique with a very good cost-to-benefit ratio — then explain exactly what problems tree-based recursive aggregation and graph retrieval each solve, what they cost, and when not to use them.

Today's goals 0/3

Sign in to tick these off and save your progress.

Today's Goals

  1. Implement parent-child and summary indexes, and explain which category of question each makes answerable
  2. Land contextual retrieval: add contextual descriptions to each chunk, and work out the one-time cost of building the index
  3. Explain what problems tree-based recursive aggregation and graph retrieval each solve, and under what conditions their cost isn't worth it

Yesterday's effort went into what happens after a query arrives; today switches sides: the query stays and the index changes. Come back and tick off the three goals.

Plain-Language Walkthrough

One book, several catalogs

A thick book usually has more than one listing: contents by chapter at the front, a subject index at the back. Not one word of the book changed; what changed is what the cards are filed by. For what chapter seven covers, the contents are fastest; for every mention of the recycle bin, the subject index is.

Retrieval is the same. For ten days we built one index: cut documents into chunks, one entry each, and search that set. That works for a question like how many days the retention period is, and has almost nothing for another three kinds:

  • The hit chunk is too small and the model sees half a sentence (context completeness);
  • A chunk lost its belonging when cut, so alone it does not say whose retention period (chunk self-sufficiency);
  • The question wants a summary of the whole store rather than a few passages (global questions).

Today builds several more catalogs over the same documents so each of those three has somewhere to go. The index structure changes and the retriever needs not one line changed — the precondition for every comparison here.

Which raises the question: with three indexes built over one corpus, what decides which one a query takes?

Parent-child indexes: the retrieval unit and the context unit need not be the same

Day four's chunking left one sentence hanging: small chunks retrieve precisely, large chunks give complete context, and can we have both. The answer is yes, by making them different things.

Cut by heading node into large chunks called parents, and cut a parent into 200-character small chunks called children. Only children enter the index, with parents kept aside and hung by parentId; retrieval hits a child and context assembly swaps it for its parent — like a catalog card reading "row 3, slot 2" while what you fetch by the card is a whole book.

mdxmdx
Child (indexed, 200 chars)  →  hit  →  swapped by parentId for the parent (into context, a whole section)
parent-child.js
// A parent = one heading node; a child = that section cut into 200-character pieces
export function chunkParentChild(doc) {
  const children = []
  const parents = new Map()
 
  doc.nodes.forEach((node, i) => {
    const parentId = `${doc.docId}#p${String(i + 1).padStart(2, '0')}`
    const heading = node.headingPath.join(' > ')
    parents.set(parentId, { chunkId: parentId, text: `${heading}\n${node.text}` })
 
    // A child's head also carries the heading path, matching the flat-chunk convention
    for (const part of splitLong(node.text, 200, 40)) {
      children.push({
        docId: doc.docId,
        chunkId: `${doc.docId}#k${String(children.length + 1).padStart(2, '0')}`,
        text: `${heading}\n${part}`,
        parentId, // the key: a child knows which parent it belongs to
      })
    }
  })
  return { children, parents }
}

What is easy to get wrong is not the cutting but the assembly. One parent is often hit by several children, and stuffing them in by rank puts the same passage in three times, exhausting a 600-token budget on two chunks. So deduplicate parents, and skip a duplicate by continuing to the next entry rather than stopping — other parents wait behind it.

The cost is more index entries (134 chunks becoming 158 on this corpus) and larger pieces entering the context: trading index volume and context budget for chunk completeness, not something for nothing.

A caution: this evaluation set cannot measure parent-child indexing's benefit. Single-document recall is already 100% under every configuration, and the material completeness parent-child restores does not show in a binary did-the-answer-document-enter metric. Matching the baseline does not mean it is useless, only that this ruler cannot measure it — that needs a different ruler, such as a model judge deciding whether the material suffices.

Summary indexes: locate the book first, then the page

The second catalog is for many long documents: generate a hundred-word summary per document and index only the summaries. A query searches the summaries first, locates the three to five most relevant documents, and then searches finely within those.

The benefit is direct: ten thousand documents make hundreds of thousands of chunk-level entries and only ten thousand summary entries; in production the second stage needs no separate index, since a vector store filter on document id suffices.

And it is a net loss on our corpus: baseline recall 93.8% against the summary index's 87.5%; multi-hop falls from 75% to 50% and the answer document's average rank retreats from 2.44 to 3.63.

The first stage keeps only three documents, and if either of a multi-hop question's two documents looks irrelevant at the summary level, it is cut in stage one and no accuracy in stage two recovers it. The computation it saves is paid for entirely by stage one possibly cutting wrongly. Remember the criterion as one sentence: a summary index starts paying off only once the document count makes whole-store chunk-level retrieval itself the bottleneck; before that it merely manufactures a recall ceiling for itself.

Contextual retrieval: add a locating line per chunk, then look honestly at the numbers

The third catalog is the most widely circulated technique lately, and its method is one line: have the model read the whole document and write, for each chunk, one line saying which part of the document it is, prefixed to the chunk before indexing.

"The retention period is 30 days" alone tells nobody whose retention period; prefix "Drive and File Management, Recycle Bin:" and a query about how long the recycle bin keeps things can match it.

contextual-header.js
// The cache breakpoint goes after the whole document: from the second chunk on you pay only the cache read price
const res = await client.messages.create({
  model: 'claude-sonnet-5',
  max_tokens: 100,
  messages: [
    {
      role: 'user',
      content: [
        { type: 'text', text: `Full text:\n${doc.body}`, cache_control: { type: 'ephemeral' } },
        { type: 'text', text: `One passage from it:\n${chunk.text}\n\n${INSTRUCTION}` },
      ],
    },
  ],
})
// The header goes only into the indexed text, never into the text entering the context
const indexText = `${res.content[0].text.trim()}:\n${chunk.text}`

The order cannot be reversed: caching matches by prefix, so the whole document comes first; put per-chunk content first and the prefix changes every time and the cache never hits.

Now the numbers. Day four measured a counter-intuitive result under pure BM25: adding headers left the hit rate unchanged, raised index tokens by a tenth, and pushed the answer document's average rank back from 2.88 to 3.25. The explanation was that a header spreads a document's heading terms across every chunk, lowering their own inverse document frequency and diluting keyword retrieval; and the note then was that its benefit should be on the vector side. Today settles that bill.

Split context into three levels and run each on three retrieval routes (30 documents, a 20-question golden set, chunk-level retrieval, a 600-token budget, offline hash vectors):

Retrieval routeRecall ①→②→③Answer document average rank ①→②→③nDCG@10 ①→②→③
Pure BM2593.8% → 93.8% → 93.8%2.44 → 2.44 → 2.440.5854 → 0.6753 → 0.7312
Pure vector81.3% → 81.3% → 87.5%3.75 → 2.94 → 3.000.4152 → 0.5088 → 0.6185
Hybrid93.8% → 93.8% → 93.8%2.44 → 2.44 → 2.440.5530 → 0.6438 → 0.7218

① is a bare chunk, ② is a chunk whose head carries the heading path, and ③ is a chunk with a generated header. Index tokens go from 15,638 to 18,036 to 22,339 along the way. ② corresponds to day nine's configuration, except the heading path is prefixed once — day nine's implementation prefixed it twice, so this chapter's absolute numbers are not strictly comparable with days eight and nine, and only relative differences within this chapter should be read.

Three conclusions, each less like marketing than the last:

First, the vector route rises on its own, and that rise proves nothing. Pure vector recall goes from 81.3% to 87.5% and nDCG@10 from 0.5088 to 0.6185. The problem is that offline mode's "vector" is a hash vector preserving literal overlap — its rise shows only that the header added more literally matchable words, not that a real embedding becomes more accurate for having semantic context. Those two look alike and are not the same thing.

Second, day four's rank regression did not reproduce. Pure BM25's average rank is 2.44 at all three levels. The difference is the chunking: day four hard-cut at 400 characters so boundaries did not align with sections and headers pulled in heading terms not belonging to that chunk; today cuts by heading node, so a chunk sits inside one section and the header overlaps heavily with what it already has. So the conclusion is not that headers harm BM25 but that they harm it when chunk boundaries do not align with structure — the precondition matters more than the conclusion.

Third, on the hybrid route, headers buy ranking quality and not recall. Recall stays at 93.8% and the answer document's average rank stays at 2.44, with only nDCG@10 rising from 0.6438 to 0.7218. Pick the wrong metric and this whole passage gives the opposite conclusion: watching nDCG alone suggests a 12.1% gain, and watching recall alone suggests it did nothing.

Costs go in two ledgers, and this is the section's most practical passage.

The one-time build: 30 documents, 134 chunks. Without caching each chunk rereads the whole document at 103,017 input tokens; with caching each document is written once (17,340), later chunks are cache reads (60,137), plus uncacheable text and instruction (25,540) and output (13,400). At placeholder prices that is about 29% cheaper, and the finer the chunks the higher the ratio.

Per query: once a header is in the store it is read twice on every query — once in reranking and once in the context — raising cost by about 12.3%. And amortizing the one-time cost below a tenth of the per-query cost takes only 217 queries.

So the conclusion is counter-intuitive: the index build is the small money, and the few dozen extra tokens per query are the long-term bill. That ledger also yields an immediately usable optimization: headers go only into the index and not into the context. The model generating an answer does not need that locating line; it is useful only to the retriever. Flipping that one switch on the same index leaves every metric unchanged and fits 36 more tokens into the 600-token budget (500 becoming 536).

Tree-based recursive aggregation: making "roughly what this material covers" retrievable

The three catalogs above all optimize finding that one passage. One class of question is not that shape at all:

How many departments does Skyladder's knowledge base cover in all, and roughly what is each about?

Run it and you see the difficulty: a candidate pool of 20 covers 12 documents while the store has 30. The answer is spread across every document, and no top-k assembles it — it wants a summary of the whole store rather than a few passages.

Tree-based recursive aggregation's idea is that since the summary is not in the corpus, manufacture it and index it. Cluster all chunks by vector and have a model write a summary per cluster; those summaries become a new layer of nodes to cluster and summarize again, recursing to the top. The index then holds both leaf-level original chunks and several layers of summary chunks above: detail questions hit leaves and summary questions hit high-level summaries — one index, two granularities.

The cost is in building: clustering the whole store computes every vector once, and each cluster of each layer costs one model call, with a corpus change forcing recomputation of the affected branches. The criterion is what share of questions are summary-type — under a tenth and do not adopt it yet.

Graph retrieval: strong at multi-hop and global, expensive to build

One evaluation question asks who must approve a production database failover in writing and what that person's name is. The answer spans two documents, one stating it requires the platform team lead's written approval and the other stating who the platform team lead is.

That question fails under all five index structures in exactly the same way: the document with the name never once appears in the 20-candidate pool. The query contains neither the name nor any word literally or semantically close to that document. Chunking, headers, and parent backfill are all irrelevant; it was simply never retrieved.

Graph retrieval targets that gap: extract entities and relations into a graph first, and at retrieval time walk one or two hops along the edges. The second document is not fetched by similarity but walked to along an edge.

Building costs far more than one model call: entities need disambiguating, relations deduplicating, and a document update recomputes the affected subgraph, plus a graph store to maintain (incremental updates on day thirteen). The barrier is not technical but whether you have enough must-cross-entities questions to amortize it.

A glance at multimodal, and which catalog a query actually takes

A knowledge base often also holds charts and screenshots. The least-effort approach is turning them into text before indexing: have a multimodal model write a description per image, index that as a chunk, and keep the image path in the metadata. Retrieval goes through the text path unchanged, and the original image is attached beside the citation afterwards. Separate vector spaces for images and text are more refined and need a model change and an index rebuild, whose benefit must first be proven with day eight's evaluation.

Back to the opening suspense: with three indexes built, which does a query take?

By default, none of them; take the one you already had. All five of today's structures stopped at 93.8% recall and not one beat the baseline; the only thing that moved is nDCG@10 (headers lifting it from 0.6438 to 0.7218), and the summary index fell to 87.5%. That does not mean the techniques are useless; it means each patches one specific shortfall, and without that shortfall your system gains only the cost.

So the order is: look at what your failure cases look like using the evaluation set. Chunks cut apart, adopt parent-child; chunks that alone do not say what they are about with vectors as the main route, adopt contextual retrieval; a high share of summary questions, adopt tree aggregation; a high share of cross-entity chains, adopt graph retrieval. Failure cases first, index structures second.

If you genuinely run several at once, the routing criterion is not which is most accurate but the question's shape — which is what yesterday's intent router does. A misclassification falls back to the default rather than querying all of them in parallel.

Source Reading

Hands-On Lab

🧪 D11 lab: implementing parent-child indexes and contextual retrieval, with their metric gains against day nine's configuration

Code location: labs/rag-14days/day-11-parent-child-and-contextual

Acceptance criteria:

  1. Table one's parent-child row shows 158 chunks (baseline 134), with context tokens comparable to the baseline (532 against 539).
  2. Table one's last two rows have identical index tokens (22,339) and different context tokens (500 against 536), showing the headers-only-in-the-index switch took effect.
  3. Table two's pure vector recall rises from 81.3% to 87.5% in the third column, while hybrid recall is 93.8% in all three columns with nDCG@10 rising from 0.6438 to 0.7218.
  4. Table six measures the vector path's unique candidates at 5.8% and containing the answer document 0 times, from which you can state which question this check cannot answer.
  5. Table five's with-caching row is cheaper than the without row, with a positive saving (about 29%).

Run starter/ as-is and most acceptance items fall short: the header column is identical to the heading path, the summary index's two rows match exactly, and the caching ledger is negative. The five exercise points fix them one at a time, all under MOCK=1 with neither network nor key.

  1. Implement parent-child chunking: store heading nodes as parents, cut 200-character children within a section and attach their belonging, and watch table one's chunk count become 158.
  2. Implement the contextual header: a rule version offline and a model version online, and watch table two's third column pull away from the second.
  3. Add parent backfill and deduplication to context assembly, and watch parent-child's context tokens and recall become normal.
  4. Wire up the summary index's two-stage retrieval, watch table three's two rows diverge, and work out why recall falls.
  5. Compute the prompt caching ledger, watch table five's saving go from negative to about 29%, then change the placeholder prices once and rerun to see the share flip.

Interview Questions

Today's 4 questions are in the question bank below, weighted toward where each index structure applies, contextual retrieval's cost and benefit, and graph retrieval's adoption threshold. Expand each one and read the analysis before the key points — practicing the derivation beats memorizing bullets.

Checklist and Tomorrow

  • Implement parent-child and summary indexes, and explain which category of question each makes answerable
  • Land contextual retrieval: add contextual descriptions to each chunk, and work out the one-time cost of building the index
  • Explain what problems tree-based recursive aggregation and graph retrieval each solve, and under what conditions their cost isn't worth it
  • Explain why headers-only-in-the-index is a free gain
  • Name this chapter's two experimental boundaries and which question they make unanswerable
  • All 5 acceptance criteria of the lab pass
  • Answer at least 3 of the 4 interview questions without looking at the key points

Tomorrow (D12) wraps retrieval as a tool inside an agent loop, letting the model decide whether to search, how many times, and whether to start over. The order is deliberate: today's recurring failure mode is one retrieval not assembling the answer — that approver question failed under all five index structures. What index structures cannot solve can only be solved by searching several times, and that requires somebody to decide what to search and when to stop. That somebody is tomorrow's protagonist.

Interview questions

  • Parent-child indexing and contextual retrieval both patch the same problem — chunks losing their context. What actually distinguishes them?父子索引和上下文检索都在补『块被切碎』这个问题,它们的差别到底在哪?
    Common in ChinaCommon overseasIntermediate#indexing#contextual-retrieval#chunking

    How to reason about it · think before answering

    1. The hinge is which half of the pipeline each one fixes. Answering 'one is a chunking trick, the other adds a prompt' just describes implementations; the interviewer wants to know where each acts.
    2. Split the pipeline in two and ask separately: what does the retriever see, and what does the generator see. Parent-child changes the generation side — retrieval still runs on small chunks, but a hit is swapped for its parent. Contextual retrieval changes the retrieval side — the header exists so the chunk can be found at all, and the generator does not need it.
    3. Conclusion: parent-child fixes 'found it but can't read it'; contextual retrieval fixes 'readable but never found'. Neither changes what the other changes, so they compose.
    4. That difference also dictates which metric can see each one. Contextual retrieval moves rank, so recall and nDCG catch it. Parent-child moves 'is the evidence sufficient to answer', which a binary recall metric cannot see. Our 20-question set is already saturated at 100% on single-document questions, so parent-child comes out level with the baseline — that is the ruler failing, not the technique.
    5. That difference yields a free optimization: since the header only serves retrieval, keep it out of the context window. Leaving it in pays rent on every single query. Flipping that one switch in our lab freed 36 tokens inside a 600-token budget with every metric unchanged.
    6. The costs differ too. Parent-child costs index entries and a bigger context unit. Contextual retrieval costs one model call per chunk up front plus a permanently larger index. One is space; the other is time and space.
    7. Expect the follow-up 'why not both'. Look at the failure logs first: are you mostly seeing incomplete evidence, or nothing retrieved at all? Without the matching failure mode, neither is worth its price.

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

    1. 这题的题眼是『补的是哪一半』。答成『一个是切块技巧、一个是加提示词』就是在描述实现,面试官想听的是它们各自作用在检索管道的哪一段。
    2. 拆的办法是把管道分成两段问:检索时看到什么、生成时看到什么。父子索引改的是**生成侧**——检索单位还是小块,只是命中之后把上下文单位换成大块;上下文检索改的是**检索侧**——块头拼进去是为了让这一块能被检索到,模型生成时并不需要它。
    3. 结论:父子索引解决『找到了但看不全』,上下文检索解决『看得全但找不到』。前者不改变谁被检索到,后者不改变模型看到多少。它们正交,可以叠加。
    4. 这个差别还决定了它们各自要用什么指标去量:上下文检索动的是名次,用召回率和 nDCG 量得到;父子索引动的是『材料够不够答』,召回率这种二值指标量不出来。我们那份 20 题评估集单文档档已经 100% 饱和,父子索引在表里跟基线持平——那不是它没用,是尺子量不了它。
    5. 顺着这条差异能推出一个立刻能用的优化:既然块头只服务检索,就不该进上下文。它进了上下文就是在每一次查询里白占预算,而且这笔钱是长期的。我们的实验里把这个开关一改,五列指标一个不变,600 token 的预算里多装进了 36 个 token。
    6. 代价也不同:父子索引的代价是索引条目变多、每次装进上下文的东西变大;上下文检索的代价是一次性要给每块调一次模型,加上索引 token 永久变大。前者是空间,后者是时间加空间。
    7. 可预期的追问是『那我全都上』。答案是先看失败案例:日志里是『材料不完整』多,还是『压根没检索到』多。没有对应的失败模式就不该上,这两个手法都不是免费的。

    Key points

    • Parent-child acts on the generation side: retrieve small, swap in the parent for context. It fixes 'found but unreadable'.
    • Contextual retrieval acts on the retrieval side: the header makes the chunk findable. It fixes 'readable but never found'.
    • They are orthogonal and compose; keep the header in the index only, never in the context window.
    • Parent-child costs more index entries and a larger context unit; contextual retrieval costs one call per chunk plus a permanently larger index.
    • Pick based on the observed failure: incomplete evidence points to the former, zero retrieval to the latter.

    答题要点

    • 父子索引作用在生成侧:检索单位是小块,上下文单位换成父块,解决『找到了但看不全』。
    • 上下文检索作用在检索侧:块头让块能被检索到,解决『看得全但找不到』。
    • 两者正交可叠加;块头只该进索引不该进上下文,否则每次查询都在为它付钱。
    • 父子索引的代价是索引条目与上下文单位变大;上下文检索的代价是一次性建索引调用加永久变大的索引。
    • 选哪个看失败案例:材料不完整选前者,压根没检索到选后者。
  • Contextual retrieval needs one model call per chunk. How do you estimate that one-off cost, and what levers bring it down?上下文检索要给每个块调一次模型,这笔一次性成本怎么估?有哪些办法能压下来?
    Common in ChinaCommon overseasDeep dive#contextual-retrieval#prompt-caching#cost

    How to reason about it · think before answering

    1. This checks whether you have actually done the arithmetic. Saying 'prompt caching makes it cheap' without knowing which line item it touches is a tell.
    2. Split the bill first: one-off = per-chunk input + output + full re-embedding; per-query = the header read twice, once by the reranker and once in the context. Keep them separate, because they scale with completely different things.
    3. The dominant term on the one-off side is how many times the same document is re-read. A doc split into n chunks is read n times. Prompt caching attacks exactly that: put the whole document first and mark it cacheable, pay a cache write once, then cache reads for the remaining n-1, typically an order of magnitude cheaper than input.
    4. Order matters. Caching is prefix-matched, so the document must come first and the chunk after. Put the varying part first and the prefix changes every call — zero cache hits. This is the most common way people get it wrong.
    5. Our measurement: 30 docs, 134 chunks. Without caching, 103017 input tokens; with caching, 17340 written plus 60137 read, cutting the one-off cost by roughly 29%. The finer the chunks, the bigger the saving, because re-reads multiply.
    6. The counter-intuitive part is the useful part: the one-off cost amortizes below 10% of per-query cost after about 217 queries. The lasting bill is the extra tokens every query carries (we measured +12.3%). So the first lever is not cheaper index building — it is keeping the header out of the context, keeping it short, and not generating it for the whole corpus indiscriminately.
    7. A bonus point: before spending any of it, confirm your evaluation setup can actually detect the benefit. In our offline harness the vector route contributed exactly zero unique answer documents, so it cannot answer whether headers help embeddings at all — an A/B run there hands you a wrong conclusion that looks numerically supported.

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

    1. 这题考的是你有没有真的算过账。只会说『用提示词缓存就便宜了』属于听过没做过——面试官会追问缓存到底省在哪一项上。
    2. 先把成本拆开:一次性 = 每块的输入 + 输出 + 全量 embedding;每次查询 = 块头在重排和上下文里各被读一遍。**这两笔要分开记**,因为它们随业务量的增长方式完全不同。
    3. 一次性那笔的主项是『同一篇文档被重复读了多少遍』。一篇切成 n 块就要读 n 遍,这是成本的大头。提示词缓存省的正是这一项:把整篇放在提示词最前面并标记为可缓存,第一块付一次缓存写入,后面 n-1 块只付缓存读取,而读取价通常比输入价低一个数量级。
    4. 顺序不能反:缓存按前缀匹配,整篇必须在前、块内容在后。把变化的块放前面,前缀次次都变,缓存一次都不会命中——这是最常见的翻车点。
    5. 我们的实测:30 篇、134 块,不开缓存输入 103017 token,开缓存后拆成写入 17340 加读取 60137,一次性成本降约 29%。**块切得越碎这个比例越高**,因为重复读的次数更多。
    6. 结论反直觉但很实用:一次性那笔是小钱,摊到 217 次查询就降到每次查询成本的一成以下;真正的长期账是每次查询多出来的那几十个 token(我们量到 +12.3%)。所以压成本的第一优先级不是压建索引,而是让块头别进上下文、别过长、别对全库无差别地生成。
    7. 最后一条是加分项:花这笔钱之前先确认你的评估环境**测得出**收益。我们的离线环境里向量路对召回的独立贡献实测为 0,所以它根本没法回答『块头对向量侧有没有用』——在这种环境里做的 A/B 会给你一个看起来有数字支撑的错误结论。

    Key points

    • Split into one-off (per-chunk input/output plus re-embedding) and per-query (header read by both reranker and generator).
    • The one-off is dominated by re-reading each document n times; caching turns that into one write plus n-1 reads.
    • Caching is prefix-matched: the full document must come first, the chunk after, or you get zero hits.
    • Measured on 30 docs / 134 chunks, caching cut the one-off cost by about 29%, and finer chunks save more.
    • The lasting cost is per query: keep headers out of the context window, keep them short, and generate them selectively.

    答题要点

    • 把账拆成一次性(每块的输入输出 + 全量 embedding)和每次查询(块头在重排与上下文里各读一遍)两笔。
    • 一次性的大头是同一篇被重复读 n 遍;提示词缓存把它压成一次写入加 n-1 次读取。
    • 缓存按前缀匹配,整篇必须放在提示词最前面,块内容在后,顺序反了一次都不会命中。
    • 实测 30 篇 134 块,一次性成本降约 29%,块越碎省得越多。
    • 长期账在每次查询:块头别进上下文、控制长度、只对真正需要的文档生成。
  • What kind of question actually requires graph retrieval? Give one concrete case where it is justified and one where it is not.什么样的问题必须上图检索?给一个该上的具体例子和一个不该上的例子。
    Common in ChinaCommon overseasDeep dive#graph-rag#multi-hop#cost

    How to reason about it · think before answering

    1. This one tests whether you reach for tools you don't need. If the answer is 'multi-hop questions need a graph', the interviewer knows you haven't shipped one — multi-hop is necessary, nowhere near sufficient.
    2. Anchor the criterion on something observable: does the second required document share any lexical or semantic overlap with the query? If it does, ordinary hybrid retrieval will surface it and the hop is illusory. If it shares nothing, only a relation edge gets you there — that is graph territory.
    3. Justified case: 'who must sign off on a production failover, and what is that person's name?' One doc says the platform lead must approve; another says who the platform lead is. The second shares not one term with the query. Across all five index structures we tested, it never once appeared in a 20-item candidate pool — rechunking, headers and parent backfill all failed.
    4. Unjustified case: 'which process covers a capacity change, and how many working days ahead must the ticket be filed?' Also two documents, but both overlap the query lexically; hybrid retrieval ranked them second each, and one pass collected both. Building a graph for this buys a solved problem at several times the cost.
    5. Then state the cost, which is what makes the answer sound operational: graph building is not one extraction call. Entities need disambiguation, relations need dedup, updates force recomputing affected subgraphs, and you now run a graph store and its update pipeline.
    6. Expect 'what else could you do instead'. Hand multi-hop to agentic retrieval: let the model retrieve the intermediate entity first, then issue a second query with it. Near-zero build cost, paid back in latency and call count per query. Try that before you build a graph.

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

    1. 这题在考你会不会为了用而用。只要答案里出现『多跳问题就要上图检索』,面试官基本就知道你没落地过——多跳只是必要条件,远不是充分条件。
    2. 判据要落在一个可观察的现象上:**答案的第二篇文档和查询之间,有没有字面或语义上的重合**。有重合,普通的混合检索就能捞到它,多跳是假的;完全没有重合,只能靠一条关系边走过去,这才是图检索的领地。
    3. 该上的例子:问『生产库主备切换必须谁书面审批、这个人叫什么』。一篇写着须平台组组长审批,另一篇写着平台组组长是某人。第二篇跟查询一个词都不重合,我们在五种索引结构下测了一遍,它在 20 条候选池里一次都没出现过——换切法、加块头、父子回填全都无效。
    4. 不该上的例子:问『扩容要走哪个流程、最晚提前几个工作日提单』。同样跨两篇文档,但两篇都跟查询有明显字面重合,混合检索把它们分别排在第 2 名,一次检索就凑齐了。为它建图是拿几倍成本买一个已经解决的问题。
    5. 然后说代价,这一段决定了你像不像做过:建图不止一次抽取调用,实体要消歧、关系要去重、文档更新时受影响的子图要重算,还要多维护一套图存储和一套更新链路。
    6. 可预期的追问是『不上图检索还有什么办法』。答案是把多跳交给 Agentic 检索:让模型先查出中间实体,再拿这个实体发起第二次检索。它的一次性成本几乎为零,代价换成了每次查询的延迟与调用次数——先试这条,试不通再考虑建图。

    Key points

    • The test is not 'is it multi-hop' but 'does the second document overlap the query at all' — only zero overlap earns a graph.
    • Justified: the approver question, where an intermediate entity is the only bridge and the second doc never enters the candidate pool.
    • Not justified: a multi-hop question whose documents both overlap the query — hybrid retrieval collects them in one pass.
    • Real graph cost is entity disambiguation, relation dedup, incremental subgraph recomputation and a whole extra store — not a single extraction call.
    • Try two-pass agentic retrieval first; build the graph only when that fails.

    答题要点

    • 判据不是『是不是多跳』,而是『第二篇文档跟查询有没有字面或语义重合』——没有重合才轮得到图检索。
    • 该上:审批人那类问题,中间实体是唯一的桥,第二篇文档在候选池里一次都不出现。
    • 不该上:两篇都跟查询有重合的多跳题,混合检索一次就能凑齐。
    • 建图的真实成本是实体消歧、关系去重、增量重算和一套额外的图存储,不是一次抽取调用。
    • 先试 Agentic 检索的两次查询,走不通再考虑建图。
  • You have built three different indexes over the same corpus. How do you decide which one a query goes to?同一份语料建了三套索引,检索时你怎么决定走哪一套?
    Common in ChinaCommon overseasIntermediate#index-routing#evaluation#architecture

    How to reason about it · think before answering

    1. Whether this is an easy point or a lost one depends on whether you first ask 'do we actually need three?'. Jumping straight to routing accepts an unverified premise.
    2. Step one is admitting the answer is usually 'none of them — use the default'. Across 30 documents we measured five index structures and every one landed at 93.8% recall, none beating the baseline. The only metric that moved was nDCG@10, which headers lifted from 0.6438 to 0.7218, while the two-stage summary index fell to 87.5%. Each structure patches one specific weakness; without that weakness it is pure overhead.
    3. Step two is routing, and the criterion is not 'which index is more accurate' — that is an offline evaluation question, not something you know at request time. What you do have at request time is the shape of the question: detail-seeking, summarizing, or entity-chaining. Those map onto the chunk index, the tree-summary index and the graph index.
    4. Implementation is a lightweight intent classifier — the same one from the previous day's intent routing, no need to invent another. Carry the decision as request metadata so you can replay it later.
    5. Spell out the fallback: on a misclassification, fall back to the default index rather than fanning out across all three and fusing. Fan-out looks safe but multiplies latency and cost by the number of indexes, and the extra routes usually never make it into the context budget anyway.
    6. Expect 'how do you know the classifier is right'. Log every routing decision and replay the golden set periodically: run each question through all three indexes and check whether the classifier picked the best-scoring one. It is a standing offline job that needs no human labeling.

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

    1. 这题是送分还是丢分,取决于你有没有先反问一句『真的需要三套吗』。上来就答路由策略的人,默认了一个没被验证的前提。
    2. 第一步是承认多数情况下答案是『都不走,走默认那套』。我们在 30 篇语料上把五种索引结构各测一遍,**召回率全部停在 93.8%,没有一种跑赢基线**;唯一动了的是 nDCG@10(块头把它从 0.6438 抬到 0.7218),而两段式的摘要索引还掉到了 87.5%。每种结构补的都是一个特定短板,你没有那个短板时它只带来成本。
    3. 第二步才是路由,而判据不是『哪套准』——那是离线评估该回答的问题,不是运行时能知道的。运行时能拿到的只有**问题的形状**:细节型(答案落在某一段)、概括型(要全库的一个概括)、多跳型(要跨实体串联)。按形状分流,正好对应块级索引、树状聚合索引、图索引。
    4. 实现上就是一个轻量意图分类器,跟前一天的意图路由是同一套东西,不必再造一个。分类结果作为元数据带进请求,方便事后拿评估集回看分错了多少。
    5. 兜底策略要说清楚:分类错了**回落到默认那一套**,不要并行全查一遍再融合。并行看着稳,实际上把延迟和成本按索引套数翻倍,而多出来的那两路大概率一条都进不了上下文预算。
    6. 可预期的追问是『怎么知道分类器分对了』。答案是把路由决策记进日志,定期拿标准答案集回放:对每个问题分别走三套索引,看分类器选的那套是不是指标最好的那套。这是一个能持续跑的离线作业,不需要人工标注。

    Key points

    • First challenge the premise: all five index structures landed at the same 93.8% recall in our measurement, so an index without a matching weakness is pure cost.
    • At request time the usable signal is question shape — detail, summary, or entity-chaining — mapping to chunk, tree-summary and graph indexes.
    • Reuse the previous day's intent router for classification and record the routing decision as request metadata.
    • Fall back to the default index on misclassification instead of fanning out and fusing, which multiplies latency and cost.
    • Replay the golden set periodically to check whether the classifier picks the best-scoring index.

    答题要点

    • 先反问是否真需要三套:实测五种索引结构召回率全部持平在 93.8%,没有对应短板就是纯成本。
    • 运行时的判据是问题的形状——细节型、概括型、多跳型,分别对应块级、树状摘要、图索引。
    • 复用前一天的意图路由做分类,把路由决策记进请求元数据。
    • 分类错了回落到默认索引,不要并行全查再融合——延迟和成本按套数翻倍。
    • 用标准答案集定期回放,检验分类器选的那套是不是指标最好的那套。

Comments