Harness Engineering 的介绍与实践

20260423182027

同样是用 AI 编程,有的团队已经能让 Agent 稳定改代码、跑测试、收敛结果;有的团队却还停留在“写得挺像,但一跑就炸”。差距往往出在模型外面那套工程系统,也就是让 AI 能安全干活的 Harness。

为什么会有 Harness Engineering

这两年 AI 编程工具变化很快。

最早大家更多是在“问模型”:解释代码、生成函数、补一段脚本。这个阶段最重要的是 Prompt Engineering,也就是把需求讲清楚,减少模型理解偏差。

后来大家发现,只会写提示词还不够。模型如果不知道项目目录、接口约定、历史设计和运行方式,就很容易一本正经地瞎猜。于是 Context Engineering 开始被反复提起:该给模型哪些文件、日志、文档和规则,才能让它少幻觉。

但当 AI 真的开始改文件、跑命令、修测试,问题又变了。

这时最让人头疼的,开始变成这些事:

  1. 改错文件;
  2. 破坏已有结构;
  3. 不按既定文档开发;
  4. 规避失败,假装成功;
  5. 顺着错误假设越修越远;
  6. 长任务做着做着忘了原目标;
  7. 执行高风险命令却没有人工确认。

这些问题,光加一句“请谨慎操作”没什么用。你需要一套外部机制,让 AI 的行为有边界、有反馈、能收敛。这套机制,就是 Harness。

一个很好记的公式是:

Agent = Model + Harness

模型负责推理和生成,Harness 负责环境、工具、约束、状态和反馈。没有 Harness,模型更像一个会说话的大脑;有了 Harness,它才更像一个能在工程环境里干活的代理。

Harness 到底在管什么

如果一定要找个中文说法,我更愿意把 Harness 理解成:护栏 + 工具链 + 运行框架

别把它理解成某个单独工具,也别理解成一个提示词模板。更准确地说,它是一层围着模型搭起来的工程控制系统。

落到 AI 编程场景,Harness 一般要把几件事管起来:

  1. 上下文管理:让代理知道项目结构、任务目标、相关文件和编码约束;
  2. 工具接口:让它能读文件、搜代码、跑测试、打补丁,少靠猜;
  3. 执行沙盒:让命令运行在受限环境里,出错也别伤到真实环境;
  4. 规则约束:用 lint、类型检查、架构规则和权限边界限制越界动作;
  5. 验证循环:把测试失败、构建报错、审查意见重新喂回去,让它继续修;
  6. 人工闸门:删文件、改生产配置、发版部署这类动作,必须有人点头。

所以我现在更倾向于把 Harness Engineering 看成一件工程活。它要解决的是环境问题:就算模型犯错,错误也尽量落在可控范围内。即:用流程与规范来约束模型。

它和 Prompt、Context 的关系

这三者可以按顺序叠起来看。

20260423182027

阶段主要问题关注点常见手段
Prompt Engineering任务没说清怎么表达角色、步骤、示例、输出格式
Context Engineering模型不知道事实给什么信息检索文件、注入文档、压缩上下文
Harness Engineering行为不可控怎么执行和验收沙盒、工具、验证、审批

Prompt 做得好,模型更容易听懂。

Context 给得对,模型更不容易瞎编。

Harness 搭得稳,模型就算一开始想偏了,也不会一路狂奔到把仓库搞坏。

换句话说,前两者主要解决“想清楚”,Harness 主要解决“做稳”。

一个好用的 Harness 有哪几层

如果把 Harness 拆开看,我觉得至少有五层:项目地图、工具层、沙盒层、验证层和收敛层。

用图来理解,会更直观一点:

flowchart TD A[项目地图<br/>先知道项目结构、入口和禁区] B[工具层<br/>能读文件、搜代码、改文件、跑命令] C[沙盒层<br/>把权限、目录和环境范围卡住] D[验证层<br/>用测试、构建、lint 和 review 给反馈] E[收敛层<br/>判断任务是否完成,避免越修越偏] F[人工闸门<br/>高风险动作先审批] A --> B --> C --> D --> E C -.高风险操作.-> F E -.未收敛继续修.-> B F -.批准后继续.-> E

