并行探索:让多个代理独立研究再汇总
TL;DR: 并行探索适合大任务的前期判断。让多个 subagent 分别研究不同方向,再由主会话整合方案。并行会增加总 token 消耗,但显著减少挂钟时间。关键前提:任务必须能拆成相互独立的问题。
问题
大型改造开始前,最耗时的是理解:哪些模块相关、现有模式是什么、风险在哪里、测试怎么跑。一个会话串行探索会慢,也容易遗漏。
但串行探索有一个不容易注意到的隐性成本:上下文污染累积。在主会话里连续探索 5 个模块,前 3 个模块的探索细节会和后 2 个模块的实现需求混在一起。到真正开始写代码时,上下文里塞满了探索阶段的只读信息,留给推理和实现的空间不足。
还有一个更容易忽略的问题:认知疲劳。主会话在连续探索第 4 个模块时,对前面 3 个模块的细节记忆已经开始模糊。它可能重复读取已经看过的文件,或者遗漏和前面模块的关联。这不是模型能力的问题——任何上下文窗口都有信息密度的极限。探索的内容越多,每条信息的平均"注意力权重"就越低。
并行探索的核心思路:把探索任务拆给多个独立 subagent,每个 subagent 只关注一个方向,在自己的上下文里完成探索。主会话只接收精炼后的结果。
但并行不是银弹。它有自己的成本结构:总 token 消耗更高(每个 subagent 都有独立的上下文初始化开销),结果整合需要额外的工作(去重、合并、冲突解决),而且不是所有任务都能拆成独立子任务。并行探索的前提是每个子任务之间确实没有依赖——如果子任务 A 的结果影响子任务 B 的搜索方向,那就不能并行,只能串行。
并行派发架构
基本模型
主会话
├─ 派发任务 A → Subagent Alpha(独立上下文)→ 返回结果 A
├─ 派发任务 B → Subagent Beta(独立上下文)→ 返回结果 B
├─ 派发任务 C → Subagent Gamma(独立上下文)→ 返回结果 C
└─ 汇总 A + B + C → 形成完整方案
主会话的角色从"执行者"变成"编排者":定义问题、拆分任务、派发代理、汇总结果。它不需要亲自读文件、搜代码——这些脏活由 subagent 在各自的上下文里完成。
派发格式
主会话向每个 subagent 发送明确的问题描述:
给 Explorer A 的任务:
"查找用户认证相关的所有文件。关注:
1. 认证中间件的实现位置和调用方式
2. Session/Token 的存储和验证逻辑
3. 权限校验的调用链
返回:文件清单、调用链图、已知模式"
给 Explorer B 的任务:
"查找数据模型层与用户相关的所有文件。关注:
1. User 模型的字段定义和关联关系
2. 用户数据的读写路径
3. 数据库 migration 历史
返回:数据模型图、读写路径、最近的 schema 变更"
给 Reviewer C 的任务:
"审查当前认证系统的安全风险。关注:
1. Token 验证是否有绕过可能
2. 密码存储方式
3. Session 管理的安全性
返回:风险清单(按严重度排序)"
关键:每个任务描述都包含关注点和期望输出格式。这确保 subagent 返回的结果可以被主会话直接使用,而不需要二次加工。
真实场景:权限系统改造的前期探索
需求描述
"给现有系统添加角色权限控制。当前只有简单的登录/未登录区分,需要支持多角色、多权限。"
这个改造涉及业务逻辑、数据模型、安全风险、测试覆盖四个方向。主会话同时派发四个 subagent 并行探索:
主会话 → Explorer A(业务逻辑层)
"查找所有涉及权限判断的业务代码。当前系统如何区分已登录/未登录?
哪些 API 有权限检查?哪些没有?返回文件清单和权限检查分布图。"
主会话 → Explorer B(数据模型层)
"查找用户相关的数据模型。User 表结构、关联表、数据库 migration。
返回 ER 图(文字描述)和最近的 schema 变更。"
主会话 → Reviewer C(安全风险评估)
"审查当前认证和授权实现的安全风险。Token 管理、Session 处理、
密码存储、权限绕过可能。返回风险清单。"
主会话 → Explorer D(测试覆盖现状)
"查找认证和权限相关的测试文件。哪些行为有测试覆盖?哪些没有?
测试框架和运行方式是什么?返回覆盖度评估。"
各代理返回的典型结果
Explorer A(业务逻辑层):
### 文件清单
| 文件 | 作用 | 权限检查 |
|------|------|---------|
| src/middleware/auth.ts | 认证中间件 | ✓ 检查 token |
| src/routes/api.ts | API 路由定义 | 部分,只有 /admin 有检查 |
| src/routes/user.ts | 用户路由 | 无权限检查 |
| src/routes/order.ts | 订单路由 | 无权限检查 |
| src/services/user.ts | 用户服务 | 无权限逻辑 |
### 现有模式
- auth.ts 导出 requireAuth 中间件
- 只有 /admin/* 路由使用了 requireAuth
- 其他所有路由都没有权限检查
- 已登录判断靠 token 解析后挂到 req.user
### 发现的问题
- /api/user/:id 可以访问任意用户数据(无权限检查)
- /api/order 列表返回所有订单(无过滤)
Explorer B(数据模型层):
### User 模型
| 字段 | 类型 | 说明 |
|------|------|------|
| id | UUID | 主键 |
| email | VARCHAR(255) | 唯一 |
| password_hash | VARCHAR(255) | bcrypt |
| role | VARCHAR(20) | 'user' 或 'admin' |
| created_at | TIMESTAMP | 创建时间 |
### 关联表
- orders: user_id -> users.id(一对多)
- sessions: user_id -> users.id(一对多)
### 模式发现
- role 字段已存在但只在 /admin 路由检查
- 没有权限表(permissions table)
- 没有角色-权限关联表(role_permissions)
### 最近变更
- 2024-11: 添加 role 字段(只有 'user' 和 'admin')
- 2024-09: 添加 sessions 表
Reviewer C(安全风险评估):
| 严重度 | 问题 | 位置 |
|--------|------|------|
| blocker | 任意用户数据访问 | /api/user/:id 无权限检查 |
| blocker | 订单数据越权 | /api/order 无用户过滤 |
| warning | Token 无刷新机制 | auth.ts 只检查过期,不刷新 |
| warning | Session 无并发控制 | 同一用户可无限 session |
| suggestion | 密码策略弱 | 注册时无密码强度检查 |
Explorer D(测试覆盖现状):
### 测试框架
- Vitest + Supertest
- 运行: npx vitest
### 认证测试覆盖
| 场景 | 有测试 | 文件 |
|------|:------:|------|
| 登录成功 | ✓ | tests/auth.test.ts |
| 登录失败(错误密码)| ✓ | tests/auth.test.ts |
| Token 过期 | ✓ | tests/auth.test.ts |
| 未登录访问受保护路由 | ✓ | tests/auth.test.ts |
| 越权访问其他用户数据 | ✗ | - |
| 管理员操作权限 | ✗ | - |
| 角色变更 | ✗ | - |
### 覆盖度评估
- 认证流程覆盖良好(4/4 基础场景)
- 授权场景完全缺失(0/3 关键场景)
- 需要新增权限相关测试文件
主会话的汇总
四个 subagent 的结果汇总后,主会话形成了清晰的改造方案:
1. 数据层:扩展 User.role 为多角色,新增 permissions 和 role_permissions 表
2. 业务层:将 requireAuth 扩展为 requireRole(role) 和 requirePermission(perm)
3. 安全层:先修两个 blocker(越权问题),再改造权限系统
4. 测试层:新增 tests/authorization.test.ts,覆盖越权和角色场景
5. 风险:改造需要分两阶段——先修安全漏洞,再做权限系统扩展
整个探索过程并行完成。如果串行执行,每个方向需要 3-5 分钟,总计 12-20 分钟。并行后,总挂钟时间取决于最慢的那个 subagent,通常 4-6 分钟。
结果整合策略
信息合并
多个 subagent 返回的结果可能有重叠或互补。整合策略:
1. 去重:多个代理引用了同一文件,只保留描述最完整的那个
2. 互补:Agent A 说了"文件作用",Agent B 说了"文件依赖",合并为完整描述
3. 冲突:如果两个代理对同一文件的描述矛盾,主会话亲自验证
4. 排序:按改造优先级排序所有发现(安全漏洞 > 数据模型 > 业务逻辑 > 测试)
冲突解决
当两个 subagent 的发现互相矛盾时:
场景:Explorer A 报告"/api/order 有权限检查"
Explorer B 报告"/api/order 没有权限检查"
解决步骤:
1. 主会话亲自读取 /api/order 路由文件
2. 确认实际情况(可能一个看了旧版本,一个看了新版本)
3. 以主会话的直接观察为准
原则:subagent 的结果是"初步发现",不是"最终结论"。
冲突时,主会话亲自验证。
Token 成本对比
并行 vs 串行的 token 消耗对比:
场景:权限系统改造的 4 方向并行探索
并行模式(4 个 subagent):
Explorer A: ~3,500 tokens(独立上下文)
Explorer B: ~2,800 tokens(独立上下文)
Reviewer C: ~2,200 tokens(独立上下文)
Explorer D: ~3,000 tokens(独立上下文)
主会话汇总: ~1,500 tokens(读结果 + 推理)
──────────────────────────
总 token: ~13,000 tokens
挂钟时间: ~5 分钟(取最慢的)
主会话上下文: 只占 ~1,500 tokens(结果摘要)
串行模式(主会话逐一探索):
探索业务逻辑: ~3,500 tokens
探索数据模型: ~2,800 tokens
探索安全风险: ~2,200 tokens
探索测试覆盖: ~3,000 tokens
──────────────────────────
总 token: ~11,500 tokens
挂钟时间: ~15 分钟(串行执行)
主会话上下文: ~11,500 tokens(全部探索细节)
对比结论:
| 指标 | 并行 | 串行 | 差异 |
|---|---|---|---|
| 总 token | ~13,000 | ~11,500 | 并行多 ~13% |
| 挂钟时间 | ~5 分钟 | ~15 分钟 | 并行快 ~67% |
| 主会话上下文占用 | ~1,500 | ~11,500 | 并行省 ~87% |
| 信息遗漏风险 | 低(多视角) | 高(认知疲劳) | 并行更全面 |
关键洞察:并行的 token 开销比串行多,但主会话上下文占用大幅减少。总 token 多出的 ~13% 是 subagent 的独立上下文开销。但主会话只接收摘要,上下文从 ~11,500 降到 ~1,500。这意味着主会话有更多空间用于后续的实现和推理。
什么时候 token 多花是值得的:当主会话的上下文空间是瓶颈时(复杂任务需要大量推理),并行探索的上下文节省比总 token 开销更重要。典型场景是大型改造:前期探索需要读几十个文件,但后续实现需要在清晰的上下文里做复杂推理。如果探索阶段把主会话上下文塞满了,实现阶段的质量会显著下降。
什么时候不值得:当探索任务很简单(只需要读 2-3 个文件),并行调度的固定开销(subagent 创建、上下文初始化、结果传输)可能比任务本身还大。或者当后续实现很简单(不需要大量推理),主会话上下文压力不大,节省上下文空间的收益微乎其微。
还有一个隐藏的权衡:结果整合的认知成本。并行探索返回多份结果,主会话需要花精力理解每份结果、找出重叠和冲突、合并成统一视图。这个整合过程本身消耗注意力和上下文空间。如果并行返回的信息量很大、冲突很多,整合成本可能抵消并行带来的上下文节省。
故障隔离
并行探索的一个重要特性:一个 subagent 失败不会阻塞其他 subagent。
场景:4 个并行 subagent
Explorer A: 正常完成 → 返回结果
Explorer B: 正常完成 → 返回结果
Reviewer C: 超时/出错 → 返回错误信息
Explorer D: 正常完成 → 返回结果
主会话收到:
- A、B、D 的完整结果
- C 的错误信息
处理方式:
1. 基于 A、B、D 的结果继续工作
2. 安全风险评估由主会话自行补充(用已有的代码结构信息)
3. 标记安全审查为"待补充"
不会因为 Reviewer C 失败而整个探索流程卡住。
这比串行探索更健壮。串行探索中,如果第三步的安全审查超时,后续的测试覆盖探索也无法开始。
决策矩阵:并行 vs 串行 vs 主会话
任务特征评估:
1. 任务是否能拆成 3+ 个独立问题?
是 → 考虑并行
否 → 串行或主会话
2. 探索结果是否会污染主会话上下文?
是(大量文件、长日志)→ 并行
否(少量文件、短输出)→ 主会话
3. 探索时间是否是瓶颈?
是(挂钟时间 > 10 分钟)→ 并行
否(挂钟时间 < 3 分钟)→ 主会话
4. 各子任务之间是否完全独立?
是 → 并行
有依赖 → 串行
5. 探索后的实现是否需要大量主会话上下文?
是(复杂推理)→ 并行(省上下文给实现)
否(简单修改)→ 主会话
| 场景 | 并行 | 串行 | 主会话 |
|---|---|---|---|
| 大型改造前期探索 | ✓ | ||
| 多方向技术调研 | ✓ | ||
| 安全 + 性能并行审查 | ✓ | ||
| 中等需求,3-5 个文件 | ✓ | ||
| 有依赖的多步分析 | ✓ | ||
| 小 bug fix,1-2 个文件 | ✓ | ||
| UI 调整,需要看浏览器 | ✓ | ||
| 简单问题,Google 就能回答 | ✓ |
并行 Subagent 故障隔离模式
并行探索的一个核心工程优势是故障隔离——单个 subagent 失败不会阻塞整体流程。这里展开说明不同故障类型的隔离策略。
故障类型及处理
故障类型 1:超时
症状:某个 subagent 超过预设时间仍未返回
影响:不影响其他 subagent 的执行
处理:
- 设置每个 subagent 的超时阈值(通常 5 分钟)
- 超时后主会话标记该方向为"待补充"
- 基于已完成的其他 subagent 结果继续工作
- 后续用主会话或单独 subagent 补充缺失方向
故障类型 2:权限不足
症状:subagent 报告"无法完成,缺少 XX 工具"
影响:该 subagent 返回错误信息,其他 subagent 不受影响
处理:
- 记录权限缺失的具体情况
- 评估是否需要调整该角色的 tools 配置
- 本次用主会话补充该方向的探索
- 下次并行探索时使用更新后的配置
故障类型 3:结果质量低下
症状:subagent 返回了结果,但明显遗漏或错误
影响:不会直接阻塞流程,但整合结果时需要额外验证
处理:
- 主会话对低质量结果进行二次验证
- 验证方式:亲自读 1-2 个关键文件确认
- 标记低质量结果的可信度
- 基于可信结果做决策,低可信结果仅作参考
故障类型 4:Subagent 间结果冲突
症状:两个 subagent 对同一事实给出矛盾描述
影响:需要主会话介入裁决
处理:
- 主会话亲自验证冲突点(读源文件)
- 以直接观察为准,subagent 结果标记为"初步发现"
- 分析冲突原因:可能是版本差异、搜索范围不同、理解偏差
- 更新 subagent 的 system prompt 减少未来冲突
故障恢复的工程实践
最佳实践:并行探索的容错设计
1. 冗余派发(高可靠场景)
对关键方向派发两个 subagent,交叉验证结果
适用场景:安全审计、核心模块探索
成本:token 消耗翻倍,但结果可靠性显著提升
判断标准:该方向的探索结果如果错误,会导致多大的损失?
2. 降级策略(资源敏感场景)
并行探索中某个 subagent 失败后,不重新派发
而是由主会话快速补充该方向的探索
适用场景:token 预算有限、时间不紧急
成本:挂钟时间增加,但总 token 消耗不增加
3. 渐进式并行(探索范围不确定时)
先派 2 个 subagent 摸底
根据初步结果决定是否需要更多 subagent
适用场景:任务范围一开始不确定
成本:可能比一次性并行多花挂钟时间,但避免了无效派发
实战案例:3+ 并行 Subagent 解决复杂任务
场景:微服务拆分的前期调研
任务描述:
"将单体应用拆分为微服务。需要了解当前架构、
服务边界、数据依赖、API 调用链、部署配置。"
这是一个典型的大型探索任务——5 个方向,每个方向都需要读大量文件,
方向之间相对独立。串行探索预计需要 25-40 分钟。
并行派发 5 个 subagent:
派发配置
Subagent A(路由层分析):
角色:Explorer
任务:"分析 src/routes/ 目录下所有路由定义。输出:
1. 路由 → handler 映射表
2. 每个路由的中间件链
3. 路由之间的调用关系
4. 鉴权/授权分布图"
预计输出:~800 tokens
Subagent B(数据层分析):
角色:Explorer
任务:"分析 src/models/ 和 src/db/ 目录。输出:
1. 所有模型定义和字段
2. 模型之间的关联关系
3. 数据库 migration 历史
4. 跨模型的查询(join 操作)"
预计输出:~1,000 tokens
Subagent C(服务层分析):
角色:Explorer
任务:"分析 src/services/ 目录。输出:
1. 每个服务的职责描述
2. 服务之间的调用依赖
3. 共享工具函数
4. 外部 API 调用"
预计输出:~800 tokens
Subagent D(配置与部署分析):
角色:Explorer
任务:"分析部署配置文件。输出:
1. Docker/容器配置
2. CI/CD 流程
3. 环境变量和配置管理
4. 监控和日志配置"
预计输出:~600 tokens
Subagent E(安全审查):
角色:Reviewer
任务:"审查当前架构的安全风险。输出:
1. 认证/授权实现的安全评估
2. 数据库访问的安全性
3. API 端点的暴露面
4. 敏感数据处理方式"
预计输出:~800 tokens
结果汇总与冲突解决
5 个 subagent 并行执行,耗时约 6 分钟(取最慢的)
汇总过程:
步骤 1:独立验证(~2 分钟)
快速扫描每个 subagent 的输出,检查格式完整性
Subagent D 的输出最短(~400 tokens),发现部署配置很简单
Subagent E 报告了 2 个 blocker 级别的安全问题
步骤 2:交叉引用(~3 分钟)
对比 Subagent A(路由)和 Subagent C(服务)的输出
发现 3 处路由-服务映射不一致:
A 报告"/api/order 由 OrderService 处理"
C 报告"OrderService 已废弃,实际由 CheckoutService 处理"
→ 主会话亲自读 src/routes/order.ts 确认
→ 确认 C 的发现正确,OrderService 文件存在但未被引用
步骤 3:构建整体视图(~2 分钟)
合并 5 份结果,形成微服务拆分建议:
- 识别出 4 个潜在的服务边界
- 标记 2 个跨服务的数据依赖需要解决
- 2 个安全 blocker 需要在拆分前修复
- 部署配置简单,容器化改造难度低
总耗时:~11 分钟(含汇总)
总 token:~22,000(5 个 subagent + 主会话汇总)
对比串行执行:
预计耗时:~30 分钟
预计 token:~18,000(省了 subagent 初始化开销)
主会话上下文:~18,000 tokens(全部挤在一个上下文里)
结论:并行方案用多 ~22% 的 token,换来 ~63% 的时间节省
和 ~89% 的主会话上下文节省。对于后续的复杂拆分方案设计,
干净的主会话上下文比 token 节省更有价值。
并行 vs 串行的详细性能数据
基于多个项目的实测数据:
小任务(探索 5 个文件以内):
并行:3,800 tokens,2 分钟
串行:2,200 tokens,3 分钟
结论:不值得并行,调度开销占比过高(~40%)
中任务(探索 5-15 个文件,2-3 个方向):
并行:8,500 tokens,4 分钟
串行:7,200 tokens,10 分钟
结论:并行划算,时间节省 60%,上下文节省 70%
大任务(探索 15+ 个文件,4+ 个方向):
并行:22,000 tokens,11 分钟
串行:18,000 tokens,30 分钟
结论:强烈推荐并行,时间节省 63%,上下文节省 89%
超大任务(全项目级探索,6+ 个方向):
并行:35,000 tokens,15 分钟
串行:28,000 tokens,50 分钟
结论:必须并行,串行的认知疲劳会导致重大遗漏
反模式:简单任务的过度并行
经过
团队接到一个 bug 修复:用户头像上传后偶尔显示旧图片。这是一个缓存问题,预计改动不超过 10 行。
负责的工程师决定"用并行探索找到根因",派发了 5 个 subagent:
Subagent 1: 查找头像上传相关的所有文件
Subagent 2: 查找图片缓存相关的所有代码
Subagent 3: 查找 CDN 配置和缓存策略
Subagent 4: 查找前端图片组件的实现
Subagent 5: 查找相关的历史 bug 和修复记录
结果
Token 消耗:
5 个 subagent 各消耗 ~2,000-3,000 tokens
主会话汇总消耗 ~1,500 tokens
总计:~14,000 tokens
实际根因:
图片上传后,CDN 缓存没有失效。
修复:上传成功后调用 CDN purge API。
改动:1 个文件,3 行代码。
如果主会话自己处理:
读上传 handler → 发现没有缓存失效逻辑 → 修复
预估:~2,000 tokens,5 分钟
根因
过度并行化。5 个 subagent 里有 3 个根本没找到有用信息(CDN 配置、前端组件、历史 bug 都和根因无关)。并行化是对的,但不是所有任务都需要并行化。
判断标准出了问题:
- 任务复杂度不匹配。一个 10 行以内的 bug fix,不需要"全方向探索"。主会话读一个文件就能定位根因。
- 子任务不是真正独立的。5 个子任务都在找同一个东西(缓存逻辑),只是搜索角度不同。这不是并行——这是重复搜索。
- 固定开销不成比例。创建 5 个 subagent 的调度开销(~5,000 tokens)比任务本身(~2,000 tokens)还大。
修复
并行化的前提条件检查:
派发并行 subagent 前,确认:
1. 每个子任务返回的信息对其他子任务是独立的
(不是不同角度搜索同一个东西)
2. 预估每个子任务的输出都大于调度开销(~500 tokens)
3. 主会话单独处理的总时间预计 > 5 分钟
4. 探索范围涉及 > 10 个文件
不满足任意一条 → 不要并行,主会话自己处理。
对于这个头像 bug,正确做法:
1. 主会话读取上传 handler 文件
2. 发现上传成功后没有调用缓存失效
3. 加上缓存失效调用
4. 跑测试确认
总耗时:3 分钟
总 token:~2,000
不需要任何 subagent。
交叉参考
- 12 - Subagents 心智模型:并行探索背后的核心机制——独立上下文和专门角色
- 13 - 高价值角色:Explorer、Reviewer、Test Runner 的角色定义和组合模式
- 16 - 不该用 Subagent 的场景:并行探索的边界——哪些任务不值得并行化
- 14 - 工具权限:并行探索中每个 subagent 的工具权限配置
评论
还没有评论
欢迎留下第一条评论,帮助这篇内容更快形成讨论。