Harness Engineering:构建稳定可靠的 AI Agents 全指南

@LunarResearcher
英语2026年9月06日
117K
217
30
5
381

TL;DR

本指南介绍了 Harness Engineering,这是一门专注于围绕 AI 模型构建结构化环境的学科,旨在通过契约、验证和持久化状态管理来确保系统的可靠性。

大多数人在错误的层面上试图改进 AI Agent。

当 Agent 失败时,他们会重写提示词。

当它再次失败时,他们会添加更多指令。

开始之前:

关注我的 Substack,获取最新的 AI 前沿动态、Agent 工作流和分步指南,内容会早于 X 平台发布:[https://substack.com/@lunarresearcher

然后他们更换模型,添加更多工具,增加上下文窗口,并希望下一次运行会有所不同。

但许多 Agent 的失败并非推理失败。

它们是环境失败。

Agent 不知道哪些文件是重要的。

它在错误的地方使用了正确的工具。

它丢失了之前会话中做出的决策。

它声称成功却没有运行检查。

它在部分失败后重复了一个操作。

它有权执行本应需要批准的操作。

问题不一定出在模型上。而是模型周围的系统不完整。

这个系统就是“控制框架”(Harness)。

设计它正在成为一门独立的工程学科。

控制框架工程(Harness Engineering)是一门构建环境的实践,旨在将模型的智能转化为可靠的工作。

一个提示词只改变一次尝试。

一个控制框架改变每一次尝试。

本指南将解释如何构建一个控制框架。

Lunar - inline image

1. 模型不是 Agent

模型可以推理、生成、比较和选择。

但一个 Agent 还必须与真实环境进行交互。

它需要:

  • 理解任务
  • 找到相关上下文
  • 选择并使用工具
  • 保持状态
  • 遵守权限
  • 检查结果
  • 从失败中恢复
  • 证明工作已完成

模型是该系统内部的推理引擎。

控制框架则是让推理得以运作的一切。

text
1用户请求
2 |
3 v
4+-----------------------------+
5| 控制框架 |
6| 合约 | 上下文 | 策略 |
7| 工具 | 状态 | 检查 |
8| 追踪 | 恢复 |
9+-----------------------------+
10 |
11 v
12 模型
13 |
14 v
15 真实环境

一个强大的模型置于一个薄弱的控制框架内,仍然是一个薄弱的 Agent。

Lunar - inline image

它可能会产生令人印象深刻的单个响应,但在长时间的任务、变化的环境和部分失败的情况下,它的行为会不一致。

控制框架工程的目标不是消除模型的不确定性。

而是将这种不确定性包含在一个能够观察、验证和恢复的系统内。

2. 从任务合约开始

大多数 Agent 任务始于模糊的意图:

改进用户引导流程。

这句话对于对话来说可能足够了。

但对于自主执行来说远远不够。

在 Agent 行动之前,控制框架应将请求转换为任务合约。

一个有用的合约回答了五个问题:

Lunar - inline image
  1. 必须存在什么结果?
  2. 范围之内是什么?
  3. 什么不能改变?
  4. 什么证据能证明完成?
  5. 哪些行动需要人工批准?
yaml
1目标:减少用户引导流程中的流失
2
3范围:
4 - 注册流程
5 - 用户引导分析
6
7约束:
8 - 不改变身份验证
9 - 保留现有移动端行为
10
11验收标准:
12 - 测试通过
13 - 分析事件被触发
14 - 截图覆盖桌面端和移动端
15
16需要批准:
17 - 生产环境部署
18 - 数据库迁移

这将 Agent 的问题从:

我下一步该做什么?

转变为:

什么行动能使环境朝着合约规定的成果发展?

没有合约,Agent 会优化看似合理的活动。

有了合约,它就可以优化可验证的完成度。

3. 给 Agent 一张地图,而不是一本手册

将整个代码仓库、文档集和对话历史都塞进上下文,这不是好的上下文工程。

这是上下文泛滥。

Lunar - inline image

控制框架应该首先提供一张小地图,然后让 Agent 在需要时检索详细信息。

text
1项目地图
2
3产品规则 -> docs/product/
4架构 -> docs/architecture.md
5前端 -> apps/web/
6后端 -> services/api/
7测试 -> tests/
8命令 -> docs/commands.md
9发布规则 -> docs/release.md

这是渐进式信息呈现:

text
1任务
2 -> 项目地图
3 -> 相关子系统
4 -> 确切文件
5 -> 本地指令

上下文应该因为任务需要而扩展,而不是因为信息存在。

一个好的上下文编译器决定:

  • 哪些总是需要的
  • 哪些可以稍后检索
  • 哪些已经过时
  • 哪些可以总结
  • 哪些必须保持原样

目标不是最大化的上下文。

而是每个 Token 的最大化信号。

4. 构建一个工具网关,而不是工具堆

给一个 Agent 二十个工具并不会让它变得强大。

这给了 Agent 二十种犯错的方式。

Lunar - inline image

每个工具都应该有一个清晰的合约:

text
1工具:edit_file
2
3输入:
4 path
5 patch
6
7前置条件:
8 path 存在
9 path 在允许的工作区内
10
11成功证据:
12 补丁已应用
13 返回生成的差异
14
15失败行为:
16 无部分覆盖
17 返回结构化错误
18
19风险等级:
20 可逆

控制框架应控制工具的暴露和使用方式。

它可以:

  • 隐藏不相关的工具
  • 验证参数
  • 限制路径和域名
  • 附加超时
  • 使重试幂等
  • 标准化输出
  • 对高风险操作要求确认
  • 返回证据,而不仅仅是“成功”

这创建了一个重要的分离:

text
1模型决定意图
2网关验证行动
3工具改变环境
4传感器观察结果

模型可以提出一个行动。

工具网关决定该行动是否足够有效以执行。

5. 分离大脑、双手和历史

许多脆弱的 Agent 将所有内容混合到一个不断增长的记录中。

推理、工具调用、文件、决策、错误和旧的观察结果都在争夺同一个上下文窗口。

一个更强的系统分离了三个职责:

Lunar - inline image
text
1大脑
2规划、推理、选择
3
4双手
5在受控环境中执行工具
6
7历史
8存储持久的事实、决策和运行状态

模型不需要在活动上下文中包含每一个原始事件。

它需要正确的当前状态。

沙盒不需要理解整个目标。

它需要安全地执行一个有边界的行动。

会话日志不需要推理。

它需要在当前上下文消失后保留所发生的事情。

这种分离使得长时间运行的 Agent 更容易恢复、检查和修复。

它也允许你替换一个部分而无需重建整个系统。

6. 记忆必须成为持久状态

对话历史不是可靠的记忆。

它是一个事件流。

有用的记忆应该被转换为显式状态。

Lunar - inline image

至少,保留四个类别:

text
1事实
2关于环境发现的稳定信息
3
4决策
5做出的选择及其背后的原因
6
7进度
8已完成、进行中、受阻和剩余的工作
9
10经验教训
11应改变未来行为的失败

例如:

yaml
1事实:
2 - 结账验证逻辑位于 services/orders
3
4决策:
5 - 重用现有的验证管道
6 - 原因:避免第二个事实来源
7
8进度:
9 已完成:
10 - 添加了服务器端规则
11 剩余:
12 - 更新集成测试
13
14经验教训:
15 - 本地测试命令需要 TEST_DB_URL

这比重播五十页的记录并希望模型注意到重要行要有用得多。

存储原始历史记录以供审计。

编译持久状态以供执行。

7. 完成需要证据

一个 Agent 说“完成了”并不是任务完成的证据。

它只是另一个模型输出。

Lunar - inline image

完成必须由环境中可观察到的变化来决定。

text
1声称 证据
2--------------------------------------------------
3"bug 已修复" 失败的测试现在通过了
4"页面工作正常" 浏览器流程已完成
5"迁移是安全的" 试运行和回滚都通过
6"报告是正确的" 数值与源数据匹配
7"任务已完成" 每个验收检查都通过

控制框架应该首先运行最便宜的确定性检查。

text
1语法
2 -> 类型
3 -> 针对性测试
4 -> 集成测试
5 -> 视觉或语义审查
6 -> 人工批准

不要用另一个模型来回答编译器、模式、校验和、查询或测试就能回答的问题。

对模糊性使用模型。

对管道工作使用代码。

模型可以提议任务已完成。

只有环境才能证明它。

8. 验证应该攻击结果

执行者和评估者不应共享同一个目标。

执行者试图创建最强的解决方案。

评估者试图找到它应该被拒绝的理由。

Lunar - inline image
text
1执行者
2 -> 产生候选方案
3
4验证者
5 -> 检查合约
6 -> 搜索遗漏的情况
7 -> 测试不支持的声明
8 -> 尝试破坏结果
9
10通过
11 -> 接受
12
13失败
14 -> 返回有针对性的证据

这种不对称性很重要。

如果你让同一个 Agent,在同一个上下文中,“再次检查它的工作”,它通常会保留导致错误产生的假设。

一个有用的验证阶段应该具备:

  • 明确的拒绝标准
  • 访问生成的工件
  • 访问验收合约
  • 需要时使用独立的工具或新的上下文
  • 有权拒绝而不修复

验证不是第二意见。

它是一种试图证伪。

9. 模型提议,策略授权

有些规则永远不应依赖于模型是否记得它们。

text
1未经批准绝不发布
2绝不泄露机密
3绝不写入工作区之外
4绝不超出支出上限
5除非测试已运行,否则绝不标记测试通过

这些不是提示建议。

它们是策略。

最安全的设计是将策略置于推理循环之外。

Lunar - inline image
text
1低风险
2读取文件、搜索、检查
3-> 自动执行
4
5可逆变更
6编辑工作区、运行测试
7-> 自动执行并记录
8
9外部影响
10发送消息、部署、购买
11-> 明确批准
12
13不可逆或敏感操作
14删除数据、轮换凭证、全球发布
15-> 硬性限制或禁止

后果越严重,限制越严格。

自主性不是缺乏控制。

它是在一个明确强制执行的边界内自由操作的能力。

10. 恢复应针对失败类别

最常见的恢复策略是:

出错了。再试一次。

那不是恢复。

那是重复。

Lunar - inline image

控制框架应在选择下一步行动之前对失败进行分类。

text
1工具超时
2-> 带退避的重试
3
4无效参数
5-> 修复工具调用
6
7缺少上下文
8-> 检索特定来源
9
10测试失败
11-> 检查失败的行为
12
13权限被拒绝
14-> 请求批准或选择安全路径
15
16矛盾的需求
17-> 升级给人类
18
19重复相同的失败
20-> 停止循环

一次重试应至少改变一个相关条件。

否则系统就是在花钱重现同样的失败。

一个有边界的 Agent 循环如下所示:

text
1观察
2 -> 决定
3 -> 行动
4 -> 衡量
5 -> 接受
6 -> 修复
7 -> 升级
8 -> 停止

每个循环都需要一个预算:

  • 最大尝试次数
  • 最大时间
  • 最大支出
  • 最大破坏范围
  • 升级条件

可靠的 Agent 知道如何继续。

它们也知道何时继续不再合理。

11. 指令应成为基础设施

Agent 指令在解释局部现实时很有用。

但仅靠指令是薄弱的强制手段。

如果一个规则反复重要,就把它向下移动堆栈。

text
1"使用格式化工具"
2-> 自动运行格式化工具
3
4"不要跨层导入"
5-> 添加架构测试
6
7"包含迁移回滚"
8-> 在 CI 中要求回滚文件
9
10"不要修改生成的文件"
11-> 阻止写入生成的路径
12
13"引用每个外部声明"
14-> 验证引用覆盖率

这创建了一个指令阶梯:

text
1解释
2 -> 检查清单
3 -> 模板
4 -> 自动化检查
5 -> 强制执行的策略

尽可能将重要知识沿阶梯向下移动。

提示词应解释判断。

控制框架应强制执行不变量。

12. 观察运行过程,而不仅仅是最终答案

一个干净的最终工件可能隐藏着一个糟糕的过程。

Agent 可能:

  • 访问了错误的数据
  • 忽略了一个失败的命令
  • 重试了两次外部操作
  • 消耗了预期预算的十倍
  • 出于错误的原因得出了正确的答案

你需要能够重建运行过程的追踪记录。

text
109:14 合约已创建
209:15 上下文源已加载:architecture.md
309:17 文件已编辑:checkout.ts
409:18 针对性测试失败:重复优惠券
509:21 实现已修复
609:22 针对性测试通过
709:24 集成测试通过
809:25 外部部署被阻止:需要批准

一个有用的追踪记录记录:

  • 状态转换
  • 上下文来源
  • 工具输入和输出
  • 环境变化
  • 验证结果
  • 重试原因
  • 批准决策
  • 成本和延迟

目标不是监视。

目标是局部修复。

当一次运行在第 18 步失败时,你应该能够从一个可信的检查点重新开始,而不是重放整个任务。

13. 每次运行都需要一份变更收据

冗长的 Agent 记录难以审查。

在运行结束时,控制框架应编译一份简短的变更收据。

text
1目标
2修复结账过程中重复应用优惠券的问题。
3
4变更
5- 结账验证逻辑
6- 针对性回归测试
7
8已验证
9- 代码检查通过
10- 单元测试通过
11- 结账集成测试通过
12
13未验证
14- 生产支付提供商
15
16决策
17- 保留了现有的优惠券优先级顺序
18
19风险
20- 旧版移动客户端在本地不可用
21
22需要批准
23- 部署到预发布环境

收据不是模型所说内容的摘要。

它是系统能够证明的内容的摘要。

这为人类提供了一个紧凑的审查面,并为下一个 Agent 会话提供了一个可信的起点。

最好的交接不是“这是对话记录”。

而是“这是状态、证据和未解决的风险”。

14. 每次失败都应升级控制框架

最弱的团队修复失败的输出。

最强的团队也会修复允许失败发生的系统。

在失败之后,问:

text
1任务合约是否模糊?
2重要的上下文是否不可见?
3是否暴露了错误的工具?
4是否缺少前置条件?
5结果是否无法验证?
6策略是否留在了提示词中?
7恢复策略是否过于宽泛?
8追踪记录是否不足?

然后将经验教训转化为可复用的改进。

text
1失败
2 -> 诊断
3 -> 新的传感器、规则、地图、测试或工具合约
4 -> 未来的运行自动改进

这就是控制框架的飞轮效应。

系统变得更可靠,因为失败留下了基础设施。

一个修正后的答案帮助一次运行。

一个修正后的控制框架帮助每一次未来的运行。

Lunar - inline image

15. 控制框架也会衰退

更多的控制框架并不总是更好。

模型在改进。工具在改进。任务在变化。旧的安全措施可能变成不必要的摩擦。

为昨天的模型创建的变通方法,可能会阻止今天的模型使用更好的策略。

这导致了控制框架的衰退:

text
1旧模型限制
2 -> 控制框架变通方法
3 -> 模型改进
4 -> 变通方法仍然存在
5 -> 系统变得更慢或能力更弱

像对待生产代码一样对待控制框架组件。

衡量它们是否仍然提供价值。

对于每个路由器、评估器、记忆层和重试规则,问:

  • 这防止了哪种失败?
  • 那种失败多久发生一次?
  • 这增加了多少延迟和复杂性?
  • 现在能否用更简单的方式达到同样的结果?
  • 如果我们移除它会发生什么?

最好的控制框架不是最大的那个。

它是能够可靠地弥合意图与证据之间差距的最小系统。

为删除而构建。

16. 最小可行控制框架

你不需要一个编排平台才能开始。

分层构建控制框架。

第一层:有边界的任务

  • 目标
  • 范围
  • 约束
  • 验收检查

第二层:清晰的环境

  • 项目地图
  • 命令
  • 本地指令
  • 已知依赖

第三层:受控的行动

  • 类型化工具
  • 参数验证
  • 路径和权限边界
  • 结构化结果

第四层:持久的执行

  • 显式运行状态
  • 检查点
  • 决策
  • 经验教训

第五层:证据

  • 确定性检查
  • 对抗性验证
  • 变更收据

第六层:恢复与学习

  • 失败分类
  • 有边界的重试
  • 升级
  • 来自重复失败的控制框架更新

构建能够消除你实际遇到的失败的最小层。

不要因为单个提示偶尔需要澄清就开始构建多 Agent 架构。

复杂性应该由观察到的失败来证明。

17. 可复用的控制框架规范

在给予 Agent 有意义的自主权之前,定义以下内容:

text
1AGENT 控制框架规范
2
31. 合约
4 目标:
5 范围:
6 约束:
7 验收证据:
8
92. 上下文
10 始终加载的地图:
11 检索来源:
12 本地指令:
13 新鲜度规则:
14
153. 工具
16 允许的工具:
17 前置条件:
18 副作用:
19 成功证据:
20 超时和重试策略:
21
224. 状态
23 事实:
24 决策:
25 进度:
26 经验教训:
27 检查点格式:
28
295. 策略
30 自动行动:
31 需要批准的行动:
32 禁止的行动:
33 预算限制:
34
356. 验证
36 确定性检查:
37 对抗性检查:
38 验收规则:
39
407. 恢复
41 失败类别:
42 重试限制:
43 升级条件:
44 安全回滚:
45
468. 可观测性
47 追踪事件:
48 指标:
49 最终变更收据:

如果这些字段未定义,那么 Agent 就不是自主的。

它是在即兴发挥。

18. 在正确的层面衡量系统

Token 数量不是最终指标。

尝试的任务数量也不是。

有用的单位是已验收的工作。

一个实用的指标是:

text
1已验收的输出
2------------------------------
3人工审查分钟数 + 运行成本

同时追踪:

  • 首次通过验收率
  • 工具失败后的恢复率
  • 重复失败率
  • 每个任务的人工干预次数
  • 未经支持的完成声明
  • 从请求到验证结果的时间
  • 按组件划分的控制框架开销

这可以防止一种常见的错觉:

一个 Agent 可能看起来生产力很高,同时却创造了昂贵的审查工作。

目标不是更多的 Agent 活动。

而是每单位人类注意力产生更多可信的结果。

19. 何时不需要繁重的控制框架

并非每次模型调用都需要一个操作系统。

在以下情况下使用简单的提示词:

  • 任务简短
  • 输出易于检查
  • 失败代价低
  • 没有外部副作用发生
  • 用户保持在循环中

在以下情况下添加控制框架:

  • 工作跨越多个工具或会话
  • 环境可能发生变化
  • 行动有实际后果
  • 完成度难以手动判断
  • 相同的失败反复出现
  • 人工审查成为瓶颈

控制框架的目的不是让演示看起来复杂。

而是让实际工作变得可靠。

真正的转变

第一代 AI 产品是围绕提示词构建的。

下一代产品正在围绕环境构建。

问题不再仅仅是:

我们如何让模型回答得更好?

而是:

我们如何构建一个系统,使得好的行动变得容易,危险行动得到控制,失败可见,完成可证明?

这就是从提示词工程到控制框架工程的转变。

模型提供智能。

控制框架提供结构。

它们共同产生可靠的执行。

如果你的 Agent 不断崩溃,别再往提示词里加形容词了。

构建它成功所需的环境。

如果你读到了这里

收藏本指南。

在 X 上关注 @LunarResearcher

订阅我的 Substack

把这篇文章发给那些仍在试图用更长的提示词来修复每一个 Agent 失败的人。

二次创作

使用 YouMind 创作爆款文章

收集素材、拆解爆点、生成视觉资产、撰写内容,并在一个 AI 工作空间里完成分发。

了解 YouMind
写给创作者

把你的 Markdown 变成干净的 𝕏 文章

图片上传、表格、代码块,往 𝕏 上手动重排太痛苦。YouMind 把整篇 Markdown 一键转成干净、可直接发布的 𝕏 文章草稿。

试试 Markdown 转 𝕏

更多可拆解样本

近期爆款文章

探索更多爆款文章