这张图没有把所有细节都画全,主要想表达一点:Harness 要靠多层配合,让 Agent 一步步靠近可交付结果。

项目地图

20260423184126

AI 进入一个项目,最怕两件事:找不到入口,不知道禁区。

所以我越来越看重项目里有没有一份足够短、但足够管用的说明文件。名字不重要,AGENTS.mdCLAUDE.md、团队手册都行。关键是它能不能把下面这些事讲明白:

  1. 项目是什么技术栈;
  2. 源码、测试、配置分别在哪里;
  3. 常用构建和验证命令是什么;
  4. 代码分层和依赖方向是什么;
  5. 哪些目录不能手动改;
  6. 常见坑和禁止模式是什么。

对代理来说,这份文件就是第一张地图。

很多人喜欢把所有规则一次性塞进提示词里,我现在反而觉得不如给一个清晰入口,让代理按需读。这样更省上下文,也更不容易漏重点。

工具层

模型本身不会真的“看见”仓库,它只能通过工具接触代码。

最基础的一组工具,通常包括:

  1. read_file:读文件;
  2. rg / grep:搜索代码;
  3. list_files:看目录结构;
  4. shell:跑构建、测试和脚本;
  5. apply_patch:用可审查的方式改文件;
  6. git diff:确认改动范围。

很多时候,代理好不好用,模型能力只占一部分,工具顺不顺手也很关键。

  • 工具太少,它只能猜;
  • 工具太散,它容易乱试;
  • 工具权限太大,又会变成安全问题。

比较理想的状态是:给它完成任务所需的能力,但把危险能力放到审批之后。

沙盒层

AI 跑命令之前,最好先问一句:它失败了,会不会伤到真实环境?

沙盒的意义就在这儿。它不一定多炫技,但它决定了你敢不敢真的让 AI 动手。

常见限制包括:

  1. 只允许修改当前工作区;
  2. 外部网络访问需要额外批准;
  3. 删除文件、重置分支、部署服务要人工确认;
  4. 临时文件只能写到指定目录;
  5. 密钥和生产配置不直接暴露给代理。

这些限制看起来麻烦,但正因为有限制,我们才敢把更多实际任务交给 AI。

现在的编程工具大部分都会默认创建一个沙盒了。

人工闸门

现在强大的模型搭配合适的工具会自动提示风险,便于提供给用户介入。

20260423182745

验证层

AI 写代码最麻烦的地方,往往不在语法。

真正难受的是:它写出来的东西乍一看像那么回事,跑起来又露馅。

所以 Harness 里必须有验证回路,不能让代理靠一句“我已经改好了”就结束任务。常见验证信号包括:

  1. 格式化检查;
  2. lint;
  3. 类型检查;
  4. 单元测试;
  5. 集成测试;
  6. 构建结果;
  7. 静态安全扫描;
  8. 人工 review。

这些检查不一定一次全上,可以分层跑。越便宜、越快的越该前置;越重的越适合放到 CI 或人工验收阶段。

更关键的是,测试失败之后,代理还能不能拿着错误信息继续修。

如果它看到报错就停,测试只是拦截器;如果它能进入“修改 -> 验证 -> 读错误 -> 再修改”的循环,测试才真正变成反馈系统。

收敛层

长任务里,AI 很容易出现一种情况:修 A 引入 B,修 B 又破坏 C,最后越改越偏。

所以一个好的 Harness,要同时告诉代理怎么做事、什么时候才算做完

这个“做完”不能只听模型自己说,要看外部事实。比如:

  1. 目标文件确实改到了;
  2. 相关测试通过了;
  3. 构建通过了;
  4. diff 范围基本符合预期;
  5. 没混进无关改动;
  6. 高风险操作已经获得确认;
  7. 最终说明和实际变更对得上。

这些条件满足了,任务才算真的收敛。

如果代理连续几次都卡在同一个错误上,Harness 也该让它停一下,重新分析,别无休止地试错。

拿修一个 bug 举个例子

