YouMind
登录

Harness Engineering:如何构建真正可用的 AI Agents

@0xjmori
英语2026年9月27日
328K
196
24
17
638

TL;DR

本文介绍了“Harness Engineering”这一概念,指出 AI Agents 的可靠性取决于其周围的系统(如契约、工具、状态和验证机制),而不仅仅是模型或提示词本身。文章提供了一份构建稳健 Agent 基础设施的综合指南。

大多数人都在错误的层面上试图修复 AI Agent。

当 Agent 失败时,他们会重写提示词。如果再次失败,他们就添加更多指令、切换模型、扩大上下文窗口,或者接入另一个工具。

然后,同样的问题又卷土重来。

Agent 会忘记一个重要的决定;用错工具;忘了三步之前发生了什么;没检查结果就宣称任务完成;反复重试同一个失败的操作,直到预算耗尽。

问题并不总是出在模型上。

问题出在它周围的环境。

这个环境就是 harness(执行框架)。

Harness Engineering(框架工程)指的是围绕模型构建一套系统,由它来决定模型能看到什么、能做什么、记住什么、怎样算成功,以及出错时该怎么办。

更好的提示词只能改善单次回答。

更好的 harness 能让每一次运行都变得更好。

关注我的 Substack,获取更多关于 AI Agent、自动化和生产系统的实战拆解:

substack.com/@lunarresearcher

1. 模型不等于 Agent

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

但这并不能让它成为一个可靠的 Agent。

真正的 Agent 还需要找到正确的上下文、使用工具、保持状态、遵守权限、验证自己的工作,并在环境表现与预期不符时进行恢复。

模型只是推理引擎。

而 harness 是把这种推理变成真正执行的一切。

text
1用户请求
2 |
3 v
4+-----------------------------+
5| HARNESS |
6| |
7| 契约 上下文 |
8| 工具 状态 |
9| 策略 验证 |
10| 追踪 恢复 |
11+-----------------------------+
12 |
13 v
14 模型
15 |
16 v
17 真实环境

把同一个模型放进聊天框,它只会回答问题。

Mori - inline image

把它放进一个拥有终端访问权限、测试、浏览器工具、项目记忆、受控权限和审查循环的代码仓库里,它就能完成真正的工作。

模型没有变。

变的是 harness。

2. 把每个请求都变成一份契约

自然语言是灵活的。

但自主执行不该如此。

像这样的请求:

优化新用户引导流程。

当有人坐在模型旁边盯着时,这么写没问题。

但作为生产环境的指令,它糟透了。

在 Agent 动手之前,先把请求转化为一份有边界的任务契约。

Mori - inline image
yaml
1objective: 降低新用户引导流失率
2
3inputs:
4 - 产品简介
5 - 分析数据
6 - 代码仓库
7
8constraints:
9 - 保留身份验证逻辑
10 - 不修改数据库结构
11 - 保持当前移动端行为不变
12
13deliverable:
14 - 可审查的 pull request
15
16done_when:
17 - 测试通过
18 - 埋点事件正确触发
19 - 桌面端流程通过审查
20 - 移动端流程通过审查
21
22approval_required:
23 - 生产环境部署

最关键的部分是 done_when(何时算完成)。

没有它,Agent 可能会去解决一个稍微简单点的版本,然后依然自信地宣布任务完成。

有了它,完成度就变得可衡量。

Agent 不该问:

我接下来该做什么?

它应该问:

哪个动作能让当前环境更接近契约约定的结果?

这是一个强得多的循环。

3. 给 Agent 一张地图,而不是一个巨大的上下文窗口

面对 Agent 犯错,常见的反应是给模型塞更多上下文。

更多文档。

更多对话历史。

更多文件。

更多工具输出。

最终,Agent 收到了一切,却理解得更少。

上下文不是存储空间。

它是注意力预算。

Mori - 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/security.md

只在需要时才展开细节。

