Skip to content

71. 子代理隔离系统 (Sub-Agent Isolation)

v5.0.1.7+ — SubAgentContext 上下文隔离与协作管理

概述

子代理隔离系统为多代理协作场景提供了上下文级别的隔离。通过 SubAgentContext 隔离原语,每个子代理拥有独立的消息历史、上下文引擎和工具白名单,仅将摘要结果返回给父代理,避免中间推理步骤和工具输出污染父代理上下文。

设计动机

问题分析

  1. 共享可变 messages 数组:agentLoop 将所有工具调用和结果追加到同一 messages[]
  2. 全局上下文注入:CLIContextEngineering 的 BM25/记忆/偏好注入不区分任务范围
  3. 单例内存泄漏:hierarchical-memory 的 _working/_shortTerm 是模块级全局 Map
  4. Cowork 交叉污染:Debate moderator 接收所有 reviewer 的完整输出
  5. Skill 无隔离:skill handler 在主代理同一上下文运行

设计目标

  • 子代理拥有独立消息历史,不与父代理共享
  • 子代理仅返回摘要结果(三级策略)
  • 记忆系统按命名空间隔离
  • 上下文注入按角色/任务范围过滤
  • 工具使用按角色白名单限制
  • 向后完全兼容,不使用隔离功能时行为不变

架构设计

模块依赖

agent-core.js
  ├── sub-agent-context.js    (隔离运行)
  │     ├── cli-context-engineering.js (scope参数)
  │     └── hierarchical-memory.js (namespace参数)
  ├── sub-agent-registry.js   (生命周期追踪)
  └── agent-coordinator.js    (任务分解+执行)

SubAgentContext 类设计

+-----------------------------------+
| SubAgentContext                    |
+-----------------------------------+
| + id: string                      |
| + parentId: string|null           |
| + role: string                    |
| + task: string                    |
| + messages: Message[]             | ← 隔离
| + contextEngine: CLIContextEng    | ← 独立实例
| + allowedTools: string[]|null     |
| + maxIterations: number           |
| + status: "active"|"completed"|"failed" |
| + result: Result|null             |
+-----------------------------------+
| + create(options): SubAgentContext |
| + run(prompt, opts): Promise<Result> |
| + summarize(content): string      |
| + forceComplete(reason): void     |
| + toJSON(): object                |
| - _getFilteredTools(): Tool[]     |
+-----------------------------------+

命名空间化记忆

之前 (全局共享):
  _working: Map<id, entry>
  _shortTerm: Map<id, entry>

之后 (命名空间隔离):
  _workingNS: Map<namespace, Map<id, entry>>
  _shortTermNS: Map<namespace, Map<id, entry>>

  向后兼容代理:
  _working.size      → _workingNS.get("global").size
  _working.get(id)   → _workingNS.get("global").get(id)
  _working._nsMap     → 直接访问命名空间 Map

三级摘要策略

                    ┌─ ≤500 chars ──→ 直接返回

输入内容 ──→ 长度检查 ┤

                    └─ >500 chars ──→ 检查结构化标题

                                      ├─ 有 ## Summary/Result → 提取 section (≤1000)

                                      └─ 无 → 截断前500字符 + "[truncated, N chars]"

角色工具白名单 (ROLE_TOOL_WHITELIST)

code-review:    [read_file, search_files, list_dir]          # 只读
code-generation: [read_file, write_file, edit_file, run_shell, search_files, list_dir]
data-analysis:  [read_file, search_files, list_dir, run_code, run_shell]
document:       [read_file, write_file, search_files, list_dir]  # 无执行
testing:        [read_file, write_file, edit_file, run_shell, search_files, list_dir, run_code]
general:        null (所有工具)

生命周期管理

SubAgentRegistry

+----------------------------------+
| SubAgentRegistry (Singleton)      |
+----------------------------------+
| - _active: Map<id, SubAgentCtx>  |
| - _completed: RingBuffer(100)     |
| - _totalTokens: number           |
| - _completedCount: number        |
+----------------------------------+
| + getInstance(): SubAgentRegistry |
| + register(subCtx): void         |
| + complete(id, result): void     |
| + forceCompleteAll(sessionId)     |
| + cleanup(maxAgeMs): void        |
| + getActive(): object[]          |
| + getHistory(): object[]         |
| + getStats(): Stats              |
+----------------------------------+

集成点

