How I Built a Software Development Agent Team with Paseo + Beads (Part 1)

这是一个如何更快速烧token的解决方案,哈哈哈。

这个系列会分三个部分,分别介绍我的想法的由来,以及在实践中我发现了哪些问题,从而一共优化了三版不同的方案。

我为什么想要一个Agent Team

大部分人开始用 coding agent 的时候,其实还是把它当成一个增强版助手。比如我告诉它帮我改一下这个接口,或者帮我检查一下这个页面为什么报错,再或者补一个单元测试。

这种方式很好用,但它有一个问题:人还是那个中心节点,人也成为那个效率瓶颈。

所有任务都要我来切换,所有上下文都要我来组织,所有进度都要我来记住。Agent 负责执行,但我负责把整个项目重新塞进它的上下文里。

如果只是一个很小的功能,这没有问题。但当我开始同时处理前端、后端、数据库、测试、部署这些事情时,我发现自己并没有真的变轻松,只是把“写代码”的一部分压力转移成了“不断给 Agent 派活、解释、检查、纠偏”。

所以我想,是不是可以用agent来模拟人类软件开发团队。我们会有需求、任务、Issue、状态、依赖、Review、Release。那 Agent Team 也一样,不能只靠 prompt 堆起来,它也需要任务结构。

Paseo 和 Beads:一个管人,一个管事

我当时看到两个工具之后,突然意识到“这两个东西可以拼起来”用。

第一个是 Paseo。简单来说,它是一个用来管理 coding agent 的工具。它会在本地跑一个 daemon,然后你可以通过桌面端、手机端、Web 或者 CLI 去连接它,启动和管理不同的 coding agent。所以我对 Paseo 的理解是:它更像一个 Agent 调度台。它解决的问题不是“任务是什么”,而是“这些 Agent 怎么跑起来、怎么被管理、怎么让我方便地看到它们在做什么”。

第二个是 Beads。它是一个面向 coding agent 的本地 issue / 记忆系统。相比普通的 Markdown Todo,Beads 更强调结构化任务、依赖关系和状态追踪。也就是说,它不是只让你写一堆待办事项,而是把任务变成 agent 可以持续读取、更新和推进的工作对象。所以它很适合作为本地的数据管理。

这两个工具放在一起,Paseo 负责让多个 Agent 跑起来,且支持多个客户端查看;Beads 负责让多个 Agent 知道自己该做什么,作为标准数据源。我来负责定义目标、判断优先级、验收结果。

第一版工作流:Release → Issue → Agent

有了这个想法之后,我的第一版设计还是基于原有的流程建立。之前的文章中我也介绍过我是如何把Obsidian作为数据源用来管理release,feature和bug,以及如何跟GitHub issue同步,然后让agent开自动读取issue开发的。

入口依旧是 Release。也就是说,我会先定义一个版本目标:这一版大概要完成哪些功能,修复哪些问题,最后要达到什么样的状态。然后,我会自己把这个 Release 拆成一组 Issue,放到 Beads 里。这里的 Issue 大体分成两类:一类是 Feature,也就是需要新增或改造的功能;另一类是 Bug,也就是在开发、测试或者使用过程中发现的问题。

为了让这个agent team自动工作起来,我增加了一个Dispatcher,并且写入了一些rules用于任务的分配逻辑。这个 Dispatcher 的作用,是从 Beads 里读取当前存在的 Issue,然后把它们分配给不同的 Agent 去处理。Feature 通常会由开发 Agent 领取并遵循TDD来实现,并且Test agent会持续地将发现的Bug记录到Beads中。而Bug 则可以被空闲的Agent 自动触发、自动领取、自动尝试修复。

这时候整个流程就变成了一个不断运转的循环。而且因为Paseo支持不同的provider,所以我用一个配置文件给不同的agent分配的不同的模型(这一步纯看个人财力,token自由的可以忽略)。最终在review之后,再由我来介入看功能是否按照我的想法和需求完成,最终批准后自动提交PR。

而且我为整套流程做了一个kanban,可以看到哪些issue是给哪些agent在做,哪些走到了我审批的流程,并且可以直接在界面中审批,然后就会自动提交PR了。

它确实跑起来了

第一版真正跑起来的时候,我其实是很兴奋的。

不过,这套流程跑了一段时间之后,我也看到了很多问题。

第一个问题是,前期的需求澄清和任务拆分仍然完全依赖我。

