游乐游手机版
首页/AI热点日报/热点详情

大仓AI工程化实战 从Vibe Coding到Harness

类型:热点整理2026-07-16
针对大型多仓库工程(30+微服务、10+前端微应用),搭建包含规则、技能、子代理、13阶段工作流与门禁脚本的Harness系统,解决PRD不可信、方案与代码脱节、改完无人验证、交付环节琐碎等痛点,使AI在真实业务中稳定跑完需求。

大仓AI工程化实战:让AI在真实业务中稳定跑完需求,我们踩过的坑与填平的方案。
核心内容:
1. 大仓多服务工程下AI落地的核心挑战与应对策略
2. Harness系统从搭建到撞墙的完整复盘与经验总结
3. 关键模块(门禁脚本、Team Mode)的深度踩坑与解决方案

这是一篇关于后端微服务加前端微应用大仓的Harness实战经验分享。我们不空谈理念有多重要,而是聚焦于我们如何一步步搭建、遇到哪些问题、以及如何修复这些问题的完整过程。

这篇文章的核心议题非常具体:如何让AI在跨多个仓库的前后端业务工程中,稳定地完成一个完整的产品需求

如今,AI模型的能力越来越强大,但当你尝试让AI独立完成一个完整的产品需求——从产品经理在TAPD中创建的需求单开始,到方案设计、代码实现、接口调试、代码审查,最终提交MR——你就会发现一个关键问题:模型能力足够,但工程体系却没有跟上。AI无法独立跑完整个流程,因为整条链路中,除了“写代码”本身,还涉及大量协作、流程规范、信任建立和最终收尾的工作。

以TAB实验平台为例,这是一个典型的前后端业务为主的技术平台:它包含30多个微服务、10多个前端微应用以及各平台SDK库,全部集成在一个大仓中进行统一管理。我们通过沙箱进行集成验证,用TAPD管理需求输入,iWiki沉淀方案,工蜂托管代码。在这样的工程环境中搭建Harness,会遇到一系列非常实际的挑战,例如:

  • 你可能需要同时修改跨5个submodule的代码,而不是只改动一个仓库
  • 你不仅要验证一个功能能否运行,还要拉取沙箱、刷新schema、启动Redis、运行真实的HTTP接口测试,确保功能上线后绝对可靠
  • 你面对的不再是单一的本地用户文档,而是需要同时管理TAPD需求单、iWiki文档、工蜂MR和Knot知识库这四套外部输入输出系统

经过一段时间的努力,我们逐步搭建起了这套Harness系统。在这个过程中,我们踩了很多坑,碰了不少壁,也删除了不少最初自以为正确的设计。本文将对这段经历进行完整的复盘,希望能为正在做类似工作的同学提供有价值的参考。

全文阅读约需25分钟。全文共10个小节,按照“项目背景介绍 → 方法论阐述 → 踩坑经历分享 → 取舍决策总结”的顺序展开。如果时间有限,可以直接跳到第六章(门禁脚本)和第七章(Team Mode踩坑复盘)——这两章内容密度最高,踩坑最深,对其它团队也最具参考价值。

第一章:TAB工程背景

在介绍如何搭建Harness之前,有必要先让大家了解我们是在什么样的工程环境中进行搭建的。否则,后续的所有取舍和决策都无法被理解——同一套方法论,应用于不同的工程,最终呈现出的形态会大相径庭。

1.1 TAB 工程画像

TAB是公司内部的 A/B 实验平台——产品同学发起一个实验,配置人群、指标,进行灰度发布和全量推送,背后是一整套从实验编排到效果统计的服务体系。从技术角度看,它有几个显著特征:

维度TAB 的特征
仓库形态多工作区 + 多子仓库(实验编排服务、人群服务、指标服务、网关、前端微应用…)
主语言Go、Ts 为主,同时融合各平台 SDK 技术栈,以及少量 Python 工具链
架构分层胶水层(协议↔领域对象转换)→ 接口层 → 服务层 → 领域层(数据访问 + 领域模型)
横切关注点7 个切面顺序串成一条链:错误 → 日志 → 数据库上下文 → 鉴权 → 参数校验 → 事务 → 出参整形
验证手段一键拉起完整沙箱环境(Docker Compose),数据库 / 缓存全新初始化,可运行真实 HTTP 测试
外部协作TAPD 管理需求单、iWiki 沉淀制品方案、工蜂托管代码 + Knot 知识库管理 + MR、企微通知等