如果把场景换成“让 AI 修一个后端接口 bug”,一个比较像样的流程应该长这样:

  1. 用户描述问题,并给出复现方式;
  2. 代理先找接口代码、日志、测试和最近相关改动;
  3. 它给出计划,说明准备动哪些文件;
  4. 通过 patch 做受控修改,不要直接重写整块模块;
  5. 先跑最相关的局部测试;
  6. 如果失败,把错误日志重新喂回去继续分析;
  7. 局部通过后,再扩大验证范围;
  8. 最后输出改动摘要、验证命令和风险点,交给人看。

真实工作里,最容易出问题的,往往卡在这些地方:

  • 上下文没找全;
  • 失败日志没看懂;
  • 明明只该改一个函数,却顺手改了一片。

AI 会写代码已经不稀奇了。真正难的是,让它在错误反馈里不断缩小问题范围,别一路拍脑袋往前冲。

怎么开始实践Harness?

  1. 模型的能力是第一位,模型能力跟不上,harness再多也是徒劳。

  2. 一开始没必要先搭很重的平台。一个最小可用的 Harness,通常可以从四件事开始。

写清楚项目入口

最容易见效的一步,是维护好项目根目录的 AGENTS.md

它不需要写成长篇论文,但至少要能回答:

# 项目说明

## 项目架构

## 技术栈
- Hugo static site
- 自定义 thinkblog 主题

## 常用命令
- hugo server -D
- hugo

## 目录约定
- content/post/ 存放文章
- themes/thinkblog/ 存放主题源码
- public/ 为构建产物,不要手动编辑

## 修改原则
- 优先小步修改
- 不要混入无关格式化
- 修改主题后需要验证首页、详情页、列表页和搜索页

## 任务流程

## 注意事项

Claude.md 20260423184232

这其实就是最小可用版 Harness。很轻,但常常比一堆空泛要求更有用。

它在代理动手前给方向,在代理动手后给验收条件。如果某类错误反复出现,就继续把它写进去。这相当于给项目补长期记忆。

建一张命令清单

很多项目其实有验证命令,只是命令散落在 README、CI 配置和开发者记忆里。

对 Agent 来说,最好把命令整理成一张小表:

场景推荐命令说明
改后端逻辑go test ./internal/...先跑相关模块
改前端组件npm run test -- Button先跑局部测试
改全局样式npm run lint && npm run build检查样式和构建
改 Hugo 内容hugo检查 front matter 和模板

这张表不用替代 CI,它主要帮代理判断“先验证什么最划算”。

给任务分风险等级

不同任务不应该用同一套权限。

一个简单分级可以是:

  1. 低风险:改文案、补注释、加测试,可以让代理直接做完并给出 diff;
  2. 中风险:改业务逻辑、改构建配置,必须跑对应验证;
  3. 高风险:删文件、改数据库迁移、改权限规则,必须人工确认;
  4. 生产风险:发版、部署、操作线上数据,代理只能准备步骤,不能直接执行。

分级越清楚,越容易把自动化范围往前推,也越不容易把“省时间”变成“埋雷”。

定义完成标准

很多 AI 任务失败,常常卡在“完成”的定义太模糊。有些AI去取巧,绕过事实,利用打桩或者借口,忽略失败。

可以把完成标准写得更具体一点:

  1. 改动只覆盖任务相关文件;
  2. 关键测试或构建命令已经执行;
  3. 失败日志已经处理或明确说明原因;
  4. 没有引入无关格式化;
  5. 最终说明包含改了什么、如何验证、还有什么风险。

这几个条件一旦固定下来,Agent 的输出就会更像工程交付,少一点看起来很自信的空话。

有哪些技术可以构建harness?

利用subagent增强Harness

Subagent 这件事,表面上看像“多开几个 AI 一起干活”,但实际要好用,前提是 Harness 已经把分工和边界画清楚了。

不然多 Agent 很容易从提效工具变成混乱放大器:都在读同一堆上下文,都想改同一批文件,最后互相覆盖,主代理还得花时间收拾残局。

所以 subagent 更适合这种场景:

  1. 任务能拆成几个相对独立的小块;
  2. 每个小块都有明确产出;
  3. 写入范围可以尽量错开;
  4. 主代理能负责最后集成和验收。