虽然 Agent 可以领取 Issue,Dispatcher 可以分配任务,测试发现的 Bug 也可以重新写回 Beads,但最开始的 Feature 怎么定义、需求怎么拆、Issue 怎么写,还是要靠我。这意味着整个系统看起来已经有了自动循环,但它的效率瓶颈还是我。只要我没有把需求拆清楚,后面的 Agent 就无法稳定推进。只要我没有把 Issue 写明白,Dispatcher 分配得再积极,也只是把不清楚的任务更快地推给 Agent。

第二个问题是,Issue 必须写得非常明确。

开发者在拿到一个模糊任务时,往往会主动追问,或者凭借项目经验补全上下文。但 Agent 不一定会这样。它有时候会过度自信地开始执行,甚至会根据一个不完整的 Issue 做出错误判断。

如果 Issue 里没有写清楚背景、边界、验收标准和相关依赖,它就可能误解任务。如果多个 Issue 之间的关系没有描述清楚,它也可能在不该动的地方动手。如果一个 Bug 只是简单写了现象,没有说明它出现在哪个功能、哪个版本、哪个上下文里,Agent 就很容易把它当成一个孤立问题处理。

第三个问题是,Agent 不一定真的理解背景。

这是第一版里最关键的问题。在 Release → Issue 的拆分方式里,我原本以为 Release 提供了大方向,Issue 提供了具体任务,这样就足够了。但真正跑起来以后我发现,Agent 领取到的往往只是某一个 Issue,而不是完整的 Release 背景。

也就是说,它知道自己手里有一张工单,但不一定知道这张工单为什么存在。它知道要修一个 Bug,但不一定知道这个 Bug 和当前版本目标有什么关系。它知道要实现一个 Feature,但不一定理解这个 Feature 在整个产品流程里的位置。

对我来说,一个 Issue 背后通常有很多隐含信息:这个版本为什么要做它,哪些功能暂时不能动,哪些模块只是临时方案,哪些问题应该等后续版本解决。但对 Agent 来说,如果这些背景没有被显式写进 Issue,或者没有通过某种机制传递给它,它就很可能只看到局部任务,看不到整体意图。

第四个问题是,临时加入的 Bug 会让系统变得混乱。

一开始,我觉得 Bug 可以自动进入 Beads,再由 Agent 自动领取解决,这是一件很自然的事情。因为这看起来很像一个自我修复的循环:测试发现问题,写回 Issue,Agent 再去修。但后来我发现,如果缺少 Release 背景和任务上下文,临时加入的 Bug 会打乱 Agent 对当前工作的理解。

有些 Bug 其实只是当前 Feature 没完成时产生的中间状态,有些 Bug 和当前 Release 的目标并不一致,应该放到后面处理,有些 Bug 看起来很急,但实际上它依赖另一个还没完成的任务,还有些 Bug 会让 Agent 跳到另一个模块里改代码,结果引入新的冲突。

这时候,Beads 里的 Issue 数量虽然变多了,但系统并不一定更聪明。因为 Issue 本身只是任务对象,它还需要足够的背景、优先级和依赖关系,才能变成真正可执行的工作流。

第一版不是失败,而是必要的原型

第一版不是失败。

它完成了一个非常重要的任务:让我第一次把多个 Agent 串成了一个可以运转的开发循环。在这一版之前,我的问题是:多个 Agent 能不能围绕同一个项目协作?在这一版之后,我的问题变成了:如果它们真的能协作,那我应该如何组织它们,才能避免混乱?

第一版让我看到了 Agent Team 的可能性。但它也让我意识到,光有 Issue 和自动分配是不够的。因为真正限制效率的,不是 Agent 执行任务的能力,而是任务进入系统之前有没有被澄清;Agent 领取任务时有没有理解背景;临时 Bug 进入循环时有没有被放到正确的位置。也就是说,Agent Team 的难点不只是“让 Agent 干活”,而是“让 Agent 在正确的上下文里干正确的活”。

所以第二版里,我开始尝试解决这些问题。

既然第一版里需求澄清、任务拆分、优先级判断都还压在我身上,那能不能把这些职责也拆出去?既然真实的软件团队里有产品经理、项目经理、前端、后端、数据库和测试,那 Agent Team 是不是也应该这样组织?

于是,我开始了第二版实验:把 Agent Team 拆得更像一个真实的软件开发team。结果,新的问题也来了。