第四课:为什么 Agent 会忘记规则
诊断与预防上下文漂移
≈18 分钟 · AI 时代战略型工程师 · 课程 0004 · 2026-06-15
前置:第三课·编排大重构 · 参考:术语表 · 能力速查表
你的问题,先正名
你说:做了一组自动化测试的 skill 编排,执行中 agent 有时忽略你前面强调过的规则,整体还行但过程容易跑偏。你问:这是不是 trace?
不是。你遇到的病叫指令遵循衰减 / 上下文漂移(instruction drift)。trace(执行轨迹)是诊断这个病的工具,不是病本身。
类比:你的车开着开着偏离了路线(drift);行车记录仪(trace)帮你回放、看清在哪一公里偏的——但记录仪不负责把方向盘掰正。很多人把"加个 trace"当解法,其实它只是诊断的第一步。
把这两个分清楚,是这一课的第一个收获。下面按 正名 → 机制 → 诊断 → 预防 走,最后落到你的 skill 编排该怎么改。
机制:为什么它"越到后面越不听话"
关键认知,能让你不再自责"是不是我规则写得不好":这不是模型不够强,是 Transformer 注意力的架构属性。2026 年最强的模型(Opus 4 系、GPT-5 系)全都有,有研究实证。
上下文开头中间结尾(最近)
注意力强度沿上下文位置的 U 形分布 —— "Lost in the Middle"(Liu et al. 2023, TACL)
三个实证结论,直接解释你的现象:
1
Lost in the Middle(U 形):模型对开头和结尾注意力最强、中间最弱。中间信息准确率比两端低 30%+。你流程开头强调的规则,执行到中段时正落在注意力洼地。
2
Context Rot(上下文腐烂,Chroma 2025):输入越长,哪怕信息明明在窗口里、哪怕任务很简单,性能也单调下降。你的 skill 编排越往后,中间塞满了工具日志/中间结果,早期规则被越埋越深。
3
超 50% 满后退化为"按距结尾的距离衰减":上下文塞过一半,U 形会塌成"只偏好最近的内容"。这就是为什么开头放的规则最先失效——它离"现在"最远。根因是 RoPE 的 long-term decay。
一句话记住病理:规则放在开头 = 放在注意力最弱、且随流程推进越来越远的位置。模型不是"忘了",是"看不见了"。Chroma: Context Rot · Lost in the Middle 工程解读
Claude Code 和 Codex 表现不同在哪
你观察到"两边都偏但表现不同",这是对的,根源在两者怎么装载你的规则:
Claude Code
CLAUDE.md 的规则是以
user message 形式注入在 system prompt
之后的——是"上下文"不是"强制配置",所以本就不保证严格遵守。好消息:
项目根 CLAUDE.md 扛 compaction(压缩后会从磁盘重读重注入);坏消息:
子目录 nested CLAUDE.md 不重注入,子 agent 还可能根本不继承(Explore/Plan 直接跳过 CLAUDE.md)。
Codex
读
AGENTS.md。长任务里同样衰减,但它有个 Claude 没有的原生武器:
/goal——把目标冻进一个"目标生命周期",系统级 event bus 跨 turn/中断/resume
反复把目标 steering 注入回模型的回复流。也就是说 Codex 在"保持长程目标"上有机制兜底,而规则细节同样会漂。
诊断:用 trace 定位"在哪一步偏的"
现在 trace 登场——它的作用是把"过程跑偏"从模糊感觉变成可定位的一行。拿到执行轨迹,你要回答一个二选一的问题:
规则失效,只有两种可能,trace 帮你区分:
① 规则被挤出了注意力(加载了,但被中间内容淹没)→ 解法是重注入到最近上下文
② 规则压根没加载(子 agent 没继承 / nested 文件没读到)→ 解法是修加载,重注入没用
Claude Code 拿 trace
· 会话本身就是 JSONL transcript
· 用 hook 写结构化时间线:
PostToolUse /
Stop 把每步事件追加成 NDJSON
· 诊断"是否加载":
InstructionsLoaded hook 能记录哪些指令文件被加载、何时、为何 —— 直接区分上面的 ①/②
Codex 拿 trace
·
codex exec --json:每个状态变更输出一行 NDJSON 事件,天然是可解析的执行轨迹
·
--output-schema 可约束输出结构
·
codex exec resume 续跑时也能接着收事件
诊断也能委派(呼应第二课):跑完别自己读几百行日志——丢给一个分析 agent:"读这份 trace,找出第一个'动作与我开头定的规则矛盾'的步骤,告诉我那一步之前上下文里还能不能看到规则。" 让它替你定位 ①还是②。
预防:从源头让它不漂(重点)
诊断完就该治。核心心法一句话——别指望模型自觉记住开头的规则。四个层次,从轻到重:
1
不变量钉磁盘 + 每步读回(你已有这条规范,这里是工具化)。把硬规则/验收口径冻进一个短文件(PLAN.md / INVARIANTS.md),编排里每个 skill 第一步就是"读回该文件",不靠对话记忆。这把规则从"开头一次性说"变成"每步重新放到最近上下文"。
2
短宪法重注入(对抗 recency 偏置的主力)。用确定性 hook 在每轮/每次工具调用前把 3-5 条硬规则塞回最近上下文——不靠模型,hook 是确定性的。
3
硬约束走拦截,不走"提醒"。必须遵守的(比如"切 ADBKeyboard 后必须切回原 IME""不删用户数据")用 hook 直接拦死违规动作,而不是写进规则祈祷它记得。提醒会漂,拦截不会。
4
拆子任务隔离上下文。长编排切成独立步骤,每步给干净的上下文,让规则永远处在"开头"而不是被埋在第 47 步。子 agent 隔离天然实现这点。
落到命令:两个工具具体怎么做
Claude Code
重注入短宪法(每轮):
UserPromptSubmit hook 返回
additionalContext 字段塞 3-5 条硬规则。
硬拦截:
PreToolUse 返回
permissionDecision:"deny" 或 exit code 2 拦危险动作;
Stop 返回
decision:"block" 逼它补跑校验(如"测试没过不许停")。
子 agent 不丢规则:把硬规则写进子 agent 的
prompt(=它的 system prompt body)或用
skills 字段预注入,并在派活 prompt 里要求"动手前先读回 PLAN.md"。
临时强调的规则:写进
项目根 CLAUDE.md(扛 compaction),别只放 nested。
Codex
冻结长任务目标:
/goal <objective> 把目标写进生命周期,系统跨 turn 自动把目标推回模型。
硬拦截:hook(5月GA) 的
Stop 返回
{"decision":"block","reason":"..."} 不达标逼它再来一轮;
PreToolUse deny 危险操作。
外化状态四件套(官方长任务方法论):Prompt.md(spec,写死"done when") + Plan.md(里程碑+验收命令) + Implement.md(runbook) + Documentation.md(实时状态),每个里程碑后跑 test/lint/build 立即修。
落到你的 skill 编排:三步改造
把你那组自动化测试 skill 改成不漂的(约 40 分钟)
不用大改,按这三步加护栏:
① 抽出 INVARIANTS.md
把你"前面强调的规则"写成 5 条以内硬清单→
② 每个 skill 开头读回
第一步动作 = 读 INVARIANTS.md→
③ hook 重注入 + 拦截
每轮塞回短宪法,违规动作拦死
第一步话术(让 Claude 帮你抽,你裁决):
读我这组自动化测试 skill 的定义,把我在里面反复强调、但执行容易被忽略的
硬规则提炼成 INVARIANTS.md,5 条以内,每条必须是可检查的祈使句
(不要"注意XX",要"做XX前必须先YY")。
第三步话术(加重注入 hook):
给我一个 UserPromptSubmit hook,每轮把 INVARIANTS.md 的内容作为
additionalContext 重新注入;再给一个 PreToolUse hook,拦截违反其中
"硬拦截类"规则的工具调用(deny + 说明原因)。
验证它真不漂了:改造前后各跑一次同样的长编排,用 codex exec --json 或 Claude 的 JSONL 各留一份 trace,对比"后半程违反规则的次数"。把这个对比发回给我——这是检验本课是否成立的证据。
自测(先回忆,再点选)
1. agent 在长流程后段忽略早前的规则,根本原因是什么?
这是 Transformer 注意力的架构属性(lost in the middle + context rot),2026 最强模型都有。规则写清楚有帮助,但根因是"开头的规则落在注意力洼地、且离当前越来越远"。换模型也治不了。
2. 关于 trace 和上下文漂移的关系,正确的是?
trace 是行车记录仪——帮你回放定位在哪步偏的,但不掰方向盘。治漂移要靠重注入/拦截/隔离,trace 只负责诊断。
3. 诊断时发现"规则压根没加载",正确的解法是?
规则失效分两种:被挤出注意力(→重注入) vs 压根没加载(→修加载,如子agent没继承/nested没读到)。没加载时重注入也是注入了个寂寞,得先让它真正进 context。Claude 用 InstructionsLoaded hook 能区分这两种。
4. 必须 100% 遵守的硬约束,最可靠的做法是?
放开头会被埋、放结尾会被新内容挤走、强调措辞会漂——凡是"靠模型记得"的都不可靠。真正硬的约束用 hook 拦死(PreToolUse deny / Stop block),让它无视模型怎么想都执行不了违规动作。
首选阅读(一篇就够)
Chroma — Context Rot: How Increasing Input Tokens Impacts LLM Performance(约 15 分钟,含 18 个模型的受控实验图表)。读完你会彻底理解"为什么不是你的错",并对"上下文越短越聚焦越可靠"形成肌肉记忆。
引用文献
🧠背诵区
点卡片翻面。记的是能用的判断核心,不是定义。
闪卡 1 / 正名
Agent 长流程中忘记早前规则,这是"trace 问题"吗?该怎么定性?
翻面
不是。这叫
上下文漂移(instruction drift),是病;
trace 只是诊断工具,不是病本身。根因是 Transformer 注意力架构属性(lost in the middle / context rot),不是你的错。
闪卡 2 / 机制
为什么连 2026 最强模型也会在长流程中途丢规则?
翻面
注意力呈
U 形——开头结尾记得牢,中间最易丢(lost in the middle);上下文越长、噪音越多,遵循度越降(context rot)。这是架构属性,不靠"模型更强"消除,只能靠机制对治。
闪卡 3 / 预防闭环
防 skill 编排漂移的三步改造是什么?
翻面
①把关键规则抽进
INVARIANTS.md(短宪法);②
每步从磁盘读回不变量,不靠对话记忆;③用 hook 把不变量重注入每个子 agent,并拦截违规动作。核心:把规则钉在磁盘 + 每步读回。
⏱ 间隔复习:明天扫一遍,3 天后再来。交织:翻一张第三课「编排大重构」的旧卡——流水线"每关把门、关卡间读回产物"正是这里"每步从磁盘读回不变量"的同一招。
🗣复述区
能讲清楚,才是真懂——比能回忆高一层。
复述任务
用一段话讲清楚:
你的自动化测试 skill 执行到后面会忽略前面强调的规则,根因是什么、为什么"换更强的模型"解决不了、正确对策是什么?
参考表述
根因不是模型不行,而是 Transformer 注意力的架构属性:上下文里中间位置的信息最容易被忽略(lost in the middle),上下文越长、越嘈杂,对早前指令的遵循度越下降(context rot)。这是结构性的,2026 最强模型也有,所以"换更强模型"治不了。正确对策是用机制把规则锚定住:把关键不变量抽成一份简短的 INVARIANTS.md 钉在磁盘上,让编排的每一步都先从磁盘读回这份约束再动手,而不是指望它一直记在对话里,再用 hook 在每个子 agent 启动时重注入、并拦截违规动作。本质是不跟模型的记忆较劲,而是把规则放到它每步都必须重新看到的地方。
讲不顺的地方就是还没真懂的地方 —— 发给我,我帮你补上。