Agent 老是散架?该修的是 harness,不是提示词

大多数 agent 失败不是推理失败,是环境失败。提示词改变一次尝试,harness 改变每一次尝试。19 节清单:从任务契约到变更回执,从工具网关到"构建是为了删除"。

分享
Agent 老是散架?该修的是 harness,不是提示词

大多数人在改错的那一层。

agent 失败的时候,他们重写提示词。再失败,就加更多指令。然后换模型、加工具、把上下文窗口调大,希望下一次跑出来不一样。

但很多 agent 失败不是推理失败,是环境失败:

  • 它不知道该看哪些文件;
  • 它在对的地方用了错的工具;
  • 它把上一轮会话里做的决定丢了;
  • 它没跑检查就宣称成功;
  • 它在一次部分失败之后重复了同一个动作;
  • 它拿到了本该需要审批的权限。

模型未必是问题所在;模型周围的系统不完整。这个系统叫 harness,而设计它正在变成一门自己的工程学科。

提示词改变一次尝试,harness 改变每一次尝试。

下面这份指南来自英文长文《Harness Engineering: The Complete Guide to Building AI Agents That Don't Fall Apart》(Lunar,2026-09-06)。原文 19 节,本文完整编译全部要点,并在最后加上我们的对照整理与边界说明。


一、模型不是 agent

模型能推理、生成、比较、选择。但 agent 还必须与真实环境交互:理解任务、找到相关上下文、选择并使用工具、保持状态、遵守权限、检查结果、从失败中恢复、证明工作确实完成了。

模型是这套系统里的推理引擎,harness 是让推理变得可运行的一切。

user request
     |
     v
+-----------------------------+
|           HARNESS           |
| contract | context | policy |
| tools    | state   | checks |
| traces   | recovery          |
+-----------------------------+
     |
     v
    model
     |
     v
real environment

一个强模型装在弱 harness 里,仍然是弱 agent。 它可能偶尔给出惊艳的单项回答,但在长任务、变化的环境与部分失败面前,表现会不稳定。

harness 工程的目标不是消除模型的不确定性,而是把不确定性关进一个能观察、能验证、能恢复的系统里。

二、从一份任务契约开始

大多数 agent 任务从一句模糊的意图开始:"优化一下注册流程。" 这句话够对话用,不够自主执行用。

在 agent 动手之前,harness 应该把它变成一份任务契约,回答五个问题:

  1. 必须存在的结果是什么?
  2. 范围之内包含什么?
  3. 什么不能变?
  4. 什么证据能证明完成?
  5. 哪些动作需要人批准?
objective: reduce onboarding drop-off

scope:
  - signup flow
  - onboarding analytics

constraints:
  - do not change authentication
  - preserve existing mobile behavior

acceptance:
  - tests pass
  - analytics event is emitted
  - screenshots cover desktop and mobile

approval_required:
  - production deployment
  - database migration

这件事改变的是 agent 的问题:从"我下一步该做什么?"变成"哪个动作让环境朝契约里的结果前进?"

没有契约,agent 会为"看起来在做事"优化;有契约,它才能为"被验证的完成"优化。

三、给地图,不给手册

把整个仓库、整套文档、整段历史都塞进上下文,不叫上下文工程,叫上下文洪水。

harness 应该先给一张小地图,等细节相关时再让它去取。

PROJECT MAP

product rules     -> docs/product/
architecture      -> docs/architecture.md
frontend          -> apps/web/
backend           -> services/api/
tests             -> tests/
commands          -> docs/commands.md
release rules     -> docs/release.md

这就是渐进披露:任务 → 项目地图 → 相关子系统 → 具体文件 → 局部说明。上下文该因为任务需要而展开,而不是因为信息存在而展开。

一个合格的"上下文编译器"要决定四件事:

  • 什么永远需要;
  • 什么可以稍后检索;
  • 什么已经过期;
  • 什么可以摘要,什么必须逐字保留。

目标不是最大上下文,而是每个 token 的最大信号。

四、造工具网关,不要堆工具

给 agent 二十个工具,不会让它变强,只会给它二十种犯错的方式。

每个工具都该有清晰的契约:

TOOL: edit_file

inputs:
  path
  patch

preconditions:
  path exists
  path is inside allowed workspace

success evidence:
  patch applied
  resulting diff returned

failure behavior:
  no partial overwrite
  structured error returned

risk class:
  reversible

harness 要控制工具怎么被暴露、怎么被使用:隐藏无关工具、校验参数、限制路径与域名、挂超时、让重试幂等、归一化输出、对高风险动作要求确认、返回证据而不是一句 success。