它的真实复杂度在于:任何一个看似简短的需求,都可能涉及3个子仓库、修改5个协议字段、增加8个服务方法、补充12个单元测试、添加2个接口测试等一系列复杂流程

1.2 Harness 在 TAB 上要解决的真实痛点

团队共同梳理后发现,在TAB上运行PRD的真实痛点并非“AI写得不够准”,而是以下四个核心问题:

真实卡点具体表现
PRD 不可信产品一句话:“加个白名单删除”。但删除后是否触发下游回收?灰度如何处理?接口是否幂等?无人知晓
方案与代码脱节方案写得漂亮,但具体修改哪些服务、增加几个协议字段、如何与现有数据访问层对齐——难以判断
改完无人验证“我改完了”和“我跑过沙箱接口测试且新增覆盖率 ≥85%”是两回事。前者是AI的口头汇报,后者是机器可验证的事实
交付环节碎片化写完代码后,需要去TAPD更改单子状态、去iWiki沉淀方案、去工蜂提交MR、在评论区贴度量——所有操作都正确,但完全依赖人工记忆

请注意,这四点没有一个是模型本身的问题。它们都是协作问题、流程问题、信任问题

换句话说,我们要搭建的Harness,主要不是为AI服务的,而是为团队服务的。它的目标不是让AI看起来更聪明,而是让AI在TAB这个工程中稳定、规范、可被审计地完成正确的事情

1.3 SPEC-First:从一份完整的设计文档开始

Harness落地的第一步不是编写Rule,也不是拆分Agent,而是先与团队一起打磨出一份完整的全链路产研流程技术设计文档。这份文档的核心作用是:

  • 将目标拆解为四个子目标:PRD质量、需求分析、自动实现、集成验证
  • 明确划分“AI能完成什么”和“必须由人工介入什么”
  • 确定“完成哪些工作算作Harness一期”,并达成共识

没有这份SPEC,Harness要么无法搭建,要么会被搭建歪。因为Harness不是一组工具,而是一种工程纪律。纪律的前提是必须有共识。

第二章:Harness 在 TAB 上由哪几块东西组成

这套Harness由六个层次的资产组成:Rule(规则)、Skill(标准操作手册)、Sub Agent(专职角色)、Workflow(流程定义)、Scripts(门禁脚本)、MCP(外部系统接口)。这些概念在不同工程中会呈现不同形态,下面将介绍它们在TAB大仓中的具体实现。

2.1 Rule:我们最终写得很少

这可能与直觉相悖。Rule是写给AI看的自然语言约束,看起来最容易编写,也最容易想到。但Rule有一个天然缺陷:自然语言天然可以被解释性执行——AI可能会说“这条规则在当前场景下不适用”、“我做了等价操作”、“这是历史遗留问题”,每一句都可能是真的,但你无法每次都去翻git log验证。

因此,我们的经验是:在业务大仓中,Rule几乎全部被下沉为Skill或脚本,独立的Rule反而最少

为什么?因为Harness中几乎所有约束都有明确的判定标准

  • “数据访问层必须用GORM,不许直接拼SQL” → 写成lint规则即可
  • “错误必须用统一错误码包,不许用标准库error” → 一个lint检查器就能搞定
  • “服务层覆盖率 ≥70%、数据访问层 ≥50%” → 通过脚本进行强制规定
  • “任何写操作必须走事务切面” → CR阶段进行静态扫描

能判定的就不要留在Rule里。这是我们与其他工程的一个明显区别,我们会更早地将所有规则脚本化。

2.2 Skill:注意力管理而非能力增强

目前我们只保留了11个Skill,按职责分为四组:

脚手架与代码层规范(4个)

  • 协议与领域模型脚手架
  • 数据访问层规范手册(GORM规约 + 数据库mock单测约束)
  • 业务服务层规范手册(面向对象写法 + 切面对齐)
  • HTTP处理层规范手册

测试规范(2个)

  • 单元测试规范(mock框架 + 函数打桩约定等)
  • 接口测试生成(沙箱真实HTTP等)

需求理解阶段(3个)

  • PRD完整性自评工具(5维度评分 0~100)
  • 影响半径分析工具(涉及多少个子仓库、多少个接口等)
  • PRD模板

代码审查阶段(2个)

  • 范围溢出检查(对比是否超出技术方案的计划)
  • 前端增量与视觉审查

每个Skill解决的核心问题相同:将“这件事具体怎么做”从主prompt中剥离出去,让主Agent的注意力只集中在当前的认知任务上

