拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

多Agent协作开发AI编程:架构师与代码审查Agent为何被砍掉

多Agent协作开发AI编程:架构师与代码审查Agent为何被砍掉

1. 从"给AI配团队"到"全砍掉":一个反直觉的工程决策

去年下半年,我花了大概六周时间,给手里的 AI 辅助开发流程搭了一套"虚拟团队"——一个负责架构设计的 Agent,一个负责代码审查的 Agent,再加上一个测试驱动的调度层。听起来很美好对吧?架构师 Agent 先出方案,开发 Agent 写代码,审查 Agent 挑毛病,测试 Agent 跑用例,一条流水线下来,人只需要在最后点个头。

结果呢?六周之后我把架构师和代码审查这两个角色全砍了,只留下一个精简过的测试驱动环节。不是它们不能用,而是它们带来的收益远远覆盖不了引入的复杂度、延迟和上下文损耗。

这篇文章就是把这六周踩过的坑完整拆开讲。如果你正在做 AI Agent 开发、AI 编程辅助工具链,或者单纯想搞清楚"多 Agent 协作到底值不值得",这篇应该能帮你省下不少试错时间。核心关键词就几个:AI 编程、Agent 开发、架构师角色、代码审查、测试驱动。我会从最初的动机讲起,到具体怎么配的、踩了什么坑、为什么最后砍掉、砍掉之后换成了什么方案,全程给数据和判断依据。

先说结论,免得你看到一半觉得我在劝退:多 Agent 协作不是不能用,而是大多数团队在错误的粒度上用了它。架构设计和代码审查这两个环节,恰恰是最不适合拆成独立 Agent 的,原因后面会详细展开。

2. 当初为什么要给开发 AI 配"架构师"和"审查员"

2.1 单 Agent 写代码暴露出的三个真实痛点

最开始我用的是最朴素的模式:一个对话窗口,把需求描述清楚,让 AI 直接写代码。小功能没问题,但项目一旦超过几千行,问题就集中爆发了。

第一个痛点是全局一致性崩坏。AI 在写第三个模块的时候,已经"忘记"了第一个模块里定义的接口约定。比如我在项目初期定了一个Result<T>的统一返回结构,写到后面它开始返回裸对象,再往后又变成抛异常。每次都要人工去纠正,纠正完下一个文件又犯。

第二个痛点是局部最优陷阱。你让 AI 实现一个功能,它会用最直接的方式写出来,但这个方式可能和整体架构冲突。举个具体例子:我让它写一个数据同步模块,它直接在业务逻辑里调了数据库写入。功能是对的,但我的架构里所有写操作都应该走一个统一的事件队列。它不知道这个约束,因为约束散落在我的脑子里和之前的对话里。

第三个痛点是审查缺失导致的低级错误累积。AI 写代码很快,但边界条件、空值处理、并发安全这些地方经常出问题。一个人肉审查所有产出根本不现实,量太大了。

2.2 "虚拟团队"方案的诱惑力在哪里

面对这三个痛点,"给 AI 配一个架构师和一个审查员"的想法就显得特别自然。逻辑链条是这样的:人类团队里,架构师负责全局一致性,审查员负责质量把关,那我把这两个角色也 Agent 化,不就能自动化解决了吗?

具体设计是这样的:

  • 架构师 Agent:输入是完整需求文档和现有代码库摘要,输出是模块划分、接口定义、数据流图、技术选型建议。它的产出会作为"架构约束"注入到后续所有开发 Agent 的上下文里。
  • 开发 Agent:接收架构约束和具体任务,产出代码。
  • 审查 Agent:接收开发 Agent 的代码 diff 和架构约束,逐条检查是否符合规范、是否有潜在 bug,输出审查意见。
  • 调度层:负责在几个 Agent 之间传递上下文,处理审查不通过时的回退重写。

