05 Harness:给 AI 装一套“骑手装备”
该节点所属的教程路径尚未上线,仅能预览本节内容。
你有没有遇到过这种情况:AI 写代码写到一半,突然开始重复调用同一个工具,或者干脆忘了自己刚才在干什么。你换了更强的模型,补了更详细的提示词,它还是会在某个环节卡住。
问题可能不在模型本身,而在于模型外面那套东西没搭好。
Harness Engineering 聊的就是模型外面那套东西。
先看一个让人意外的数字
Can.ac 做过一次编码评测,同一个模型,只换了文件编辑接口,得分从 6.7% 跳到了 68.3%。模型参数一点没变,变的只是“它被允许怎么操作文件、怎么拿到结果、出错后怎么收到反馈”。
LangChain 也做过类似的事。他们没换模型,只是优化了文档组织、验证回路和追踪系统,在 Terminal Bench 2.0 上的排名就从第 30 名升到了第 5 名,得分从 52.8% 涨到 66.5%。
这些数字说明一件事:很多时候,Agent 表现不好,不是因为模型不够聪明,而是因为模型外面的系统没给它铺好路。
比喻:模型是马,Harness 是马具
“Harness”这个词本身就有马具的意思——缰绳、马鞍、护具。马跑得快不快,看马本身;但马往哪儿跑、什么时候停、遇到沟坎怎么办,看的是马具和骑手。一匹好马配一副烂马具,照样跑不出好结果。
Agent = Model + Harness
这句话是理解 Harness Engineering 的钥匙。
Model 负责推理和生成。它很聪明,但它不会天然记住多轮对话的历史,不会自己跑命令,不会知道代码是不是真的通过了测试,也不会自动判断哪些信息该留、哪些该扔。
Harness 就是模型之外的一切。系统提示词、工具调用接口、文件系统、沙箱环境、编排逻辑、钩子中间件、反馈回路、约束机制——这些东西加在一起,才是完整的 Agent。
打个比方。模型像一个刚毕业的聪明新人,脑子好使,但没在公司待过。他不知道公司的代码规范长什么样,不知道提 PR 要走什么流程,不知道测试挂了该找谁。你得给他配电脑、开权限、定规矩、告诉他“改完代码先跑 CI,挂了就回来修”。这套东西就是 Harness。
比喻:Harness 之于 Model,就像操作系统之于 CPU
CPU 再强,如果操作系统天天崩,你用起来照样难受。模型再聪明,如果外面的系统乱七八糟,Agent 照样干不好活。
它和 Prompt、Context Engineering 什么关系
这三样东西经常被放在一起比,但它们其实不是同一个层面的东西。
Prompt Engineering 管的是“话怎么说”。你把角色、任务、约束、格式交代清楚,模型就能听懂你要什么。适合单次问答。
Context Engineering 管的是“该给模型看什么”。在合适的时机,把正确的信息放到模型的视野里。适合需要外部知识的场景。
Harness Engineering 管的是“系统怎么持续跑下去、跑歪了怎么拉回来”。模型能不能操作文件、执行完怎么验证、失败了怎么重试、状态丢了怎么恢复——这些是 Harness 的事。
你可以把它们想成一层套一层的。Prompt 是最里面那层,管单次沟通。Context 往外扩一层,管信息供给。Harness 再往外扩一层,管整个执行环境的搭建和运行。
比喻:Prompt 是告诉实习生怎么写邮件,Context 是把参考资料放到他桌上,Harness 是给他配电脑、开权限、定流程、装监控
你只写张便签说“给王经理发邮件确认合同”,那是 Prompt。你把合同模板、客户信息、历史邮件都整理好放他桌上,那是 Context。你给他开邮箱权限、告诉他发送前必须过一遍审批、发出后抄送给法务、如果被退回了该怎么处理——这才是 Harness。
Harness 里到底该放什么
想知道 Harness 该放什么,可以反过来问:模型做不到什么?
模型不会记住跨会话的历史,Harness 就给它配记忆系统,每次请求把历史拼进上下文。模型不会自己跑代码,Harness 就给它提供 Bash 和代码执行环境。模型不知道新库的版本号,Harness 就接上 Web Search 和 MCP 工具。模型判断不了自己有没有做对,Harness 就搭一套验证闭环,让它跑测试、看结果、发现错误。
把这些“模型做不了、但你又希望 Agent 能做到”的部分补上,就是 Harness 的组件清单。
一个成熟的 Harness 通常可以拆成六层:
| 层级 | 管什么 | 打个比方 |
|---|---|---|
| L1 信息边界层 | Agent 该知道什么、不该知道什么 | 岗位说明书 |
| L2 工具系统层 | Agent 怎么和外部世界交互 | 办公工具 |
| L3 执行编排层 | 多步骤任务怎么串起来 | 标准操作流程 |
| L4 记忆与状态层 | 长任务的中间结果怎么管 | 项目管理系统和笔记本 |
| L5 评估与观测层 | Agent 怎么知道自己做对了没有 | 质检流程 |
| L6 约束与恢复层 | 出错了怎么办 | 红线规则和应急预案 |
起步阶段不用六层全上。先把 L1 和 L6 搭好就够了——前者让 Agent 知道该干什么、不该碰什么,后者在它越界或失败时能拦住、能恢复。等任务变复杂了,再逐步补中间几层。
为什么瓶颈经常不在模型
一个很容易被忽略的问题是 model-harness 耦合。
Claude Code、Codex 这类产品,是模型和 Harness 一起调优出来的。模型已经习惯了某套工具的逻辑和返回格式。你把它换到另一套 Harness 上,即使模型本身更强,效果也可能反而变差。
所以选 Harness 的时候,不能默认“模型自带的那套就是最好的”。得看你的任务需要什么工具、什么约束、什么验证方式。
还有一个值得记住的经验:模型升级之后,Harness 应该简化,而不是越堆越厚。
Anthropic 发现,从 Sonnet 4.5 升级到 Opus 4.6 之后,原本每个 Sprint 都要检查一遍的 Evaluator 机制可以完全去掉,只在最后检查一次就行。因为 Sonnet 4.5 需要频繁检查的那个假设——模型自己搞不定中间验证——在 Opus 4.6 上不成立了。
Harness 里的每一个组件,都隐含着一个假设:“模型自己做不到这个”。模型变强了,这些假设就该重新检查一遍,冗余的保护机制该拆就拆。
几个团队的真实做法
OpenAI 用 3 个工程师、5 个月、约 100 万行代码、零手写代码做了一次实验。他们最核心的经验是:给 Agent 一张地图,不要塞一本千页手册。他们的 AGENTS.md 只有大约 100 行,像一本书的目录,指向更深层的设计文档。Agent 需要什么,就顺着目录去翻什么。
Anthropic 遇到的问题是“上下文焦虑”。Sonnet 4.5 在上下文快满的时候会变得犹豫,甚至在任务没做完的时候就提前收尾。他们的解法不是硬压,而是重启——把当前状态、已完成的工作、待办事项整理成一份交接文档,然后启动一个全新的 Agent,只把这份文档交给它。历史对话不占用新会话的上下文。
Stripe 走的是另一个极端:高度自动化、无人值守。开发者发一条 Slack 消息,Agent 就从写代码、跑 CI 到提 PR 全部完成,人只在最后审查。他们每周有超过 1300 个完全由 Agent 生产、没有人类手写代码的 PR 被合并。
Stripe 的做法有一个很聪明的思路:该确定的地方确定,该灵活的地方灵活。跑 lint、推送代码这类步骤走确定性流水线;实现功能、修 CI 错误这类需要判断的部分交给 Agent。
说到底
Harness Engineering 的核心思想,用一句话就能说清楚:用外部化的结构约束,替代对模型内在能力的依赖。
你不要指望模型自己记住规矩、自己发现错误、自己纠正偏差。你把这些东西设计进系统里——写进工具接口、写进验证回路、写进约束规则、写进恢复机制。
Mitchell Hashimoto 给过一个很实在的定义:每当 Agent 犯了一个错误,就花时间设计一个方案,让它以后不会再犯同样的错误。
这不是一次性的系统设计,而是一个持续迭代的闭环。每次失败,都是给 Harness 加一条新规则的机会。
Prompt 教你怎么跟模型说话。Context 教你怎么让模型看到对的东西。Harness 教你,当模型开始动手干活的时候,怎么让它干得稳、干得对、干砸了还能爬起来。