举个例子。数据访问层有一套非常严格的规矩:必须使用GORM、必须用数据库mock写单测、增量覆盖率必须 ≥80%、错误必须用统一错误码包、包内类型必须按统一前缀命名等。如果将这些规矩全部塞进开发Agent的主prompt中,会导致两个问题:

  1. 主prompt越来越长,开发Agent真正需要关注的需求上下文被淹没
  2. 修改一条规矩,每个Agent都需要同步更新

因此,我们将其独立成一份“数据访问层规范手册”,开发Agent在处理数据访问任务时按需加载。这就是Skill的本质——AI在某一类任务上的标准操作手册。在后端开发中,它的价值更直接:Skill不是AI的能力增强,而是AI的注意力管理

2.3 Sub Agent:我们最终只保留了4个

Sub Agent这一层的本质是为认知工作划分职责——将一条长链路按照“谁该关心什么”拆分成几个独立的角色,每个角色只关注自己该看的输入,只输出自己该产出的内容。

最终我们只保留了4个:需求Agent、方案Agent、开发Agent、代码审查Agent,外加1个总控Agent在最外层进行调度。先来看一下当前的角色职责划分:

角色职责必读内容必写内容禁止行为
需求Agent将TAPD链接转化为结构化的需求理解 + 影响半径分析TAPD单 / PRD文本需求理解文档 / 代码影响地图不得编写技术方案
方案Agent将需求转化为可执行的技术方案需求理解文档 / 代码影响地图设计文档、技术规约、任务清单不得修改需求理解文档
开发Agent按设计文档编写代码 + 接口测试产物需求理解、设计、技术规约、任务实际代码 + 接口用例文档 + 增量Go接口测试 + 单元测试不得超出设计文档计划范围
代码审查Agent从4个维度进行最终收口审查上游全部产物 + git diff代码审查结论文档不得修改代码,只能输出阻塞项

为什么只有4个Agent?因为还有一类角色——流程调度、运行门禁、执行测试、提交MR——它们看起来也像“角色”,但实际上是纯确定性工作。我们将这一类全部下沉为 总控Agent + 脚本 的组合:

  • 流程调度(决定下一阶段是什么)→ 总控Agent中以伪代码形式存在的状态机
  • 门禁入口 → 统一门禁脚本
  • 测试执行 → 沙箱部署、接口测试、前端冒烟,三个独立的门禁脚本
  • 分支与交付 → 分支准备脚本 + 交付收尾脚本

它们的工作完全是确定性的:决定下一阶段、运行门禁、执行测试、提交MR。这些工作没有任何认知成分,让AI来解释执行只会增加token消耗和不确定性

能写成bash脚本的,就不要让Agent来执行——这是我们只保留4个Agent背后的真正判断标准。

2.4 Workflow:13个阶段的接力赛

Workflow不是流程图,更像是一份接力赛规则:每一棒交接什么内容、下一棒接到什么才能开始跑、跑砸了回到哪一棒重来。Agent之间是接力关系,而非协商关系——这个比喻在后续所有讨论中都非常有用。

接力赛的13棒如下:

初始化 → 需求分析 → 需求确认 → [Bug 复现] → 技术方案 → [方案确认]
→ 方案评审 → 分支准备 → 开发 → 集成测试 → 代码审查 → 验收 → 交付收尾

方括号内的是条件触发——bugfix类需求才走Bug复现;涉及修改协议或跨多个服务时才触发方案确认。

每一棒都明确写在流程定义文档中:

  • 当前阶段是哪一棒(checkpoint文件中的阶段字段)
  • 这一棒需要交付什么(产物清单)
  • 下一棒接手前必须看到什么(必读文件)
  • 什么情况下会被打回(打回规则表)
  • 打回后回到哪一棒(集成测试失败回开发、方案评审失败可以回方案Agent或需求Agent)

这套规则不是写在长篇描述中,而是单独抽离成可校验的资产——一份高层流程定义文档、一份伪代码状态机文档、再加一个自检脚本检查完整性。流程一旦从“长文中的描述”变成“机器能校验的资产”,稳定性就会大幅提升。

第三章会详细解释为什么是13棒,以及为什么不能再少。

2.5 Scripts:最硬的那道防线

这个概念指的是我们流水线上的7道门禁脚本。第六章会单独展开说明。这里只强调一点:Scripts的价值不是多了一组工具,而是将“完成”这个词的定义权从AI手中夺了回来

2.6 MCP:通往交付闭环的接口层

MCP(Model Context Protocol)这一层做的事情非常具体:让AI能在受控、结构化、可审计的边界内调用外部系统——TAPD、iWiki、工蜂、企微、Knot。

