Wynn5a 的技术博客
研发流程约 16 分钟读完

康威定律实践:如何组织和管理 AI Agent 进行软件开发

康威定律说,系统的结构总会复制设计它的组织的沟通结构。当编码工作交给 AI agent 来完成时,这条规律非但没有失效,反而因为 agent 之间的每一次沟通都落在 prompt、合同和文档里而变得格外清晰:你怎样给 agent 分工,让它们通过什么交接工作,人又站在哪个位置把关,最终都会原样体现在代码库的结构里。本文想讨论的正是这件事,即如何借助康威定律来组织一支 agent 团队,让它更好地完成软件开发。

康威定律为什么同样适用于 agent 团队#

1967 年,梅尔文·康威提出了一条后来被称为康威定律的观察:设计系统的组织,其产出的系统结构必然复制该组织的沟通结构。通俗地说,团队长什么样,系统就长什么样,三个小组协作的产品几乎必然有三个主要模块,而模块之间接口的质量取决于小组之间的沟通成本。如今开发团队里出现了一批新成员,它们不知疲倦,不要求加薪,可以随时上岗也可以随时解散,于是一个自然的问题是:当团队成员换成了 agent,这条定律是否依然成立?

答案是肯定的,而且它在 agent 团队里表现得比在人类团队里更加纯粹。要理解这一点,不妨先把 agent 世界的概念翻译成组织语言:

Agent 世界的概念组织世界的对应物
编排器(主 agent)项目经理
子 agent员工或工作小组
Prompt 与 SKILL.md任务书与员工手册
工具办公设备与权限
共享 memory 与文件内部 Wiki
Spawn 一个 agent招一名外包,干完即散

这种对应关系并不只是一个方便的比喻,agent 团队的拓扑本身就是一张组织结构图,编排代码就是团队的制度与流程。康威定律的本质也不在于人本身,而在于信息流:只要一个系统由多个需要相互通信的单元协作完成,单元之间的通信结构就会固化成系统架构。而在 agent 团队里,每一次沟通都是一段 prompt,每一次任务交接都是一次上下文的构造,沟通结构被完整地暴露出来,几乎没有含糊的余地。由此可以引出组织 agent 团队时必须正视的三个事实。

上下文就是团队的沟通带宽#

信息在 agent 之间传递时必然经过压缩与转述,传递的跳数越多,信号衰减就越严重。任务分解的层级越深,最底层的产出就越容易偏离初衷,因为初衷在每一层都被重新表述了一次,而每一次重述都可能丢掉一些细节或悄悄改变一些侧重。因此,组织 agent 团队时应当尽量减少层层转派,并让 agent 之间的接口结构化、类型化,用明确的字段和格式代替冗长的自然语言转述。

这是一个零默契的团队#

人类组织大量依赖默契与隐性知识,老员工知道跟财务提报销要提前三天,这种事无需写进任何手册;agent 却没有这一层,每次 spawn 都相当于一名新员工入职,它所知道的一切就是写进 prompt、skill 和 memory 的内容总和,没有写下来的规则对它而言就不存在。正因如此,为 agent 团队编写 prompt 本质上是在建设组织文化,团队里的每一条隐性知识都要付出一次显式化的成本。

警惕组织结构图上看不见的协作#

两个 agent 读写同一个文件,多个 agent 共享一段 memory,这些依赖不会出现在任何一张组织结构图上,却真实地决定着团队的产出。凡是 agent 之间交换信息的地方都是接口,即便是借道文件系统的场合也不例外,所以接口必须显式声明,管理者也应当定期审计所有被多个 agent 读写的共享状态,只有这样才能看清团队真实的协作结构,进而看清代码真实的架构。

先想清楚架构,再给 agent 分工#

既然团队结构决定代码结构,组织 agent 团队的第一步就不是挑选模型或编写 prompt,而是想清楚希望得到什么样的系统,再按照这个形状去安排分工,这就是所谓的逆向康威机动:与其让组织拖着架构走,不如先确定想要的架构,再重组团队去匹配它。在人类组织里,这样的重组往往伤筋动骨,而在 agent 团队里只需要修改编排代码,组织结构第一次成了可以随意重构的东西,逆向康威机动也因此从一种理想变成了日常可用的手段。

