什么是上下文工程?和 Prompt 工程有什么区别?
一句话回答
Prompt 工程关注指令怎么写;上下文工程关注每次调用模型时,上下文里到底放什么:系统指令、工具定义、检索结果、记忆、历史消息、工具调用结果,以及它们的取舍、顺序和格式。上下文是有限的预算,不是放得越多越好,信息要相关、精简、不冲突。在 Agent 场景里,上下文会随着执行步骤不断变长,要靠压缩、筛选和子任务隔离来控制。
详细解析
区别
| Prompt 工程 | 上下文工程 | |
|---|---|---|
| 关注点 | 措辞、结构、示例 | 每次调用放哪些信息、放多少、怎么排列 |
| 对象 | 一段相对固定的提示文本 | 每次调用前动态组装的完整上下文 |
| 典型问题 | 指令不清、格式不稳定 | 信息缺失、无关信息太多、上下文太长、信息互相冲突 |
| 主要场景 | 单次调用的简单应用 | RAG、多轮对话、Agent |
Prompt 工程是上下文工程的一部分。应用越复杂,效果越取决于"模型在这一步看到了什么",而不只是指令写得好不好。
上下文由哪些部分组成
每次调用前组装:
系统指令 角色和规则,稳定不变,放在最前面便于命中缓存
工具定义 只放当前任务需要的工具
长期记忆 从记忆库检索出的用户偏好、历史结论
检索结果 RAG 召回并重排后的少量片段
历史消息 最近几轮的原文,更早的内容用摘要代替
工具结果 精简后的返回值,而不是原始的大段 JSON 或 HTML
当前任务 用户这一轮的输入
每一部分都要回答两个问题:这次调用需要它吗?能不能用更少的 token 表达?
上下文是有限的预算
放得太多会带来几类问题:
- 成本和延迟:输入越长越贵,首 token 越慢,见 上下文窗口
- 注意力被稀释:无关内容会干扰模型,中间位置的信息容易被忽略
- 信息冲突:过时的记忆和新信息矛盾,几份资料说法不一,模型无所适从
- 错误累积:早期的错误结论留在上下文里,后面会被当成事实反复引用
对应的原则:
| 原则 | 做法 |
|---|---|
| 相关 | 按任务筛选;检索后重排,只保留最相关的几条 |
| 精简 | 工具结果只保留需要的字段;长内容先摘要;去掉重复的信息 |
| 不冲突 | 信息带上时间和来源,说明冲突时以哪个为准 |
| 结构清晰 | 用标签区分不同来源,方便模型引用,也方便区分可信程度 |
| 前缀稳定 | 不变的内容放前面,变化的放后面,见 Prompt Caching |
Agent 场景:上下文越来越长
Agent 每执行一步,上下文里就多一组工具调用和结果,步数一多就可能塞满。常见做法:
- 压缩:接近上限时把历史总结成摘要,保留任务目标、关键决定、当前进度和未解决的问题,丢掉冗长的工具原始输出
- 清理旧的工具结果:已经用过的结果替换成简短说明,比如"已读取 config.ts,共 120 行"
- 按需加载:上下文里只放文件路径、链接这类引用,需要时再用工具读取,而不是一开始就全部塞进来
- 外部笔记:让 Agent 把计划和进度写进文件或待办列表,需要时再读回来,见 Agent 的记忆系统
- 子任务隔离:把调研类的子任务交给子 Agent,它在独立的上下文里完成,只把精简后的结论返回给主 Agent,见 多 Agent 系统
- 工具筛选:工具很多时只提供当前需要的子集,见 工具太多时怎么让模型选对
代码示例
// 按优先级把各部分放进预算,超出时先舍弃不重要的部分
interface Section {
tag: string // 输出时用作 XML 标签名
content: string
priority: number // 越小越重要
}
function assembleContext(sections: Section[], budget: number, countTokens: (s: string) => number) {
const kept = new Set<Section>()
let used = 0
for (const s of [...sections].sort((a, b) => a.priority - b.priority)) {
const cost = countTokens(s.content)
if (used + cost > budget) continue // 放不下就跳过,也可以改成先摘要再放
kept.add(s)
used += cost
}
// 按原来的顺序输出:稳定的内容在前,便于命中提示缓存
return sections
.filter((s) => kept.has(s))
.map((s) => `<${s.tag}>\n${s.content}\n</${s.tag}>`)
.join('\n\n')
}
面试官可能追问
上下文工程是不是新瓶装旧酒?
用到的技术(RAG、记忆、摘要、工具筛选)大多早就有了。这个说法强调的是视角的变化:在 Agent 这类复杂应用里,效果主要取决于每一步给模型提供了什么信息,要把上下文当成一个系统来设计和评测,而不只是打磨一段提示词。
模型的上下文窗口越来越大,上下文工程还重要吗?
重要。窗口变大只是上限提高了,输入越长,成本越高、首 token 越慢,无关信息照样会干扰模型;Agent 的上下文还会随步骤不断增长,再大的窗口也会被填满。窗口大让取舍更从容,但"放什么、放多少"的问题一直存在。
子 Agent 隔离上下文有什么代价?
子 Agent 看不到主 Agent 的完整上下文,任务说明必须写清楚,否则会重复劳动或理解偏差;信息在交接时会有损失;总的 token 成本更高,协调和调试也更复杂。
怎么判断上下文里哪些内容是多余的?
看调用链路的记录:哪些检索片段被引用了,哪些工具结果后来根本没用到。再用评测集做对比实验,去掉某一部分后效果是否变差。同时统计每部分占用的 token 数,优先优化占用最多的部分。
易错点
- 以为窗口够大,就把所有东西都塞进去
- 工具直接返回原始的大段 JSON 或 HTML,几步之后上下文就满了
- 压缩时把用户最初的要求或约束丢了
- 把当前时间等动态内容放在最前面,破坏了提示缓存
AI 模拟面试官
用自己的话回答,AI 对照参考答案打分、指出遗漏,再追问,最多 3 轮
这道题你掌握了吗?
选一个最接近的状态,没掌握的题会出现在"我的进度 · 待复习"里。
学习记录暂存在本机浏览器。登录后自动同步到账号,换设备也能看到。