目前我们接入了5个MCP:

  • TAPD MCP:读取/修改TAPD单、添加评论、关联git分支、状态扭转等
  • iWiki MCP:编写方案、批量上传制品等
  • 工蜂 MCP:MR创建、CR评论拉取
  • Knot MCP:拉取前端设计规范以及代码规范
  • 企微 MCP:交付完成后发送通知

这一层补足的是从开发闭环到交付闭环的最后一段路——单纯写完代码并不算交付,还需要推进需求单状态、归档方案、提交MR、在群里通知,每一步都必须完成。第九章会详细展开在这条路上踩过的坑。

第三章:为什么13个阶段一个都不能合并

在TAB这种跨多个子仓库模块的环境中,每个阶段的存在都对应着一段历史教训。本章将详细阐述这些教训。

3.1 直觉上你会觉得“能不能合并”

一开始我们也想合并:初始化和需求分析合并?开发和集成测试合并?听起来合理,一个Agent顺手就把测试也写了嘛。

但每次“合并”都被现实打了回来。每一个阶段的存在都对应着一类痛点

阶段它存在的原因不分开会怎样
初始化解析TAPD链接、派生需求ID、修改TAPD状态、打Harness标签——一组只在最开头运行一次的副作用操作与需求分析混合,需求分析被打回时TAPD状态会被反复修改
需求分析将模糊需求转化为结构化的需求理解文档,并运行PRD完整性自评 + 影响半径分析直接进入技术方案,方案设计被迫脑补需求边界
Bug 复现bugfix类需求必须先在沙箱中复现,再进行修改直接修改代码,最后发现根本复现不了,前面所有工作白做
分支准备在开发之前,在每个涉及的子仓库中创建特性分支在开发过程中临时切分支,可能导致分支名跑偏,MR目标分支错乱
集成测试在代码审查之前,用真实HTTP将接口用例跑一遍留到验收阶段才发现接口对不上,代码审查已经评过,全部白评
验收代码审查之后,幂等重跑接口测试 + 运行diff基线对比没有“基线对比”,AI会用“这是历史问题”来搪塞
交付收尾提交、推送、提MR、度量、推iWiki、回写TAPD评论散落在开发末尾,必然会遗漏某项

合并阶段省下来的是流程图的复杂度,但代价是状态机中会多出一堆隐式分支。最终我们接受了“流程图复杂一点”的代价。

3.2 一个值得展开讲的故事:集成测试是如何从“后置”挪到“前置”的

这是我们走过的最值得分享的一段弯路。

最初的设计中没有集成测试这一步。接口测试放在验收阶段,与“日志验收”并列。逻辑看起来很顺畅:代码审查评完代码 → 验收阶段跑测试 → 通过 → 交付收尾。

但在运行了几个真实需求之后,我们发现了一个令人沮丧的循环:

开发完成 → 代码审查Agent仔细审查了整个diff的200行 → 代码审查通过

验收阶段运行接口测试 → 失败(路径写错 / 参数对不上 / 错误信息没对齐)

打回开发 → 修改 → 重新过代码审查 → ...

代码审查是整个链路中最昂贵的环节,每次运行都需要审查Agent重新审视整个diff。但接口测试问题实际上是一个几秒钟就能验证的事情——我们却让它躺在代码审查之后,让最昂贵的环节承担最便宜的失误。

决策:将接口测试前置到代码审查之前,作为强制硬门禁。不通过则不准进入代码审查

开发Agent编写业务代码 + 单测
→ 同时产出接口用例文档 + 增量Go接口测试代码
→ 集成测试阶段拉取沙箱 + 真实HTTP运行一遍
→ 通过后才进入代码审查

这一改动之后,代码审查阶段的平均打回次数从1.8次降到了0.4次。

但这次调整真正值得说的不是“少打回了”,而是它顺便改变了“开发完成”的定义:以前“开发完成 = 业务代码 + 单测”,现在“开发完成 = 业务代码 + 单测 + 接口用例文档 + 增量接口测试代码”。

让产生问题的人,同时产生验证手段——这才是真正交付完整的开发阶段该有的样子。

3.3 一个反过来的故事:Bug 复现怎么从“必走”变成“可选”

接下来说一个相反方向的取舍。Bug复现这个阶段最初是所有bugfix必须经过的——不复现不允许修改。

运行了几次后发现一个问题:很多bug是产品同事报告的,TAPD单中已经写得很清楚(请求、期望、实际),不需要复现。强制复现等于在沙箱中多花几分钟跑一遍已经知道答案的事情。

