Skip to content

第 1 章 Agent = Model + Harness

这份手记的核心命题:决定一个 Agent 好坏的,不是模型有多强,而是 harness(脚手架)有多好。

开篇:我把 prompt 调到怀疑人生

我一度相信,Agent 不好用,就是 prompt 没写好。

那是我刚开始做 Agent 项目的时候。我让 Agent 做一件不算太复杂的事——在群聊场景里,该响应的时候响应,不该响应的时候闭嘴。听起来很简单,对吧?

结果我折腾了整整三天。

第一天,我发现 Agent 对"该不该响应"判断不准。我的第一反应是:system prompt 写得不够清楚。于是我加规则:"当用户直接 @ 你时必须响应;当用户在闲聊且没有明确指向你时,保持沉默。" 加完一跑,好了一点,但还是会误触发。

第二天,我觉得是例子不够多。于是我在 prompt 里塞了一堆示例(术语叫 few-shot,就是直接在提示词里给模型看几个"输入→正确输出"的范例,让它照着学)。什么情况要响应、什么情况不要,每种列了五六个例子。prompt 膨胀到两千多字。这回准确率上去了,但又出新问题:Agent 的响应变得特别啰嗦,因为它"记住"了那些示例里的详细回复风格。

第三天,我放弃了调 prompt,回头去看代码。这一看才意识到,真正的问题压根不在提示词——是我自己在代码里埋了一颗雷。

我当时图省事,用最直觉的方式实现了触发判断:在代码里写了 if 判断,如果消息是 @ Agent 的,走一条完整的处理路径(意图识别 → 记忆读写 → 生成回复);如果不是 @ Agent 的,走另一条简化路径。两条路径,各自一套逻辑。

这个写法的问题在第三天才暴露出来:Agent 的行为像两个人格。 被 @ 的时候它是个"完整助手",没被 @ 的时候它是个"缩水版"。更糟的是,两条路径共享同一份记忆,却不共享上下文——Agent 被 @ 之后的对话,和没被 @ 时的上下文是断开的,它表现得像失忆了。

我花了三天调 prompt,一无所获,因为问题根本不在 prompt。问题在于我用传统程序员的惯性,用 if-else 把一个本该由模型统一决策的东西,硬切成了两条割裂的路径。

那一刻我意识到,有一个我从来没正眼看过的东西,比 prompt 重要得多——它叫 harness

模型之外,皆是工程

那次经历之后,我回头梳理了一下自己到底栽在哪。我栽在的那个东西,有个名字:

Addy Osmani 说

A decent model with a great harness beats a great model with a bad harness. (一个中等模型配优秀的 harness,胜过顶级模型配糟糕的 harness。)

Harness 这个词,直译是"马具"或"挽具",在 Agent 语境里,我翻译成"脚手架"——它指的是模型之外的一切

  • 工具的定义和描述
  • 编排逻辑(什么时候调什么工具、循环几次)
  • 上下文管理(给模型哪些信息、什么顺序)
  • 错误处理(工具失败返回什么、循环耗尽怎么办)
  • 验证机制(怎么知道输出是对的)

这些加在一起,就是 harness。而 Agent 的实际表现,等于模型能力 × harness 质量。模型是乘数,harness 也是乘数——但 harness 是你能控制的那个。

一个让我彻底服气的数据

如果你觉得上面这些都是我的一面之词,有个公开数据:TerminalBench 基准测试里,研究者只换了 harness 设计(模型完全不变),Agent 的排名就变化了 20 多个位次。

20 多个位次。同一个模型,换一套脚手架,排名从上游掉到下游,或者从下游冲到上游。

这意味着什么?意味着你花在优化 harness 上的每一小时,比花在挑选模型上的回报高得多。而很多团队恰恰相反——一遇到 Agent 不行,第一反应是"换个更强的模型",而不是"查查 harness 哪里有问题"。

我以前也这样。直到那次三天的 prompt 噩梦之后。

脚手架的共生演化

把 harness 当成工程资产,有一个更深的认知,我花了更长时间才想明白:harness 不是越多越好。

这听起来有点反直觉。多加点约束、多加点规则,不是更稳吗?不一定。Anthropic 提过一个概念叫"scaffolding"(脚手架),它打了个比方特别贴切:harness 就像建筑施工的脚手架,它编码了对模型能力的假设。

举个例子。早期的模型经常输出格式不对,所以大家会在 prompt 里加很多格式约束:"必须输出 JSON""不要用 markdown""字段名用小写"。这些约束就是脚手架——它假设"模型自己管不住格式"。

但模型在升级。现在的主流模型,输出 JSON 的能力已经相当稳了。这时候,那些过时的格式约束就该拆掉。不拆会怎样?prompt 会被脚手架塞满,反而挤占了真正有用的上下文空间。