具体到分工方式,比较稳妥的做法是把每个业务领域交给一个领域 agent,由它对内封装实现、对外定义协议。这一思路其实是三种经典思想的合流,即 Parnas 在 1972 年提出的信息隐藏(模块化的依据是隐藏可能变化的设计决策)、领域驱动设计中的限界上下文,以及上面提到的逆向康威机动。

分工的维度应当是业务能力而不是技术步骤,判断时可以先问一问:这个 agent 端到端拥有什么?如果按技术层分工,设立前端 agent、后端 agent 和数据库 agent,团队最终交付的会是一个分层单体;如果按业务域分工,设立订单、支付、库存等领域 agent,得到的则是高内聚的服务。这背后起作用的仍然是沟通成本:跨 agent 传递上下文的代价很高,团队会自然而然地减少跨域改动,而这恰恰是我们希望代码具备的架构属性。

领域 agent 是一个角色,而不是一个常驻进程#

落到开发实践中,领域 agent 并不是一个长期运行的进程,而是一个角色加上一个上下文包,这个上下文包通常包括:

  • 一个专属仓库或仓库内的专属目录,存放领域代码与测试;
  • 一份对外合同,写明能力 schema、副作用和失败模式;
  • 一份员工手册,涵盖编码规约、架构约束和领域术语;
  • 一套覆盖竞态分支的评测用例;
  • 一份设计决策记忆。

每次启动一个 coding agent 并注入这个包,就相当于让该领域的一名工程师上岗,因此上下文包的质量决定了这个角色能力的上限。也正因为如此,上下文包本身应当被视为一个需要评审的工件:包太大会稀释 agent 的注意力,包太小又会导致重复建设,其中的取舍需要像评审代码一样认真对待。

用合同而不是代码来协作#

有了分工,接下来的问题是 agent 之间如何沟通。在一个组织良好的 agent 团队里,沟通结构具体表现为工件流:领域 agent 之间不阅读彼此的代码,只阅读对方的合同;一切跨域协调都通过合同、PR 和事件 schema 这类显式工件发生。跨域的业务流程则交给一个专门的角色,本文称之为编织 agent,需要强调的是,它是团队中负责跨领域协调的成员,而不是系统里的某个运行时组件:它只读需求与各领域的合同,交付物是把各领域能力串成业务流程的工作流代码。康威定律保证,这样的沟通结构会固化为松耦合的代码架构;反过来,如果让两个领域 agent 共享完整上下文、互相翻看对方的实现,生成的代码里就会出现跨域依赖,那正是组织结构图上没有画出的汇报关系,只不过这一次它会以非法依赖的形式暴露在编译器面前。

星型的沟通结构#

在这种组织方式下,领域 agent 对外提供的门面既不面向最终用户,也不面向其他领域,而只面向编织 agent:领域 agent 是能力的提供者和合同的持有者,编织 agent 读取各领域的合同,再把它们组合成业务流程。整个团队的沟通因此呈星型而不是网状,领域之间不直接对话,只通过合同被编织 agent 认识。

正在渲染图表…

之所以选择星型,是因为沟通连线的数量差异会随团队规模迅速拉开:N 个领域两两直接沟通,最多会产生 N(N−1)/2 条连线,而星型结构只有 N 条,领域越多,网状团队的接口就越难以管理,星型团队则始终保持线性增长。康威定律在这里给出了直接的回报,星型的沟通结构固化为星型的代码架构,领域之间没有直连,耦合只发生在合同上。

星型结构的瓶颈在编织 agent#

星型结构并非没有代价,所有合同最终都汇聚到编织 agent 那里,它的上下文也就成了团队新的瓶颈:领域越多、流程越复杂,编织 agent 需要装进上下文的东西就越多,而前文已经说过,上下文过大会稀释注意力。缓解的办法其实都来自前面的原则。首先,编织 agent 只读合同、不读实现,这本身就是对上下文最有效的压缩,合同写得越精炼,编织 agent 的负担就越轻;其次,可以按业务流程拆分编排职责,让每个编织 agent 只负责一条流程,例如订单超时取消是一条,退款是另一条,它只需加载这条流程涉及的那几份合同;最后,合同本身也应当保持简洁,只暴露消费方真正需要的能力,这与后文提到的防止合同膨胀是同一件事。