因此,我们将Bug复现改为条件触发:仅当需求类型是bugfix 用户明确要求复现时才执行。默认跳过,直接进入技术方案。

这件事的小教训:流程要为“已经明确的事情”留一条快车道。强制所有需求走最严格的路径,会惩罚那些准备已经充分的需求。

3.4 阶段切分的判断标准

最后总结出的“是否应该独立成阶段”的判断标准只有两条:

  1. 它是否有独立的失败模式?(集成测试失败 ≠ 代码审查失败 ≠ 开发失败)
  2. 它失败时回退的位置是否不一样?(集成测试失败回开发、代码审查失败可能回到方案)

两个都是“是” → 必须独立。否则就合并。13个阶段每一个都经过了这两道筛子的检验。

第四章:四个Agent是被问题一步步逼出来的

我们的4个Agent不是设计出来的,而是被一次次撞墙逼出来的。本章将完整复盘这条演进路径。

4.1 第一阶段:单Agent跑全流程

最初我们尝试过“一个Agent干到底”——它读取TAPD、写方案、写代码、写单测、自己审查、自己跑测试。

运行了几个需求后,就出现了一组典型问题:

  • 上下文混杂:它分不清“TAPD里写的”和“它自己推断的”
  • 天然缺乏制衡:它写的方案它自己审查,几乎不会否决
  • 倾向往前推进:它会主动找理由说“问题不大,继续吧”
  • token爆炸:从PRD到MR一路,单次上下文1M都不够用

最致命的是第三点。这个Agent不会主动停下来。它会反复说服自己继续。

4.2 第二阶段:拆出需求Agent和方案Agent

第一刀拆的是需求理解和方案设计。这一刀拆完之后立刻见效:

  • 方案Agent在查看需求Agent写的需求理解文档时,会指出哪些边界没有说清楚
  • 很多原本会被“自我推断”埋进代码里的假设,被方案Agent主动暴露出来

但问题没有完全解决。方案Agent经常会觉得需求Agent写得不严谨,顺手把验收标准改了。这件事看上去是在“提高效率”,实际造成的混乱是:代码审查阶段审查代码时,不知道哪句验收标准是产品要求的、哪句是方案Agent自己加的。

于是我们制定了Harness中最重的一条纪律下游Agent不可直接修改上游产物。需要修改时只能提出阻塞项,由总控Agent打回上一棒。

这条纪律比任何prompt调优都关键。它解决的不是技术问题,而是责任边界问题

4.3 第三阶段:拆出代码审查Agent

第二刀拆的是代码审查。收口角色必须有人盯着——不能让写代码的Agent顺手把自己写的代码也审了。这一点几乎是所有多Agent设计绕不开的硬规矩。

但一开始我们设计的代码审查太“普通”——就是一个普通的code review,看看有没有逻辑bug、有没有违反规范。

运行了一段时间后,发现这样不够。代码审查应该承担的是整条链条的最终收口

审查维度审查内容
方案一致性实现是否真的按照设计文档执行?有没有偷偷添加范围之外的东西?
验收标准覆盖需求理解中每条验收标准,是否都有对应的代码 + 测试?
质量基线接口测试是否完整?覆盖率是否达标?错误处理是否符合TAB错误码规约?
前端增量(条件触发)涉及前端时,按照前端审查Skill的问题模板输出阻塞项

注意“方案一致性”这一维度——它专门用来防范一类很顽固的现象:AI解释性执行。AI在实现过程中经常会觉得“设计这里写得不好,我顺手改一下”,从它的角度看是“优化”,但从工程的角度看是“擅自改设计”。代码审查Agent就是专门来抓这个的。

4.4 第四阶段:开发Agent不再只写代码

最后一刀其实不是“拆”,而是“扩”。

最初开发Agent只编写业务代码 + 单测。集成测试前置之后,开发Agent的职责被扩展为“业务代码 + 单测 + 接口用例文档 + 增量接口测试代码”。

这件事看似只是产物清单变长,实际改变的是设计哲学:每个角色对自己产物的“可验证性”负责——你写了代码,你也要按照方案提供验证它的手段。否则验证会被推到下游,而下游的成本永远比上游高。

4.5 为什么不再继续拆

在系统稳定运行后,我们也考虑过是否要继续拆分——比如把开发Agent拆成“数据访问层、服务层、处理层”三个Agent,按层并行执行。

