上下文工程实战:把正确的信息在正确的时刻放进窗口
上下文工程实战:把正确的信息在正确的时刻放进窗口
模型上下文窗口越来越大,但「塞得下」不等于「用得好」。把 100K 资料一股脑丢进去,模型反而容易在中间部分丢信息、被无关内容稀释注意力。上下文工程(context engineering)要解决的问题是:在有限的窗口里,放什么、按什么顺序放、什么时候刷新。它是 RAG、提示工程、记忆管理的上层设计,也是 Agent 系统能不能稳定跑的关键。
30 秒版本
先判断负载类型:用户在等结果走在线端点,不在等就组织成批量队列。具体模型 ID 以 /models 目录实时为准,价格只链 /pricing。
上下文由哪几部分组成
一次请求的上下文通常包含五块内容,每一块都在争夺窗口预算:
| 组成 | 作用 | 常见浪费 |
|---|---|---|
| 系统提示 | 角色、规则、输出格式 | 塞满每次都用不到的示例 |
| 工具定义 | 可用工具与参数 | 全量挂载、不按任务裁剪 |
| 检索片段 | RAG 取回的资料 | 取回太多、相关性低 |
| 对话历史 | 多轮连贯性 | 全量携带、从不摘要 |
| 输出约束 | 格式、语气、边界 | 与系统提示重复 |
关键认识:窗口是预算,不是容器。每一块都要回答「这块信息对当前这一步有必要吗」。
三类典型失败模式
1. 信息稀释。 检索取回十个片段,真正相关的只有两个,其余八个把注意力摊薄。对策:收紧 top-k、加相似度阈值、重排序后截断。
2. 中间遗忘。 长上下文里,放在中间的信息比放在开头和结尾的更容易被忽略。对策:把最关键的约束放到系统提示(开头)和紧邻问题的位置(结尾),长资料做结构化摘要再放中间。
3. 历史膨胀。 每轮对话都把完整历史带进去,窗口很快被旧内容占满,新信息进不来。对策:最近 N 轮保留原文,更早的做摘要;或按主题检索历史片段,而不是全量携带。
先诊断再优化
上下文问题的表现往往是「模型变笨了」「回答跑偏」,但根因可能在检索、切分、历史策略的任意一环。先用一组固定问题跑对照(只改一个环节),定位是哪一块在拖后腿,再动结构。
压缩与分层策略
摘要压缩:把长资料、旧对话压成要点,保留结论与数字,丢弃过程性文字。
分层放置:稳定的规则放系统提示(每次都在、可缓存);动态的资料放检索片段(按需取回);临时的中间结果放工具回传(用完即弃)。
按需检索:不要一开始就取回全部候选,先让模型判断需要哪类信息,再取回对应片段(Agent 式检索)。
结构化表达:用标题、列表、表格组织上下文,比一整段自由文本更容易被模型定位。
# 历史压缩的最小形态:保留最近 3 轮,更早的做摘要
def build_context(history, retrieved, system_prompt):
recent = history[-3:]
older_summary = summarize(history[:-3]) if len(history) > 3 else ""
parts = [system_prompt, older_summary, *recent, "相关资料:\n" + retrieved]
return "\n\n".join(p for p in parts if p)
与 RAG / 提示工程的关系
| 概念 | 关注点 | 层级 |
|---|---|---|
| 提示工程 | 单条指令怎么写 | 最底层 |
| RAG | 怎么取回相关资料 | 中层组件 |
| 上下文工程 | 所有内容怎么组织进窗口 | 上层设计 |
三者不是替代关系:提示工程写好系统提示,RAG 产出检索片段,上下文工程决定它们的顺序、配额和刷新时机。RAG 系统效果不好时,先别急着换 Embedding 模型——很可能只是取回的片段太多、历史没压缩这类上下文问题。
一个完整例子:客服问答的上下文设计
把上面的原则落到具体场景:一个基于内部知识库的客服问答系统。
系统提示(稳定前缀):角色、语气、拒答规则、输出格式,约 200 token,每次不变,可复用缓存。
检索片段(动态):用户提问后取回 3 个最相关片段,按相关性排序,用标题分隔。不要取回十个低相关片段稀释注意力。
历史(压缩):最近 3 轮原文,更早的压成一句摘要。多轮追问时,把「用户真正在问什么」重写成一条独立问题再检索,避免拿整段历史去匹配。
输出约束(结尾):把「只依据资料回答、资料不足就说明」放在紧邻问题的位置,而不是埋在长上下文中段。
这样一条请求的上下文是「稳定前缀 + 3 个片段 + 3 轮历史 + 结尾约束」,而不是「系统提示 + 全部资料 + 全部历史」。效果差异通常非常明显,且不需要换模型。
常见问题
窗口越大越不用管上下文吗?
检索片段取几个合适?
对话历史怎么管?
上下文工程和 prompt 缓存冲突吗?
怎么判断是上下文问题还是模型能力问题?
价格在哪里看?
相关阅读
- RAG 知识库搭建实战 — 检索与上下文的配合
- 模型评测方法论 — 用固定评测集做回归
- Qwen 成本优化实战 — token 消耗控制
- 显存计算实战 — 并发的显存上限
- 定价 — 云端实时价格