一份合格的合同需要写清什么#

由于合同是 agent 之间唯一的沟通渠道,它必须写得足够完整,让消费方无需翻看实现也能正确使用。跨域的一致性依赖 saga 模式,即编织方持有流程、领域负责做到补偿友好,为此合同至少要写清四件事:一是幂等键,用来保证重试安全;二是副作用标注,用来区分查询与命令,缺少它时,由模型担任的编织者最常犯的错误就是把命令当作查询来调用;三是以语义命名的失败模式,让编织方能够分流处理竞态与异常;四是补偿语义,说明一个命令如何撤销。值得一提的是,并发问题在这里几乎免费地获得了合同化的表达,把订单已支付声明为一种失败模式,本身就是对支付与取消之间竞态的显式声明。

划清领域与编排的职责边界#

在这种团队结构里,最关键的管理决策是接口粒度,因为它决定了业务流程归谁负责。常见的反面做法是为某个具体功能开一个大接口,例如批量取消超时未支付订单这样的接口,一次调用全部搞定,但这样会把超时、批量之类的流程语义泄漏进领域,此后每次政策调整,无论是超时时长变更、会员豁免还是大促期间的特殊规则,都要去改领域 agent 负责的代码,编织 agent 也就形同虚设。

判断粒度是否合适,只需要问一个问题:当这条规则变化时,你希望修改哪个工件?未支付订单能否取消,属于领域规则,应当由领域 agent 负责;而多久没付才取消、谁可以豁免,属于编织政策,应当交给编织 agent。换句话说,领域接口应当小而稳定,编织工件则应当可以频繁变更,所以在一个健康的团队里,最活跃的仓库是编织层,最安静的仓库是领域层;如果情况恰好相反,往往说明接口粒度切错了,职责也随之分错了。

一个完整的例子:定时取消未支付订单#

为了把前面的分工、沟通和职责边界串起来,下面用一个假设的需求完整走一遍团队的协作过程。需要说明的是,这是一个用于说明流程的示例,其中的细节都是为了演示而设定的,并非某个真实项目的记录。

从需求到合同草案#

假设业务方提出:下单后超过 15 分钟仍未支付的订单应当自动取消,并释放其占用的库存。需求首先交给编织 agent,它并不直接动手写实现,而是先产出一份流程草案和一份能力缺口清单:流程是定时触发、分页拉取超时未支付的订单、逐单取消并释放库存,支付竞态单独处理,其余异常进入死信队列;缺口清单则列出这条流程需要订单域提供的查询超时未支付订单与取消订单两项能力,以及仓储域提供的释放库存预留能力。这份草案本身就是一份接口需求说明书,派单之前还应当先检索各领域已有的能力,已经存在的直接复用,只把真正缺失的部分派发出去。

缺口随后被派发给订单 agent 和仓储 agent,由它们各自起草合同。订单 agent 的合同节选如下,其中查询能力被标注为无副作用、可以随意重试,取消能力则被标注为写命令,要求调用方提供幂等键,并声明了两种失败模式:

yaml
# 订单 agent 的能力合同(节选)
capabilities:
  - name: list_unpaid_orders
    effect: none                    # 查询,可随意重试
    input:  { older_than: duration, cursor: string? }
    output: { orders: [OrderSummary], next_cursor: string? }
 
  - name: cancel_order
    effect: writes                  # 命令,需幂等键
    input:  { order_id: id, reason: string, idempotency_key: string }
    failure_modes:
      - already_paid: 订单已支付,拒绝取消
      - already_cancelled: 幂等成功,返回当前状态

人类评审、领域实现与合同测试#

合同在进入实现之前必须经过人类评审,agent 可以起草,但不能自我认证。评审关注的恰恰是前面提到的那几件事,举例来说,如果订单 agent 的初稿里漏掉了 already_paid 这一失败模式,评审者就应当指出:用户可能在取消任务执行的同一时刻完成支付,合同必须把这种竞态显式声明出来,否则编织 agent 无从知道该如何处理;同样,如果取消命令没有要求幂等键,定时任务一旦重试就可能产生重复操作。这类问题在合同阶段发现,修改的只是一份 yaml,而一旦进入实现乃至上线之后才暴露,代价就完全不同了。