最终没有拆。原因有两个:

  1. TAB的四层架构存在强依赖关系(数据访问 → 服务 → 处理层)。并行的时间收益不大,但协调成本极高
  2. Skill已经解决了“分层规范”的问题——开发Agent在处理数据访问任务时加载“数据访问层规范手册”,处理服务层任务时加载“服务层规范手册”。Skill本质上就是“虚拟的子Agent”

能用Skill解决的问题,就不要再开一个Agent。Agent是带状态、带轮次、带token成本的;Skill是无状态的文档加载。

第五章:人工关卡——半自动模式才是当前的最优解

本章要讲一件特别容易被低估的事情:Harness不是越自动越好,关键节点必须留有人工参与。这不是技术保守,而是基于对模型行为实测得出的判断。

5.1 我们为什么坚持半自动

理论上,我们可以让一个Reviewer Agent去判断“这个方案能不能进入开发阶段”。我们尝试过,结论是:不行

原因不是模型不够强,而是模型对自己生成的东西天然没有“否决的欲望”。它倾向于推进,不倾向于停下。一个上游Agent写的方案,下游Agent在99%的情况下会觉得“看上去挺好”。这个偏差是模型层面的,不是prompt层面能控制的。

所以最终确定:关键节点必须有人工参与。不是不信任AI,而是承认AI现阶段不擅长“否决自己人”。

5.2 人工关卡是怎么设计的

我们一共保留了5个人工关卡:

关卡做什么用户实际花费时间触发频率
需求确认查看5行需求摘要,点击“确认继续”或“我要修改”10~30秒每个需求1次
方案确认仅在跨子仓库 / 修改协议时弹出,查看层级变更清单30~60秒约40%需求
方案评审打回极少触发,触发说明真的有问题1~2分钟<10%
前端冒烟选择仅纯前端 / 涉及前端时弹出,三选一:运行 / 复用 / 跳过5秒涉及前端时
熔断暂停任意阶段连续打回 ≥3次时触发越短越好异常情况

关键原则:不能让用户每分钟点击一次以上——这是后来设定的硬性约束。半自动不仅要求“流程对”,更要求“体感对”。体感不对,团队会主动绕过工具,退回Vibe Coding状态,这与我们的目标背道而驰。

5.3 一个真实痛点:弹窗审批密度

讲一个具体的撞墙故事。

将4个Agent拆出来之后,新问题立刻出现:用户每次点击“确认继续”,子Agent每次写产物文件时都会弹出一个“Are you sure you want to write to ...”。一次需求分析要写3~5份,开发阶段要写几十次。

体感上从“半自动”瞬间退化成“全人工 + AI假装在帮忙”。

经过一番排查,找到了根因:调起子Agent时没有显式声明权限模式,IDE默认采用最严格的写文件审批模式,每次写文件都需要点击确认。

修复只改了一行代码:将权限模式显式声明为“自动接受文件编辑”。

但这件事后来专门留下了一条经验:任何让用户每分钟点击一次以上的交互,都属于设计缺陷,都值得被优化。

5.4 人工关卡的三级兜底

每个人工关卡都同时设计了三级解析兜底

  1. UI按钮(主通道):弹窗 + 按钮,用户点击按钮
  2. 纯文本关键词(兼容通道):“确认继续”、“重做”、“A”/“B”/“C”等
  3. 语义识别(降级通道):包含“改”、“调整”、“重做”/“不对”→ 自动路由到“修改请求”分支

为什么要设计三级?因为我们遇到过IDE版本回退、MCP客户端切换等场景下按钮渲染异常的情况。三级兜底确保无论在哪个客户端,用户都能用最自然的方式表达意图。

这条经验的本质是:人工关卡不是“等待人输入”,而是“以最低摩擦的方式听懂人想干什么”。

第六章:7道门禁脚本——把“完成”的定义权拿回来

这一章是整套Harness中最有共鸣的部分。前面所有章节都在解决“怎样让AI去做事”,本章解决的是另一个问题:做完之后,到底算不算做对了

6.1 为什么脚本最终一定会变得越来越重要

随着实践深入,体会越来越深:Rule越多,AI的解释空间就越大。同一条规则放在不同需求中,AI总能找到看似合理的理由来绕过它:

  • “这个测试不通过不是我引入的,是历史遗留问题”
  • “这条规则这次场景特殊,可以先不管”
  • “我做了等价验证,不需要完全照规则来”

这些话每一句都可能是真的。但你不可能每次都去翻git log来验证

所以最终所有“能判定”的约束都会下沉成脚本。脚本最大的价值不是“多了一组工具”,而是它把“完成”这个词的定义权从AI的口头汇报中拿了回来—— “做完”不再是“AI觉得做完了”,而是“统一入口的脚本判定通过了”。脚本一共7道:

