先说个背景。我过去一年多的时间,几乎每天都泡在各种 AI 编程工具里,从最开始把它当“高级补全插件”用,到后来让它直接写模块、写测试、改 bug,再到最近半年把整套流程固化成一个能跑在 CI 里的框架。如果你只是让 AI 写个函数、补个单测,那 Copilot 或 Chat 模式已经够用;但一旦你的项目到了几十个文件、十几个服务、多人协作的阶段,你就会发现零散的 AI 提问根本控不住质量——它今天能给出一版看起来很合理的代码,明天换个上下文改出来的东西,可能把之前精心设计的接口全打乱。
我最终沉淀下来的东西,就是标题里说的 Agentic Harness Workflow。简单说,它不是又一个 AI 编程助手,而是把“AI 写代码”这件事放进一个可编排、可观测、可回滚的工程流水线:需求拆解、代码生成、静态检查、单测、构建、人工审批、合入,每一步都明确输入输出和验收标准。这篇文章我会从设计思路讲到最小可落地实现,再把我踩过的坑和排查方法全盘托出。适合正在把 AI 编程往团队级流程里推的工程师,也适合想搞清楚“AI 编程到底怎么工程化”的人。
1. 为什么需要把 AI Coding 工程化
1.1 单体 Copilot 模式的瓶颈
最早接触 AI 编程时,多数人的路径是从 IDE 里的补全插件开始的。它非常好用,因为你敲出函数签名,它能补齐实现,敲出 TODO,它能给个雏形。问题出在规模上:一旦任务是“给整个订单模块加一个库存预占逻辑”,需要动的不只一个文件,而是数据库表设计、领域服务、接口层、调用方、单元测试、迁移脚本等等,你在单一对话框里根本描述不完这个需求。即便你把上下文塞得满满的,模型一次能“看到”的窗口也是有限的,它只能基于你给的那几个文件做局部最优解。
第二种普遍做法是让 AI 直接生成一大包代码,然后人去看。你让 AI“写一个用户管理模块”,它能吐一个包含 Controller、Service、Repository、实体、DTO、数据库 SQL 的全家桶。表面上看效率极高,但你进入 review 阶段就痛苦了:它生成的代码风格可能和团队现有代码不一致,它自己造的抽象别人看不懂,它假设的数据库字段和现有表结构对不上。更麻烦的是,这包代码不是从你自己的代码库上下文里长出来的,它对现有实现的了解非常有限。最后你的确“验收”了代码,但那些梗你不一定都咽得下去。
还有个隐蔽的问题:模型写代码是概率性的。同一个需求,同一套提示词,跑十次可能有八种不同的输出。如果每次生成的代码都在变,团队根本无法收敛出一个稳定的代码基线,更谈不上让 AI 参与长期演进的项目。它今天重构出来的模块和你上周手工写的模块,风格、命名、异常处理方式都可能完全不同。
这些瓶颈的共同点是:AI 被当作一个“单发大炮”,你开一炮,得到一个结果,然后拿这个结果去和代码库硬碰。你缺少一个机制来约束它、引导它、验证它的产出。工程化的本质,就是把不可控的单发行为变成多阶段、可控的流水线行为。你需要的不是更强的模型,而是一套“驾驶舱”,让模型在有限跑道里安全起飞和降落。
1.2 从“单次对话”到“持久化流水线”的转变
我踩了大概两个月的坑之后,才意识到一个关键点:AI 写代码并不缺“能力”,缺的是“过程管理”。人写代码的时候,脑子里有个任务模型,知道先看需求、再定接口、再写实现、再自测、再提交;AI 如果不给过程,它就会一上来就写一堆代码,因为训练目标决定了它倾向于直接输出“最终答案”。
Agentic Harness 的核心思路,就是把“让 AI 一次写对”变成“让 AI 在一个受控的过程中逼近正确”。它借鉴了传统软件工程里的流水线思想:需求分析、设计、编码、测试、发布,这些阶段不是人类工程师独有的,同样可以赋予 AI Agent。但 Agent 不是独立地完成整个流程,而是 Harness(流程框架)在控制节奏。Harness 知道当前处于哪个阶段、这个阶段的输入是什么、输出需要满足什么条件、不满足就回到哪个阶段修复。
从单次对话到流水线,最大的区别在于状态。后者把一次任务的中间产物全部落盘:需求理解、接口契约、实施计划、生成的代码、测试结果、修复记录。任何一步出问题,你都可以回溯到具体环节,而不是对着模型说你刚才哪里错了。而且因为中间产物是结构化的,你可以把 AI 的产出直接接到原有的 CI/CD 工具链里:代码生成完接着就跑 lint、跑单测、跑构建,有了结果再决定要不要进人工。
一句话总结就是:AI 是一个很强但不可靠的执行者,Harness 是那个把“不可靠”变成“可以频繁纠错”的管理者。后面我会详细说 Harness 里到底有哪些构件。
2. Agentic Harness 框架的整体设计
2.1 核心抽象:任务、步骤、上下文、验证
我设计的框架,地基是四个抽象概念:任务、步骤、上下文、验证。没有这些抽象之前,你所有的 prompt 和工具调用都是“一次性关系”;有了它们,整个流程才能被描述、被执行、被复盘。
先说任务。任务不是“帮我改一下登录接口”这种口头表述,而是一个结构化对象,至少包含:任务标题、详细描述、关联代码路径、验收标准、约束条件。验收标准尤其重要,它是判断“做完了没有”的唯一依据。比如“登录接口改为邮箱或手机号均可登录,且日志里记录登录方式”,这就比“支持多种登录方式”可执行得多。
步骤就是流水线里的一个阶段。每个步骤有明确的输入和输出,步骤之间可以串行,也可以分叉,还可以带循环(比如失败后回到上一步)。一个典型任务会被拆成:解析需求步骤、生成实施计划步骤、按计划写代码步骤、运行测试步骤、修复失败步骤、生成提交信息步骤。步骤本身不关心具体用什么模型、什么工具,它只管“给定输入,产出输出,触发下一步”。
上下文是整个框架最容易翻车的地方。AI 写错代码,一半以上的原因是上下文给得不对。Harness 里的上下文分三层:全局上下文(代码库结构、技术栈、编码规范)、任务上下文(需求、约束、相关文件)、步骤上下文(这一步需要的局部信息)。我在框架里强制的规则是:每个步骤只装配它需要的上下文,不能把全部代码库都塞给模型。比如生成实施计划步骤,只需要了解代码结构和相关文件的概要,不需要看到每个函数的实现;而写代码步骤,就需要把涉及到的文件完整内容给到模型。
验证是最后一道关。它是个可扩展的接口,内置静态检查、编译、单测、契约校验、风格检查等实现。验证结果会成为“步骤是否通过”的唯一标准。我见过很多团队只用“模型说它做完了”作为完成信号,这等于让运动员当自己的裁判。验证必须是非模型的、客观的、可重复的程序化检查。
2.2 角色编排与工具注册
框架里我设计了几个固定角色,而不是让一个大模型从头干到尾。每个角色有专门的职责和配套的 prompt 风格、工具权限。
第一个是规划者,负责把任务描述拆解成可执行的步骤清单,并估计每个步骤涉及的文件和风险点。第二个是实施者,真正调用代码生成能力,按规划者的步骤写代码、改文件。第三个是审查者,它不是普通的“代码 review”,而是拿着验收标准和全局上下文,去检查实施者改出来的代码有没有偏离需求、有没有破坏现有接口、有没有明显的逻辑漏洞。第四个是修复者,当验证失败时,它拿到失败日志和代码,针对性修复,而不是重写整个模块。
工具注册表也很重要。模型不能想干什么就干什么,它只能用框架注册过的工具。我在框架里注册的工具包括:读文件、写文件、执行 shell 命令、运行指定测试用例、搜索代码(基于 grep 和语义索引)、修改 git 分支、创建 commit、向外部系统查数据(比如读取 CI 结果)等等。工具权限分为只读和执行两类,规划者、审查者只给只读权限,实施者才给写和执行的权限。
为什么把角色分开?一是职责隔离,避免模型在同一个上下文里既当运动员又当裁判;二是 prompt 可以针对角色特化。规划者的 prompt 里强调影响分析和步骤拆分;实施者的 prompt 里强调“严格按计划输出,不要擅自扩大改动范围”;审查者的 prompt 里强调“按照验收标准逐项核对,给出 PASS/FAIL 和理由”。长期跑下来,这种角色分离明显降低了“模型自由发挥”的概率。你可能会问:现在的大模型能力很强,一个模型干四件事不行吗?行,我初期就是这么干的,结果就是它自己给自己找台阶下,明明测试没过,它在总结里还会说“由于环境问题测试未运行”。角色分离之后,每个角色都只对单一职责负责,推诿的空间小很多。
工具注册的另一个好处是可观测。每一步的每一次工具调用都记录在案:用了什么工具、输入了什么、返回了什么、耗时多少。排查问题的时候,你能精确知道模型是在哪一步产生了错误的假设,而不是靠猜。
2.3 可观测性与复盘机制
工程化和非工程化之间有条清晰的分界线:可观测性。零散的 AI 对话也有日志,但那是聊天记录;Harness 里的可观测性是针对流程步骤的元数据。每跑完一个任务,框架会产出一份流水线报告,包含:每个步骤的状态、耗时、输入输出摘要、验证结果、工具调用轨迹,以及最终的代码差异统计。
报告有实时和汇总两种形态。实时形态就是跑任务时终端或者 Web 界面上的滚动日志,方便你在任务挂掉的时候第一时间看到是哪一步出了问题。汇总形态是任务结束后的 markdown 报告,可以直接贴到 PR 描述里,让评审人知道这段代码是 AI 怎么生成出来、怎么验证的。我团队的评审同事对这种报告很买账,他们说以前看到 AI 生成的 PR 心里发怵,现在至少有完整的生成和验证链路可追溯。
复盘机制则更进一步:框架会把“成功任务”和“失败任务”分别归档。定期分析失败任务的共性原因。我做过一次统计,发现排名前三的失败原因是:上下文缺失(模型不知道某个函数已存在)、验证规则过严(测试依赖的外部服务在本地环境起不来)、需求描述含混(验收标准无法被程序化验证)。这三类原因后来都反向推动我改了框架配置:给特定步骤加了更多上下文检索能力、把外部依赖的测试标记为集成测试单独处理、在需求输入模板里强制要求写明可验证标准。这是一个很朴素但很有效的闭环:流程产生的数据反哺流程本身的改进。
3. 落地实操:搭建一个最小可用的 Harness
3.1 定义任务模板与输入输出契约
如果你想在自己项目里落地,我建议从一套任务模板开始,别上来就写一个很完善的框架。我把最小可用的模板称为“三件套”:任务描述、验收标准、涉及路径集合。
任务描述里必须写清楚背景和动机。比如“订单模块目前在下单时不校验库存,导致超卖,需要在下单事务内增加库存预占逻辑”,这句话比“优化订单模块”有用得多,因为模型能从背景里推断出它需要理解事务边界、库存表结构、现有下单流程。
验收标准要写成能被客观检查的条目。我常用的两条准则是:每条标准必须对应一个“机器可查”的事实,比如“代码通过编译”“单测通过”“新方法有 90% 的行覆盖率”“数据库迁移脚本可回滚”;每条标准尽量不加主观形容词,比如“性能很好”就不合格,“下单接口在库存不足时返回 400 错误码”才是合格标准。
涉及路径集合用来限制模型的探索范围。模型读完整个代码库再去写代码,既慢又容易迷路。我给每个任务模板配一个路径清单,包括:自然语言描述的路径规则(比如“订单模块下的所有文件,不包括测试目录”),以及一条补充规则(遇到不在规则内的路径时,必须先报告再决定是否深入)。这个补充规则特别重要,因为模型经常需要读一些间接依赖的文件,你完全锁死路径会让它卡住。
然后就是输入输出契约。每个步骤的输入和输出都定义成 JSON Schema,既方便校验,也方便和外部工具集成。比如“生成实施计划”步骤,输入是任务对象和全局上下文,输出是一份计划对象,包含 steps 数组、每个 step 的文件列表、风险标记、预估耗时。如果模型输出的计划不符合 Schema(比如缺失风险标记),框架会直接要求它重做,而不是稀里糊涂地往下走。这个机制很多人低估了,觉得一个 Schema 有什么了不起,但在实际操作中,它能让模型跑偏后的纠错成本降低一个数量级:你有明确的“不合格”定义,而不是靠肉眼读输出判断“看起来差不多。
恰好说到 Schema,你也不用一上来就定义得非常精细,先用一个能覆盖常用字段的版本,跑几个真实任务后迭代字段即可。
3.2 搭建步骤流:解析、规划、生成、验证、修复
一个最小可用的步骤流,我建议只有五步:解析、规划、生成、验证、修复。这五步就像一个标准迭代循环,几乎所有代码生成任务都可以映射到这个框架里。
解析步骤,输入是原始任务模板,输出是结构化任务对象。它要做的事是:把自然语言需求拆成字段、目标、约束;识别涉及的模块和技术栈;判断这个任务是否需要读取额外的上下文(比如某个接口的定义、某个配置文件的用途)。解析步骤的 prompt 里我特意加了一句“如果需求描述不足以支撑后续规划,必须列出需要补充的问题清单”。这一问句设计对结果影响很大,不加的时候模型经常会把含糊需求强行理解,加了之后它反而更谨慎,或者至少会标注“需求模糊假设已用 XXX 补齐”。
规划步骤需要输出一份实施计划。我之前踩过的一个坑是,规划步骤的模型总是试图“顺便”重构代码。为了抑制这一点,我在规划步骤里显式加了规则:“不要对任务范围之外的代码提出改动建议”“如果发现问题属于范围外,添加到风险清单而不是修改计划”。规划的输出不仅供实施者使用,也供人来看,所以规划文档可读性要高:文件路径、改动类型、影响范围、依赖关系,四类信息一个都不能少。
生成步骤是真正写代码的地方。它接收实施计划和相关文件,按计划里的顺序逐个文件生成。一个很关键的实操技巧是:不要在同一个上下文里让模型一口气生成所有文件,而是每个文件单独生成、单独落盘。好处是单个文件的输出窗口更充裕,且某个文件生成失败时不会影响其他文件的产出。我还会在生成每个文件后立刻跑“单文件语法检查”,比如用编译器或 linter 查一遍,做到小步快跑,而不是等所有文件生成完再一起查。
验证步骤我不建议用模型来验证,而是挂上真实工具链。标记语言无关,以 typeScript 项目为例,就是 tsc 编译加 eslint;有单测就跑 jest;有构建流程就跑 npm run build;如果项目有数据库迁移,就加一个迁移脚本的可回溯性检查。验证结果作为步骤状态返回。
修复步骤就交给修复者角色,它拿到失败日志和当前代码,定位失败原因,修改代码。修复者最容易犯的错误是:看到失败就大改,可能把原来正确的东西也改坏了。我在修复者的 prompt 里强调“最小改动原则”和“解释性修复”:每次修复前必须先在回复里写清楚失败原因和拟改动的具体文件/函数,然后再动手。强制写解释,本质上是对模型思维过程的一种约束,能显著降低乱改的概率。
3.3 评测与回归:让每个改动都有据可查
流水线跑通之后,很快会有一个新问题:怎么知道这次 AI 生成的质量比上次好,还是更差?这就是评测与回归要回答的。
我在框架里预留了一个评测层,不是用来评价“代码好不好看”,而是评价“是否满足验收标准”。最简单的做法是:每次任务完成后,把验收标准的通过情况逐条记录下来。通过合并、失败、未覆盖三种状态。这样积累一段时间,你就能清楚看到哪些类型任务的验收标准最容易出问题。比如我这边就发现,涉及数据库事务的任务,验收标准里“回滚逻辑”的通过率明显低于其他条项。于是我把“事务回滚”提升为这类任务的必检项,并在验证步骤里增加了对回滚分支的测试要求。
另一个很有用的事是“回归集”。我把项目里几条最核心的链路做成固定的验收任务,每次 AI 改了其他代码,都会跑一遍这个回归集,确保核心链路没被破坏。有人会说这不就是跑集成测试吗?是,也不全是。回归集的特殊之处在于它混合了客观测试和少量模型判断:比如“核心下单链路中,库存扣减和支付确认是否在同一个事务里”,这类问题没法纯靠测试断言,就需要用一个固定 prompt 的审查角色去检查,并把结果记录到评测报告里。
框架还会做一件小事,但对团队协作很关键:把每次生成任务的“模型版本、prompt 版本、依赖版本”记入报告元数据。因为模型版本更新可能带来行为变化,如果没有版本记录,同一段流程明天跑出来的结果可能就完全不一样,而你无法归因。
3.4 一个完整示例:从需求到 PR
光说抽象概念不容易形成体感,我给你看一个具体例子。假设任务是:“在购物车结算接口中增加库存预占,预占失败时返回特定的库存不足错误码。”按框架配置,流程这样走:
解析步骤输出:任务对象为“在 orders 下的 checkout 接口增加预占动作”,涉及路径为app/order/service、app/order/repository、app/order/api、数据库脚本目录,验收标准为“库存不足时返回 INSUFFICIENT_STOCK,预占成功后库存表有记录”。
规划步骤输出:四步改动计划,第一步在仓库层新增预占方法;第二步在服务层调用预占并在失败时映射错误码;第三步在 API 层增加错误码文档;第四步编写事务回滚测试。每一步都标出涉及文件、如何改、依赖关系。
生成步骤分别生成这四个改动点,每点生成后先跑 TypeScript 类型检查。在这过程中模型一度尝试修改不属于任务范围的价格计算逻辑,框架因为它在规划文件里没提到价格相关文件,所以对这个文件写入操作直接拒绝,并把它标记到“范围外动作列表”里。
验证步骤:跑 tsc、eslint、两条新增单测、一条原有回归单测。单测中有一条失败,原因是预占方法里用了错误的库存字段名。修复步骤拿到失败日志,修复字段名,重新触发生成相关文件,再次验证通过。
最后产出 PR 描述,里面带着流水线报告的链接和验收标准逐条核对表。评审人只需要重点看一下 diff,不用再问“这代码怎么来的”这种问题。整个过程跑下来大概不到十分钟,而之前纯手工给 AI 分发这种任务、review、修 bug,一般要花一整个下午。
4. 质量保障与安全边界
4.1 给 Agent 划跑道:作用域与护栏
AI 编程框架最大的安全隐患,是模型运行了超出预期的命令、修改了不该改的文件。我给代理人加了两层护栏:作用域和执行白名单。
作用域基于仓库进行配置,支持三种粒度:仓库级、目录级和文件级。默认情况下,除任务描述里明确提到的路径,Agent 无权写任何文件。出于安全性考虑,写入操作还需要走一次“意图检查”:Agent 在写文件前必须声明“我要写哪个文件、为什么”,框架检查这个文件是否在允许清单里。如果你配置得非常激进(允许 Agent 自主添加新文件),至少要设置新增文件的后缀白名单,防止它给你生成一个脚本并在后续步骤里执行它。
执行白名单就是 shell 操作控制:只有注册过的命令才能跑。常用安全命令包括tsc、eslint、git diff、jest、npm test等。禁止命令包括rm、curl(除非特定域名)、git push等。很多人第一步配置得很松,结果模型主动执行了git reset --hard,把本地改动全冲掉了。这个教训挺痛的,建议一开始就配置严格的白名单。如果你担心白名单影响 Agent 的自主性,那就需要一条中间策略:模型可以提出一个命令并说明意图,框架在执行前自动给人工发审批请求。
护栏杆还有一个很实际的功能,就是限定 Agent 在“生成阶段”不允许读取生产环境配置或密钥文件。AI 模型上下文窗口会把读取的内容传出去(即使你用的是私有化部署,我也不想它把密钥写进 prompt 里),所以我把.env、config/prod这类路径默认设为可读禁止项。
4.2 人工审批点与关键关卡
完全自动化的流水线听起来很美好,但在代码工程里,至少有三个关卡必须有人工介入:任务启动阶段、代码合入阶段、以及模型行为异常阶段。
任务启动阶段的人工干预,主要是确认任务模板里的验收标准和范围没有被模型误解。模型可能把“增加预占”理解成“重建整个结算模块”,如果你不看解析结果直接跑,后面代码生成阶段就会出格。我现在的做法是:解析步骤的输出会以对比形式显示原始需求与结构化任务,人工一键确认或修改,再进入规划。
代码合入阶段的人工审批,严格来说不是让工程师盯着每一行 AI 生成代码看,而是让他们重点检查 diff 里的“模型特有痕迹”:比如无中生有的注释、过度设计的抽象、不合理的常量命名。这部分内容很难被静态检查覆盖,却很容易被流水线整体通过掩盖掉。我有一次就发现模型在业务逻辑里硬塞了一个“策略模式”,原因只是它觉得这样“设计更优雅”。它通过了所有测试,但给团队增加了不必要的维护成本。
第三个关卡是模型行为异常。怎么定义异常?框架里我配置了“异常信号列表”:规划里出现不存在的文件路径、一步之内修改了超过目标文件数量的代码、在工具调用返回结果里出现可疑的注入内容。一旦触发这些信号,流水线会暂停并升级给人工处理,不会继续往下跑。这一步设计得很省心,相当于给 Agent 装了个烟雾报警器。
4.3 成本与效率的平衡
用框架跑任务比普通对话模式贵,这是必须面对的现实。一次完整任务可能要调用几十次模型接口,涵盖多角色、多轮对话。成本控制我有几条实操建议。
控制上下文长度。给模型喂的内容越少,token 成本越低,而且响应也更快。Harness 的上下文裁剪机制在这里发挥作用:生成步骤只给相关文件,而不是全仓库。哪怕任务涉及十个文件,每次迭代也只传给当前改动的两三个。这一条能省掉相当比例的 token。
分层模型策略。不是每个角色都需要旗舰模型。我的做法是规划者、审查者用强模型(更强的推理能力),生成者和修复者可以用标准模型(生成效率优先),解析者用轻量模型即可。具体到实际值,我这边用旗舰模型跑审查、标准模型跑生成的组合,整体成本比全部用旗舰模型低了百分之四十,质量基本没差别。
缓存策略。验证步骤里的 lint、编译、测试结果做好缓存,同一份代码没改变就不重复跑。模型生成失败后,修复者的小改动不应该触发全量验证,而是只验证受影响的部分,这样既省时也省钱。
还有一条是流量与配额控制。模型接口偶尔超时或限流,框架要做重试和降级:重试次数默认三次,间隔递增;如果三次仍失败,不是直接报错,而是标记出问题步骤并尝试改用备用模型或模型版本。我遇到过一些供应商限流只出现在高峰期,加了降级策略后,流水线的整体完成率从 82% 提到 97%。
5. 踩坑实录与排查技巧
5.1 上下文污染导致的“幻觉式改代码”
那是在做一个后台管理系统的权限模块升级时,任务本身很简单:给角色表增加一个字段并同步到前端下拉。解析、规划都很顺利,但生成步骤出的代码里,把权限校验逻辑里一个已有的“超级管理员跳过校验”分支给删了。测试竟然还全过了,因为那个分支没有对应的测试用例。
排查链路是这样的:我先从流水线报告里看生成步骤的输入上下文,发现规划者写给生成者的文件清单里,把权限校验的旧代码文件完整贴进去了,而生成者在生成的回复里去掉了那个分支,只留了一句“此处逻辑已简化”。这很典型:模型在决策时不需要删除,但它倾向于“简化”上下文里看起来冗余的东西。它不觉得自己删错了,因为它没法执行代码去验证逻辑。
修复方法分两层。第一层是在生成者的 prompt 里增加硬性规则:“只实现规划要求,禁止修改与本次任务无关的已有代码逻辑,尤其是包含特定关键字的逻辑分支(如 super、admin、whitelist)。”第二层是把它系统性解决:我把“无任务动因的代码删除”加为审查者的固定检查项,审查者每次拿到 diff 后逐条列出“新增、修改、删除”,删除条目详细解释原因后才能通过。从那以后这种“幻觉式简化”基本杜绝。
5.2 工具链不稳定:超时、重试与幂等
AI 生成的步骤里经常要跑命令,第一次真正跑起来时,我发现最大的问题是命令效率低下。模型跑一个测试会用jest --runInBand从头跑到尾,即便它只改了一个小函数。更糟的是,有些命令本身不幂等,比如数据库迁移脚本,跑了两次就会出现重复执行错误。
工具链不稳定,直接表现为流水线步骤随机失败。我给框架加了“工具调用前检查”机制:每个命令执行前先做一次“预检”,比如测试命令会先看上次的构建产物是否存在、迁移类命令会先检查版本表。如果预检不过,就直接跳到修复步骤,告诉模型“环境状态不对,不要盲目重试”。
另一招是命令模板化。我不再让模型自己拼 shell 命令,而是给每种操作预定义带参数的模板。比如“运行某个测试文件”有固定模板,模型只需给出目标文件的路径,框架就会拼出npx jest --testPathPattern <路径> --silent。这既降低了命令执行的风险,也更容易做并发控制和资源限制。现在框架里没有被模板覆盖的操作,模型可以发起请求,但默认情况下请求会被标记为“需人工确认”,防止它自由发挥出各种奇怪命令。
5.3 模型输出格式漂移的处理
有一段时间,我的验证步骤经常报“解析 JSON 失败”,流水线大量重试。后来发现是模型在结构化输出时格式不稳定。你用 json 模式要求它输出一个包含“steps”字段的对象,它有时候给你加个注释,有时候字段大小写不对(Steps 而不是 steps),有时候整个输出被 markdown 代码块包住,而这破坏了严格模式解析。
这不是模型能力问题,而是输出契约没有得到强约束。我的处理方式有两步:第一,凡是结构化输出步骤都设置“多重容错解析”:先按严格 JSON 解析,失败则自动剥离 markdown 代码块标记再解析,再失败则使用正则提取关键字段。第二,也是更根本的,把格式要求直接写进模型的工具参数 schema 里,让模型走我们这边的强制 JSON 模式,而不是让它自己自由发挥。现在的框架里几乎所有结构化输出都走强制 schema,格式问题基本绝迹。
如果你用的是不支持强制 schema 的模型,我的建议是给每个输出步骤加“格式校验+自纠错”小循环:解析失败时把错误信息回传给模型,让它修正自己的输出,最多重试两次。大多数情况下模型都能自我纠正过来,而且第二次输出格式明显更规范。这个循环本身也值得记录到流水线报告,用来观察不同模型版本在格式纪律上的稳定性。
5.4 收益评估:什么时候值得上 Harness
最后说说什么时候不该上。我见过小型项目搭了个完整 Harness,最后发现比手动写代码还慢。原因很简单:流水线的固定开销太高。任务解析、规划、审查这几步,每个都要额外消耗模型调用和等待时间,如果项目本身只有十几个文件,需求都很简单直接,你让 AI 在 IDE 里直接生成加人工 review 反而效率最高。
适合上 Harness 的信号有三个:一是代码库规模到了“AI 常常找不到相关文件”的程度;二是任务类型高度重复(比如 API 增删改查、DTO 转换、测试补全),值得为它们沉淀固定模板;三是质量事故代价高,哪怕一个段落级 bug 也可能造成线上故障,因此值得为 AI 产出设置更多验证关卡。
如果你决定上,我的建议是先不要一上来就做全自动。把解析后的任务对象先给人确认,把生成的代码先走正常 MR 流程,只把“验证”和“报告”两个环节自动化跑起来,跑顺之后再逐步放开角色权限。这样你既能拿到 AI 工程化的红利,又不会因为一次失控的自动化改动付出过高代价。
前前后后调整了半年,我最大的体感变化是:以前是“AI 写得快但我看不懂所以不敢合”,现在是“AI 在流程里跑得稳,我只需要在最关键的节点把方向”。框架不会让 AI 变成一个不出错的神,但能把出错的概率压到可控范围,并且每次出错都有据可查、能快速定位。写代码这种事,归根到底还是要落到工程两个字上:过程可控、结果可验证、出错可回溯。Agential Harness Workflow,本质上就是给 AI 写代码这件事装上一个符合软件工程常识的栅栏和仪表盘。如果你最近也在为 AI 生成的代码质量发愁,强烈建议先在公司内部拿一个中等复杂度的模块试点跑一遍上面的最小五步流,把流水线报告贴进 PR 里让大家看看那种“透明感”,然后再决定扩展成什么形态。