合同获批之后,订单 agent 和仓储 agent 在各自的领域内完成实现,评测用例则作为合同测试进入持续集成,其中要覆盖已支付的竞态分支和重复取消的幂等分支,此后任何违背合同语义的改动都会被当作破坏性变更拦下来。由于领域之间不直接依赖,联调可以借助合同驱动的 mock 进行,不必等待所有领域都完成实现。

编织 agent 交付工作流#

与此同时,编织 agent 根据获批的合同生成工作流代码,它是一个独立版本化的工件,只通过合同调用各领域的能力,并按照合同声明的失败模式分流处理:

python
# 编织 agent 交付的工作流:独立版本化的工件
@workflow(schedule="*/1m")
def cancel_unpaid_orders(ctx):
    for batch in ctx.call("order.list_unpaid_orders", older_than="15m", paginated=True):
        for order in batch:
            r = ctx.call("order.cancel_order", order, reason="timeout", idem=order.id)
            if r.ok:
                ctx.call("inventory.release_reservation", order, idem=order.id)
            elif r.failure == "already_paid":
                pass                # 竞态:支付刚完成,跳过
            else:
                ctx.dead_letter(order)

当政策发生变化#

过了一段时间,业务方又提出两条新政策:大促期间超时时长改为 30 分钟,会员订单不参与自动取消。按照前面的粒度原则,这两条都属于编织政策,修改应当只发生在工作流这个工件上,订单域和仓储域的合同与实现都不需要变动。如果订单摘要里已经带有买家的会员信息,改动就完全局限在工作流内部;如果没有,订单 agent 需要在查询结果里补充这一字段,但这只是对合同的增量扩展,豁免与否的判断依然留在编织层,不会因此进入领域。

python
# 政策调整后的工作流(节选):只修改编织工件
timeout = "30m" if ctx.is_promotion_period() else "15m"
for batch in ctx.call("order.list_unpaid_orders", older_than=timeout, paginated=True):
    for order in batch:
        if order.buyer_is_member:   # 会员豁免属于编织政策,不进入领域
            continue
        ...

这个变化恰好印证了前面的判断标准:政策越是频繁调整,越能体现把流程语义留在编织层的价值,业务迭代的速度也因此取决于编织工件的发布速度,而不再取决于多个领域联动修改的周期。

人在其中的位置#

回看整个过程,人的角色收敛为三件事:一是做边界的所有者,决定在哪里切分领域;二是做合同的审批者,agent 起草,人类签字;三是做可读性的审计者,确保 agent 写出的代码仍然是人能读懂、能审计的。更进一步看,agent 团队的沟通结构完全由设计者定义,哪个 agent 读哪个目录、看哪份合同、产出什么工件、与谁交接,这一切都只是配置,因此管理者手里多了一根新的杠杆:想改架构,先改 agent 的组织方式,而调整 agent 的分工与信息可见性,远比重构代码便宜。

agent 团队的工作止于何处#

组织 agent 团队还需要回答一个问题,即团队的工作应当止于何处、最终交付什么。从上面的例子可以看到,编织 agent 读取合同之后交付的是确定性的工作流代码,上线后执行的不再是模型的临场规划,而是可重放、可审计、可测试的普通程序,也就是说,agent 团队扮演的是施工队与维护队的角色,交付物是一套传统的确定性系统,系统由 agent 建造,但不由 agent 运行;运行时的模型规划只应留给不确定性本身就是产品价值的少数场景,而且由于团队写下的合同恰好也是运行期智能体可以消费的格式,这条路将来随时可以打开,今天并不需要为此付出额外的复杂度。

从一个单仓库项目开始#