阶段门禁类型做什么
开发完成时覆盖率检查软门禁全量 ≥40% 增量 ≥85%(按本次diff计算)
开发完成时制品一致性检查软门禁任务清单上的勾选项是否全部勾选
开发完成时静态检查 + 安全扫描硬门禁golangci-lint 12个检查器 + 硬编码密码 + SQL拼接 + 哈希校验
集成测试沙箱部署硬门禁make sandbox-platform-full-ensure + 网关健康检查
集成测试接口测试硬门禁真实HTTP运行接口用例文档
集成测试前端冒烟软门禁(条件触发)Playwright运行路由级渲染 + DOM断言 + 截图
验收日志验收软门禁(可选)关键操作日志存在 + 敏感信息脱敏

6.2 软硬门禁的取舍

看起来有7道门禁,但硬门禁只有3道。这是有意为之的。

  • 硬门禁 = 失败立即中止流程
  • 软门禁 = 失败留下WARN痕迹但继续推进

判断标准是:硬门禁宁少不多。如果一个东西不是质量红线,就不要让它阻断流程。流程被频繁打断会让团队怀疑工程化的价值,进而退回到Vibe Coding。

前端冒烟就是一个典型例子。它对前端类需求很有价值(路由级渲染 + 控制台错误阈值 + 截图归档),但不是质量红线。如果设为硬门禁,会让“我紧急发个hotfix但前端冒烟挂了”变成阻塞事件。所以它是软门禁,且用户可以主动跳过,但跳过会在代码审查结论中留下警告痕迹,提醒使用者关注。

6.3 一个反作弊设计:基线对比

这是我最喜欢的一处设计。

AI运行完门禁后会汇报“通过/失败”。但AI对失败有非常顽强的解释能力:

  • “这个不是我引入的问题”
  • “这个警告之前就有”

因此,我们在开发启动前会先运行一次门禁脚本的“基线快照”模式——将当前状态的所有门禁输出冻结成一份基线状态文件。开发完成后,再运行一次“差异”模式:

开发前的失败集合 = A
开发后的失败集合 = B
新增的失败 = B - A

只有“新增的失败”会阻断流程。“历史问题”这把万能钥匙就这样被拿掉了。

这个机制听起来简单,但经过了好几轮迭代才意识到必须做。它的价值不在于技术本身,在于剥夺AI的解释权

6.4 软门禁失败也要留下“伤疤”

软门禁的定义是“失败不阻断”。但“不阻断”不等于“什么都不做”。

所有软门禁失败都会:

  1. 在门禁状态文件中写入一条警告记录
  2. 在代码审查结论文档中被审查Agent显式提到
  3. 在最终的度量报告“软门禁告警”段沉淀

这是一种让“绕过”在视觉上变得不舒服的设计。AI想绕没人拦,但绕了之后所有产物中都有显眼的黄色标记,代码审查必然会读到,交付收尾的度量报告上也会留下痕迹。

你不能阻止AI偷懒,但你可以让偷懒变得很醒目。

第七章:撞墙补稳——Team Mode卡死那次复盘

下面这个故事是Harness演进中最关键的一次“撞墙”,值得单独展开讲。它的价值不仅在于修复了一个bug,更在于让我们彻底理解了一种很容易踩进去的陷阱 ——“复杂度自给自足”。

7.1 症状

人工关卡(需求确认)必然卡死。用户输入“确认继续”四个字之后,主Agent完全没有反应。

体验上就是:你看着屏幕,主Agent安静地待在那里,没有任何响应。你重复输入也没有用。重启IDE就好了。

7.2 我们一开始的诊断方向全是错的

这个bug前后修复了三轮,每轮都以为已经修好了:

  • 第一轮:怀疑是标记文件残留 → 添加一个清理脚本清标记 → 没用
  • 第二轮:怀疑是60秒虚假超时 → 撤销超时改为长等待 → 没用
  • 第三轮:怀疑是按钮值没匹配 → 改成纯文本输入 → 还是没用

每一轮都局部止血了某些症状,但根因没有动。

7.3 真相

直到打开IDE的Team状态目录查看消息收件箱,发现了一个让人脊背发凉的画面:Team还活着;Team里的主控Agent的本轮对话已经结束;但用户输入的“确认继续”四个字安安静静地躺在收件箱里,没有任何Agent在消费