这套东西搭起来的时候我挺兴奋的,感觉像是给 AI 编程装上了"工程纪律"。前两周的 demo 也确实跑通了,一个中等复杂度的 CRUD 模块,从需求到可运行代码,全自动完成,审查 Agent 还真的挑出了两个空指针问题。

但问题从第三周开始集中出现。

2.3 一个被忽略的成本:上下文在 Agent 之间"蒸发"

这是最隐蔽也最致命的坑。当你把任务拆给多个 Agent,每个 Agent 都需要足够的上下文才能做出正确判断。但上下文窗口是有限的,而且上下文在传递过程中会失真。

架构师 Agent 输出的架构文档,传给开发 Agent 时,为了塞进窗口,必须做摘要。摘要就会丢信息。开发 Agent 写出来的代码,传给审查 Agent 时,又要附带架构约束,又要附带代码 diff,窗口更紧张。审查 Agent 给出的意见,回传给开发 Agent 时,又是一次压缩。

我实测过一个数据:一个原本 8000 token 的架构设计文档,经过三轮传递后,开发 Agent 实际"看到"的有效约束信息大概只剩 40%。剩下 60% 要么被摘要掉了,要么被淹没在无关上下文里。

这就导致一个荒诞的现象:审查 Agent 经常挑出"违反架构约束"的问题,但那个约束在开发 Agent 的上下文里压根就没出现过。不是开发 Agent 不遵守,是它根本不知道。

3. 架构师 Agent 最先暴露的问题:它设计的架构,开发 Agent 根本执行不了

3.1 抽象层级错位:架构师想的是"应该怎样",开发 Agent 要的是"具体怎么写"

架构师 Agent 有个天然倾向:它喜欢输出"正确但空洞"的架构。比如它会告诉你"采用分层架构,领域层不依赖基础设施层,通过依赖倒置实现解耦"。这话没错,但开发 Agent 拿到这句话,它需要的是:具体哪个接口定义在哪,依赖注入怎么配,目录结构长什么样。

我试过让架构师 Agent 输出更具体的方案,结果它开始写伪代码,伪代码又和实际语言特性对不上。比如它用 Java 的风格描述了一个泛型约束,但我的项目是 TypeScript,类型系统完全不是一回事。

这个问题的本质是:架构设计是一个需要和实现细节反复交互的过程,而独立 Agent 做的是单向输出。人类架构师之所以能设计出可执行的架构,是因为他脑子里同时装着"理想结构"和"当前代码库的现实约束",并且会在设计时不断权衡。独立 Agent 没有这个交互回路。

3.2 架构文档的"保鲜期"极短

更麻烦的是,架构不是一次性的。开发过程中需求会变,技术约束会变,架构也得跟着调。但我的架构师 Agent 是在项目开始时跑一次,产出一份文档,然后就固定了。

到第二周,开发 Agent 遇到一个架构文档里没覆盖的场景,它自己做了个决定。这个决定和原架构有轻微冲突,但能跑。到第三周,类似的"自主决定"累积了七八个,整个架构已经和最初那份文档对不上了。这时候审查 Agent 拿着旧文档去审查,满屏都是"违规",但实际上很多是合理的演进。

我后来加了一个"架构更新"的环节,让架构师 Agent 定期重新审视代码库并更新架构文档。但这又引入了新问题:每次更新都会产生大量 diff,开发 Agent 和审查 Agent 都要重新消化,上下文成本直接翻倍。

3.3 实测数据:架构师 Agent 带来的净收益是负的

我做过一个粗略的对比。同一个需求(一个带权限控制的数据导出模块),两种模式各跑五次:

指标无架构师 Agent有架构师 Agent
首次可运行率60%80%
平均返工次数2.4 次1.8 次
端到端耗时约 25 分钟约 52 分钟
人工介入次数3.2 次2.1 次
最终代码与架构一致性中等较高

