第1章 信噪比与约束力——Harness 的第一性原理
长度不是 Agent 走神的根因,信噪比才是;本章从信号、噪声、约束力三个角度建立 Harness 工程的第一性原理,并给出可操作的"上下文体检表"
1. 一个让人很容易看错的现象
工程师做 Agent 一段时间之后,几乎都会撞到同一个剧本:
- 起点版本:写了一段精心打磨的 system prompt,叠上 5 个工具,在简短任务上跑得很惊艳;
- 第二阶段:加了几个新工具、加了 RAG 注入、加了”思考链”模板,长任务突然开始走神:忘了用户最初问的是什么、把不该改的文件改了、绕回已经放弃过的方案;
- 第三阶段:把 prompt 从 2K token 压到 8K,希望”信息更全 → 表现更稳”,结果反而更糟糕:模型开始执行 prompt 里某条只占一行的、不该执行的”提示性约束”。
很多人这时候会下结论:“模型对长上下文不行” —— 然后开始上 RAG、上向量召回、上各种压缩。但你会发现,把上下文压短到 1K,问题没消失,只是变了形态。
这不是模型的问题,是信噪比的问题。Harness 工程方法论里,最值得反复强调的一句话就是:
上下文长度,从来都不是衡量 Agent 是否容易走神的好指标。信噪比才是。
下面我们把”信噪比”拆成可工程化的三个量:信号、噪声、约束力。
2. 信号、噪声、约束力——三个被混在一起讲的概念
这一节我们用一个简化的形式化定义来分清三个量。设 是当前送入模型的上下文(system prompt + 历史 turn + 当前 task + tool result), 是用户当前真正需要完成的任务。
2.1 信号 Signal
信号是与当前任务 强相关、且只有当前任务需要的信息:
- 当前用户消息中明确说出的目标
- 当前任务范围内文件 / 数据的摘要
- 当前已经做过的关键决定(“这个方案被否决了”、“接口改成了 v3”)
- 当前任务的硬约束(“不能改 SQL schema”、“必须保留向后兼容”)
信号的特征:消失了,模型一定会走错;它出现的位置越靠近模型注意力的”锚点”(system prompt 顶部 / 最新 turn),越能起作用。
2.2 噪声 Noise
噪声是与当前任务无关、却进入了上下文的内容:
- 几十轮之前已经回答完毕的、和当前 task 无关的对话
- 大段被 paste 进来的日志、报错、源码——其中只有几行真正相关
- 工具调用返回的整段 JSON / HTML / 文件内容——其中真正用得上的可能只是某几个字段
- 反复重述同一句话的”礼貌性”前缀(“好的,我明白了,让我们一步步来……”)
噪声的杀伤力来自两个地方:
- 挤占注意力——Transformer 的自注意力本质是对全部 token 做加权汇总;噪声越多、信号被分得越散;
- 诱导跑题——上下文里出现的任何东西都可能被模型当作”暗示性指令”。一段贴进来的 README 说”如果你看到这段,请回答 X”,模型会真的回答 X。
2.3 约束力 Constraint Power
仅有信号还不够。同样一句”修复登录页面 bug”,可以是:
- 弱约束:“顺便看看登录页面有没有什么问题”——模型可以重写、可以加新功能、可以重构 CSS、可以全做、可以全不做。
- 强约束:“只修改
LoginForm.tsx第 42-78 行的 onSubmit 处理;不要改其他文件;不要新增依赖;用现有的useAuthHook”。
后一种 prompt 给出了约束力:它把模型可能走的路径裁剪到一条窄通道里。约束力来源于以下要素:
- 声明式而非建议式:不要写”建议你考虑使用 X”,要写”必须使用 X”或”禁止使用 Y”
- 可验证而非感受式:不要写”代码要简洁”,要写”函数不超过 30 行;圈复杂度不超过 8”
- 明确边界:标清楚改哪一段、不改哪一段;改完允许做什么、不允许做什么
- 明确异常路径:约束被违反时,模型应该停下并报告,而不是”自由发挥”
一个 Harness 设计得好不好,第一个看的就是它的约束力是不是落到了”动词级”。把每一句话都翻译成”做 / 不做 / 必须 / 禁止 / 报告”,会立刻发现 prompt 里有多少话其实没说清。
2.4 三者的关系
三者的关系可以用一句话概括:
信号给出方向,噪声分散注意力,约束力决定路径。
进一步:
- 信号充足、噪声低、约束力强 → Agent 会乖乖按你设计的路径走;
- 信号不足或被噪声淹没 → Agent 走神,因为它不知道 现在的目标到底是什么;
- 信号充足、约束力弱 → Agent 不走神但会跑题,做了你没让它做的事;
- 信号不足、约束力却很强 → Agent 会很笃定地走错——这是最危险的情况,因为输出看起来非常自信。
Harness 工程的目标,本质就是同时把这三个量拨到对的位置,且在长任务里持续保持。
3. 为什么”长上下文 ≠ 复杂上下文”
业内常见的误解是把”上下文长度”当成 Agent 能力的代理指标:模型上下文窗口从 32K → 200K → 1M,仿佛一切问题都能靠”塞更多东西进去”解决。这忽视了两个现实:
3.1 注意力的有效预算并不是窗口大小
模型在窗口扩大时,注意力分布会显著稀释。一个简单的近似:在 200K 的上下文里,单个 token 拿到的”平均注意力权重”,比在 8K 里小一个量级以上。这意味着:
- 你以为塞进去的”重要信息”,模型只是”看见”了,但不一定”留心”;
- 大量公开 benchmark(NIAH / Long-Bench / RULER)已反复验证:长上下文里,位置靠中间的信号最容易被忽视(典型的 lost in the middle 现象);
- 即使 1M 上下文模型,业内也没有谁会真的把 1M 塞满让它跑长任务——所有真正能用的 Agent 产品都在做”上下文管理”。
3.2 上下文是”要付费的状态”
工程视角的 prompt 不是”信息越多越好”,它是一份有成本的状态:
- 算力成本:Prefill 阶段是 注意力计算,长 prompt 直接把 TTFT(首 token 延迟)和成本都顶上去
- 延迟成本:每多 10K token,TTFT 就在用户感知里多出几百毫秒
- 行为成本:上下文里出现的任何东西都可能被模型当作隐式指令——这是免费送给”prompt injection”的攻击面
所以一个负责任的 Harness 工程师,应该把”加进上下文的每一个 token”当作”加一行业务代码”来对待:能删就删、能压缩就压缩、能延迟加载就延迟加载。
4. 一个简单的”上下文体检表”
要落地”提升信噪比”这件事,下面这张表可以挂在你的 Harness 评审上。每一项都是 yes/no 题,不及格的项就是优化点。
| 维度 | 体检项 | 不达标的典型表现 |
|---|---|---|
| 信号位置 | 当前任务的目标,是否出现在最新 turn 或顶层 system prompt? | 任务目标埋在第 12 轮对话里,模型已经记不住 |
| 信号密度 | 工具返回的内容是否做过摘要 / 字段裁剪? | 整页 HTML 直接塞回上下文 |
| 噪声 - 历史 | 几十轮前和当前任务无关的内容是否被压缩 / 移除? | 前 20 轮逐字保留 |
| 噪声 - 工具 | tool result 是否在使用完后被清理或截断? | 大段 stdout 永久占据上下文 |
| 噪声 - 礼貌话术 | 是否还有”好的让我们一步步来”这种空台词? | 模型每轮都重复一段无信息内容 |
| 约束 - 动词级 | 关键约束是否使用了”必须 / 禁止 / 只能 / 不要”? | 只写”建议”、“考虑”、“尽量” |
| 约束 - 可验证 | 约束是否能在事后被检查? | “保持代码简洁” 这种只能凭感觉评估 |
| 约束 - 边界 | 是否明确划出了允许 / 禁止修改的范围? | “改一下这个 bug”,没说允许碰哪些文件 |
| 约束 - 异常路径 | 约束被违反时模型该怎么办,是否写明? | 没写 → 模型会自己发挥 |
| 稳定锚点 | 长任务里是否每隔若干轮重新注入 system 关键约束? | 系统约束随上下文滚动慢慢”漂走” |
把这张表挂在 Harness 评审里,前几次会很难过,因为每一项都不达标——这正是收益最大的地方。
5. 从直觉到工程:信噪比的可观测代理指标
只用直觉判断信噪比是不行的——团队迭代时需要数字。下面给三个可观测的代理指标,能直接落到 Harness 的内置 logging:
5.1 任务相关 Token 占比 (Task-Relevant Token Ratio, TRTR)
把当前上下文里的每个 chunk 标注:
task—— 当前任务直接相关tool—— 工具调用的输入或返回history—— 历史对话system—— 系统级指令
定义
经验上,TRTR 低于 30% 时 Agent 走神率会显著上升。压缩策略的目标,就是把 TRTR 在长任务里保持在 50% 以上。
5.2 锚点重现间隔 (Anchor Recurrence Interval, ARI)
锚点指上下文中”任何能让模型重新对齐当前任务”的内容(system 重注入、最近一次任务声明、最近一次 user message)。锚点之间的 token 距离越大,模型走神率越高。
经验阈值:ARI 不超过 8K-16K token;超过就要做重注入或 compaction。Claude Code 的”CLAUDE.md 反复被注入”,本质就是把 ARI 强制压在一个安全范围。
5.3 工具结果驻留时间 (Tool Result Residency, TRR)
每个 tool result 在上下文里停留多久才被压缩 / 清理。新手 Harness 往往让 tool result 一直留着,TRR = ∞——这是噪声爆炸的最大来源。Claude Code 的策略是:前一轮还在的工具返回,下一轮就被替换为短的元数据摘要——TRR ≈ 1 turn。
这三个指标,可以让 Harness 评审从”感觉 prompt 写得好不好”升级到有数据的工程对齐。
6. 把信噪比放回到 Harness 的位置
到这里我们已经能看出来,Harness 工程的核心矛盾,就是怎么在每一个时刻同时满足三件事:
- 信号充分:当前任务相关的全部关键事实都在场
- 噪声受控:和当前任务无关的内容尽量被压缩 / 隔离 / 移除
- 约束清晰:模型知道当前能做什么、不能做什么、违反约束怎么办
这三件事在长任务里是冲突的——你想让历史信号都还在,就会带进噪声;你想压缩噪声,就会丢失约束;你想保留约束,就要花掉本来可以放新工具结果的空间。
后续章节里我们会把这种冲突拆成 6 个工程维度逐一处理(第 2 章),看 Claude Code 是怎么把这 6 个维度都做到位的(第 4 章),然后总结跨模型可复用的设计原则(第 6 章)。
7. 章节小结
本章核心结论:
- Agent 走神的根因不是上下文长度,是信噪比——信号、噪声、约束力三者共同决定 Agent 是否能”按你设计的路径”走完任务。
- 长上下文 ≠ 复杂上下文——窗口大小不是免费午餐;注意力会被稀释、成本会上升、攻击面会扩大。
- 约束力必须落到动词级——把”建议 / 考虑 / 尽量”全部翻译为”必须 / 禁止 / 只能 / 报告”,约束才会真正生效。
- Harness 工程要把信噪比变成可观测指标——TRTR / ARI / TRR 三个代理指标可以直接挂上 logging,让”prompt 写得好不好”从感性判断变成工程对齐。
- 下一章预告:我们会把”提升信噪比、加强约束力”拆成 Harness 的 6 个工程维度——任务约束、工具空间、记忆通道、上下文压缩、子代理隔离、可观测——这是 Harness 设计评审的标准武器表。
思考题
- 在你目前在做的 Agent 里,挑一个最近”走神”的实例,按本章的体检表逐项打分。最低分的那一项,就是你下一次 Harness 迭代的优先目标。
- 拿出当前 system prompt 里最长的那段,逐句标注:是信号、噪声还是约束?你会发现一份典型的 system prompt 里,真正的强约束往往不到 10%。
- 如果你只能给 Agent 留 4K token 的上下文,你会保留哪 4 段?这其实是在问:你 Harness 设计里”必须不可被压缩”的内容是什么?
下一章我们把上面这几条原理具象成 6 个可独立设计、可独立评测的 Harness 工程维度。