由此产生一条重要的分离:

model    decides intent
gateway  validates action
tool     changes environment
sensor   observes result

模型可以提议一个动作;由网关决定这个动作是否足够合法、可以执行。

五、把脑、手、历史分开

很多脆弱的 agent 把所有东西都塞进一段越来越长的转录里:推理、工具调用、文件、决定、错误、旧观察,全都在抢同一个上下文窗口。

更强的系统把三种职责分开:

部分 职责 它不需要什么
脑(Brain) 规划、推理、选择 不需要每一段原始事件
手(Hands) 在受控环境里执行工具 不需要理解整个目标
历史(History) 保存持久事实、决定与运行状态 不需要会推理

模型需要的是正确的当前状态,不是全部事件;沙箱需要的是安全执行一个有界的动作,不是全盘理解;会话日志需要的是在当前上下文消失之后仍然留住发生了什么。

这种分离让长跑 agent 更容易恢复、检查和修复,也让你能替换其中一块而不用重建全部。

六、记忆必须变成持久状态

对话历史不是可靠记忆,它只是一个事件流。有用的记忆应该被转换成显式状态,至少保留四类:

类别 内容
FACTS 关于环境的稳定信息
DECISIONS 做过的选择以及理由
PROGRESS 已完成 / 进行中 / 阻塞 / 剩余
LESSONS 应当改变未来行为的失败
facts:
  - checkout validation lives in services/orders

decisions:
  - reuse the existing validation pipeline
  - reason: avoids a second source of truth

progress:
  completed:
    - added server-side rule
  remaining:
    - update integration test

lessons:
  - local test command requires TEST_DB_URL

这比"回放五十页转录、指望模型注意到那一行"有用得多。原始历史存起来做审计,持久状态编译出来做执行。

七、完成需要证据

agent 说"done"不是任务完成的证据,那只是又一个模型输出。完成必须由环境里可观察的变化来判定。

主张 证据
"bug 修好了" 之前失败的测试现在通过
"页面能用了" 浏览器流程走通
"迁移是安全的" dry run 与回滚都通过
"报告是对的" 数值与源数据一致
"任务完成了" 每一条验收检查都通过

harness 应该先跑最便宜的确定性检查:

syntax
  -> types
      -> focused tests
          -> integration tests
              -> visual or semantic review
                  -> human approval

不要用另一个模型去回答编译器、schema、校验和、查询或测试能回答的问题。用模型处理歧义,用代码处理管道。

模型可以提议"任务完成了",只有环境能证明它。

八、验证应该攻击结果

Worker 和 evaluator 不该共享同一个目标:worker 努力做出最强的解法,evaluator 努力找出它该被拒绝的理由。

worker
  -> produces candidate

verifier
  -> checks contract
  -> searches for missing cases
  -> tests unsupported claims
  -> attempts to break result

survives -> accept
fails    -> return targeted evidence

这种不对称很重要。如果你让同一个 agent、在同一个上下文里"复查一下自己的活",它通常会保住那个制造了错误的假设。

有用的验证环节应该具备:明确的拒绝标准;能拿到产物;能拿到验收契约;需要时能换工具或换新上下文;以及"只拒绝、不负责修"的权限。

验证不是第二意见,是一次未遂的反证(attempted disproof)。

九、模型提议,策略授权

有些规则永远不该依赖"模型是否记得住":没批准不发布、不暴露密钥、不在工作区之外写、不超预算、没跑过的测试不许标通过。

这些不是提示词里的建议,它们是策略。最安全的设计把策略放在推理回路之外:

风险档 动作 门
低风险 读文件、搜索、查看 自动
可逆变更 改工作区、跑测试 自动 + trace
外部副作用 发消息、部署、购买 显式批准
不可逆 / 敏感 删数据、轮换凭证、全局发布 硬闸或禁止

后果越强,门越硬。 而自主并不是没有控制,自主是在一个被清晰强制的边界里自由行动的能力。

(这一条和我们拆 DeepSeek super-agent 时看到的设计是同一个思路:权限由代码强制,不由提示词决定。见文末对照。)

十、恢复要针对失败类别

最常见的"恢复"策略是:出错了,再试一次。那不是恢复,那是重复。

harness 应该先分类,再选动作:

失败类别 正确动作
工具超时 退避后重试
参数非法 修工具调用
缺上下文 检索具体来源
测试失败 检查失败行为
权限被拒 申请批准或走安全路径
需求自相矛盾 升级给人
同一失败反复出现 停止循环

一次重试至少应该改变一个相关条件,否则你就是在花钱复现同一个失败。