集成模块行为
ws-session-managercloseSession()forceCompleteAll(sessionId)
agent-repl/sub-agents 命令展示活跃/历史/统计
agent-coordinatorexecuteDecomposedTask() 每个子任务一个 SubAgentContext
debate-review-clireviewer 输出截断到 300 字符传给 moderator

数据流

spawn_sub_agent 执行流程

1. LLM 返回 tool_call: spawn_sub_agent({ role, task, context })
2. executeTool → _executeSpawnSubAgent()
3.   ├── SubAgentContext.create({ role, task, inheritedContext })
4.   ├── SubAgentRegistry.register(subCtx)
5.   ├── subCtx.run(task, llmOptions)
6.   │     ├── 独立 agentLoop(subCtx.messages, ...)
7.   │     ├── 工具白名单过滤
8.   │     └── 返回 { summary, artifacts, tokenCount, toolsUsed }
9.   ├── SubAgentRegistry.complete(id, result)
10.  └── 返回 summary 给父 messages (不含子代理中间步骤)

文件清单

新增文件

文件行数说明
packages/cli/src/lib/sub-agent-context.js~290子代理上下文核心
packages/cli/src/lib/sub-agent-registry.js~190生命周期注册表
desktop-app-vue/src/main/ai-engine/agents/sub-agent-context.js~200Desktop CJS 等价实现

修改文件

文件修改说明
packages/cli/src/lib/agent-core.js添加 spawn_sub_agent 工具定义 + executeTool case
packages/cli/src/lib/cli-context-engineering.js添加 scope 参数支持
packages/cli/src/lib/hierarchical-memory.js命名空间化 + 向后兼容代理
packages/cli/src/lib/agent-coordinator.js添加 ROLE_TOOL_WHITELIST + executeDecomposedTask
packages/cli/src/lib/cowork/debate-review-cli.jsreviewer 输出截断
packages/cli/src/lib/ws-session-manager.js会话清理集成
packages/cli/src/repl/agent-repl.js/sub-agents 命令

测试策略

单元测试

测试文件测试数覆盖范围
sub-agent-context.test.js38创建、隔离、白名单、摘要、forceComplete、token预算
sub-agent-registry.test.js12单例、注册/完成、环形缓冲、清理
scoped-context-engineering.test.js8scope 构造、命名空间传递、阈值过滤
namespaced-memory.test.js9命名空间存取、隔离、统计

集成测试

测试文件测试数覆盖范围
sub-agent-isolation.test.js33spawn_sub_agent 工具、注册表生命周期、命名空间隔离、自动凝缩、token预算

E2E 测试

测试文件测试数覆盖范围
sub-agent-isolation.test.js8模块导入、工具定义、API 可用性

v5.0.1.8 增强功能

1. 系统提示词子代理引导

getBaseSystemPrompt() 现在包含 "Sub-Agent Isolation" 章节,指导 LLM 何时使用 spawn_sub_agent 工具:

  • 代码审查与代码生成分离
  • 大文件摘要后再纳入回复
  • 独立的安全/性能分析
  • 提醒不要对简单任务创建子代理

2. 自动上下文凝缩 (Auto-Condensation)

spawn_sub_agent 未提供 context 参数时,自动从父代理最近 3 条 assistant 消息中提取前 200 字符作为继承上下文。显式提供 context 时优先使用显式值。

3. Token 预算执行

SubAgentContext.run() 现在跟踪 token 消耗(基于字符长度估算,~4 字符/token),并在达到 tokenBudget 时自动 forceComplete("token-budget-exceeded")。适用于 CLI 和 Desktop 版本。

4. 并行子代理执行

executeDecomposedTask() 从串行改为批次并行执行,支持 maxConcurrency 选项(默认 3)。独立子任务在同一批次内并行运行。

5. Desktop 集成完善

  • agent-pool.js: acquireIsolatedAgent() 支持 inheritedContexttokenBudget 参数
  • autonomous-agent-runner.js: delegateToSubAgent() 新增子代理追踪(goal.subAgents 数组),支持 tokenBudget 参数

向后兼容性

  • agentLoop 签名不变,不使用 spawn_sub_agent 时行为完全不变
  • _working/_shortTerm 通过代理对象保持原有 Map API
  • storeMemory/recallMemory 不传 namespace 时默认使用 "global"
  • CLIContextEngineering 不传 scope 时行为不变
  • executeDecomposedTask() 在单个子任务时行为与串行一致
  • executeTool() context 参数新增可选 parentMessages 字段,不传时无影响
  • AGENT_TOOLS 数量从 9 增加到 10(添加 spawn_sub_agent)

基于 MIT 许可发布