04 · 上下文工程
不是所有信息都值得给模型看。选择、压缩、排序、隔离——用好有限的上下文窗口。
上下文窗口是稀缺资源
每次调用模型 API,都需要把完整的消息历史发过去。模型能处理的内容量是有限的(即"上下文窗口"),而且按 token 计费——发得越多,花得越多。
所以不能把所有信息都塞进系统提示词。要像编辑一篇文章一样,精心选择哪些信息值得呈现,哪些应该省略。
这就是"上下文工程"(Context Engineering)的核心思路。
四个操作
上下文工程可以分解为四个操作:
选择(Selection)
哪些信息应该给模型?
以会话记忆为例,agent 跟踪了三类信息:已读文件、失败命令、最近搜索。为什么是这三类?
- 已读文件——高价值。模型知道"读过什么"就能避免重复读取,也能回忆之前看到的内容。
- 失败命令——高价值。避免模型重复执行已经失败的命令,这是防止"无限重试"的关键信息。
- 最近搜索——中等价值。帮助模型保持搜索方向的连续性。
没有跟踪的信息:
- 成功的命令——低价值。
npm test成功了不需要特别记住,对话历史中已经有了。 - write_file / patch_file 的结果——低价值。文件内容已经变了,下次读取会拿到新内容。
- git_status / git_diff 的结果——低价值。这些是快照信息,很快会过时。
压缩(Compression)
怎么减少无效 token?
ContextManager 在记录信息时就做了压缩:
/** 文件内容只保留前 3 行 */
recordFileRead(path: string, content: string): void {
const lines = content.split("\n").slice(0, 3);
this.readFiles.set(path, lines.join("\n"));
}
/** 搜索结果只保留第一行,最多 200 字符 */
recordSearch(query: string, result: string): void {
const summary = result.split("\n")[0] ?? "";
this.recentSearches.push({ query, summary: summary.slice(0, 200) });
}为什么前 3 行就够了?因为前 3 行通常是 import 语句或文件头——足够让模型知道"这是一个 TypeScript 文件,导入了什么模块"。如果模型需要看完整内容,它会再次调用 read_file。
搜索结果只保留第一行也够——"找到 5 个文件"或"未找到结果"已经传达了关键信息。
排序(Prioritization)
哪些内容要优先呈现?
在系统提示词中,信息的排列顺序是:
- 角色定位(最重要——模型首先理解"我是谁")
- 工具列表(重要——模型需要知道能做什么)
- 工作方式(重要——模型需要知道怎么做)
- 行为准则(重要——模型需要知道什么不能做)
- 项目规则(补充——特定项目的约束)
- 会话上下文(补充——之前做过什么)
- 工作目录(基本——当前环境信息)
核心指令在前,补充信息在后。模型处理上下文时,越靠前的信息权重越高。
隔离(Isolation)
不同任务不要互相污染。
会话记忆中的搜索记录保留了最近 5 条。如果 agent 先搜索了"数据库连接",然后切换到"修复 CSS 样式"任务,旧的搜索记录不应该干扰新任务。
MAX_RECENT_SEARCHES = 5 就是一种简单的隔离机制——超过 5 条就丢弃最旧的,自然地让过时的搜索淡出上下文。
另一种隔离是 failedCommands 只记录失败——成功的命令不记录。这样"失败过的命令"列表只包含需要避免的操作,不会被成功的命令稀释。
系统提示词的结构
整合项目规则和会话上下文后,系统提示词变成了一个动态构建的文本:
const systemParts: string[] = [
"你是一个代码仓库助手...", // 角色
"## 可用工具", // 工具
"## 工作方式", // 方式
"## 行为准则", // 准则
];
// 可选注入
if (options?.projectRules) {
systemParts.push("", "## 项目规则", "", "...", options.projectRules);
}
if (contextText) {
systemParts.push("", contextText); // 已读文件、失败命令、最近搜索
}
systemParts.push("", `工作目录:${state.workingDir}`);这种数组拼接的方式比字符串模板更灵活——每个可选部分独立判断,不存在就跳过,不会产生多余的空行。
和第 5 章事件系统的关系
上下文工程和事件系统是互补的:
- 事件系统解决的是"实时展示"——让用户看到 agent 在做什么
- 上下文工程解决的是"信息传递"——让模型知道之前做过什么
两者都从工具执行的结果中提取信息,但提取的目的不同。事件系统提取完整信息(给用户看),上下文工程提取压缩后的摘要(给模型看)。
登录以继续阅读
解锁完整文档、代码示例及更多高级功能。