上下文工程
大约 5 分钟
上下文工程
上下文窗口:稀缺的「工作内存」
上下文窗口(如 200k token)看起来很大,但在 agent 场景下极易耗尽:
系统提示 ~3-10k (常驻)
CLAUDE.md / 记忆 ~1-5k (常驻)
任务描述 + 多轮对话 ~2-10k
每次 Read 一个文件 ~1-5k (读 10 个文件就没了一半)
工具输出(测试日志/搜索) ~1-50k (一次 npm 报错可能 10k+)
─────────────────────────────
一个中等任务跑半小时,很容易塞满窗口
上下文工程 = 在有限的窗口里,让每一轮循环时模型都能看到「当下最有用的信息」。 这是 2025 年后取代 prompt engineering 的核心话语——单次提示优化变成了持续的信息调度。
上下文的三个区域
┌─────────────────────────────┐
│ 系统提示 + 记忆文件(常驻) │ ← identity,每轮都在
├─────────────────────────────┤
│ 对话历史(增长) │ ← 会被压缩
├─────────────────────────────┤
│ 当前轮工具结果(最新鲜) │ ← 衰减最快
└─────────────────────────────┘
信息价值随时间衰减:三小时前读的配置文件内容,可能不如一句「之前确认过端口是 8080」。
机制一:压缩(Compaction)
窗口逼近上限时的处理:
硬截断(最差):丢掉最早的消息 —— 早期约束丢失,行为漂变
摘要压缩(主流):把早期对话总结成一段「工作纪要」替换原文
✅ 保住:任务目标、已做决定、关键文件路径、未完成事项
✂️ 丢弃:原始文件内容、已解决的报错细节
Claude Code 的做法:上下文快满时自动 compact,
保留最近 N 轮原文 + 前面部分的摘要,用户也可手动 /compact
摘要质量决定 agent 的「长期记忆人格」——差的压缩会让它忘记自己为什么改这个文件。
机制二:外部记忆(Memory)
把信息移出窗口,按需取回:
CLAUDE.md / AGENTS.md 项目级常驻记忆(约定、风格、命令)
~/.claude/CLAUDE.md 用户全局记忆(跨项目偏好)
memory 目录 + 索引 长期记忆:一个事实一个文件,
每次会话只把「索引」载入上下文,
需要时再 Read 具体记忆文件
设计哲学:记忆是「读时加载」而非「全量注入」。索引让模型知道存在什么,正文按需读取——这本质上是给上下文做了个虚拟内存。
机制三:记忆文件怎么写才有效
CLAUDE.md 是给模型看的「团队手册」,有效写法:
# 项目说明
(一两句话说清项目是什么)
# 约定
- 单元测试放在 test/ 目录,与源文件路径对应
- commit message 用中文
- 发布必须跑 bash deploy.sh,不要手动 git push
# 已知问题
- deploy.sh 没有 set -e,构建失败也会推送(历史遗留,别修,等 v2)
无效写法(模型会无视):
长篇大论的背景故事 / 大段吹水
与代码库可见事实重复的内容(模型自己会读代码)
模糊指令:「写优雅的代码」(没有可执行性)
原则:CLAUDE.md 只写「代码里看不见的决策与偏好」。看得见的(目录结构、函数签名)让模型自己查,别浪费常驻 token。
机制四:Prompt Caching
上下文是前缀匹配缓存的——这直接改变 harness 的设计约束:
API 侧:请求的前 N token 命中缓存 → 这部分按 1/10 价格计费且更快
前提:前缀必须完全一致
对循环的影响:
✅ 系统提示、记忆、早期对话天然命中(循环只往尾部追加)
❌ 往系统提示里放「当前时间」「随机 id」= 每轮缓存全失效
❌ 压缩/摘要会改写历史 → 缓存失效一次,之后重新命中
工程启示:只追加、不修改是上下文的黄金操作。一切「回头改历史」的机制都要付出缓存代价。
机制五:工具结果的上下文纪律
harness 侧能做的最大优化——控制工具输出尺寸:
- Read 支持行号范围:能读 50 行就别读 2000 行
- Bash 输出截断:超长输出保留头尾 + 提示被截断
- 搜索工具默认 files_with_matches,要看内容再 Read
- 结构化优先:MCP 工具返回「结论」而非「原始 JSON 大杂烩」
一个反例:让 agent 跑 npm install,依赖树输出 30k token 进上下文——一次就烧掉 15% 窗口。好 harness 会截断到「最后 20 行 + 成功/失败」。
实战:诊断「AI 变笨了」
长会话中模型开始忘事、重复劳动,排查顺序:
1. /context 或 token 计数 → 窗口用了多少?
2. 早期关键决定是否还在原文里?(还是被压缩吞了)
3. 是否被无关工具输出淹没(大文件、长日志)
4. 处理:
- 手动 /compact(带一句「保留 X 决定」的压缩指令更好)
- 或新开会话,把「任务状态摘要」贴进去
- 把长期有效的信息沉淀进 CLAUDE.md / memory
面试/交流高频概念
- Context Engineering vs Prompt Engineering:单次优化 → 持续调度系统
- Lost in the middle:长上下文中部信息召回率低 → 关键信息放开头结尾
- Compaction trade-off:省窗口 vs 丢细节,何时触发压缩是产品决策
- KV Cache 命中率:为什么「追加式」上下文是便宜的,「改写式」是贵的
下一篇:工具系统与 MCP——模型的手是怎么定义出来的。
