为什么模型这一轮看到的,从来不是你写的那段 prompt
模型每轮收到的上下文,是框架替你拼出来的一整坨;先让七层 100% 可见,才谈得上优化。
立靶:你改的是 prompt,模型吃的是一整坨上下文
很多人优化 Agent 的方式只有两招:慢了,就换更贵的模型;不听话,就把 system prompt 写得更长更细。改到三千字的提示词,模型还是时好时坏,于是开始怀疑「是不是模型不行」。
真问题往往不在那段 prompt,而在一件你没意识到的事:你根本不知道模型这一轮到底收到了哪些 token。 你以为它看到的是你写的那段话,可它实际收到的,是框架替你拼出来的一整坨——你的 system prompt,加上 SDK 偷偷加载的默认配置,加上一路累积的对话历史,加上某处注入的用户画像,加上每个工具的 schema 描述。这些「你以为没塞、实际塞了」的 token,就是上下文里的暗物质。
这就是 Prompt Engineering 和 Context Engineering 的分界线。PE 优化的是「那一段话」本身——措辞、结构、example 怎么给。CE 优化的是「那一整轮上下文是怎么装配出来的」——七层内容各从哪来、各占多少 token、哪些该缓存、哪些该压缩。把 system prompt 写长写细,做得再好也还是 PE;真正决定 Agent 稳不稳、省不省、可不可控的,是你有没有把这一整轮的装配过程管起来。
这是整个 Module E 的底座:后面每一讲——提示与指令、结构化 IO 与工具、记忆与 RAG、历史与压缩、cache 与可观测——都是在这张「七层装配图」上展开。
框架:把每一轮上下文拆成七层
任何 LLM 应用,模型每轮看到的上下文都能拆成这七层。自上而下,前面的偏静态(每轮基本不变),后面的偏动态(每轮在涨)。
| 层 | 这一层装什么 | 典型来源 | 静态 / 动态 |
|---|---|---|---|
| L1 系统提示 | 角色定义、行为准则、能力边界 | system prompt、框架 preset | 静态 |
| L2 指令 | 任务流程、优先级、单轮约束 | 拼进 system 的规则、代码追加的铁律 | 静态为主 |
| L3 用户输入 | 当前这一轮用户说了什么 | 本轮 user message | 动态 |
| L4 结构化 IO | 输出的格式契约 | JSON schema、response_format | 静态 |
| L5 工具集成 | 模型能调用哪些外部能力 | tool schema、MCP server | 静态 |
| L6 RAG 与记忆 | 检索片段、长期记忆、用户画像 | 向量库、记忆文件、用户档案 | 动态注入 |
| L7 状态与历史 | 对话历史、任务 / 用户状态 | session 历史、阶段跟踪器 | 动态累积 |
对每一层都要追问同样四个问题:内容是什么 / 谁来填 / 多少 token / 怎么 cache 加压缩。一层都答不上来,说明这层正处在「框架替你做主」的状态——而框架的默认值,几乎从不为你的场景优化。
最危险的是 L1、L6、L7 三层:很多 SDK 把它们默默塞进上下文。比如某些 agent SDK 默认会去加载一份全局配置文件当系统提示,你没写一个字,它却占了上千 token。CE 的第一步不是优化,是让七层的内容 100% 可见——把暗物质先照出来。
CE 不是孤立的技法,它和另外两件事是一组正交的「可见性」工程:
| 维度 | 优化什么 | 一句话 |
|---|---|---|
| Prompt Engineering | 单段提示词本身 | 把「那段话」写好 |
| Context Engineering | 模型每轮看到的整坨上下文怎么装配 | 把「那一整轮」拼好、对平账 |
| Harness | 跨轮、跨会话的代码状态与交接 | 让长任务跑得完、接得上 |
Harness 管「代码状态可见性」(哪条任务真通了、下次会话怎么接班),CE 管「上下文构成可见性」(每轮模型实际看到了什么、暗物质在哪)。两者互补——一个可靠的长任务 Agent,需要把单一事实源、进度、交接、以及一份 CONTEXT.md 一起管起来。
落到原则上,CE 有五条,但本质都从一句话长出来——七层是互联的,不能孤立优化某一层:改 system 可能让某个 tool 失效,加 RAG 可能把 system 里的指令冲掉。所以每次改都要跑 baseline 看数字(token / 耗时 / cache / 完成率),不能凭感觉;要围绕真实工作流设计,而不是为了把 token 压低就让模型乱答;要能撑住十倍复杂度;并且把 CONTEXT.md 当活文档维护,而不是一次性产物。
数据 / case:七层在真实场景里怎么咬人
下面是脱敏后的真实手感,每个对应一种典型的「暗物质事故」:
- 某 agent SDK 的隐式默认(某 AI 工具团队):一个 Agent 响应莫名偏慢,排查了模型、网络都没用。最后打印每轮真实 input token 才发现:SDK 一个不起眼的配置项,默认把一份约 17k token 的全局配置文件加载进了系统提示。这部分没人写、没人审、也没人需要。关掉之后,纯文本轮的延迟直接砍掉将近一半。这次优化本应在写第一行代码前就做完,而不是上线后救火。
- 某语音 Agent 的逐层审计:给一个实时语音 Agent 画 CONTEXT.md 时发现两处暗物质——一是框架托管的对话历史,代码里看不见它,但每轮 input token 随轮数线性上涨,长会话逼近上限却无人察觉;二是一段几千 token 的静态前缀本可一次缓存,却因为没做分层,每一轮都全额重发。两处都不是「写错了」,而是「没人管」——典型的 CE 缺位。
- 某成熟产品的真实账本(某团队自查):把一个成熟 Agent 产品的全部历史会话用量加总后发现,常用统计面板显示的 token 数,只取了最小的那一两个字段,把真实流量低估了近两个数量级。报一个 token 数字,先报清是哪种口径——这条会在本模块的 cache 与可观测两讲里彻底讲透。
三个案例指向同一件事:上下文的问题,几乎从不在「你写的那部分」,而在「框架默默替你拼进去、却没人对账的那部分」。
可操作做法:怎么把这套用起来
PM 视角——用它做判断和沟通:
- 接到一个 Agent 需求或故障,先问「这卡在七层的哪一层」,而不是直接想 prompt 怎么改。
- 和工程师对齐时用层号说话:「这是 L7 历史膨胀」「这是 L6 注错了记忆」,比「它老是出错」精准得多。
- 谈任何「上下文优化」之前,先要一张 CONTEXT.md——没有它,团队还停在设计稿阶段,所谓优化都是凭感觉。
- 警惕「为优化指标牺牲体验」:把 system 压到 100 token 确实省钱,但模型开始乱答,就是假省。
工程视角——用它做架构决策:
- 写第一行 SDK 配置前,先在项目根画一份 CONTEXT.md:分静态表(每轮固定,标来源 / token / 缓存策略)和动态表(每轮变化,标增量 / 压缩策略)。
- 审框架的隐式默认——配置加载项、历史截断策略、含动态信息的 preset,都是暗物质的常见来源;用任何字段前先查它的 default 和对七层的影响。
- 把静态层(L1 / L2 / L4 / L5)的前缀做到逐字节稳定、缓存接近 100% 命中,动态层(L3 / L7)一律放在静态之后。
- 加观测:每轮打印 input / cache / 历史 token,让 CONTEXT.md 这本「设计账本」和运行日志这份「对账单」能对上——对不上的差额,就是下一个要排查的暗物质。
收口
CE 的第一步从来不是优化,是让七层 100% 可见。你不能优化一坨你看不见的上下文——先把暗物质照出来、把账对平,再谈怎么省、怎么稳。