← 教程路径

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 教你,当模型开始动手干活的时候,怎么让它干得稳、干得对、干砸了还能爬起来。