【AgentScope Java新手村系列】(7)子Agent编排

第七章 子 Agent 编排:SubagentDeclaration + agent_spawn,主 Agent 委派子任务

"以前我们用 SequentialPipeline 串三个 agent、用 FanoutPipeline 并行三个 agent、用 MsgHub 在多 agent 间广播消息......2.0 把这三种用法统一成了 『子 agent + 同步/异步 spawn』 一种范式:你的主 agent 就像一个『包工头』,对 LLM 喊一声'叫个翻译来',它会自己 spawn 一个翻译 subagent 并把结果带回来。"

本章你将学到:如何用 SubagentDeclaration 描述子 agent、如何让主 agent 通过 agent_spawn 工具调用它们、同步与异步的差别、以及文件驱动的 subagent 描述如何让 1.x 的 Pipeline 写法彻底消失

7.1 Pipeline 已经是历史

1.x 提供了一组"组织多个 agent"的抽象:

  • SequentialPipeline ------ 把 agent 串成流水线
  • FanoutPipeline ------ 把同一输入广播到多个 agent
  • MsgHub ------ 多个 agent 共享同一个消息总线
  • Pipelines.conversation() ------ 让多个 agent 在同一个 hub 里自由聊天

这些 API 在 2.0.0-RC2 中被整体移除。原因也很简单:LLM 自己做编排("现在应该叫翻译")远比写死 Pipeline 更鲁棒、更灵活。2.0 用一个"工具调用"代替了所有这些------

1.x 概念 2.0 替代
SequentialPipeline(a, b, c) 主 agent 决定 调 a、agent_spawn a 拿结果、再 b、最后调 c
FanoutPipeline([a, b, c]) 主 agent 用 agent_spawn timeout_seconds=0 并行 调 a、b、c
MsgHub 多 agent 对话 主 agent 在循环里 agent_spawn 多个 subagent 并把上轮的回复喂回去
Pipelines.conversation() 同上,但用 HarnessAgent 的 subagent 文件做"角色表"

⚠️ 2.0 重大变更

2.0 移除了整个 io.agentscope.core.pipeline 包。如果你正在把 1.x 旧工程升到 2.0,遇到 import io.agentscope.core.pipeline.* 编译失败,请按本章 7.6 的迁移清单做改造。

7.2 第一个 subagent 例子:翻译

复制代码
import io.agentscope.core.ReActAgent;
import io.agentscope.core.message.UserMessage;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.subagent.SubagentDeclaration;
import io.agentscope.harness.HarnessAgent;

import java.nio.file.Path;
import java.util.List;

public class Chapter07_FirstSubagent {

    public static void main(String[] args) {
        // 1. 描述一个「翻译 subagent」:叫什么、prompt 是什么、用什么模型
        SubagentDeclaration translator =
                SubagentDeclaration.builder()
                        .id("translator")
                        .description("中英互译;输入文本,输出翻译结果")
                        .sysPrompt("你是一个中英互译助手,只返回翻译后的文本,不要解释。")
                        .model(DashScopeChatModel.builder()
                                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                                .modelName("qwen-plus")
                                .build())
                        .build();

        // 2. 构造主 agent,把 subagent 注册进去
        HarnessAgent main = HarnessAgent.builder()
                .name("main")
                .sysPrompt("""
                        你是一个调度员。
                        需要把用户输入翻译成英文时调用 translator subagent。
                        """)
                .model(DashScopeChatModel.builder()
                        .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                        .modelName("qwen-plus")
                        .build())
                .workspace(Path.of("./workspace"))
                .subagent(translator)
                .build();

        // 3. 主 agent 会自己判断要不要 spawn translator
        main.call(
                List.of(new UserMessage("user", "把'今天杭州有雷阵雨'翻译成英文。")),
                io.agentscope.core.RuntimeContext.empty())
                .block();
    }
}

跑一下你会发现:主 agent 在 1 轮里就调用了 agent_spawn 工具,把任务交给 translator,再把 translator 的输出整合成最终回复------整个过程对业务代码透明。

