Appearance
8.1.2 RAG 的上下文构造到底在做什么?
先给结论:RAG 的上下文构造,本质上是在把“检索阶段找到的候选材料”转换成“生成阶段适合模型使用的证据输入”。它不是简单拼接文本,而是在做筛选、排序、补全、压缩和结构化组织。
如果把 RAG 拆成更清楚的链路,可以大致理解成三层:
- 找什么
- 选什么
- 怎么给
其中:
- 检索更偏向回答“找什么”
- 重排和结果精选更偏向回答“选什么”
- 上下文构造更偏向回答“怎么给”
很多系统其实前两步都不差,但最后回答仍然不稳,问题常常就出在第三步。
上下文构造不是“最后拼一下 Prompt”
这是最需要先纠正的认识。
很多人会把上下文构造理解成:
- 把检索到的几段文本拼进 Prompt 模板
这只是最表层的形式。真正要解决的是:
- 哪些材料该进入 Prompt
- 这些材料以什么顺序进入
- 这些材料需要保持原样,还是先做合并、压缩、摘要或结构化
- 哪些背景该保留,哪些噪声该删掉
也就是说,上下文构造是一个“证据编排”过程,而不是简单的字符串拼接。
它在系统里到底承担什么职责
更具体一点看,上下文构造通常承担下面几件事。
1. 把候选变成最终证据集合
检索得到的是候选池,但模型不应该直接面对整个候选池。
上下文构造需要先决定:
- 哪几条最值得进入最终上下文
2. 恢复局部完整性
候选往往是切块结果,单块不一定完整。
上下文构造需要根据情况决定:
- 是否扩展相邻块
- 是否合并同一章节下的多个块
- 是否按文档结构重新组织
3. 控制噪声和重复
候选之间常常会有:
- 重复表达
- 模板块
- 背景块
- 边缘相关块
上下文构造需要把这些内容压下去,否则模型就会被“看起来很多、实际增量很少”的材料包围。
4. 控制长度和预算
上下文不是越长越好。系统需要决定:
- 最终给模型多少 token
- 哪些材料优先保留
- 哪些材料在预算不够时先删
5. 给模型更清晰的阅读结构
有些系统最终不是把块原样堆在一起,而是会把材料组织成:
- 按主题分组
- 按文档来源分组
- 按证据强弱排序
- 按问题子任务拆分
这类组织方式,本质上都是上下文构造的一部分。
一个更直观的最小链路
python
candidates = retrieve(query, top_k=20)
ranked = rerank(query, candidates)
selected = select_relevant_chunks(ranked)
context = build_context(selected, max_tokens=2500)
answer = llm(generate_prompt(query, context))这段代码想说明的是:
retrieve()不是最终输入build_context()才是把候选转成模型可用材料的关键一步
为什么这一步常被低估
因为它看起来不像“核心算法”,更像一些中间处理规则。
但真实系统里,回答质量经常就卡在这些规则上。比如:
- 要不要补相邻块
- 要不要压缩背景段
- 要不要保留同文档多个片段
- 要不要把不同来源的证据分组展示给模型
这些决定不会改变“库里有什么”,却会直接改变:
- 模型最终看到什么
而模型看到什么,往往就决定了它怎么答。
一个常见误区
很多人会把上下文构造理解成:
- 检索做完以后再随手处理一下格式
这会低估它在链路中的位置。
更准确的理解是:
- 它是检索和生成之间的关键中间层
没有这层,系统就会把“粗候选”直接交给生成;有了这层,系统才能把候选整理成更像“证据输入”的东西。
一句话总结
RAG 的上下文构造,做的不是简单拼接文本,而是把检索到的候选材料转成模型真正适合使用的最终证据输入。它承担的是筛选、补全、压缩、排序和结构化组织的职责,是连接检索和生成的关键中间层。