比如修一个稍复杂的功能时,可以这么拆:

  • 一个 subagent 去扫相关文件和历史实现,给主代理补地图;
  • 一个 subagent 只负责补测试;
  • 一个 subagent 只负责改某个独立模块;
  • 主代理最后统一看 diff、跑验证、决定要不要合并思路。

这样分才有意义。因为 subagent 擅长的是并行探路,不是替你逃避设计。

还有一点很关键:subagent 最好拿到的是收窄过的问题,而不是一句“你去帮我把这个系统搞定”。问题越具体,边界越清,回来的结果越能直接接进主流程。

所以在我看来,subagent 不是 Harness 的替代品,反而是 Harness 成熟之后才更有价值的一层。你先把任务入口、工具、权限、验证和完成标准定住,再让多个代理去并行干活,这时它们才像协作;不然就只是多人一起乱试。

利用skills增强harness

如果说 AGENTS.md 是项目级地图,那 skill 更像任务级外挂。

它解决的不是“这个仓库是什么”,而是“这类事通常该怎么做”。比如写博客、改测试、查日志、补前端样式,这些任务都有各自稳定的套路。每次都靠一大段 prompt 现编,效果往往不稳;把它们沉淀成 skill,Harness 就多了一层可复用的领域经验。

一个好用的 skill,通常会把几件事提前讲明白:

  1. 适用场景是什么;
  2. 这类任务优先看哪些文件;
  3. 有哪些固定步骤;
  4. 哪些表达或操作要避免;
  5. 最后要交付成什么样。

像我现在写这篇文章,用的其实就是博客写作 skill。它不会替我写内容,但它会提前把边界卡住:文章放哪、front matter 怎么跟旧文风格保持一致、哪些句子太像 AI 腔、哪些站内旧文值得参考。

这类东西一旦沉淀下来,收益很直接:

  • 少重复说明;
  • 少把上下文塞爆;
  • 让不同任务走不同轨道;
  • 把“经验”从人脑里搬到系统里。

我现在更愿意把 skill 理解成:可调用的任务手册。它本质上还是 Harness,只不过粒度更细,贴着具体任务类型。

不过 skill 也别贪大。最怕把十几类任务、几十条规则全塞进一个大 skill,最后谁都能用,谁都用不好。比较稳的做法还是小而专:一个 skill 只解决一类问题,必要时再挂参考文档、脚本和模板。

利用Hook增强Harness

Hook 的价值,在于把“提醒”变成“拦截”。

很多规范如果只写在文档里,模型是有可能看漏的;但如果放到 Hook 里,它就会在关键节点真的执行。比如:

  1. 修改文件前,自动检查目标目录有没有 AGENTS.md
  2. 运行命令前,识别是否包含高风险操作;
  3. 写完代码后,自动跑格式化或最小验证;
  4. 命令失败后,把 stderr 摘出来重新喂给代理;
  5. 输出结果前,补上变更摘要和验证记录。

这样一来,Harness 就不只是“告诉 Agent 应该怎么做”,而是能在生命周期节点上主动介入。

一个很常见的例子是风险命令拦截。像 rmgit reset、部署脚本、数据库迁移这类动作,你完全可以在 Hook 里先识别,再决定是直接拦、要求确认,还是转成只读预演。

还有一种特别实用的 Hook,是把失败信息整理干净。模型经常不是不会修,而是拿到的错误太脏:几百行日志混在一起,重点埋掉了。Hook 可以先把报错裁短、提取关键栈和退出码,再交给 Agent 继续分析,这种效果一般比“把原始日志整段扔回去”稳得多。

所以 Hook 更像一层自动值守。它不是替模型思考,而是在入口、执行中和收尾处,把一些确定性的动作先做掉。

利用workflow构建Harness

很多团队一开始做 Harness,容易只盯着 prompt、工具和权限。真正用久了会发现,workflow 才是把这些东西串起来的骨架

因为真实任务不是一次调用,它更像一条流水线:

接任务 -> 读上下文 -> 出计划 -> 小步修改 -> 跑局部验证 -> 失败回喂 -> 扩大验证 -> 输出结论

如果这条线没有固定下来,Agent 每次都会自己决定顺序,结果就是今天先改再测,明天先全量构建,后天又跳过验证,稳定性很差。

