Appearance
09|上下文组装:放什么、不放什么
上一篇解决了历史怎么存。但每次请求发给模型的,不只是历史——还有工具返回的日志、检索到的 Runbook、动态的项目状态。
这些材料不是一股脑全塞进去就行。无关内容会干扰判断,过期内容会误导,冲突内容会让模型左右摇摆。本篇解决"模型面前放什么":上下文不是越全越好,组装本身是一个需要设计的过程。
越全越好是个误区
一个常见错误:RAG 检索返回 10 篇文档,全部拼进上下文。觉得"多给点信息总没坏处"。

坏处很大。模型对上下文里不同位置的信息关注度不同,塞太多无关内容,关键信息反而被淹没。模型看到 10 篇文档,注意力分散,可能引用了第 7 篇里一句无关的话,而不是第 2 篇里直接相关的结论。这不是模型能力问题,是上下文组装问题——你把噪声和信号混在一起了。
组装管线的核心能力是选择,不是堆积。先按相关度排序,只取前几篇,对每篇做摘要后再放入。
组装管线要考虑什么
组装上下文不是拼字符串,是一条管线,每一步都有设计决策:
顺序。静态段在前、动态段在后(第 4 篇讲过,为了缓存)。系统指令在最前,对话历史居中,工具结果和检索材料在后。顺序错了,缓存命中不了,模型注意力也抓不住重点。
优先级。上下文窗口是有限的预算。材料多到放不下时,谁先被裁掉?原则是:用户当前问题相关 > 已确认事实 > 工具结果摘要 > 早期对话。早期对话最先被压缩或丢弃。
信息密度。大段日志原文密度低,摘要密度高。工具返回 500 行日志,不要原文塞进上下文,摘要成"14:32 出现 KEYS order:*,耗时 350ms"一行。原文存到 trace,上下文只留摘要和文件位置。
来源边界。每段材料标注来源和时间。不只是规范,是为了事后追溯——模型说"upstream 故障",看来源标注就知道它依据的是告警描述还是日志证据,是推断还是事实。
权限边界。模型需要足够证据,但不能看到不该看的内容。权限过滤放在管线的最后一步,不是材料收集阶段。原因是不同场景下敏感信息的定义不同——IP 地址在公开文档里不算敏感,在内网拓扑图里可能敏感。组装阶段才知道最终使用场景,所以过滤放最后。
一个组装管线的骨架
python
def assemble_context(state, tools_results, retrieved_docs, user_role) -> list[dict]:
items = []
# 1. 系统指令(静态段 + 动态段,第 4 篇)
items.append({"role": "system", "content": build_instructions(...)})
# 2. 早期对话摘要(不是原文,第 10 篇讲压缩)
if state.summary:
items.append({"role": "system", "content": f"会话摘要:\n{state.summary}"})
# 3. 最近几轮对话
items.extend(state.messages[-6:])
# 4. 工具结果摘要(不是原文)
for tr in tools_results:
items.append({"role": "system", "content": f"[工具结果摘要] {tr.summary}"})
# 5. 检索材料(按相关度取前几篇,带来源)
for doc in retrieved_docs[:3]:
items.append({"role": "system", "content": f"[来源:{doc.source}] {doc.snippet}"})
# 6. 权限过滤(最后一步)
items = filter_by_permission(items, user_role)
return items注意几个设计点。工具结果是摘要不是原文,原文在 trace。检索材料只取前几篇带来源。权限过滤放最后。早期对话用摘要不用原文。
来源标注的可追溯
材料标注来源和时间,是为了事后能追溯模型为什么给出某个回答:

text
[来源: nginx-error-log | 时间: 2026-06-26T14:32:01Z]
2026-06-26 14:32:01 error: upstream timed out
[来源: runbook-server | 时间: 2026-06-26T14:33:00Z]
Nginx 502 通常检查 upstream 存活、端口连通性、应用日志。如果模型把"检查 upstream"写成了"已确认 upstream 故障",查看来源标注就能发现:这条信息来自 [来源: runbook-server],是手册的建议,不是日志证据。模型把建议当成了事实。没有来源标注,这个错误无从发现。
动态组装:不是固定模板
生产系统里的上下文不是固定模板,是运行时根据用户身份、当前任务、历史状态动态组装。
同一个告警,值班人员看到的是完整排查上下文(日志、指标、Runbook),只读权限的实习生看到的是脱敏后的摘要。同一个 agent,处理告警分诊时只放分诊相关工具结果,处理根因分析时才放完整日志。组装管线根据运行时条件决定放什么、不放什么。
组装之后
组装管线把"放什么"讲清楚了。但有个问题没解决:上下文会越来越长。多轮对话累积,工具结果累积,检索材料累积,总有一天超出窗口。
下一篇解决这个。上下文太长时怎么办——不是简单截断,而是从轻到重的四层压缩策略。