看起来有架构师 Agent 质量更好对吧?但注意耗时翻了一倍多。而且人工介入次数只减少了 1.1 次,省下的这点人力,完全被翻倍的等待时间吃掉了。更关键的是,那 80% 的首次可运行率,在无架构师模式下通过一次简单的"重新生成"就能达到类似效果,成本低得多。

这里有个反直觉的点:架构一致性提升带来的收益,在中小型项目里被延迟成本完全抵消了。只有当项目大到人工审查架构不现实时,这个收益才可能转正。但真到那个规模,独立 Agent 的上下文限制又成了硬瓶颈。

4. 代码审查 Agent 的困境:它审得越细,开发越慢

4.1 审查意见的"正确但无用"问题

代码审查 Agent 最典型的行为是:它能挑出一堆问题,但这些问题里真正值得改的不到三成。

我统计过一轮审查 Agent 的输出,200 条意见里:

  • 约 90 条是风格问题(命名、注释、格式),这些用 linter 就能解决,不需要 AI
  • 约 60 条是"潜在风险"(比如"这里可能为空"),但其中大部分在当前调用路径下不可能为空
  • 约 30 条是真正的逻辑问题或边界条件遗漏
  • 剩下 20 条是误报,纯粹是 Agent 理解错了上下文

问题在于,开发 Agent 没法区分这四类。它拿到审查意见,会老老实实全部处理。结果就是:为了修 30 个真问题,它顺带改了 90 个风格问题和 60 个伪风险,代码 diff 变得巨大,引入新 bug 的概率反而上升了。

4.2 审查-重写循环的收敛问题

更头疼的是收敛性。理想情况下,审查发现问题,开发修复,再审查,应该逐步收敛。但实际跑下来,经常出现"修一个引入两个"的情况。

我记录过一个极端案例:一个 300 行的模块,审查-重写循环跑了 7 轮还没收敛。每轮审查 Agent 都能找出新问题,因为开发 Agent 在修复时改动了代码结构,审查 Agent 又基于新结构提出新意见。最后我是人工介入,直接锁定了代码,才结束这个循环。

这个问题的根源是:审查 Agent 和开发 Agent 没有共享的"完成标准"。审查 Agent 的默认行为是"尽可能挑毛病",它没有"什么时候该停"的判断。而开发 Agent 的默认行为是"尽可能满足审查意见",它也没有"哪些意见可以忽略"的判断。两个没有停止条件的 Agent 放在一起,就是一个无限循环。

4.3 审查 Agent 的上下文盲区

还有一个硬伤:审查 Agent 只能看到代码 diff 和有限的上下文,它看不到运行时的行为、看不到真实的调用链、看不到历史决策的原因。

举个真实例子。我有一段代码用了双重检查锁定来初始化一个缓存,审查 Agent 反复标记"这里存在竞态条件"。从纯静态分析角度它没错,但那段代码运行在单线程初始化阶段,根本不存在并发。我在架构文档里写过这个约束,但审查 Agent 的上下文里没有这一条。

这种"上下文盲区"导致的误报,占了审查意见的相当比例。而每一条误报,都要消耗开发 Agent 的 token 去"修复",修复本身又可能引入真问题。

5. 砍掉两个 Agent 之后,我换成了什么方案

5.1 把"架构约束"从 Agent 降级为静态规则文件

砍掉架构师 Agent 之后,我把它原本的产出——那些架构约束——变成了一份人工维护的、结构化的规则文件。不是自然语言文档,而是类似这样的东西:

# architecture-rules.yaml layers: - name: domain allowed_dependencies: [] - name: application allowed_dependencies: [domain] - name: infrastructure allowed_dependencies: [domain, application] conventions: result_type: "所有 service 方法返回 Result<T>,不抛异常" write_path: "所有写操作必须通过 EventBus.publish()" naming: service_suffix: "Service" repository_suffix: "Repository"

这份文件直接注入到开发 Agent 的 system prompt 里,不经过任何摘要。它比架构师 Agent 的自然语言输出更短、更精确、更不容易失真。而且它是静态的,不会在传递中"蒸发"。

