先说结论如果你只是需要一个“能写代码的助手”那单个 Agent 就够了大概率不需要看这篇。我这次用 Paseo 和 Beads 搭软件开发 Agent Team起因是一个特别具体的痛点让一个 Agent 从头到尾写完一个功能表面上 demo 能跑但代码根本不经看——命名随意、没有错误处理、边界条件全看运气你让它改了 A 功能它顺手把 B 的配置也改了。这种体验大概和带一个很聪明但不太靠谱的实习生差不多。后来我想明白一件事写代码这事儿本来就是可以拆的。需求解析、架构设计、编码实现、代码审查这么多个环节凭什么都压在一个 Agent 身上真实项目里不这么干是因为流程本身就是质量的一部分。于是我就开始折腾多 Agent 协作而 Paseo 和 Beads 就是这次尝试里最重要的两块骨架。Paseo 和 Beads 都是比较“窄”的工具不像全家桶那么重但搭在一起刚好覆盖我最需要的两块能力Paseo 负责 Agent 的编排与调度Beads 负责任务之间的数据流转。说得再直白一点Paseo 是导演Beads 是分镜脚本。这篇文章是系列的第一篇我先把“为什么这么搭、团队怎么设计、最小 Demo 怎么跑通”讲清楚首版实测踩的那些坑也会放在里面——因为坑恰恰最能说明这套架构的边界。这篇适合谁看如果你正准备让 Agent 参与更大一点的开发任务或者你在多个 Agent 协作时总感觉“各干各的、没有形成合力”那这篇的架构思路和落地细节可以直接抄。如果你只是想让 Agent 帮你写一次性脚本参考价值没那么大但最后一章的坑应该还是能帮你少走两步。1. 单人 Agent 写代码为什么撑不住一个完整需求1.1 表面能跑和真正可用之间隔着一条鸿沟我先给一个判断单 Agent 的瓶颈不在“模型能力”而在“过程不可控”。模型这个“人”很聪明但它工作起来像一个没有项目经理、没有测试、没有 review 的独行侠所有决策都在一次上下文里完成。举个我实际遇到的例子。我想让 Agent 写一个“读取 CSV、按指定字段排序、输出新文件”的命令行工具。单独一个 Agent 一次性生成的版本大概是这样的函数能跑但文件不存在时直接抛异常编码写死 UTF-8排序默认升序完全没有校验用户输入的字段是否存在。你追问它“处理一下异常”它能补一个 try except你再追问“字段不存在怎么办”它也能改。问题在于每一次追问都是在原来的上下文上叠加 patch上一轮已经生成的“看着还行但经不起推敲”的代码从未有人真正系统性检查过。换句话说单 Agent 模式下质量和运气强相关。还有一个更麻烦的现象Agent 会对自己的输出有一种“迷之自信”。你让它自查它多半说“看起来没问题”。这就相当于程序员自己 code review 自己的代码绝大多数人会下意识放水。不是模型故意骗你而是它在同一个上下文里很难跳出自己已经形成的结论。真实软件开发里我们靠“不同的人、不同的视角、独立的 check”来制造这种跳出。1.2 软件开发本身就是流水线思维的产物人在真实项目中为什么能稳定产出靠谱代码不是因为我们比模型聪明而是因为流程本身带校验。一个需求进来先有人把模糊表述翻译成带验收标准的任务书然后有人把任务书翻译成技术方案和接口契约开发按契约写代码测试和审查按最坏的意图去挑毛病。每个环节的输出都是下一个环节的输入而且下一个环节有权打回。这就是 Agent Team 的核心价值——不是让 Agent 更像人而是把“写代码”这个模糊的大任务拆成一段一段边界清晰、可校验的小任务。每段任务的输入输出都是结构化的模型在每段里只需要集中解决一个小问题出错面收窄质量自然上去了。这也是我在后续设计里坚持“每个 Agent 只干一件事”的原因不是不能干是干了反而破坏流程的校验能力。1.3 我需要的其实是两块基石人事系统和流水线想清楚这个目标之后我意识到手头缺的不是“更好的模型”而是两样基础设施。第一样是能管理“多个 Agent 角色”的编排层。它要知道现在团队里有哪几个 Agent谁该上场谁的上场顺序是什么每个人的上下文怎么延续哪一步需要人工介入。这个职责我给了 Paseo。第二样是能描述“任务和任务之间数据怎么流”的管道层。上游 Agent 的产物怎么包装、怎么传给下游下游拿到之后怎么验证这不是胡说验证不过怎么打回重做。这个职责我给了 Beads。这两个工具单独看都不复杂但组合起来的思路决定了整个 Agent Team 的天花板。下一章我把它们各自的定位拆开讲。2. Paseo 和 Beads 在我这个项目里分别承担什么角色2.1 Paseo导演手里的那本流程册Paseo 是我接触过的最贴合“Agent 团队编排”这个场景的工具。它的核心抽象是 Agent以及 Agent 与 Agent 之间的关系。你用 Paseo 做的是注册每个 Agent 的身份、角色、可用模型、上下文策略然后描述“这一场戏谁先上场、谁后上场、谁在什么条件下再次上场”。我自己的理解是Paseo 本质上是一个“有限状态机 会话管理”的组合。它把整次软件开发任务看作一个流程状态团队里每个 Agent 都对应一个可调用的执行者。流程在某个状态时Paseo 知道该把当前的数据包交给哪个执行者执行者返回之后Paseo 根据返回结果决定下一个状态是前进、回退还是原地重试。这个设计很朴素但胜在它把“流程控制”从“业务逻辑”里彻底剥出来了。比如在首版实现里我定义了四个状态requirement_parsing、architecture_design、code_implementation、review_check。Paseo 只管这四个状态的流转谁在哪个状态干活是注册在案的事状态怎么跳转是 Beads 链路的返回结果决定的。这样后续如果要加一个测试 Agent不需要改 Paseo 的主流程只需要新增一个执行者角色和一条跳转规则。2.2 Beads流水线上的一颗颗珠子Beads 解决的是另一个问题任务拆解和数据契约。它把整个软件开发任务拆成一串珠子——每个珠子是一个有明确输入输出格式的处理节点一个珠子的输出经过序列化和校验传给下一个珠子。为什么叫 Beads因为它的使用方式确实像穿珠子你定义每一颗珠子的进料口和出料口然后按照顺序把它们串起来数据就像线一样从第一颗流到最后一颗。如果某颗珠子发现进来的数据格式不对它会直接卡住不会把问题带到更下游。在实际项目里Beads 的节点可能就是一段普通函数但它被标记后就有了“校验层”和“上下文”概念。例如一个 code_implementation 珠子输入约定是“技术方案 需求文档”输出约定是“代码 diff 变更文件列表”。如果上游传进来的数据里没有 tech_design 字段珠子在真正调用模型之前就会报错。这种契约式的前置校验是整个链路不失控的关键。2.3 为什么是它们俩组合而不是一套全家桶也有人问我那些全家桶框架也有 Agent、Tool、Chain 的概念为什么不直接用我的回答是全家桶的问题在于抽象层级太多我想要的恰恰是足够少的抽象足够明确的边界。Paseo 和 Beads 的分工其实只有一句话Paseo 管“人”谁来做Beads 管“事”做什么、做完给谁。这两个关注点如果混在一个框架里初期看不出问题等团队规模一上来改调度逻辑会牵动数据逻辑改数据逻辑又会碰调度逻辑两边互相踩脚。拆开之后团队扩人就是给 Paseo 加执行者流程调序就是给 Beads 换排列互不干扰。当然这套组合也不是没有代价。Paseo 的状态管理和 Beads 的契约校验都需要自己定义和配置这比用全家桶的默认能力要多花不少心思。但这部分心思花得很值因为软件开发 Agent Team 里最重要的恰恰是“你对流程有多少控制力”而不是“框架替你做了多少假设”。3. 我设计的第一个 Agent Team四个角色加一条回流链路3.1 团队里坐着一个需求解析官、一个架构师、一个编码员和一个挑刺的首版团队我压到了四个角色没有更多。需求解析 Agentrequirement_parser输入是一段很模糊的用户需求输出是一份结构化的任务书包含目标、范围、取舍、验收标准。这个角色的价值在于它把“模糊”挡在团队入口后面三个 Agent 拿到的都是规整输入。架构设计 Agentarchitecture_designer基于任务书输出技术方案包括模块拆解、数据模型、接口签名、依赖选型。它必须给出“编码 Agent 只需要照着实现”的信息量而不是一句“建议使用标准库”。编码 Agentcode_writer按技术方案产出代码 diff并附一段实现说明说清楚自己改了哪些文件、为什么这么改、哪里是风险点。审查 Agentcode_reviewer接收代码 diff、技术方案和测试输出输出结构化的问题清单每条问题带严重级别blocker / major / minor并给出最终结论通过或打回。光看这个列表你可能觉得没什么特别的但真正有价值的不是角色列表本身而是每个角色的输出契约怎么定。我一开始犯的错就是把角色定义得太“软”比如“编码 Agent 负责写代码”结果它输出的东西五花八门——有只写思路的有直接改文件的有把代码和解释混在一大段文本里的。后来我把每个角色的输出都做成了固定 JSON 结构审查 Agent 的输出尤其严格必须逐条列问题。3.2 数据在 Beads 链路上怎么流一份任务书引发的旅程首版链路上有四颗珠子对应四个角色外加一个 review_fix 回流机制。拿一个实际需求举例。用户说“我想给项目里的 stats.py 加一个函数读取 JSON 文件并返回结构化统计数据格式要和现有 config.py 里的约定一致。”第一颗珠子 requirement 把这句话解析成任务书输出大概长这样{ goal: add_stats_function, target_file: stats.py, user_input: ..., acceptance_criteria: [ uses load_json config convention, returns typed dataclass StatsResult, must pass existing tests ], ambiguities: [是否需要支持增量统计待确认] }第二颗珠子 design 拿着任务书输出技术方案。第三颗珠子 implement 输出代码 diff。第四颗珠子 review 输出审查结果。如果 review 结论是 needs_fix系统会把“问题清单”作为额外输入拼到编码 Agent 的下一轮上下文里并且把 Beads 的流转指针拨回 implement而不是继续往下走。这就是回流链路也是整个 Agent Team 最核心的质量兜底。实际跑下来回流机制确实抓住了真问题。比如审查 Agent 发现编码 Agent 直接 json.load 没有处理解码异常对照验收标准又发现它没有遵循 config.py 里已有的错误处理模式。打回之后编码 Agent 再交付的版本确实规范了很多。单独让一个 Agent 一次性生成走到这一步的难度要大得多。3.3 Paseo 怎么把这一切“演”起来Beads 管住了数据流但数据流不会自己动。让它动起来的是 Paseo 的编排逻辑。在 Paseo 里我把每一次软件开发任务建模为一个 workflow 实例workflow 内部维护当前节点、历史节点和全局上下文。整个流程的状态迁移逻辑用伪代码来表达大概是这样当 review_result 是 approved进入完成态是 needs_fix回到 implement 状态并携带问题清单是 needs_more_info跳回 requirement 状态。这样一个状态机构成了整个 Agent Team 的“中枢神经”。需要特别强调的一点是人工介入点。我不信任全自动的 Agent 团队所以在 Paseo 的 workflow 里我留了两个人工 gate一个是任务书确认点需求解析完了我先看一眼任务书对不对另一个是最终合并代码前的审查确认点。这两个 gate 意味着即使自动流转出了岔子人也来得及踩刹车。首版实测里这两个 gate 至少帮我拦下了一次完全跑偏的方案设计。4. 从空目录到第一个端到端 Demo完整的落地记录4.1 环境准备比想象中省事比想象中挑剔开始之前先说明一下我下面的安装和调用方式是在我这边的环境里基于两个工具给我的默认行为做了一层薄封装之后的样子主要是为了方便团队统一使用。核心思想不变如果你直接看官方默认接口思路是一样的。环境上我用了 Python 3.10 起底。Paseo 和 Beads 都以 pip 包形式安装pip install paseo beads 就能拉下来。然后需要一个工作目录我起名叫 agent_team_demo里面建了 agents、beads、workflows、outputs 四个子目录分别放 Agent 定义、珠子定义、流程编排和产物输出。模型 API 的密钥是绕不开的。我在项目根目录放了一个 .env里面是密钥和 base_url 配置。注意两个工具本身不绑定具体模型厂商Agent 的“大脑”是我们在 Paseo 注册时指定的。这一步别偷懒把 base_url 配错或者密钥过期报错信息不会太友好排查起来容易上头。4.2 先用 Beads 把四颗珠子穿起来我习惯先把数据流定义好再回头管 Agent。首版的四颗珠子定义在我的封装下长这样from beads import bead bead(namerequirement, input_schemaUserPrompt, output_schemaRequirementDoc) def requirement_bead(prompt: str) - dict: return llm_call(...) bead(namedesign, input_schemaRequirementDoc, output_schemaTechDesignDoc) def design_bead(task: dict) - dict: return llm_call(...) bead(nameimplement, input_schemaTechDesignDoc, output_schemaCodeDiff) def implement_bead(design: dict) - dict: return llm_call(...) bead(namereview, input_schemaCodeDiffTechDesignDoc, output_schemaReviewResult) def review_bead(diff: dict, design: dict) - dict: return llm_call(...)这段代码看着简单但两个坑我是在写的时候就踩了。第一input_schema 必须和上游 output_schema 严格对应我一开始把 design 珠子输出里叫 tech_design下游 implement 珠子输入却写成了 design_doc结果链路跑到一半直接校验失败报错信息指向性很强但排查也花了我十分钟。第二每个珠子的输出必须是可 JSON 序列化的纯数据不能有对象引用、不能有大段二进制否则链路没法把数据传给下一个珠子。4.3 再用 Paseo 把“人”注册进去珠子穿好了接下来在 Paseo 里注册四个 Agent并把它们绑定到对应的珠子上。这里有个细节一个珠子可以换不同的 Agent 来执行。Paseo 提供了一种绑定机制让 workflow 在进入某个状态时去查找“当前谁负责这个珠子”。from paseo import Agent, Workflow requirement_agent Agent( namerequirement_parser, rolerequirement_analyst, modelyour-model-name, system_prompt_pathprompts/requirement_parser.md, ) design_agent Agent(...) implement_agent Agent(...) review_agent Agent(...) workflow Workflow(dev_agent_team, hooks{...})workflow 的 hooks 是我比较喜欢的设计。我可以在珠子执行前、执行后、以及整个流程结束时挂回调函数。比如我在“编码珠子执行之后”挂了一个回调自动把产出的 diff 写入 outputs/current.diff这样不管流程怎么流转我随时能看到当前最新代码变更。这不是无关紧要的贴心功能——在调试 Agent 团队的行为时能随时翻出中间产物效率是完全不一样的。4.4 跑第一个最小闭环给它一个加了类型注解的小任务环境就绪后我给的第一个端到端任务很小“给 stats.py 中已有的 load_stats 函数补充完整类型注解并确保现有测试 test_stats.py 仍然通过。”第一轮跑完流程表现如下需求解析 Agent 输出任务书把验收标准归纳为三条其中有一条是“注解使用现有类型别名 StatsDict”。这个信息是用户原始输入里没有的是它从项目代码里读出来的这一步让我觉得值回票价。设计 Agent 给出方案直接用 typing 的方式定义返回类型并指出 load_stats 的返回值目前是字典建议保持兼容包一层。编码 Agent 按时交付 diff改动符合预期。审查 Agent 首次结论是 needs_fix指出了一个 minor 问题函数内部有个变量 raw 没有注解属于漏网之鱼。整个流程从开始到结束大概用了 90 秒中间没有人工介入。我检查了审查 Agent 提的问题确实是一个真实的遗漏。这个 Demo 虽然没有挑战什么高难度任务但它证明了“四个角色 一条回流链路”的骨架是能转起来的。5. 首版实测踩过的三个坑每一个都值得写进团队规则5.1 上下文越滚越大传到后面 Agent 已经“缺氧”第一个坑来得很快。链路前两个珠子跑完任务书和设计方案已经在全局上下文里了等编码珠子要调用模型时我拼进去的上下文已经很长——包括原始需求、解析出的任务书、技术方案、几轮对话历史。模型的输出质量肉眼可见地下降开始出现低级错误。根因不是模型的问题而是我违背了 Beads 设计的初衷珠子之间只传“当前步骤需要的最小数据”而不是把前面所有中间产物一股脑往下传。解法也很直接。我在每个珠子的输入 schema 里只宣告必要字段其他历史信息统一进 Paseo 的上下文存储但不进模型的 prompt。比如编码珠子只拿 tech_design、target_file、acceptance_criteria 和文件内容不拿原始需求全文。这样就砍掉了大量冗余。5.2 口头约定靠不住设计说 4001编码实现成了 40001第二个坑属于契约纪律问题。设计 Agent 在技术方案里写“认证失败时返回错误码 4001同时在响应体里附带原因”编码 Agent 的代码里写的是 40001。更麻烦的是审查 Agent 没看出来因为二者只差一个字符模型在快速浏览时很容易认为是同一回事。这件事让我意识到Agent 之间的协作不能依赖自然语言里的“看起来对”必须有机器可校验的契约。所以我改了两件事一是让设计珠子的输出里必须包含一个 api_protocol 字段字段值是严格的 JSON 格式编码珠子读取这个字段而不是读自然语言二是加了中间校验节点比较最终代码里出现的 status_code 与设计文档里的 status_code 是否一致不一致直接判 return。5.3 审查 Agent 也会放水而且放水方式特别隐蔽第三个坑最要命。前几轮跑下来我发现审查 Agent 的“打回率”低得不正常几乎每次都 approve。一开始我以为是自己方案设计得好后来才反应过来编码 Agent 和审查 Agent 用的是同一个模型而且我给的审查 prompt 语气还是“请检查是否存在问题”。同一个模型在同一套语境下很容易对自己“刚才的产出”持宽容态度——它不是故意放水而是缺乏独立视角。对策分三层。第一审查 Agent 换用了一个参数配置不同的模型实例温度更高语境更“挑剔”。第二审查 Agent 的 prompt 里强制要求输出问题清单并且规定“如果找不出问题必须逐条对照验收标准说明为什么没有问题”而不是简单说一句“看起来可以”。第三也是最重要的一层我把审查珠子改成了“审查 测试执行”珠子审查 Agent 除了读代码还必须执行一次目标项目的测试命令并输出测试结果。模型可以放水测试不过就是不过这条铁证绕不开。坑现象根因现在团队规则上下文爆炸链路越长输出越差中间产物全塞进 promptBeads 只传最小契约字段口头契约失效设计 4001 实现 40001依赖自然语言传递协议关键协议字段单独 schema 校验审查放水打回率低得不正常同一模型缺少独立视角换模型实例 强制输出问题清单 测试执行节点6. 这篇先到这下一篇我要收拾的三件事读完前面你应该有个感觉这套 Agent Team 能跑但离“好用”还差得远。我完全同意因为首版跑通的只是“单条链路 单轮回流”的最简形态。接下来我打算解决的问题基本都围绕着一个目标让它更快、更省、更不容易被模型的主观性带偏。6.1 并行化让珠子学会分叉再学会汇合现在设计 Agent 输出的技术方案如果涉及三个相互独立的模块编码珠子会串行写三遍非常慢。我下一步打算在 Beads 层支持“分支珠子”一个珠子拆出多个并行珠子各自负责一个模块等全部完成后在汇聚点合并再统一进入审查珠子。这能显著压缩端到端耗时但代价是并发状态的管理更复杂需要 Paseo 的 workflow 状态机配合做分批等待。6.2 把“测试执行”从建议变成节点我在第三个坑里给审查珠子加了测试执行但那是调外部命令的方式目前硬编码了 pytest。下一步我想把测试变成独立的测试 Bead让它被不同 Agent 复用也能在回归时只执行增量测试。这样审查这个动作就不再依赖某次 prompt 的心情——它有一个兄弟节点负责提供“客观证据”审查 Agent 只是把证据读进结论里。6.3 局部重跑别让上游的好东西白白作废现在如果审查打回编码珠子会重新调用一次模型但上游的任务书和技术方案其实没变这些产物完全可以缓存复用。把“哪些步骤的产物还能复用”这件事想清楚之后重跑的成本能下降不少对模型 token 的消耗也更友好。这是我在写第二篇之前最想先解决的工程问题。这三个问题升级完之后我大概率会把这套 Agent Team 用到真实项目里看看它在更复杂的需求面前还能不能顶住。到那时候再回来写这个系列的第二篇。