前面描述的组织方式以每个领域一个专属仓库为理想形态,但现实中多数团队是在一个单仓库项目里,借助 Cursor、Claude Code 这类 coding agent 进行开发的,为每个领域单独建仓库的门槛并不低。好在康威定律关心的是沟通结构而不是仓库的物理形态,在单仓库里同样可以逐步落地,大致可以按下面的顺序推进:

  1. 先把业务领域映射为目录,例如订单、仓储、支付各占一个顶层目录,并通过 CODEOWNERS 之类的机制为每个目录指定负责人,让领域边界在仓库里有一个看得见的落点。
  2. 为每个领域目录准备一份规则文件,例如 AGENTS.md 或所用工具支持的模块级规则,写明这个领域的编码规约、架构约束和领域术语,它就是前文所说的员工手册,也是这个领域 agent 上下文包的核心。
  3. 把合同作为文件放进仓库,例如集中在一个 contracts 目录下,用 schema 描述能力、副作用和失败模式,合同的任何改动都走 PR,并要求人类评审通过后才能合入。
  4. 用持续集成里的依赖检查或架构测试约束依赖方向,禁止一个领域目录直接引用另一个领域的内部实现,跨域调用只能经由合同。
  5. 给每一次 agent 任务限定范围,一次只允许改动一个领域目录,需要跨域时先提交合同变更,由对应领域的任务去实现,而不是让一个 agent 顺手改遍所有目录。
  6. 不必一开始就全面铺开,可以先挑一两个边界清晰的领域试行,等规则文件、合同和检查都磨合稳定之后,再逐步扩展到其他领域。

如何判断这套组织方式是否奏效#

组织方式是否有效,最终要看团队的产出,而不是看流程文档写得多完整。这里有几个值得持续观察的信号,它们并不是固定的指标,而是帮助管理者判断方向的线索:一是跨领域 PR 的比例,如果大量 PR 同时触碰多个领域目录,往往说明领域边界划得不对,或者合同不足以支撑协作;二是合同变更与工作流变更的相对频率,健康的状态应当是领域合同相对安静、编织层相对活跃,如果合同频繁变动而工作流很少调整,就要回头检查接口粒度;三是 agent 产出因缺少上下文而需要人工返工的频率,这类返工多半意味着某条隐性知识还没有写进规则文件或合同,与其反复手工修补,不如把它补进对应的上下文包;此外,编织 agent 需要加载的合同数量如果持续增长,也提示是时候按业务流程拆分编排职责了。

新的组织方式,新的风险#

把编码交给 agent 团队之后,风险并没有消失,而是集中到了开发期,浓度也更高,因此需要相应的纪律来约束。

首先是架构漂移。每个 agent 产出的提交都局部自洽,全局的失谐却会逐渐累积,对此可以把架构规则写成持续集成中可执行的断言,例如约束依赖方向与层次的适应度函数,让这支零默契的施工队在机器执行的规则下工作,而不是依赖文档里的期望。

其次是可读性倒挂。过去写代码难、读代码易,现在 agent 写得又快又多,人类的阅读带宽却没有变化,代码可读性因此从隐性的美德升格为硬性的架构约束,因为人类是最后一道审计防线,读不懂的代码就等于不可审计。应对的办法是让合同与架构始终保持人类可读,把生成代码的复杂度预算写进规约,并让测试的地位高于实现。

再次是合同膨胀。agent 起草合同时不会心疼接口的数量,所以在派发任务之前检索既有能力、合并重复合同,应当成为流程中的强制步骤,这同时也是在为编织 agent 的上下文减负。

最后是上下文的取舍。上下文包太大,agent 的注意力会被稀释,太小又会导致重复建设,这也是前文强调上下文包本身需要评审的原因。

写在最后#

回过头看,组织 agent 团队与组织人类团队遵循的是同一条规律,区别只在于前者的沟通结构完全显式、完全可编程。人类团队的组织结构由人事与利益决定,架构师只能被动接受沟通结构对架构的牵引;而 agent 团队的分工、信息可见性和交接方式都写在规则文件、合同和配置里,可以评审、可以版本化、可以部署,因此组织结构本身成了我们手里最便宜、也最可编程的架构控制面。

康威在 1967 年观察到的规律从未过时,它只是完成了一次介质迁移,从关于组织行为的社会学观察,变成了代码库里实实在在的工程事实。当组织结构本身成为配置,逆向康威定律才算真正可执行,我们终于可以像部署代码一样部署一个团队,并期待系统长成我们设计的模样。

读完了,谢谢你读到这里

有新文章时想第一时间看到?订阅 RSS