上下文工程是把”模型这次能看到什么”当成一门设计来做的学问。它比 prompt 工程大一圈:prompt 管措辞,上下文管给什么、放哪、留多少。
Q1 上下文工程和 prompt 工程的区别是什么?
- prompt 工程优化的是一段指令怎么写;上下文工程优化的是这一次请求里所有输入的结构——系统提示、工具定义、检索材料、对话历史、中间产物,全都算。
- 分水岭在预算:prompt 工程可以无限写,上下文工程每加一样东西都要从别处扣掉额度。
- 有区分度的回答会把上下文当”有限预算的资源分配问题”,而不是”提示词美化问题”。
Q2 上下文里放什么、按什么优先级取舍?
习惯上按这个顺序排优先级(越靠前越不可省):
- 当前任务的目标与约束——省掉它,模型再聪明也白搭
- 工具定义与调用规范——缺了会导致乱调工具
- 必要的检索材料 / 事实依据
- 近期对话与工具结果
- 风格与格式偏好——最先被牺牲的一档
一个常见误区是把”历史全量对话”当默认项。历史是成本最高的那一档,也是最容易压缩的一档。
Q3 上下文塞不下了,压缩策略怎么选?
| 策略 | 做法 | 代价 | 适用 |
|---|---|---|---|
| 截断 | 丢最早的对话 | 丢失早期决策依据 | 任务短、早期内容已无关 |
| 摘要 | 用小模型把历史压成纪要 | 细节失真、不可逆 | 长任务、需要保留脉络 |
| 结构化提取 | 只保留结论/状态(如待办、已确认字段) | 需要设计状态结构 | 流程型 Agent |
| 外置记忆 | 写入文件/库,需要时再检索回上下文 | 增加一次检索往返 | 会话很长、知识需复用 |
| 子代理隔离 | 用子 Agent 干脏活,只回传结论 | 编排复杂度上升 | 搜索、批量分析类任务 |
加分的答法:指出压缩必须先做状态抽取再做摘要——把”已确定的事实”和”过程性叙述”分开,前者结构化保留,后者才适合摘要。混在一起压,模型最需要的东西往往第一个被压掉。
Q4 上下文里材料的位置有讲究吗?
有,而且这是最容易被忽略的一点:
- 长上下文存在中间衰减:放在头和尾的内容更容易被用到。
- 所以最相关的材料应该放在开头或结尾,不要埋在中间。
- 每段材料带来源标识(文件名/章节),既方便模型引用,也方便你事后核查幻觉。
- 材料之间冲突时,必须显式给出优先级规则(如”以更新时间较新的为准”),否则模型会随机挑一个。
Q5 工具结果太长,怎么处理?
- 截断是最差解:模型会基于残缺信息给出自信的错误答案。
- 正确顺序是 摘要化 → 分页 → 让模型显式请求下一段。
- 返回结构优先于自然语言:给”总数 + 前 N 条 + 是否继续”,而不是灌 500 条原始记录。
- 有个反直觉的点:告诉模型”材料可能不完整”,比假装材料完备更能抑制编造。
追问:工具返回的错误信息该怎么进上下文?
错误信息是给模型看的输入,不是给运维看的日志。要包含三件事:错在哪、期望什么格式、可以怎么改。只回一句 “failed” 等于让模型盲猜。
另外要把 空结果 和 报错 严格区分开:混在一起,模型就学不会纠正。
Q6 多轮 Agent 的上下文怎么演进?
关键在 G 那个判断点:压缩要发生在预算耗尽之前,而不是报错之后。等到接口返回超长错误再压,这一次请求已经失败了。
Q7 怎么衡量上下文工程做得好不好?
- 别只看”任务成功率”。要看 token 效率:同样的任务,上下文用量是否在下降。
- 记录压缩触发频率:频繁触发说明初始预算分配就不合理。
- 记录重复读取:同一份材料在一轮任务里被反复拉进上下文,是状态没抽取干净的信号。
- 回归手段:固定一批任务,比较”改前/改后”在相同成功率下的 token 消耗。
附:一次完整的上下文预算分配
假设单次请求预算 32k token,一个带检索的 Agent 可以这样分:
{
"budget_total": 32000,
"allocation": {
"system_prompt": 1500,
"tool_definitions": 3500,
"task_and_constraints": 1000,
"retrieved_material": 14000,
"recent_turns": 9000,
"reserve_for_output": 3000
},
"policy": {
"on_overflow": "extract_state_then_summarize",
"material_position": "head_and_tail",
"conflict_rule": "prefer_newer_source"
}
}
检索一到,先量一下再决定塞多少:
# 估算检索材料占用的 token(粗算:中文约 1 字 ≈ 1 token)
wc -c retrieved.md | awk '{ printf "≈ %d token\n", $1 / 2.2 }'
≈ 4318 token
技能上还有两条容易被忽略的:
- 用 Tab 补全式的工具选择,能省掉一大段”工具清单”叙述——让模型从候选里选,比让它读完手册再选更省。
- 化学式、脚标这类写法用 sub / sup 就能表达,比截图省几百个 token。
面试里被问到”你怎么控制上下文”,先回答预算怎么分,再回答压缩怎么选,最后补一句怎么度量。这三层答全了,基本就稳了。
延伸阅读:同专题的 RAG 专题 讲的是”材料怎么找对”,本篇讲的是”找对了之后怎么放”。两篇配合看更完整。
自检清单
- 每条材料都能说清”为什么它在上下文里”
- 最相关的材料在头或尾,没有埋在中间
- 冲突材料有显式优先级规则
- 压缩先抽状态、后做摘要
- 出错信息包含”错在哪 + 期望格式 + 怎么改”
-
把历史全量塞进去已经按优先级裁剪过
上下文越长越好 是被反复证伪的直觉。