这就引出一个我反复栽过的坑——脚手架只加不减。 我见过太多 Agent 项目(包括我自己的),harness 越堆越厚,像一栋老房子加满了承重墙和支撑柱,最后模型升级了,这些墙和柱反而成了累赘。

改了就要测

还有一层更微妙的含义:模型和 harness 是耦合训练的。

这话不是我说的,是 Anthropic 的工程团队提的。大意是,前沿模型在后训练阶段,会配合特定的工具格式、错误处理风格、上下文组织方式做优化。这意味着——你随意改动 harness 的某个细节,可能因为紧耦合导致性能退化,而且这种退化是悄悄发生的。

举个我亲历的例子。有一次我把一个工具的返回值从"JSON 对象"改成了"JSON 对象外面包一层自然语言摘要"。从工程角度看,后者信息量更大、更友好。但改完之后,Agent 调用这个工具的时机变奇怪了——它开始过度依赖这个工具,明明不需要调用的时候也调。

为什么?因为这个工具的返回值变"好读"了,模型更"喜欢"用它了。一个我以为纯改进的改动,引发了行为偏移。

结论很朴素:改了 harness 必须回归测试。 不能想当然地认为"我改得更好了,所以肯定没事"。Agent 的行为是模型 × harness 的乘积,动了一个因子,另一个因子不变,乘积也会变。

一个反模式:迷信"换模型"

讲到这里,可以点出这份手记里会反复出现的第一个反模式了。

反模式 · 迷信模型升级

Agent 表现不好 → 第一反应是"换个更强的模型" → 换了发现确实好一点 → 但根本问题还在 → 下次不行再换更强的。

这个循环的问题在于:它把 harness 的问题误诊成模型的问题。

模型升级解决的是"能力上限"——原来做不到的事,现在能做到了。但 Agent 表现不好,绝大多数时候不是能力上限的问题,而是"能力没发挥出来"——这恰恰是 harness 的锅。

怎么判断你踩的是哪种坑?其实特别简单:换个最强的模型试一次。

好了 → 是模型能力不够,等升级或换模型合理。还是不行 → 别在模型上浪费时间了,去查 harness。

就这么一条。这份手记剩下的部分,基本都在讲"怎么查 harness、怎么改 harness"。因为那是你能掌控的地方。

这一章的工具:harness 自检清单

每章结尾,我会给一个可以带走的工具。这一章的是一份 harness 自检清单。当你发现 Agent 表现不对、又不知道从哪查起时,按这个清单逐项过一遍:

🔧 harness 自检清单

遇到 Agent 表现不好时,按以下顺序排查(先别想模型的事):

1. 工具层面

  • [ ] 工具描述是否足够清晰?有没有写"什么时候用、什么时候不用"?
  • [ ] 工具描述里有没有具体的 usage example?(这是 prompt 的一部分,不是文档)
  • [ ] 工具失败时,返回的错误信息够不够?是泛泛的"出错了",还是"原因 + 当前输入 + 建议修正"?
  • [ ] 工具返回值是否包含模型下一步决策需要的信息?(还是只返回一个 ID,逼模型再查一次)

2. 上下文层面

  • [ ] 模型每次决策时,能看到它需要的所有信息吗?
  • [ ] 上下文里有没有冗余信息,挤占了有效空间?
  • [ ] 过时的格式约束、冗余的 few-shot,还在 prompt 里吗?(该拆的脚手架拆了吗)

3. 循环层面

  • [ ] Agent 的最大循环次数够不够?(太少会任务没做完就退出)
  • [ ] 循环耗尽时有没有兜底?(还是直接退出,用户什么都没收到)
  • [ ] 触发和响应有没有混在一起?(Agent 被 @ 到就必须走完整流程吗)

4. 验证层面

  • [ ] 你怎么知道这次输出是对的?(靠人眼看?还是有自动检查)
  • [ ] 工具调用的副作用,有没有被验证过安全?(比如写数据库的操作)

经验法则:这份清单查完,80% 的问题能定位。剩下的 20% 再去考虑模型。

小结

这一章想讲的,用一句话说就是:别老盯着模型,多看看脚手架。

模型是黑盒,你改不了它。但 harness 是白盒——工具描述、错误信息、上下文组织、循环结构,每一项都是你能动手、能测试、能优化的。把精力放在你能掌控的地方,回报远比挑模型高。

下一章,我会接着这个话题往下讲——当你把注意力从"模型"转到"harness"之后,会进入一条认知升级的路径。我把这条路径叫"四阶认知",它是传统程序员切入 Agent 工程的标准通道。

下一章

第 2 章 · 四阶认知:从 Prompt 到 Loop —— 传统程序员切入 Agent 工程的四个认知阶段。你在哪一阶?