你让 Agent 升级遗留服务、补齐测试、检查安全风险。几分钟后,屏幕上出现多个忙碌的子 Agent:有人读代码,有人改依赖,有人跑测试,有人写迁移说明。终端不断滚动,很像一支高效率的研发团队。 两个小时后,真正的问题才开始出现:哪个 Agent 改过公共配置?谁能证明测试覆盖了迁移风险?安全 Agent 的高危发现为什么没有阻止合并?两个 worktree 同时碰到一个接口,谁决定最终语义?外部调用超时后,系统应该重试、查询还是暂停? 这不是模型能力问题,而是研发系统问题:**任务如何表示,权限如何约束,结果如何验证,异常如何升级。**虚拟研发小队不是同时打开几个聊天窗口,而是一套有任务分解、职责边界、工件交接、质量门禁和最终责任人的生产系统。本文不比较框架,只拆解让多 Agent 真正可控的工程底座。 ## 一、先纠正一个误解:研发小队不是聊天群,而是一套生产系统 一个多人聊天群的典型特征是:每个人都能发言、都可以提出建议、谁也不对最终结果负责。很多多 Agent 原型恰好如此。主 Agent 把任务发给几个子 Agent,收集几段自然语言回复,然后再让另一个 Agent “综合一下”。流程看起来有分工,实际上没有可执行的责任边界。 研发小队则不同。它处理的不是“谁的回答更漂亮”,而是“哪个工作单元已经满足验收条件、哪个工作单元被阻塞、哪个动作不被允许、哪个失败必须由人决定”。 因此,多 Agent SWE 的第一原则是: > **Agent 之间传递的核心对象不应是对话,而应是带状态、带约束、带验收条件的 Task。** 对话可以无限延续,Task 必须有生命周期。一个合格的 Task 至少包含:目标、输入、依赖、允许操作、预算、验收条件、当前状态、产生的工件和责任归属。没有这些字段,“任务已完成”只是一句模型生成的文本;有了这些字段,它才可以被机器调度、被人审计、被失败恢复。 把系统拆开看,虚拟研发小队至少包含四个平面。 - **任务平面**:把目标拆成有依赖关系的 Work Unit,决定谁能开始、谁必须等待。 - **执行平面**:在隔离环境里运行 Agent、命令、测试和工具调用,收集标准化结果。 - **治理平面**:决定每个角色可读什么、可写什么、最多花多少预算、哪些动作必须人工批准。 - **证据平面**:保存 diff、测试输出、扫描报告、日志、审批记录和最终决策,支撑验收与追溯。 这四个平面缺任何一个,系统都会走向熟悉的两种极端:要么 Agent 被限制得只能做演示,无法完成实际工作;要么 Agent 权限过大、过程不可见,最后谁都不敢合并它的产物。  这个结构里,模型并不位于中心。模型只是执行平面中的一个决策组件。真正决定系统能否被托付的,是任务、策略和证据三者构成的外壳。 ## 二、任务图:先把依赖画出来,再谈并行 “任务分解”常常被误写成一段 checklist:先分析、再改代码、再跑测试、最后写文档。它当然比没有计划好,但对多 Agent 来说远远不够。 多 Agent 需要的是**任务图(Task Graph)**。图中的每个节点是一个可独立调度的 Work Unit,边表示依赖、阻塞或信息流。只有当一个节点的输入准备充分、权限满足、前置验收通过时,它才会从等待状态进入可执行状态。 例如,升级某个后端框架时,“修改依赖版本”和“确认弃用 API 的调用点”看似可以并行,实际上后者的输出很可能决定前者需要改哪些适配层;“补充迁移测试”又应以接口兼容策略为输入。如果没有图,调度器只能靠 Agent 自己猜什么时候该开始,最后不是反复返工,就是把不完整结论当作事实传下去。 一个好的 Task Graph 不是越细越好。节点过大,无法隔离与验收;节点过小,交接成本超过实际工作。判断粒度时,可以问四个问题: - 这个节点能否用一句明确的完成条件描述? - 它是否有稳定、可枚举的输入? - 它是否会修改别人正在修改的同一份语义? - 它失败时,能否定位到一个人或一个角色来处理,而不是把整张图打回重来? 如果前两个问题答不上来,说明需求还不清楚;如果第三个问题是“会”,说明需要串行化或设置文件/领域所有权;如果第四个问题答不上来,说明系统缺少升级策略。 任务节点建议使用结构化契约,而不是纯自然语言。下面是一个足够小、但已经能支撑工程协作的示例: ```json { "task_id": "upgrade-api-client-tests", "goal": "为新 API client 补齐超时和重试行为的回归测试", "inputs": ["migration-plan-v2", "api-client-contract"], "allowed_paths": ["tests/api_client/**"], "forbidden_actions": ["modify production credentials", "merge branch"], "acceptance": ["pytest -q tests/api_client", "coverage delta >= 0"], "artifacts": ["patch", "test_report", "assumptions"], "owner_role": "test-engineer", "budget": {"max_turns": 8, "max_minutes": 20} } ``` 注意这里的 `allowed_paths` 与 `forbidden_actions`。它们不是为了限制 Agent 的想象力,而是为了让失败的影响半径保持可控。一个只负责测试的工作单元,不该顺手改生产鉴权;一个只负责探索的工作单元,不该获得合并权限。  这张状态机有一个很重要的含义:**“Agent 说自己完成了”并不对应 `Accepted`。**它最多意味着工作单元从 `Running` 进入 `Verifying`。只有自动验证通过,或人工确认通过,任务才能被接受。 ## 三、worktree 与沙箱:隔离的是文件状态,不是责任 一提到多 Agent,很多人马上想到 Git worktree。这个方向没错,但也很容易停在表面。 Git worktree 的直接作用,是让同一个仓库同时拥有多个独立工作目录。每个 Agent 都可以在自己的目录和分支中修改、测试、回退,不会把未完成改动直接污染主工作区。这对并行试验、独立补丁和差异审阅极其有用。 但 worktree 只解决了“文件状态不要互相踩踏”。它没有自动解决四个更难的问题:两个分支是否修改了同一个业务不变量;测试是否依赖共享数据库;Agent 是否能读取不该读的密钥;哪个补丁应该被合并、以什么顺序合并。 因此,worktree 应当被放入更完整的隔离模型里: - **代码隔离**:每个可写 Work Unit 使用独立分支和 worktree,禁止直接修改主分支。 - **运行隔离**:构建、测试和工具调用尽量在容器或沙箱中进行,依赖版本和环境变量可复现。 - **数据隔离**:默认使用 fixture、脱敏副本或临时数据库;禁止多个 Agent 同时操作真实、不可回滚的数据。 - **网络隔离**:默认最小出网,外部 API、包下载、生产服务访问必须显式授权并记录。 - **身份隔离**:Agent 使用短期、范围受限的凭证;不同角色不共享同一个高权限 Token。 JetBrains Air 的产品设计很直白地体现了这个趋势:它支持并发 Agent 任务,并可在 Docker 容器和 Git worktree 中隔离工作;云端隔离执行则仍处于技术预览阶段。重点不是它用了哪一种容器,而是把“每个尝试拥有自己的可回收环境”当成多 Agent 开发的基础能力。 团队实践时,建议把“写权限”划分为三档。 第一档是只读:仓库探索、依赖盘点、日志分析、代码审阅、安全检查。它们可以大规模并行,因为最坏结果通常是错误报告,而不是错误修改。 第二档是受限写入:只能改指定路径、只能在独立 worktree、必须附带测试、不能推送或合并。这适合实现 Agent 和测试 Agent。 第三档是高风险写入:修改基础设施、数据库迁移、权限规则、发布配置、外部系统。它不应由普通子 Agent 直接完成;即使 Agent 提出动作,也必须经过策略引擎和人类批准。 这比“每个 Agent 都能不能执行命令”更有用。命令执行不是一种权限,而是一组能力:读文件、写文件、联网、安装依赖、访问凭证、调用云资源、合并分支,每一项都应该单独评估。 ## 四、权限不是一个 yes/no 开关,而是一张 Action Gate 很多 Agent 系统的权限设计只有两种状态:允许工具调用,或禁止工具调用。这在聊天助手阶段尚可接受,在虚拟研发小队里却过于粗糙。 真正需要控制的是**动作(Action)**,不是抽象的“工具”。同样是 `git`,执行 `git diff` 与执行 `git push --force` 的风险完全不同;同样是数据库客户端,查询脱敏测试数据与执行生产 `DELETE` 的后果也天差地别。 因此,一个实用的 Action Gate 至少要读取以下信息: - 发起动作的角色与当前 Task。 - 动作类型、参数和目标环境。 - 当前分支、路径范围和变更规模。 - 数据敏感等级与是否存在外部副作用。 - 已用预算、重试次数和前置验证状态。 - 是否有对应的人类审批或变更窗口。 它的输出不应只有 Allow / Deny,还应包括:允许但记录、要求二次确认、降级为草稿、延迟到窗口、转人工处理。这样,Agent 才能在低风险任务上保持流畅,在高风险任务上保持克制。  这里最值得警惕的一点是“模型理解了任务,所以可以扩大权限”。这是错误的。模型可以根据上下文提出一个貌似合理的新动作,但权限扩大必须由确定性策略、明确授权或人类确认触发。否则,一份被网页、Issue 或日志污染的提示,就可能成为越权执行的入口。 还有一个常被忽略的工程细节:**高风险动作必须可对账。**例如 Agent 调用一个外部发布接口后连接超时,系统不能简单重试,因为第一次调用可能已经成功。正确的顺序通常是查询幂等键或外部状态,确认未生效后再重试;无法确认时,暂停并升级。多 Agent 越多,这类“谁到底执行过什么”的问题越不能靠聊天记录解决。 ## 五、验证器:不要让模型给自己盖“完成”印章 虚拟研发小队最容易自欺欺人的地方,是把 Review Agent 当成质量保证。 Review 很重要,但它不是最终验证。一个模型审阅另一个模型的代码,能发现命名、边界、遗漏和明显逻辑问题;它却无法替代编译器、测试、静态分析、依赖扫描、运行时监控和业务验收。尤其当实现者与评审者共享相似上下文或模型偏好时,它们容易一起忽略同一个错误前提。 更可靠的验证体系应当分层: - **确定性验证**:格式化、类型检查、编译、单元测试、集成测试、契约测试、数据库迁移 dry-run。 - **安全与治理验证**:密钥扫描、依赖漏洞检查、许可检查、危险命令检查、变更范围检查。 - **语义验证**:由独立评审 Agent 或人类根据需求、边界和反例清单检查实现是否偏题。 - **生产前验证**:灰度环境、特征开关、回滚演练、关键指标守护。 这些层级不是每个任务都要全开。重要的是,Task 契约必须明确“这个任务以什么证据证明完成”。一个补文档的任务可能只需要链接检查和人工审阅;一个涉及鉴权的改动却需要更严格的负向测试、权限差异检查和人工合并门禁。 验证器的另一个职责是把自然语言结论翻译成机器可消费的状态。不要只保存“测试通过”,还应保存测试命令、执行环境、退出码、覆盖范围、失败摘要和关联 commit。这样,当某个集成节点失败时,主控系统不需要重新问一遍“发生了什么”,而可以直接读取证据决定重试、修复还是升级。 LangGraph 的 evaluator-optimizer 工作流展示了一种有用的控制形态:生成者产出候选结果,评估者给出结构化反馈,条件边决定通过、回到生成还是结束。把它用于代码 Agent 时,评估者应当尽可能绑定外部验证结果,而不是只凭“看起来合理”评分。后续第三篇会把这个闭环展开。 ## 六、可观测性:你要看到任务如何失败,而不只是看到它“在工作” 多 Agent 的可观测性,经常被误做成一个漂亮的调用瀑布图:哪个 Agent 调了哪个模型,花了多少 Token,耗时多久。这些数据有价值,但它们只回答“系统有多忙”,没有回答“系统为什么可靠或不可靠”。 一支可运营的虚拟研发小队,至少需要同时观测四条链。 第一条是**任务链**:Task 从创建到接受经历了哪些状态,卡在哪个依赖、哪个重试、哪个人工审批。 第二条是**工件链**:每个结论引用了哪些代码、日志、测试结果和文档;每个 patch 来自哪个 worktree;最终合并的 commit 对应哪些验证报告。 第三条是**权限链**:哪些动作被允许、拒绝、降级或要求审批;一次性凭证何时签发、何时失效;是否出现越界尝试。 第四条是**成本与质量链**:每种任务的耗时、Token、工具调用、人工退回率、测试失败率、合并冲突率和线上回滚情况。 这四条链一旦断开,排障就会退化成读聊天记录。更糟的是,多 Agent 系统里一个错误结论可能被下游多个节点复用;如果没有工件溯源,你很难确定到底应该修复实现、更新规则、重跑哪个节点,还是撤销整条任务链。 所以,记录每次调用的完整 prompt 并不是最佳答案。高质量观测应该记录**决策所依据的可复核引用**,而不是无边界地保存全部上下文。这样既能提高可追溯性,也能减少敏感数据泄露与存储成本。 ## 七、人工升级与最小落地版本:给系统一个正式出口 许多团队把人工介入理解成自动化失败后的无奈补救:Agent 不会了,人才来接手。这个视角太被动。 在高质量系统中,人工升级是 Task Graph 的正式状态,是对不确定性和责任边界的尊重。它至少应该在四类情况触发: - 验收条件矛盾或需求本身不完整。 - 动作会触及生产、资金、身份、合规或不可逆外部副作用。 - 同一类验证连续失败,修复预算已经耗尽。 - 两个合法的 Work Unit 给出了互相冲突、且不能由自动证据裁决的结论。 升级给人时,最怕把一团上下文扔过来:“Agent 卡住了,请处理。”正确的升级包应包含任务目标、当前状态、已尝试动作、失败证据、影响范围、候选方案、风险、需要人做出的唯一决策,以及恢复后从哪个节点继续。 人类不应该重新阅读完整对话,更不应该猜 Agent 到底做过什么。人类应当只负责处理机器无法合法或可靠裁决的那一个关键决策。这才是“人机协作”真正节省认知负担的方式。 ### 从低风险任务开始:先做可控,再做自治 如果团队刚开始尝试多 Agent SWE,不需要先采购一个大平台。可以从下面这个最小版本开始。 第一,选一个低副作用、边界清晰的场景,例如废弃 API 扫描、依赖升级影响盘点、测试缺口发现。不要以生产故障修复或跨服务重构作为试点。 第二,用 Markdown、JSON 或 Issue 模板定义 Task 契约。只要团队还说不清“输入、允许路径、验收命令和升级条件”,就不要让 Agent 开始写代码。 第三,使用两个只读 Agent 和一个受限写 Agent:一个探索代码,一个生成反例/测试清单,一个在独立 worktree 中做小范围实现。所有写入都需要测试证据,所有合并都由人或固定集成节点完成。 第四,给每个任务加上预算与中止条件。限制轮数、时间、可修改文件、命令白名单和外部访问。不要指望模型“自己知道什么时候停”。 第五,把任务状态、diff、验证输出和人工决定写入统一位置。先让系统可回放、可审阅、可追责,再逐步增加自治程度。 这条路径看起来没有“十六个 Agent 自动写完整产品”那么酷,但它更接近工程现实。真正能长期运行的系统,几乎都先把边界和证据做扎实,再把自动化范围一点点推开。 ## 结语:虚拟研发小队的核心不是分工,而是责任可落地 多 Agent SWE 不是把一个开发者拆成多个聊天人格。它是一种把研发流程显式化的方式:让任务有图、执行有隔离、动作有权限、结果有验证、过程可观测、异常能升级。 当这些底座缺位时,多 Agent 只是并行生成更多文本;当它们到位时,Agent 才能成为受约束的工作单元,承担探索、测试、实现和审阅中的一部分责任。 把本文收束成一句话: > **没有任务图、权限边界和独立验证器的多 Agent,不是虚拟研发小队,只是一场成本更高、责任更模糊的群聊。** 下一篇,我们把这些底座压缩成一个最小的 LangGraph 闭环:`plan -> implement -> test -> review -> repair(max 2) -> human merge`。重点不在于让模型反复“自我反思”,而在于让每次重试都由测试和结构化反馈驱动,并且在该停的时候把接力棒交给人。 ### 参考资料 - [Git:git-worktree 文档](https://git-scm.com/docs/git-worktree) - [JetBrains:Air Launches as Public Preview](https://blog.jetbrains.com/air/2026/03/air-launches-as-public-preview-a-new-wave-of-dev-tooling-built-on-26-years-of-experience/) - [GitHub Docs:Custom agents and sub-agent orchestration](https://docs.github.com/en/copilot/how-tos/copilot-sdk/features/custom-agents) - [GitHub Docs:About custom agents in Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-custom-agents) - [LangGraph:Workflows and agents](https://docs.langchain.com/oss/python/langgraph/workflows-agents)