# 11. 子 Agent 使用边界和多 Agent 协作 本文用于推进 ZK Data Agent 后续的子 Agent 能力增强。目标不是“让模型更爱开子 Agent”,而是把子 Agent 收敛为一种可靠的编排手段:只在长耗时、可并行、边界清晰、上下文可隔离的任务里使用。 调研日期:2026-06-12。 ## 1. 外部实践共识 ### 1.1 Anthropic Research:适合宽度优先和并行探索 Anthropic 的 Research 多 Agent 系统采用 lead agent + parallel subagents。Lead agent 负责分析用户问题、制定研究策略,再派出多个 subagent 同时探索不同方向。 它强调几个判断点: - 多 Agent 特别适合开放式研究,因为研究路径不可提前硬编码,需要根据中间发现动态调整。 - Subagent 可以拥有独立上下文窗口,并行探索不同方面,再把压缩后的结果交回主 Agent。 - 多 Agent 在 breadth-first query 上更有效,尤其是多个方向可以同时查的时候。 - 成本明显更高。Anthropic 提到 agent 通常比普通聊天消耗更多 token,多 Agent 系统消耗更高,因此只适合任务价值足够高的场景。 - 如果所有 Agent 都必须共享同一上下文,或者子任务之间依赖很多,就不适合多 Agent。 参考:https://www.anthropic.com/engineering/multi-agent-research-system ### 1.2 OpenAI Agents SDK:handoff 是专业化分工 OpenAI Agents SDK 的 handoff 用于把任务委托给另一个 Agent,特别适合不同 Agent 专注不同领域的场景。Handoff 本身以 tool 的形式暴露给 LLM,让模型决定是否转交。 这给我们的启发是: - 子 Agent 不应该只是“再开一个一样的模型”,而应该有明确 profile。 - Profile 描述要告诉模型什么时候使用该 Agent。 - Handoff 可以带输入过滤和动态启用条件,避免把全量上下文无脑传给子 Agent。 参考:https://openai.github.io/openai-agents-python/handoffs/ ### 1.3 LangChain / LangGraph:上下文工程比拆 Agent 更重要 LangChain 对多 Agent 的总结非常贴近我们的情况:多 Agent 成败的关键不是数量,而是 context engineering。每个 subagent 需要明确目标、输出格式、工具范围、数据来源和边界,否则容易重复工作、遗漏信息或互相冲突。 另一个重要观点是:以“读”为主的多 Agent 更容易成功,以“写”为主的多 Agent 更难。多个 Agent 同时写代码、写文档或写同一份数据,容易产生冲突;更好的方式是让多个子 Agent 读、查、分析,最后由主 Agent 统一合成和写入。 LangGraph Supervisor 也采用 supervisor-worker 模式:单一 supervisor 负责用户交互,worker agent 只和 supervisor 通信。 参考: - https://www.langchain.com/blog/how-and-when-to-build-multi-agent-systems - https://changelog.langchain.com/announcements/langgraph-supervisor-a-library-for-hierarchical-multi-agent-systems ### 1.4 AutoGen:多 Agent 是编排框架,不是默认答案 AutoGen 强调可对话、可定制、可集成工具和人工反馈的 Agent 协作。它适合构建复杂 LLM workflow,但也意味着需要显式设计对话模式、工具权限、人类检查点和终止条件。 对 ZK Data Agent 来说,这说明多 Agent 能力应该服务于“工作流编排”,不能变成模型遇到复杂任务就随意分身。 参考:https://microsoft.github.io/autogen/0.2/docs/Use-Cases/agent_chat/ ## 2. ZK Data Agent 当前机制 当前子 Agent 的创建不是后端自动发生的,而是主模型调用 `Agent` 或旧名 `delegate_agent` 工具后触发。 关键链路: ```text 主 Agent 进入 turn loop -> 模型返回 tool_calls -> tool_call.name == Agent / delegate_agent -> _execute_delegate_agent(arguments) -> 解析 subagent_type / prompt / subtasks / max_turns / allow_write -> 创建 LocalCodingAgent 子实例 -> 子 Agent 完成后把 child_results / delegate_batches 写回工具结果 -> 主 Agent 继续总结或执行下一步 ``` 当前实现里的重要约束: - `subtasks` 最多取前 8 个。 - 子 Agent 默认不能递归调用 `Agent` / `delegate_agent`。 - Explore、Plan、verification 等只读 Agent 禁止写文件。 - 写权限需要父 Agent 允许,并且工具参数显式 `allow_write=true`。 - 子会话会标记 `session_metadata.visibility = child`,默认不进入左侧主会话列表。 - 右侧活动区通过 `child_results`、`delegate_batches`、`dependency_skips` 展示汇总。 相关代码: ```text src/agent_tools.py Agent 工具 schema 和描述 src/agent_prompting.py 子 Agent 系统提示词注入 src/builtin_agents.py 内置 Agent profile 和 when_to_use src/agent_runtime.py _execute_delegate_agent / _run_single_subtask frontend/.../activity-panel 子 Agent 活动汇总展示 ``` ## 3. 我们的设计定位 ZK Data Agent 里应该有三层能力: ```text 主 Agent 负责用户意图、当前会话状态、Skill 选择、最终决策、最终写入和回复。 Skill 负责领域流程、业务知识、稳定脚本、review 门禁和产物规范。 子 Agent 负责边界清晰的独立子任务,尤其是读、查、分析、验证、候选召回。 ``` 子 Agent 不是 Skill 的替代品,也不是主 Agent 的替代品。 - Skill 回答“这类业务流程应该怎么做”。 - Tool 回答“这个确定性动作怎么执行”。 - 子 Agent 回答“这个可隔离子任务能不能交给另一个 Agent 独立完成”。 ## 4. 什么时候应该优先使用子 Agent ### 4.1 明显适合 满足下面多个条件时,可以优先考虑子 Agent: | 判断项 | 说明 | 示例 | |---|---|---| | 长耗时 | 主 Agent 直接串行做会占用很多轮 | 查多个索引、读大量文件、批量分析 badcase | | 可并行 | 子任务之间没有强依赖 | 同时分析 5 个 rid、同时对比 3 个标签边界 | | 可隔离 | 子任务只需要一小段输入,不依赖完整上下文 | 只给某个文件路径、某个 request_id、某个候选集合 | | 读多写少 | 子任务主要是检索、阅读、总结、验证 | Explore / Plan / verification | | 输出可压缩 | 子 Agent 结果能用结构化摘要交回主 Agent | 输出发现、证据、风险、建议 | | 价值足够高 | 多消耗 token 和时间是值得的 | 线上事故排查、复杂数据策略、发布前验证 | 典型场景: - 多个 request_id / session / badcase 可以独立排查。 - 多个文件目录需要分别探索,再合并成架构判断。 - 一个任务需要先从多个候选方向召回证据。 - 非平凡代码修改后,需要 verification agent 独立跑测试和检查。 - 上下文窗口快满,且有一个清晰阶段可以交给新上下文继续探索。 ### 4.2 可以使用,但需要谨慎 这些场景可以用子 Agent,但必须限制边界: - 需要生成多个候选方案,但最后只能采用一个方案。 - 需要多个 Agent 分别给 review 意见,但最终修改只能由主 Agent 做。 - 需要长时间跑工具或搜索,但要避免子 Agent 自己继续扩散任务。 - 需要子 Agent 写临时文件,必须限定在当前 session 的 scratchpad 或 output,并明确 `allow_write=true`。 ### 4.3 不应该使用 这些场景默认不要开子 Agent: | 场景 | 原因 | |---|---| | 一次普通问答或一次工具调用 | 额外开 Agent 只会增加延迟和 token | | 强依赖连续上下文 | 子 Agent 容易拿不到主会话里的隐含状态 | | 子任务之间依赖链很长 | 调度成本高,失败恢复复杂 | | 多个 Agent 同时写同一份产物 | 容易冲突,合并困难 | | 需要和用户持续互动 | 子 Agent 的交互会割裂主会话体验 | | 主 Agent 自己还没想清任务边界 | 边界不清时拆出去只会放大混乱 | | 业务流程已有明确 Skill | 应先用 Skill,而不是直接用通用子 Agent | ## 5. 子 Agent 调用前检查表 主 Agent 在调用 `Agent` 前,应在内部完成这个检查: ```text 1. 这个任务能否直接用一个工具完成? 能 -> 不开子 Agent。 2. 这个任务是否命中明确 Skill? 是 -> 先调用 Skill,除非 Skill 内明确建议拆子 Agent。 3. 是否存在独立子任务? 没有 -> 不开子 Agent。 4. 子任务是否可以用少量输入描述清楚? 不能 -> 不开子 Agent,先由主 Agent 整理上下文。 5. 子任务结果是否能用结构化摘要交回? 不能 -> 不开子 Agent。 6. 子任务是否主要是读、查、分析、验证? 是 -> 适合。 否 -> 需要明确写权限、路径和合并策略。 7. 是否有并行收益或上下文隔离收益? 没有 -> 不开子 Agent。 ``` ## 6. 子 Agent Prompt 契约 每次委托都应该给子 Agent 一个完整契约。不要只写“帮我看看这个”。 推荐格式: ```text 任务目标: 你要完成什么,不要做什么。 输入材料: 文件路径、request_id、query、候选数据、时间范围等。 上下文边界: 只依赖这些输入;不要假设完整主会话上下文。 允许动作: 只读 / 可运行命令 / 可写临时文件 / 可写 output。 禁止动作: 不修改平台代码;不提交 git;不改非本 session 文件。 输出格式: 用固定字段返回,例如 findings、evidence、risks、next_actions。 失败处理: 找不到数据时说明尝试过的路径和下一步建议。 ``` 示例: ```text 请作为只读 Explore 子 Agent,分析 request_id=xxx 的线上日志。 只允许读取 ELK 查询结果和当前 session 文件,不写文件。 目标是判断是否能还原 query、prev_session、模型 prompt、模型输出。 输出 JSON: { "request_id": "...", "found_fields": [], "missing_fields": [], "evidence": [], "recommended_next_query": "" } ``` ## 7. 和 Skill 的组合方式 ### 7.1 Skill 内可以建议子 Agent,但不应该滥用 Skill 可以在流程里写: - 当候选样本超过一定数量,可以用 Explore 子 Agent 并行抽样。 - 当多个 rid 独立排查,可以每个 rid 一个子 Agent。 - 当生成数据前需要多标签边界 review,可以让多个只读子 Agent 分别分析边界。 但 Skill 不应该写: - 每次执行都必须开子 Agent。 - 所有生成都交给子 Agent。 - 让多个子 Agent 同时写最终数据。 ### 7.2 主 Agent 负责最终合成 推荐模式: ```text 子 Agent A:查证据 子 Agent B:查另一批证据 子 Agent C:做只读验证 -> 主 Agent 汇总 -> 主 Agent 决定下一步 -> 主 Agent 调脚本写最终产物 ``` 不推荐: ```text 子 Agent A 写一半数据 子 Agent B 写另一半数据 子 Agent C 修改格式 -> 主 Agent 被动猜测哪个文件是最终版 ``` ## 8. UI 和可观测性原则 子 Agent 不应该像普通会话一样挤进左侧列表。用户关心的是: - 主任务有没有拆子任务。 - 拆了几个。 - 每个子任务是否完成、失败、跳过。 - 每个子任务的关键发现是什么。 - 必要时能 drill down 到子会话详情。 因此 UI 默认应该: - 左侧会话列表只显示主会话。 - 右侧活动区展示子 Agent 汇总、批次、子任务摘要。 - 子 Agent 详情默认折叠。 - 子 Agent 输出应该有结构化摘要,不展示完整长日志。 ## 9. 后续增强方向 ### P0:收敛提示词和工具描述 - 在系统提示词里明确“子 Agent 不是默认策略”。 - 把“适合/不适合”的判断表加入子 Agent 指导。 - `Agent` 工具描述中补充:优先用于独立、可并行、长耗时、读多写少的子任务。 - 对 product-data、online-mining-v2、label-master 的 Skill 文档增加是否建议子 Agent 的边界。 ### P1:结构化委托和活动展示 - 为 `Agent` 参数增加更明确的 `output_contract` 或 `expected_fields`。 - 活动区展示子任务输入、状态、摘要、失败原因。 - 支持从活动区打开 child session,但默认隐藏。 - 对运行中的子 Agent 做更稳定的 live event 汇总。 ### P2:策略控制和评估 - 增加每轮最多子 Agent 数量、并发数、总 token 预算。 - 增加“只读子 Agent”默认模式。 - 记录每次子 Agent 的收益:是否减少主任务耗时、是否提升结果质量、是否造成失败。 - 建立小型 eval:同一任务单 Agent vs 子 Agent,对比准确率、耗时、token、用户体验。 ### P3:业务化多 Agent - online-mining-v2:多个 rid / 多个索引方向并行探索。 - label-master:多个候选标签边界并行查证,然后主 Agent 汇总裁决。 - product-data:批量数据质量 review 可并行,但最终 records 写入必须由主 Agent 或确定性脚本完成。 ## 10. 当前建议 短期不要把多 Agent 做成自动默认能力。更稳的路线是: ```text 默认:主 Agent + Skill + Tool 遇到明确并行探索 / 独立验证 / 长耗时检索 -> 主 Agent 显式调用子 Agent -> 子 Agent 只返回结构化摘要 -> 主 Agent 合成、写入、回复 ``` 一句话原则: ```text 子 Agent 负责把复杂任务拆成可独立完成的观察和验证; 主 Agent 负责保持用户上下文、做最终决策和产物写入。 ```