text
1任务
2 |
3 v
4项目地图
5 |
6 v
7相关系统
8 |
9 v
10具体文件
11 |
12 v
13局部指令

原文把这称为渐进式披露(progressive disclosure):harness 应该因为任务需要才加载更多信息,而不是仅仅因为信息存在就全塞进去。

目标不是最大化上下文。

目标是最大化有效信号。

4. 在模型和工具之间加一道网关

给模型二十个工具,并不意味着它的能力自动翻了二十倍。

它可能只是多了二十种出错的方式。

每个工具都应该有一份契约。

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

于是执行路径变成了:

text
1模型提出方案
2 |
3 v
4网关切校验
5 |
6 v
7策略授权
8 |
9 v
10工具执行
11 |
12 v
13HARNESS 记录结果

模型决定它想做什么动作。

harness 决定这个动作是否合法、被允许且安全。

Mori - inline image

当工具能发消息、改生产环境、花钱或删数据时,这个区分就变得至关重要。

一个好的工具网关还能加上超时控制、校验参数、限制文件路径、统一错误格式,并让重试变得安全。

好的工具能减少模型需要猜的东西。

5. 把记忆移出对话

对话不应该成为系统的唯一记录。

长时间运行的 Agent 终究会撞上上下文上限、崩溃、重启,或者把工作交接给另一个会话。

如果所有重要决定都只存在于聊天记录里,那这个工作流就非常脆弱。

把持久化状态单独存起来。

Mori - inline image
json
1{
2 "task_id": "feature_042",
3 "status": "verifying",
4 "current_step": "mobile_check",
5
6 "completed": [
7 "implementation",
8 "unit_tests",
9 "desktop_check"
10 ],
11
12 "decisions": [
13 "复用现有的导出接口",
14 "保留当前的日期格式"
15 ],
16
17 "artifacts": [
18 "export.csv",
19 "desktop-after.png"
20 ],
21
22 "open_risks": [
23 "移动端工具栏可能会溢出"
24 ],
25
26 "next_action": "渲染移动端视口"
27}

一个好用的系统会把记忆分成四类:

text
1事实
2稳定的知识
3
4决策
5选了什么,为什么这么选
6
7状态
8当前运行到哪一步了
9
10经验教训
11那些应该影响未来运行的失败

下一个 Agent 会话继承的应该是工作的状态,而不是一段被压缩过的“上次聊了什么”的故事。

6. 让证据成为完成的门槛

Agent 说一句“搞定了”,并不能证明活儿真干完了。

Mori - inline image

那只是模型的又一次输出。

harness 需要可观测的证据。

text
1主张 证据
2
3"bug 修好了" 原本失败的测试现在通过了
4
5"页面能用" 浏览器流程跑通了
6
7"数据是对的" 数值与源数据一致
8
9"迁移是安全的" 预演 + 回滚通过
10
11"任务完成了" 所有验收检查都通过

优先使用确定性检查。

text
1语法
2 |
3 v
4类型
5 |
6 v
7定向测试
8 |
9 v
10集成测试
11 |
12 v
13视觉 / 语义审查
14 |
15 v
16人工审批

别用另一个模型去回答编译器、测试、schema 或数据库查询就能证明的事。

让模型负责判断。

让确定性系统负责事实。

模型产出交付物。

环境产出关于交付物的证据。

harness 判断证据是否充分。

7. 把构建者和验证者分开

自己审查自己还有另一个问题。

制造错误的那个 Agent,往往会把同样的假设带进审查环节。

Mori - inline image

更稳健的架构会把执行者和验证者分开。

text
1构建者
2 |
3 v
4生成候选结果
5 |
6 v
7验证者
8 |
9 +-- 检查契约
10 +-- 寻找遗漏的用例
11 +-- 测试站不住脚的主张
12 +-- 尝试破坏结果
13 |
14 +------ 通过 ------> 接受
15 |
16 +------ 失败 ------> 返回证据

