主 Agent 通过 task 工具并行召唤只读子 Agent 探查代码库,避免上下文膨胀;子 Agent 独立返回精确答案,主 Agent 聚合。UNIX 极简哲学的 AI 编码 Agent 实现。
当一个 Agent 需要理解代码库时,它只有两种选择:逐个文件试探(慢,消耗 token),或者把所有内容都塞进 context(大型项目不可能)。无论哪种方式,主 Agent 的 context 都会被探索过程的噪音填满,导致编码性能下降。
跟随大多数主流 coding agent 的做法,我们决定构建子代理,但我们需要设计符合 zerostack UNIX 式最小化哲学的子代理。
子代理是由主代理通过 task 工具生成的只读子 Agent。每个子代理接收一个精确的技术问题,返回一个聚焦的答案。如果传入多个 prompt,它们会通过 tokio::spawn 并行运行。
Main Agent Subagent(s)
┌──────────────┐ ┌─────────────────────┐
│ read/write │ │ read │
│ edit/bash │ calls "task" │ grep │
│ task ────────│ ─────────────────→│ find_files │
│ │ with prompt(s) │ list_dir │
│ │ spawns parallel │ todo │
│ │ tokio tasks │ memory_read* │
│ │ returns findings│ memory_search* │
└──────────────┘ └─────────────────────┘
设计上只读——无 write、edit、bash、memory_write 或 mcp_tool
无权限系统——所有工具以 permission: None 运行(安全,因为它们只能读取)
可选功能——受 subagents Cargo feature 门控(默认开启)
这确保了子代理不会执行危险操作,也不会产生条件竞争问题,无需实现文件锁。
当你向 task 工具传入多个 prompt 时,每个 prompt 都会生成自己的 async task。futures::future::join_all 收集结果。一个子代理失败(panic 或 error)时会向 Agent 显示其错误,而其余子代理正常完成,允许 Agent 随后重新发送子代理或使用自己的工具完成任务(例如:发送给子代理的任务需要使用 git bash 命令)。结果按原始 prompt 索引排序。
zerostack 系统提示词中的理念是:子代理应被视为主代理的下属,接收高级问题(例如"认证是如何工作的?"),输出低级答案(例如"在 src/auth.rs 中有 AuthManager……")。
子代理可以使用与主代理不同的模型/提供商,在启动时创建单独的 API 客户端,允许使用更便宜更快的模型进行代码库探索(通过子代理),而重型模型执行真正的编码任务。
在我们的系统提示词中:
描述子代理:
描述 task 工具:
子代理让主代理能够委托深度探索而不会造成 context 膨胀。单个回合可以生成 3-5 个并行调查,每个调查返回结构化的发现,主代理将其整合为一个连贯的计划。当与 ARCHITECTURE.md 结合使用时尤其强大——子代理自动接收架构上下文,因此它们带着设计意识开始探索,而不是从零开始。
结合我们受限的只读操作和更快的 I/O 实现,我们成功构建了一个更简单、更快的子代理方案,在代码探索时间上比 opencode 的子代理实现了 25% 的提升。
整个实现共 414 行代码(用 Rust 编写)。