把 workflow 固定下来之后,很多事就顺了:

  1. 什么时候该读文档;
  2. 什么时候该给计划;
  3. 什么时候只能小步改动;
  4. 什么时候先跑局部验证;
  5. 什么时候必须人工确认才能继续。

常见误区

把 Harness 当成提示词模板

提示词模板当然有用,但它只是 Harness 的一小部分。

真正的 Harness,一定得有外部验证和执行约束。否则系统只能说“请遵守规范”,却不能在越界时发现并拦住,那顶多算建议,还谈不上护栏。

把所有知识塞进一个大文件

超长说明文件很容易把重点冲淡。

我现在更喜欢“入口索引 + 按需读取”这套方式:入口文件只写关键规则,再把更细的内容拆到别的文档、脚本说明和测试说明里。这样既省上下文,也更不容易漏关键约束。

只盯着模型升级

更强的模型当然重要,但可靠性不能只靠模型本身。

没有测试、没有沙盒、没有权限边界、没有人工闸门,再强的模型也可能在错误路径上高速前进。Harness 的价值,就是拿软件工程的方法,去对冲模型本身的不确定性。

不区分任务风险

改文案、补测试、修 lint、改数据库迁移脚本,这几件事的风险完全不是一个量级。

所以 Harness 最好按风险分级:低风险任务可以自动完成;中风险任务至少要跑验证;高风险任务必须人工确认;生产操作要有单独审批。

怎么判断 Harness 有没有用

看演示效果不太够,还是得看长期指标。

比较值得盯的,有这些:

  1. 任务解决率:AI 在少干预情况下完成任务并通过验证的比例;
  2. 首次通过率:第一次修改就过测试的比例;
  3. 返工率:合并后还要人工二次修的比例;
  4. 无关变更率:一次任务里混进不相关改动的比例;
  5. 验证覆盖率:关键路径有没有自动化检查兜底;
  6. 人工中断次数:高风险动作有没有被正确拦住。

这些指标能帮你判断,问题到底出在模型、上下文,还是 Harness 本身的约束和反馈设计。

harness发展的两个方向

  1. 内化到模型里
  2. 内化到编程工具里

结语

如果让我用一句话概括我现在对 Harness Engineering 的理解,大概就是:

每当你发现 Agent 犯了一个错误,你就花时间设计一个解决方案,使 Agent 永远不再犯同样的错误。——Harness Engineering

这句话我很喜欢,因为它一下子把重点说透了。

按这个思路做,就不能把希望寄托在模型下一次“自己聪明一点”上。出了问题也别只盯着这一次修补,最好顺手把护栏补上。

比如这次是上下文没给够,那就补检索和项目地图;这次是改动越界了,那就补权限和审批;这次是测试过不了还硬说完成,那就补验证回路和收敛条件。

也就是说,Harness Engineering 想做的,是把错误慢慢沉淀成系统能力,别让同一类问题反复重演。

所以我越来越觉得,未来程序员的工作不会只是“自己写代码”,还会越来越多地变成下面这些事:

  1. 设计任务边界;
  2. 编写项目规则;
  3. 维护验证体系;
  4. 建立自动化反馈;
  5. 审查 AI 无法自证的部分。

AI 负责把速度拉起来,人负责守住工程确定性。

当 AI 写代码的速度已经快到人很难逐行盯完时,真正让人安心的,往往是你有没有能力把它犯过的错,持续变成下一次不会再掉进去的工程护栏。

参考资料

  1. 本地参考稿:《AI Harness 工程详解与实践》
  2. 知乎参考链接:https://zhuanlan.zhihu.com/p/2021716359613032366
  3. LangChain Blog: The rise of context engineering
  4. Agents Cookbook: Harness engineering
  5. Thoughtworks: Patterns for building effective AI coding assistants

版权声明: 本文首发于 指尖魔法屋-Harness Engineering 的介绍与实践https://blog.thinkmoon.cn/post/993_harness-engineering%E7%9A%84%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%AE%9E%E8%B7%B5/) 转载或引用必须申明原指尖魔法屋来源及源地址!