《Claude Code工程化实践》加课5 -Context Engineering :给模型正确的上下文,而不是更多的上下文
AI编程会遇到过这种情况: 开局聊得挺好,结果越聊越不对劲——它开始忘记你十分钟前说过的约束,引用一个根本不存在的文件,或者把一个早就解决掉的 bug 又"修"了一遍。你以为是模型变笨了。其实大多数时候,不是模型笨,而是喂给它的上下文出了问题。
Karpathy 说过一句话:Agent 不缺记忆,缺的是"知道自己有记忆"。
这句话背后,是整个 AI 工程范式的切换:从 Prompt Engineering(提示词工程,1.0),走向Context Engineering(上下文工程,2.0)。
这篇文章是系统研究 Claude Code 后的一次完整复盘。聊一聊:什么是上下文工程、为什么它比提示词重要 10 倍、以及 5 个可以直接抄作业的上下文管理机制。
01 | 提示词工程解决"听懂",上下文工程解决"做对"
先厘清一个最常见的误解。
Prompt Engineering 关心的是:模型能不能听懂我?
于是大家研究角色扮演、思维链、Few-shot……一句话,把话说漂亮。
Context Engineering 关心的是:模型手里有没有正确的材料?
模型再聪明,如果它打开的是错误的文件、读到的是过期的需求、记住的是无关的历史,输出必然是错的。就像你让一个顶级厨师做菜,但冰箱里只有过期食材——厨艺再好也白搭。
一个 Agent 的"上下文",其实由五部分构成:
- 短期上下文:对话历史、当前问题、工具返回结果
- 长期记忆:全局 CLAUDE.md、自动记忆
- 项目记忆:项目里的 CLAUDE.md、规则目录、Skills
- 外部上下文:MCP 工具调用、Hook 注入
- 状态持久化:子代理报告、流水线中间结果
注意,核心命题来了:
上下文不是越多越好,而是越准越好。
塞太多 → 模型注意力被稀释,关键信息淹没在噪声里。
塞太少 → 模型无从推理,只能靠猜。
上下文工程的全部艺术,就是在这两个极端之间走钢丝。
02 | 一行代码,通过率 80%:上下文工程的"神奇瞬间"
先讲一个让我印象极深的实验,来自 Karpathy 的 Autoresearch 项目。
一个自主 Agent,连续执行多轮研究任务。前面十几个版本,团队不断优化工具、优化流程,效果始终差一口气。
第 19 个版本,突破来了。改动有多大?
一行代码。
# v19 突破(仅一行代码):ctx=f"Task #{n+1}. Memory:{mem_count}tool outputs saved."就是在 prompt 里告诉模型一句话:“这是第 N 个任务,你已经存了 M 条工具结果在记忆里。”
结果:通过率 80%,总 token 643K(基准是 641K)——额外开销只有 0.3%。
用 0.3% 的成本,换来通过率的质变。
这一行代码做的事,本质上就是上下文工程:不是给模型更多信息,而是给模型"正确的元信息"——让它知道自己手里有什么牌。
记住这个感觉,后面所有机制都是它的延伸。
03 | 五个上下文管理机制(Claude Code 实战拆解)
机制一:CLAUDE.md 四级记忆层级
Claude Code 的记忆不是一个文件,而是一套分层的记忆系统,按优先级从低到高:
| 层级 | 位置 | 存什么 |
|---|---|---|
| 用户级 | ~/.claude/CLAUDE.md | 个人偏好,跨项目生效 |
| 项目级 | ./CLAUDE.md | 项目 DNA,团队共享,进 git |
| 本地级 | ./CLAUDE.local.md | 本机特有,必须加 .gitignore |
| 规则目录 | ./.claude/rules/*.md | 按主题拆分的细则 |
设计哲学很像操作系统的配置覆盖:越具体、越局部,优先级越高。
反面教材警告:千万别把 CLAUDE.md 写成 1000 行的"项目百科全书"。它每次对话都会占住上下文窗口——你写得越全,留给真正对话的空间就越少。记忆文件的目标是"最少必要信息",不是"应有尽有"。
机制二:Skills 渐进式披露
这是最优雅的设计。一个 Skill(技能包)分三层加载:
- frontmatter(约 50 tokens)——启动时全量加载,只包含名字和描述,让模型"知道它存在"
- SKILL.md 正文(约 2K tokens)——触发时才加载
- references/ 参考文件——按需加载,用多少读多少
像查字典:你先翻目录,再读词条,而不是把整本字典背下来。
怎么衡量你的 Skills 设计得好不好?三个指标:
- 加载率= 实际加载 / 总大小,理想5–15%
- 命中率= 实际引用 / 加载总量,理想70–90%
- 维护成本= 一次修改要动几个文件,理想1–2 个
加载率太高说明 frontmatter 写太多,命中率太低说明加载了一堆用不上的东西——这两个数一高一低,上下文就漏了。
机制三:SubAgent 上下文隔离
子代理启动时,主对话的上下文不会被带过去(除非你显式传入)。
子代理拿到的是:自己的 system prompt + 一段任务描述。然后它自己读文件、自己推理、自己干活,最后只回传一段摘要给主对话——不是全部中间过程。
这解决了什么?主对话的上下文窗口不会被"探索过程"污染。
你让子代理去排查一个 bug,它可能读了 20 个文件、跑了 10 条命令、走了 3 条弯路——这些过程对主对话毫无价值,有价值的只是结论:“bug 在 auth.ts 第 47 行,原因是 token 过期没刷新。”
隔离的意义不在于保护子代理,在于保护主对话。
机制四:Hook 上下文压缩
Hook 是在特定事件点自动触发的脚本,两种典型用法:
- PostToolUse 自动格式化:工具跑完自动 lint/format,避免噪声输出污染后续对话
- SubAgentStop 验收:子代理结束时自动把报告汇总到状态文件,形成持久化沉淀
一句话:让"清理上下文"这件事自动化,不依赖人的自觉。
机制五:主动压缩与清零
长对话中,Claude Code 会自动压缩早期内容(保留关键决策、文件路径、错误信息,丢弃过程性输出),你也可以手动干预:
/compact# 摘要式压缩:保留决策和结论,丢掉过程/clear# 会话清零:只留 CLAUDE.md 和项目记忆原则只有一句话:
任务有连续性,就别 compact;发生阶段切换,就果断 clear。
最常见的翻车场景:任务做到一半无脑/compact,压缩完 Agent 忘了刚才读过什么,一切推倒重来。
04 | Token 经济学:三个立竿见影的省钱技巧
Token 消耗有三大来源:模型推理(输出)、工具调用(输入+输出)、系统提示(每次会话固定)。我们能压的主要是前两项。
三个直接能用的技巧:
① grep 优于 Read。
想确认 30 个文件里有没有某个 pattern?一条grep -rn pattern src/搞定。别让 Agent 一个个 Read——30 次工具调用,30 份文件全文进上下文,账单和注意力一起爆炸。
② git diff 优于文件全文。
Review 改动时,你只关心 diff,未改动的部分是纯噪声。
③ 批处理优于循环。
一个 Bash 调用里跑 5 条命令,比发 5 次 Bash 调用便宜 5 倍——因为系统提示只算一次。这个差距在规模化使用时会非常惊人。
05 | 进阶视野:上下文工程之后,是什么?
上下文工程不是终点。行业前沿已经在探索下一层:
Anthropic 的 Plan-Execute-Verify(PEV)闭环,把 Agent 的每一步变成可验证的工程对象:
- Plan as Contract:规划不只是步骤分解,而是写明文件范围、预期不变量、验证命令、回滚点的"契约"
- Sandboxed Execution:在隔离的文件系统与权限边界中执行(Daytona、E2B、OpenHands)
- Permissioned State Transition:多级权限模型(只读 → 沙箱编辑 → 完全访问),高风险操作必须人工确认(HITL)
- Deterministic Verification:用 Linter、测试、静态分析这些确定性手段验证,而不是让模型自说自话
另一个有意思的方向是工具 Schema 白盒化(Hermes 范式)——在工具定义里显式声明风险等级:
exportdefaultdefineTool({name:"Read",description:"Read a file from the filesystem...",input:z.object({...}),risk:"low",// ← 显式告诉 Agent 这个工具的危险等级asyncexecute({file_path}){...}});注意那个risk: "low"。对比 Claude Code 的隐式风控(只能靠 deny 规则硬拦),这是把安全信息前置进上下文,让 Agent 自主选工具时就能参考。
如果说上下文工程是"给模型正确的材料",那 PEV 和白盒工具就是在回答下一个问题:给了材料之后,怎么保证它不乱来?——这就是 Harness Engineering(范式 3.0)的地盘了。
06 | 四个最常见的坑(踩过的人都懂)
最后,盘点一下高频翻车现场:
上下文堆太多。什么都往对话里塞,模型注意力稀释,关键信息被淹没。记住:越准,不是越多。
CLAUDE.md 写成百科全书。1000 行的记忆文件占满上下文窗口,真正对话的空间被挤光。记忆文件要做减法。
压缩时机错误。长任务做到一半
/compact,Agent 瞬间"失忆",刚读过的文件全部作废。阶段切换才 clear,任务连续别 compact。描述不够详细。Skill 和工具的描述写得太简略,Agent 不知道该什么时候触发、去哪找正确的上下文,行为开始混乱。描述就是入口,入口模糊,全盘皆输。
写在最后
回到开头那个"越聊越笨"的 AI。
现在你知道了:模型没有变笨,它只是在一个被污染、被稀释、或者干脆错误的上下文里苦苦挣扎。
Prompt Engineering 的时代,我们学习"怎么跟 AI 说话"。
Context Engineering 的时代,我们学习"怎么给 AI 搭一个好的工作台"。
而后者,才是 AI 工程真正的分水岭——因为模型能力是大家共享的,上下文质量才是你自己的护城河。
那一行让通过率飙到 80% 的代码,就是最好的注脚:
给模型正确的上下文,而不是更多的上下文。