7.3 SubagentDeclaration 字段速查

SubagentDeclarationio.agentscope.core.subagent)描述一个 subagent:

字段 必填 说明
id 唯一 ID,主 agent 通过这个 ID 来 agent_spawn
description 主 agent 看这段描述来决定是否调用------写好描述等于写好路由表
sysPrompt subagent 的系统提示
model 缺省时继承主 agent 的 model
tools 缺省时继承主 agent 的 tool 组
middleware subagent 自己的中间件(不继承主 agent)
workspace 缺省时与主 agent 共享 workspace

写好 description 非常关键------主 agent 完全靠它判断"我该不该调这个 subagent"。描述里务必写清楚:subagent 是干嘛的、什么时候该调、输入和输出是什么。

7.4 同步 vs 异步:靠 timeout_seconds

agent_spawn 工具的入参:

字段 含义
agent_id 要调用的 subagent ID
task 给 subagent 的自然语言任务
timeout_seconds 同步超时阈值> 0 同步等待 N 秒;= 0 立即返回(异步)

7.4.1 同步 spawn(timeout_seconds > 0

主 agent 等到结果回来再继续推理。最常用------"主 agent 把 subagent 当成工具函数"。

复制代码
主 agent:
  1. LLM 决定调用 translator,timeout_seconds=10
  2. Harness 启动 translator subagent,等它跑完(最多 10 秒)
  3. 把 subagent 的最终输出回填给主 agent
  4. 主 agent 继续推理

7.4.2 异步 spawn(timeout_seconds = 0

主 agent 立刻拿到一个"任务 ID + 状态"对象,主 agent 可以继续做别的事 ,稍后再用 agent_list / agent_send 拉结果。

复制代码
主 agent:
  1. LLM 决定"同时调研 3 个问题",对 3 个 subagent 各发一次 async spawn
  2. 3 个 subagent 并行启动(fanout)
  3. 主 agent 立即拿到 3 个 task_id
  4. 主 agent 写 `todo_write` 记下要跟踪
  5. 后续轮次里主 agent 用 `agent_send` 问"搞完没?"

异步 spawn 的最佳搭档是 todo_write :主 agent 起任务时把 task_id 写到 todo 列表,每轮 agent_send 看哪些完成、回填哪些结果。详见第 12 章 Plan Mode。

7.5 文件驱动的 subagent:让 prompt 离开 Java 代码

SubagentDeclaration 写死在 Java 里没问题,但生产中我们常希望"产品经理改一段描述就能调整路由"------2.0 推荐用文件描述:

复制代码
workspace/
└── subagents/
    ├── translator.md
    ├── weather_lookup.md
    └── invoice_parser.md

每个文件就是一份 YAML/Markdown 描述:

复制代码
# translator.md
id: translator
description: 中英互译;输入文本,输出翻译结果
sysPrompt: |
  你是一个中英互译助手。
  只返回翻译后的文本,不要解释。

然后:

复制代码
HarnessAgent main = HarnessAgent.builder()
        ...
        .workspace(Path.of("./workspace"))   // 自动扫描 subagents/*.md
        .build();

HarnessAgent.builder().workspace(...) 会自动加载 workspace/subagents/ 下所有 *.md / *.yaml 文件,省去 Java 端重复注册。

7.6 最小迁移清单(1.x Pipeline → 2.0 subagent)

1.x 用法 2.0 等价
SequentialPipeline(a, b, c).run(x) 主 agent 依次 agent_spawn a / b / c(同步)
FanoutPipeline([a, b, c]).run(x) 主 agent 一次发 3 个 timeout_seconds=0 的 async spawn
MsgHub.broadcast(msg) 主 agent 写一段自然语言 prompt,让所有 subagent 各自跑
Pipelines.conversation([a, b, c]) 主 agent 持有 subagent 列表,每轮 agent_spawn + 拼接
pipeline.run(Msg) main.call(List.of(new UserMessage("user", task)), ctx)

迁移技巧:把 Pipeline 的每一步都想象成"主 agent 的一个工具调用"。1.x 写死的执行顺序,2.0 让 LLM 在 system prompt + subagent description 的引导下自主决定------一开始可能觉得不踏实,跑两个 case 就发现它比硬编码灵活得多。

7.7 完整可运行示例

复制代码
import io.agentscope.core.RuntimeContext;
import io.agentscope.core.message.UserMessage;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.subagent.SubagentDeclaration;
import io.agentscope.harness.HarnessAgent;

import java.nio.file.Path;
import java.util.List;

public class Chapter07_Fanout {

    public static void main(String[] args) {
        DashScopeChatModel model = DashScopeChatModel.builder()
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .modelName("qwen-plus")
                .build();

        // 3 个并行调研 subagent
        SubagentDeclaration legal   = research("legal",   "做法律合规研究");
        SubagentDeclaration finance = research("finance", "做财务分析");
        SubagentDeclaration tech    = research("tech",    "做技术可行性评估");

        HarnessAgent main = HarnessAgent.builder()
                .name("project_due_diligence")
                .sysPrompt("""
                        你是一个项目尽调主管。
                        同时调用 legal / finance / tech 三个 subagent 调研同一议题,
                        最后综合三方结果给出一句话结论。
                        """)
                .model(model)
                .workspace(Path.of("./workspace"))
                .subagent(legal)
                .subagent(finance)
                .subagent(tech)
                .build();

        main.call(
                List.of(new UserMessage("user", "我们想在杭州开一家 50 平米咖啡店,请三路调研。")),
                RuntimeContext.empty())
                .block();
    }

    static SubagentDeclaration research(String id, String role) {
        return SubagentDeclaration.builder()
                .id(id)
                .description(role + ";输入是项目描述,输出是结构化要点(最多 5 条)")
                .sysPrompt("你是一个尽调分析师,专注 " + role + "。")
                .build();
    }
}

跑一下你会看到三个 subagent 的输出被自动拼成一份"尽调备忘录"。

7.8 本章小结

  • 2.0 移除了 1.x 的 Pipeline / MsgHub;改用 SubagentDeclaration + 主 agent 自带的 agent_spawn 工具。
  • 同步 spawn(timeout_seconds > 0)= 拿结果再走;异步 spawn(timeout_seconds = 0)= 立即返回 task_id,主 agent 后续用 agent_send 拉。
  • 写好 description 字段 = 写好路由表------主 agent 全靠它判断"该不该调"。
  • 文件驱动:workspace/subagents/*.md 让产品经理也能调路由。

下一章我们把同样的思路推到"多 agent 协作"------用 orchestrator + workers 的模式做狼人杀 / 群聊 / 多 agent 决策。

相关推荐
一个做软件开发的牛马1 小时前
Spring Boot Web 开发实战:RESTful API 设计、统一异常处理、参数校验与拦截器
java·后端
yongche_shi1 小时前
ragas官方文档中文版(十六)
python·ai·智能体·ragas·使用工具
yurenpai(27届找实习中)1 小时前
Feed 流推送与附近商户:从推模式到 GeoHash,一条 Timeline 的完整旅程
java·数据库·oracle·feed
小bo波1 小时前
Java反射机制——运行时"透视"类的秘密
java·jvm·反射·源码分析·动态代理·进阶·spring底层·框架原理
IT 行者1 小时前
GitHub Spec Kit 实战(三):写一份能管住所有 spec 的 /speckit.constitution
java·github·ai编程·claude
java1234_小锋1 小时前
Spring Boot 的核心注解 @SpringBootApplication 由哪三个注解组成?
java·spring boot·后端
::呵呵哒::1 小时前
在macOS/Linux上优雅管理多个JDK版本:环境变量与别名配置指南
java·linux·macos
Master_Azur1 小时前
Web后端基础-Spring分层解耦
spring boot·后端·spring
IT 行者1 小时前
GitHub Spec Kit 实战(二):写一份不偏的 /speckit.specify
java·github·ai编程·claude