验证者不该问:

这看起来不错吧?

它应该问:

什么情况会让它不可接受?

这把审查从“确认”变成了“试图证伪”。

原文明确建议:给验证环节设定独立的拒绝标准,并赋予足够的独立性,去挑战产生第一个结果时的那些假设。

8. 把权限移出模型

有些规则永远不该指望模型去记住。

text
1未经批准绝不发布
2绝不泄露密钥
3绝不超出支出上限
4绝不在工作区之外写入
5没跑过测试就绝不声称测试通过

这些不是提示词里的建议。

Mori - inline image

它们是策略。

一个简单的权限阶梯:

text
1低风险
2
3读取
4搜索
5检查
6
7-> 自动放行
8
9可逆操作
10
11编辑工作区
12运行测试
13创建草稿
14
15-> 自动放行 + 记录追踪
16
17外部影响
18
19发送
20部署
21购买
22
23-> 需要审批
24
25不可逆 / 敏感操作
26
27删除数据
28轮换凭证
29全局发布
30
31-> 硬性拦截或禁止

后果越严重,控制就要越强。

模型可以推荐动作。

harness 负责授权。

工具负责执行。

自主性不是没有控制。

而是在强制边界内的自由。

9. 别再盲目重试了

最糟糕的恢复策略之一是:

出错了,再试一次。

如果什么都不改变,系统只是在花钱重复同一个错误。

失败应该先分类。

Mori - 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 v
4决策
5 |
6 v
7行动
8 |
9 v
10衡量
11 |
12 +---- 接受
13 |
14 +---- 修复
15 |
16 +---- 上报
17 |
18 +---- 停止

每个循环都应该对尝试次数、时间、花费和破坏范围设限。

可靠的 Agent 需要知道怎么继续。

也需要知道什么时候再试一次已经不值得了。

10. 把重复的指令变成基础设施

假设提示词里写着:

始终运行格式化程序。

如果格式化程序能自动运行,这条规则会更牢固。

假设指令说:

UI 代码不能直接访问数据库。

把它变成一个架构测试——一旦违规就让测试失败——会更强。

演进过程是这样的:

text
1说明
2 |
3 v
4清单
5 |
6 v
7模板
8 |
9 v
10自动化检查
11 |
12 v
13强制执行策略

提示词应该解释判断逻辑。

harness 应该强制保证不变量。

每一个反复出现的错误,都应该顺着这个阶梯往下推一点。

最终,模型不再需要记住这个教训。

环境替它记住了。

11. 记录运行过程

完美的最终产物,可能掩盖了一条糟糕的执行路径。

也许 Agent 访问了错误的数据源。

也许它忽略了一个失败的命令。

也许它把某个外部操作重复执行了两次。

也许它花了十倍于预期的预算。

也许它用错误的理由得出了正确的答案。

记录足够的信息,以便还原到底发生了什么。

text
109:14 创建任务契约
209:15 加载 architecture.md
309:17 编辑 checkout.ts
409:18 定向测试失败
509:21 修复实现
609:22 定向测试通过
709:24 集成测试通过
809:25 部署被拦截:需要审批

有用的追踪信息包括:上下文来源、工具调用、状态变更、验证结果、重试原因、审批决定、成本和延迟。

重点不是为了好玩而收集日志。

重点是让失败局限在局部。

如果第 18 步出了问题,你应该能只修复第 18 步。

而不是被迫重跑整个过程。

12. 给每次运行一张回执

别逼着人去翻四十条消息的聊天记录。

把结果整理成一张简短的回执。

text
1目标
2
3修复优惠券重复使用的问题。
4
5变更内容
6
7结账校验
8回归测试
9
10已验证
11
12lint 通过
13单元测试通过
14集成测试通过
15
16未验证
17
18生产环境支付服务商
19
20风险
21
22旧版移动端客户端不可用
23
24需要审批
25
26部署到 staging