observe
  -> decide
      -> act
          -> measure
              -> accept / repair / escalate / stop

每个循环都要有预算:最大尝试次数、最大时间、最大花费、最大破坏范围、升级条件。可靠的 agent 知道怎么继续,也知道什么时候继续不再理性。

十一、把指令变成基础设施

当 agent 指令解释"本地现实"时,它很有用;但指令本身是弱强制。一条规则如果反复重要,就把它往下挪一层。

从 到
"记得用格式化工具" 自动跑格式化
"不要跨层 import" 加一条架构测试
"迁移要带回滚" CI 里要求回滚文件存在
"不要改生成文件" 阻断对生成路径的写入
"每个外部主张都要引用" 校验引用覆盖率

于是有了一条指令阶梯:解释 → 清单 → 模板 → 自动检查 → 强制策略。

能往下挪就往下挪。提示词负责解释判断,harness 负责强制不变量。

十二、观察过程,不只看结果

一个干净的最终产物可以掩盖一个糟糕的过程:它可能访问了错的数据、忽略了失败的命令、把外部动作重试了两次、花掉十倍预算、或者用错误的理由得到了正确的答案。

你需要能把这次运行重建出来的 trace:

09:14  contract created
09:15  context source loaded: architecture.md
09:17  file edited: checkout.ts
09:18  focused test failed: duplicate coupon
09:21  implementation repaired
09:22  focused test passed
09:24  integration test passed
09:25  external deployment blocked: approval required

一份有用的 trace 要记:状态迁移、上下文来源、工具输入输出、环境变化、验证结果、重试原因、批准决定、成本与延迟。

目的不是监视,是局部修复:当一次运行在第 18 步崩掉时,你该能从一个可信的检查点重启,而不是从零重放整个任务。

十三、每次运行都要一份变更回执

长转录很难评审。一次运行结束时,harness 应该编译出一份小小的变更回执:

OBJECTIVE
Fix duplicate coupon application during checkout.

CHANGED
- checkout validation logic
- focused regression test

VERIFIED
- lint passed
- unit tests passed
- checkout integration test passed

NOT VERIFIED
- production payment provider

DECISIONS
- preserved existing coupon priority order

RISKS
- legacy mobile client was not available locally

APPROVAL NEEDED
- deploy to staging

回执不是"模型说了什么"的摘要,而是系统能证明什么的摘要。它给人一个紧凑的评审面,也给下一个 agent 会话一个可信的起点。

最好的交接不是"这是对话记录",而是"这是状态、证据,和未解决的风险"。

十四、每次失败都该升级 harness

最弱的团队修掉失败的产出;最强的团队同时修掉让这个失败成为可能的系统。

失败之后问八个问题:契约含糊吗?上下文不可见吗?暴露了错的工具吗?缺了前置条件吗?结果不可验证吗?策略被留在提示词里吗?恢复范围过宽吗?trace 不够吗?

然后把教训变成可复用的改进:失败 → 诊断 → 新的传感器 / 规则 / 地图 / 测试 / 工具契约 → 未来的运行自动变好。

这就是 harness 飞轮:修好一个答案只帮一次,修好 harness 帮每一次。

十五、harness 自己也会腐坏

不是越多越好。模型在变强、工具在变强、任务在变,昨天的护栏可能变成今天的摩擦:为旧模型写的绕行方案,会挡住新模型的好策略。

old model limitation
  -> harness workaround
      -> model improves
          -> workaround remains
              -> system becomes slower or less capable

把 harness 组件当生产代码对待:对每个 router、evaluator、记忆层、重试规则都问——它防的是哪种失败?这种失败现在还有多常见?它增加了多少延迟和复杂度?同样的结果现在能不能更简单地达到?如果删掉会发生什么?

最好的 harness 不是最大的那个,而是能可靠闭合"意图到证据"之间差距的最小系统。

构建是为了删除(build to delete)。

十六、最小可行 harness:六层

你不需要一个编排平台才开始。分层搭:

层 内容
1 有界的任务 目标、范围、约束、验收检查
2 可读的环境 项目地图、命令、局部说明、已知依赖
3 受控的动作 带类型的工具、参数校验、路径与权限边界、结构化结果
4 持久的执行 显式运行状态、检查点、决定、教训
5 证据 确定性检查、对抗式验证、变更回执
6 恢复与学习 失败分类、有界重试、升级、把反复出现的失败变成 harness 更新

先建能消除你当下真实失败的最小一层。 不要因为"单个提示词偶尔需要澄清"就上多 agent 架构——复杂度要靠观察到的失败来赚。

十七、可复用的 harness spec

在给 agent 实质自主权之前,把这八节填完:

AGENT HARNESS SPEC

1. CONTRACT
   objective / scope / constraints / acceptance evidence

2. CONTEXT
   always-loaded map / retrieval sources / local instructions / freshness rules

3. TOOLS
   allowed tools / preconditions / side effects /
   success evidence / timeout and retry policy

4. STATE
   facts / decisions / progress / lessons / checkpoint format

5. POLICY
   automatic actions / approval-required / prohibited / budget limits

6. VERIFICATION
   deterministic checks / adversarial checks / acceptance rule

7. RECOVERY
   failure classes / retry limits / escalation conditions / safe rollback

8. OBSERVABILITY
   trace events / metrics / final change receipt

这些字段没定义,agent 就不是自主的,它是在即兴发挥。

十八、在正确的层级度量

token 数不是终点,尝试过的任务数也不是。有用的单位是被接受的工作:

accepted outputs
--------------------------------
human review minutes + run cost

另外跟踪:一次通过率、工具失败后的恢复率、重复失败率、每任务人工干预次数、没有依据的"完成"声明、从请求到被验证结果的时间、各组件的 harness 开销。

这能防住一个常见错觉:一个 agent 看起来极其高产,实际上在制造昂贵的评审工作。 目标不是更多 agent 活动,而是每单位人类注意力换到更多可信结果。

十九、什么时候不需要重 harness

不是每次模型调用都需要一个操作系统。以下情况用简单提示词就够:任务短、输出容易检查、失败代价低、没有外部副作用、人一直在回路里。

该上 harness 的信号:工作跨多个工具或会话、环境会变、动作有真实后果、完成与否难以人工判断、同一种失败反复出现、人工评审成了瓶颈。

harness 的目的不是让 demo 看起来高级,而是让真实工作可靠。

真正的转变

第一代 AI 产品围绕提示词构建;下一代正在围绕环境构建。

问题不再只是"怎么让模型答得更好",而是:怎么建一个系统,让好动作容易发生、危险动作被控制、失败可见、完成可证明?

这就是从提示词工程到 harness 工程的转变。模型提供智能,harness 提供结构,两者合起来才有可靠执行。

如果 agent 老是散架,别再往提示词里加形容词了——去搭它成功所需要的环境。


我们的整理:这份清单和我们写过的三篇怎么对

这份指南的机制 我们站内的对应拆解 差异
"模型提议,策略授权"+风险四档 DeepSeek super-agent:把「别打扰人」写成一张准入表:显式 / 推断 / 准入表三档 + 不受理的情况 本篇给的是通用原则;那篇是已落地的实现(不可变 Mandate、默认 observe、恢复前重校验)
"每次失败升级 harness"、"有界循环" 循环在节点之内,图在节点之间:循环负责做对、图决定哪几步存在 那篇讲控制流结构,本篇讲运行环境;两者互补,不重叠
"验证要攻击结果"、"完成需要证据" Agent 安全事故九起与六项控制:真实事故里的控制项 那篇是事后取证,本篇是事前设计

三件最容易今天就做、收益最大、成本最低的事:

  1. 写一份任务契约(第五问"哪些动作要批准"经常被漏)。一份 YAML 就能把"看起来在做事"变成"可验收"。
  2. 把一条提示词下沉成检查。挑一条你重复提醒过的规则(不许跨层 import、必须带迁移回滚),把它变成 CI 里的一条断言。这一步比再加十句提示词有效。
  3. 加一份变更回执。哪怕只是一个 Markdown 模板,要求 agent 每次收尾填 VERIFIED / NOT VERIFIED / DECISIONS / RISKS。它会同时改善评审体验和下一轮的上下文。

边界

  • 本文完整编译英文长文《Harness Engineering: The Complete Guide to Building AI Agents That Don't Fall Apart》(Lunar / @LunarResearcher,X Article,2026-09-06,约 2,900 万浏览)。原文为经验性方法论,没有基准测试、没有实测数据;刊出时间距本文约 57 天,属"近 60 天"窗口内。
  • 原文的推荐语与引流(Substack、收藏、转发)未保留;结构图与代码块按原文顺序保留,转为等价的表格与代码块。
  • 这不是"用了这套就不会失败"的保证。文中若干主张(如"同一上下文里自我复查会保住错误假设")是作者的工程经验判断,没有给出实验;我们在正文里按"主张"而非"结论"处理。
  • 本文由 Software 2.0 编译整理,转载请注明出处;我们未对其中的方法做本地复测。

Sources

同主题阅读

这是「Agent / MCP」专题的一部分。完整地图见:Agent / MCP / 自动化完全指南