需要更新架构时,我人工改这个文件,改完所有后续开发自动生效。这比让架构师 Agent 重新生成一份文档再层层传递,成本低了一个数量级。

5.2 用 linter + 类型系统替代 80% 的审查工作

审查 Agent 挑出的问题里,那 90 条风格问题和 60 条伪风险,其实大部分可以用传统工具解决。我做了这几件事:

  • 配了一套严格的 ESLint 规则,把命名、格式、导入顺序全部自动化
  • 开了 TypeScript 的 strict 模式,把空值检查、类型不匹配在编译期就拦掉
  • 写了一个自定义的架构约束检查脚本,扫描 import 语句,发现跨层依赖直接报错

这三样加起来,覆盖了原来审查 Agent 大约 80% 的工作量,而且是确定性的、零延迟的、不会误报的。剩下的 20%——真正的逻辑问题和边界条件——才交给 AI 处理。

5.3 保留并强化测试驱动环节

测试驱动是我唯一保留并强化的环节。原因很简单:测试是唯一有客观通过/失败标准的环节。

我的做法是:开发 Agent 写完代码后,必须同时产出测试用例。测试用例不是让 AI 自己判断对不对,而是真的跑起来。跑不过就重写,跑过了就进入下一环节。这个循环有明确的终止条件(测试全绿),不会像审查循环那样无限发散。

而且测试用例本身也成了一种"可执行的架构约束"。比如我要求所有 service 方法必须有对应的测试,测试里必须覆盖空输入和异常路径。这比在文档里写"注意边界条件"有效得多。

实测下来,这套精简方案的效果:

指标多 Agent 方案精简方案
端到端耗时约 52 分钟约 18 分钟
首次可运行率80%75%
人工介入次数2.1 次1.5 次
代码返工率35%20%

耗时降到三分之一,人工介入反而更少。首次可运行率略低,但那 5% 的差距通过一次快速重试就能补回来,成本远低于多 Agent 方案的延迟。

6. 如果你还想试多 Agent,这几条经验能帮你少走弯路

6.1 只在"有客观验证标准"的环节拆 Agent

这是我从这次踩坑里提炼出的最核心的一条。测试驱动能保留,是因为它有客观标准。架构设计和代码审查被砍掉,是因为它们的"好"是主观的、需要权衡的,而 Agent 不擅长做权衡。

如果你要拆 Agent,先问自己:这个环节的产出,有没有一个不依赖主观判断的验证方式?有,就可以拆;没有,就别拆。

6.2 上下文传递要做"无损压缩",而不是"摘要"

如果非要传递上下文,尽量用结构化格式(YAML、JSON、类型定义),而不是自然语言摘要。结构化格式在压缩时丢的是冗余,自然语言摘要丢的往往是关键约束。

我现在的做法是:所有跨环节传递的信息,都先转成结构化格式,再注入。比如架构约束用 YAML,接口定义用 TypeScript 类型声明,测试用例用实际的测试文件。这些东西即使被截断,也不会产生歧义。

6.3 给每个 Agent 设明确的"停止条件"

审查 Agent 之所以会无限挑毛病,是因为它没有停止条件。如果你要用审查类 Agent,必须给它一个明确的预算:比如"最多提 5 条意见"、"只检查 P0 级问题"、"风格问题一律不报"。

同理,开发 Agent 也要有"哪些意见可以忽略"的判断规则。否则两个 Agent 就会陷入互相拉扯的死循环。

6.4 先跑单 Agent,遇到瓶颈再考虑拆分

我最后的建议是:不要一上来就搭多 Agent。先用单 Agent 跑,把架构约束写成静态规则文件,把能自动化的检查交给 linter 和类型系统,把验证交给测试。等你真的遇到单 Agent 解决不了的瓶颈——比如上下文实在装不下、或者需要并行处理多个独立任务——再考虑拆 Agent。