这不是模型自称发生了什么的总结。

而是 harness 能证明发生了什么的总结。

正是这个区别,让回执在审查、交接和未来的 Agent 会话中真正有用。

13. 让每次失败都改进 harness

大多数团队只会修复那个失败的输出。

更好的做法是修复允许这次失败发生的系统。

text
1缺少上下文
2-> 改进项目地图
3
4用错工具
5-> 改进路由或工具契约
6
7输出质量差
8-> 增加验证器
9
10死循环
11-> 加重试上限
12
13不安全操作
14-> 加权限关卡
15
16丢失决策
17-> 持久化状态
18
19未知失败
20-> 改进追踪

这就是 harness engineering 开始产生复利的地方。

修复一个输出,只帮到一次运行。

修复一次 harness,能让之后的每一次运行都变好。

最优秀的 Agent 系统之所以越来越可靠,是因为错误留下了基础设施。

14. 从最小可用的 harness 开始

你不需要一开始就搭一个庞大的编排平台。

分层构建。

text
1第 0 层
2
3提示词
4模型
5
6第 1 层
7
8任务契约
9项目地图
10工具
11
12第 2 层
13
14结构化状态
15验证
16有界循环
17
18第 3 层
19
20权限
21追踪
22恢复
23人工关卡

一个简短的研究任务,可能只需要一条提示词和一次审查。

而一个长达六小时、涉及文件访问、网络访问和部署能力的编码任务,需要的就多得多。

只有当失败面大到值得时,再加复杂度。

别只是因为 Agent 架构看起来很酷就去堆料。

Harness Engineering 检查清单

在给 Agent 真正的自主权之前,先问自己:

text
1[ ] 执行前是否已经定义了成功标准?
2
3[ ] Agent 能否在不加载全部内容的情况下
4 找到正确的上下文?
5
6[ ] 每个工具是否有明确的用途、
7 schema 和失败状态?
8
9[ ] 重要决策是否存储在
10 对话之外?
11
12[ ] 完成是否需要证据?
13
14[ ] 高风险操作是否受策略保护?
15
16[ ] 每个循环是否有重试上限?
17
18[ ] 中断后运行能否恢复?
19
20[ ] 你能否还原每一个重要操作?
21
22[ ] 失败是否能改进某条规则、工具、
23 测试、地图或权限?
24
25[ ] 最终变更能否回滚?

如果有好几个答案都是“否”,那么换个更强的模型也不会自动让 Agent 变可靠。

它可能只会让失败来得更快、更贵。

真正的转变

Prompt engineering 问的是:

我该告诉模型什么?

Context engineering 问的是:

模型此刻应该知道什么?

Harness engineering 问的是:

什么样的系统能让模型行动、验证自己的工作、从失败中恢复并安全运行?

text
1提示词
2-> 指令
3
4上下文
5-> 工作视图
6
7HARNESS
8-> 运行环境
9
10循环
11-> 局部修正
12
13图
14-> 协调

模型会不断迭代。

持久的优势长在它们周围。

你的契约会越来越好。

你的工具会越来越好。

你的测试会越来越好。

你的状态会越来越干净。

你的权限会越来越安全。

你的恢复逻辑会越来越聪明。

你的失败会变成基础设施。

这就是强大的模型变成可靠 Agent 的方式。

这就是 Harness Engineering。

如果你读到了这里

收藏这份指南。

在 X 上关注我: x.com/0xjmori

订阅我的 Substack: substack.com/@lunarresearcher

把这篇文章转给那些还在试图用更长提示词来修复 Agent 各种报错的人。

一键保存

使用 YouMind AI 深度阅读爆款文章

保存原文、追问细节、总结观点,并在一个 AI 工作空间里把爆款文章沉淀成可复用笔记。

了解 YouMind
写给创作者

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

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

试试 Markdown 转 𝕏

更多可拆解样本

近期爆款文章

探索更多爆款文章