这一期聊 harness 工程:用四个确定性组件把 LLM 包裹起来,让 Agent 在自动修复编码循环里安全地生成代码。我的实测结论是,模型负责"想",harness 负责"做、记、查",四件套缺了任何一件,自动修复都只能停留在 demo 阶段。
最近一轮技术演示里,演示者用 ADK 2.0 与 Antigravity SDK 组合跑通了一个自动修复编码循环:代码构建失败,Agent 自己定位错误、生成补丁、重跑测试,直到绿灯。整个过程不需要逐行人工审查。我按同一思路在 4sapi(https://4sapi.com)统一网关环境下复现并拆解了这套结构,下面是完整过程。
一、开篇:我为什么需要 harness
先回答一个直接的问题:Agent 生成代码的能力已经很强了,为什么还要在外面套一层工程结构?
原因在于模型本身的属性。LLM 是概率性的生成器,同样的 prompt 两次生成的代码可能完全不同;一次编译通过,不代表下一次修复还可靠。但自动修复编码循环里真正需要被信任的环节,恰恰是确定性的:补丁应用在哪个目录、允许访问哪些网络、失败后重试几次、这次修复算不算通过。这些环节如果交给模型临场发挥,结果就无法复现、无法审计、无法承担责任。
harness 工程的定义因此非常朴素:用确定性组件包裹 LLM。模型继续负责生成,但生成之外的一切——调度、隔离、记忆、判定——由确定性的代码接管。我拆解后的核心是四个组件:编排层、执行沙箱、状态持久化和验证工具,下面逐一展开。
二、开篇痛点:能写代码的 Agent,没人敢放权
自动修复编码循环的真正瓶颈不在模型会不会写代码,而在敢不敢让它自己改代码。我归纳了四个痛点:
- 生成的代码没人担保:Agent 写出的补丁可能编译不过、跑挂已有测试,甚至引入新的回归;
- 逐行审查不可持续:一轮修复往往要迭代三五次,每次迭代都等人工确认,自动化的意义就消失了;
- 让模型自评不可靠:模型的自我检查是概率输出,"我觉得没问题"和测试真正通过是两回事;
- 长会话状态容易丢:断线、超时、进程被杀之后,补丁、测试日志、迭代进度全部丢失,循环只能从头再来。
这四个痛点指向同一件事:缺少模型之外的确定性保证。harness 四件套恰好分别回答这四个问题——编排层管流程、沙箱管风险、持久化管记忆、验证工具管结论。
三、原理速览:harness 工程是什么
用一张图概括 harness 的整体结构:
一句话概括:模型负责"想",harness 负责"做、记、查"。四个组件全部是确定性的,不依赖模型的临场发挥。这样设计的好处是:即使模型某轮生成了错误的补丁,失败也会被验证工具拦截、被沙箱限制在隔离环境内、被持久化记录在案,最终由编排层决定是否进入下一轮迭代。
四、第一件:编排层——循环的大脑
编排层回答的问题是"下一步做什么"。它是整个自动修复循环的调度中枢,演示里的 ADK 2.0 就承担了这部分职责。在一个典型的修复循环里,编排层负责:
- 把构建失败、测试失败等信息构造成结构化的修复任务;
- 决定何时调用模型生成补丁、何时把补丁交给沙箱执行、何时宣布任务完成;
- 限制最大循环次数与单轮超时,从根上掐断无限重试;
- 把验证工具的失败输出整理成可回喂的上下文,在下一次模型调用时携带。
编排层还决定失败信息的回喂方式。原始测试日志往往很长,直接全量塞进上下文既费 token 又稀释注意力;更稳妥的做法是截断、去重、只保留错误摘要与失败断言,让模型每一轮都看到"干净的失败信号"。
五、第二件:执行沙箱——风险半径的边界
补丁写出来之后必须真的跑一遍,自动修复才有意义。但"跑一遍"发生在哪里,决定了整个系统的风险半径。执行沙箱就是这道边界,我从三个维度控制它:
- 文件系统隔离:Agent 只能读写被授权的工作区目录,工作区之外的代码、配置、密钥一律不可见;
- 网络隔离:默认禁止出网,需要下载依赖时按域名白名单放行,防止补丁里的恶意代码外联;
- 资源配额:CPU、内存、单命令超时都设上限,失控进程可以被强制终止。
沙箱的意义在于把试错的代价兜住。自动修复本质上是一个反复试错的过程,前几轮生成的补丁大概率是错的;如果这些错误补丁直接跑在真实环境里,一次误删或误发布就可能造成事故。在沙箱里试错,成本只是一次隔离环境里的失败。
需要说明的是,沙箱不是万能的安全方案。如果沙箱里挂载了生产密钥、拥有无限制的网络出口和可写的数据库,它仍然可能造成严重影响。隔离、最小权限与验证必须组合使用。
六、第三件:状态持久化——循环的记忆与账本
自动修复是典型的长会话任务:模型调用、补丁应用、测试执行交错进行,一轮失败的输出是下一轮的输入。如果这些中间状态没有落盘,任何一次断连或进程重启都会让整个循环归零。
状态持久化组件保存三样东西:
- 每轮生成的补丁原文与应用的先后顺序;
- 每轮验证工具的退出码与失败日志摘要;
- 循环的整体进度:当前是第几轮、还剩几次重试、任务是否已收敛。
持久化还有一个容易被忽略的价值:可审计性。修复结束后,谁在什么时间生成了什么补丁、验证结果如何,都能从持久化记录里完整还原。这比"模型记得自己做过什么"可靠得多——记忆会漂移,账本不会。
七、第四件:验证工具——确定性的裁判
验证工具回答"这次修复到底成没成"。它是整个循环里唯一有资格下结论的组件,判定依据是确定性的规则:编译是否通过、测试是否全绿、类型检查与 lint 是否有错误。
我把四个组件放在一起对比过各自的分工:
| 组件 | 职责 | 没有它会怎样 |
|---|---|---|
| 编排层 | 调度循环、控制次数与超时 | 循环没有边界,可能无限重试 |
| 执行沙箱 | 隔离环境、限制文件/网络/资源 | 错误补丁直接污染真实环境 |
| 状态持久化 | 保存补丁、日志与进度 | 断连即归零,无法审计追溯 |
| 验证工具 | 确定性判定 pass/fail | 修复是否成功只能靠模型自评 |
验证工具的关键特征是"不依赖模型判断"。失败就是失败,退出码和断言结果是客观事实。只有当验证工具给出绿灯,编排层才会收工并把补丁作为最终结果输出;否则失败信息被回喂,进入下一轮迭代。这正是"不需要逐行人工审查"能成立的前提——人工审查替代不了,但确定性验证可以把需要人看的内容压缩到极少数边界情形。
八、自动修复编码循环:四件套怎么协作
把四件套串起来,就是完整的自动修复循环。我用文本图把流程固定下来:
循环的每一圈都有明确的所有者:编排层决定转不转下一圈,沙箱承担试错代价,持久化保证断点可恢复,验证工具给出唯一的通过依据。四件套是流水线关系,任何一件缺席,其他三件都会失真——没有沙箱,验证工具不敢放心跑;没有持久化,编排层无从恢复进度;没有验证工具,编排层不知道该不该收工。
九、接入 4sapi:把模型调用接到统一网关
循环里频率最高、也最需要稳定的环节是模型调用。我选择把这一环统一接到 4sapi(https://4sapi.com)网关,请求流如下:
网关把鉴权、限流、计费和格式转换集中在一个入口,循环里只需维护一个 base_url。演示中的 ADK 2.0 与 Antigravity SDK 组合,走的是同一类接入姿势:Agent 框架负责编排与工具调用,模型服务统一由网关分发。
接入代码,Python 示例(OpenAI 兼容客户端):
接入时有两点值得注意:一是模型名要与网关侧开通的模型一一对应,调用前先核对;二是每轮循环的 token 消耗都在累计,用网关的用量统计接口盯住单任务成本,比事后看总账单直观得多。
十、成本与风险提示
把这一期的坑集中列一下:
- 循环是天然的多调用负载:一轮修复往往多次调用模型,且上下文随迭代变长,token 消耗呈叠加式增长,务必由编排层写死循环次数与单轮超时;
- 失败日志回喂要控制长度:全量塞入既费 token 又稀释信号,截断到错误摘要即可;
- 沙箱不等于安全:挂载密钥、开放网络的白名单配置不当,隔离就形同虚设,最小权限要逐项核对;
- 验证工具只保证"测试过的行为正确",测试覆盖不到的路径仍然可能出错,高风险改动上线前仍建议人工复核关键差异;
- 这一期讨论的全部是合法接入、架构设计与负载均衡层面的内容,不涉及任何绕过官方限制的做法。
十一、harness 工程治理清单
上线一个自动修复循环前,我至少按下面这份清单过一遍:
- [ ] 编排层:设置最大循环次数、单轮超时与重试策略
- [ ] 执行沙箱:隔离文件系统、网络白名单、CPU/内存配额
- [ ] 状态持久化:每轮补丁、验证日志、进度均可落盘与恢复
- [ ] 验证工具:编译、测试、lint 全部确定性判定,不依赖模型自评
- [ ] 失败信息:截断整理后结构化回喂,限制单次回喂长度
- [ ] 模型接入:经 4sapi(https://4sapi.com)统一网关,核对模型名与用量统计
- [ ] 注入防护:在代码与文档里放入注入文本,确认不会改变修复目标与权限
- [ ] 成本核算:记录单任务 token 消耗与网关账单,验证循环预算在控制内
总结
harness 工程的价值不在模型本身,而在模型外面的确定性结构:编排层让循环有边界,执行沙箱让试错有代价上限,状态持久化让长会话可恢复、可审计,验证工具让"修复成功"有了唯一客观的定义。四件套组合起来,自动修复编码循环才真正摆脱了对逐行人工审查的依赖,从演示走向可落地。这一轮我在 4sapi(https://4sapi.com)的网关日志里,能同时看到循环的调用次数、token 消耗与模型分账,四件套加统一网关,是我目前最顺手的 Agent 工程化组合。欢迎在评论区发表想法,一起聊聊 harness 的接入与落地经验。