大多数项目根本到不了那个瓶颈。我见过不少团队,项目才几千行代码,就搭了一套五六个 Agent 的流水线,结果大部分时间花在调试 Agent 之间的通信上,真正写业务代码的时间反而少了。

7. 一个具体的对比:同一个需求,两种方案的实际执行记录

为了让你更直观地感受差异,我把同一个需求在两种方案下的执行记录整理出来。需求是:实现一个带分页和筛选的用户列表接口,包含数据层、服务层、控制器层,以及对应的单元测试。

多 Agent 方案的实际时间线:

  1. 架构师 Agent 分析需求,产出架构文档(约 4 分钟)
  2. 文档摘要后注入开发 Agent,开发 Agent 写数据层(约 3 分钟)
  3. 审查 Agent 审查数据层,提出 12 条意见(约 2 分钟)
  4. 开发 Agent 根据意见重写数据层(约 3 分钟)
  5. 审查 Agent 再审,提出 5 条新意见(约 2 分钟)
  6. 开发 Agent 再改(约 2 分钟)
  7. 重复步骤 2-6 处理服务层和控制器层(约 25 分钟)
  8. 测试 Agent 跑测试,发现 3 个失败(约 2 分钟)
  9. 开发 Agent 修复,再跑测试(约 5 分钟)
  10. 人工审查最终代码,发现架构一致性问题 2 处(约 4 分钟)

总计约 52 分钟,人工介入 2 次。

精简方案的实际时间线:

  1. 开发 Agent 读取静态架构规则文件,直接写数据层 + 服务层 + 控制器层(约 6 分钟)
  2. 同时产出单元测试(约 2 分钟)
  3. 跑测试,2 个失败(约 1 分钟)
  4. 开发 Agent 根据失败信息修复(约 3 分钟)
  5. 再跑测试,全绿(约 1 分钟)
  6. 人工快速扫一遍代码,确认架构规则文件里的约束都满足(约 3 分钟)

总计约 16 分钟,人工介入 1 次。

差距一目了然。多 Agent 方案多出来的 36 分钟,几乎全部消耗在 Agent 之间的通信、审查循环和上下文重建上。而这些消耗,并没有换来成比例的质量提升。

8. 写在最后:关于"给 AI 配团队"这件事的几点个人判断

踩完这一轮坑,我对"给开发 AI 配架构师和审查员"这件事有了比较清晰的判断。

第一,Agent 的数量不等于能力。一个 Agent 加上好的规则文件和验证机制,往往比三个互相通信的 Agent 更有效。通信本身是有成本的,而且成本不低。

第二,架构和审查这两个环节,本质上需要"全局视野 + 实时权衡",这恰恰是当前 Agent 架构的弱项。它们擅长在明确约束下执行,不擅长在模糊约束下决策。把需要决策的环节交给它们,就是把不确定性引入了流水线。

第三,测试驱动是 AI 编程里被低估的环节。它提供了客观标准,让整个流程有了收敛的锚点。我现在会把更多精力放在设计好的测试用例上,而不是设计更复杂的 Agent 协作。

第四,规则文件比 Agent 更可靠。一份维护良好的架构规则文件,可以稳定地约束所有后续开发,不会因为上下文传递而失真。它的维护成本远低于维护一个架构师 Agent。

如果你正在做类似的事情,我的建议是:先把单 Agent + 静态规则 + 测试驱动这套跑通,跑到你觉得"这套东西的瓶颈在哪里"的时候,再针对那个具体瓶颈去考虑要不要拆 Agent。不要因为"多 Agent 听起来更先进"就上多 Agent,那大概率会让你多花几周时间,最后又砍回来。

我砍掉那两个 Agent 的时候,说实话有点心疼那六周的投入。但砍完之后流程跑得更顺,那种感觉比留着两个"看起来很厉害但实际拖后腿"的 Agent 要好得多。工具是拿来解决问题的,不是拿来撑门面的。

返回列表