根因:我们使用的“启动子Agent并等待”机制让主Agent的本轮对话跨越了整个子Agent执行时间。主Agent抛出确认提示后本轮对话自然结束,但IDE的Team Mode将后续用户输入路由到主控Agent的收件箱——可主控Agent已经下班了

消息有目的地,但目的地下班了。

7.4 真正的解法不是修这个bug,是删掉这个机制

盯着架构图看了很久,意识到一件事:Harness的4个spawn点全部是“串行单个”模式,从来没用过Team Mode的任何独有能力——并行spawn Agent、互发消息、长驻留、跨turn共享。Team Mode带来的复杂度,只是为了解决它自己引入的问题

这就是经典的“复杂度自给自足”陷阱。当一个机制的存在主要是为了fix它自己引入的副作用时,它有80%的概率应该被删掉

最终决策:彻底删除Team Mode,改用IDE原生支持的项目级自定义子Agent + 同步阻塞调用

维度旧架构(Team Mode)新架构(项目级子Agent)
调起协议三步法:清理标记 + 启动子Agent + 等待子Agent单步:直接同步调用
子Agent返回方式三通道:标记文件 + 消息发送 + 关闭请求单通道:返回结构化结果
Team生命周期每个需求初始化时创建、交付时销毁、关卡前清理无Team概念
人工关卡必然卡死 ❌天然生效 ✅
辅助脚本3个(等待、清理、确认前清理)0个(全部删除)

删完之后,人工关卡卡死问题彻底消失,主Agent的代码反而少了将近200多行

7.5 这次撞墙留下的方法论

这件事留下了三条特别值得分享的经验:

第一,永远警惕“自给自足的复杂度”。一个机制如果主要是在解决它自己带来的副作用,删掉它是更好的选择。

第二,先grep自己的代码再修bug。如果更早地确认“我们一次都没用过Team Mode的并行能力”,就不会在它的内部时序问题上浪费三轮迭代。

第三,YAGNI(You Aren't Gonna Need It)原则在Harness设计中特别重要。保留可选路径意味着维护两套协议,不如先删掉,未来真需要时再加回来——那时候加,会比现在保留干净得多。

7.6 顺手讲一下“人工关卡反复弹审批”这个相关坑

去掉Team Mode之后,相关的另一个坑是用户每次“确认继续”,子Agent写产物时都要弹“Are you sure?”,一次需求分析要弹5次。

修复就一行:在调起子Agent时显式声明权限模式为“自动接受文件编辑”(在第五章已经讲过)。

但这件事和Team Mode撞墙的故事其实是同一类问题:Harness架构中只要有一处“人体感知能感受到的卡顿”,就会被团队当成失败信号,整个Harness的可信度就会崩溃。所以在做撞墙复盘时,不能只看技术正确性,还要看体感正确性。

第八章:让AI带上“整个项目的记性”

Harness运行稳定之后,下一个绕不开的问题是:AI缺乏对整个项目的全局视野。在TAB这种跨多个submodule的大仓中,这一层是必修课,不是可选项。

8.1 问题:AI重复造轮子

运行了一段时间后,发现了一个尴尬现象:

  • 同一个工具方法,在公共工具包中已经存在,开发Agent在新需求中又写了一遍
  • 同一个错误码,在统一错误码包中已经定义,开发Agent又起了一个新的
  • 同一个数据访问方法,在某个数据访问子仓库中已经存在,开发Agent又造了一个新的

这不是模型不够强,而是它没有“项目记性”。它每次只看当前任务的上下文,不知道仓库中已经长成什么样。

8.2 我们的两层项目级索引

最终我们落了两层:

第一层:仓库代码导航地图:所有子仓库的开发地图

这是一份约26KB的导航文档,由开发Agent自己维护(谁动谁更新)。它写的不是文件列表,而是“这座工程长什么样”:

某个功能一般落在哪些子仓库
某类服务怎么注册(trpc-go风格 vs chi风格)
某类配置通常在哪定义
改某个子仓库可能会牵动哪些下游链路
项目里已有的标准写法长什么样

核心一条:先搞清楚这里已经长成了什么样,再下手。

需求Agent启动时会先读这份地图的“全景索引”段,决定本次需求大概会落在哪几个子仓库,然后才进入需求理解。这一步避免了80%的“在错的子仓库里改”的情况。

第二层:任务看板:跨需求的任务总览

这是一份跨需求的任务总览,由总控Agent维护的Checkpoint文件:

来源:https://www.53ai.com/news/LargeLanguageModel/2026070706291.html

相关热点

继续查看同栏目近期热点。

延伸阅读

补充最近整理过的热点入口。