【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.message.UserMessage;
import io.agentscope.core.model.OpenAIChatModel;
import io.agentscope.core.formatter.openai.OpenAIChatFormatter;
import io.agentscope.harness.HarnessAgent;
import io.agentscope.harness.agent.subagent.SubagentDeclaration;

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

public class Chapter07_FirstSubagent {

    public static void main(String[] args) {
        // 1. 描述一个「翻译 subagent」:叫什么、prompt 是什么(模型继承主 agent)
        SubagentDeclaration translator =
                SubagentDeclaration.builder()
                        .name("translator")
                        .description("中英互译;输入文本,输出翻译结果。当你需要对用户输入进行翻译时,调用此子 agent。")
                        .inlineAgentsBody("你是一个中英互译助手,只返回翻译后的文本,不要解释。")
                        .build();

        // 2. 构造主 agent,把 subagent 注册进去
        HarnessAgent main = HarnessAgent.builder()
                .name("main")
                .sysPrompt("""
                        你是一个调度员。
                        需要把用户输入翻译成英文时调用 translator subagent。
                        """)
                .model(OpenAIChatModel.builder()
                        .apiKey(System.getenv("OPENAI_API_KEY"))
                        .modelName("gpt-4o-mini")
                        .baseUrl("https://api.openai.com")
                        .stream(true)
                        .formatter(new OpenAIChatFormatter())
                        .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.harness.agent.subagent)描述一个 subagent:

字段必填说明
name唯一 ID,主 agent 通过这个 ID 来 agent_spawn
description主 agent 看这段描述来决定是否调用——写好描述等于写好路由表
inlineAgentsBodysubagent 的系统提示
model模型名称字符串(如 "qwen-plus"),缺省时继承主 agent 的 model
steps最大推理轮次(默认 10)
tools缺省时继承主 agent 的 tool 组
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.agent.RuntimeContext;
import io.agentscope.core.message.UserMessage;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.harness.agent.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()
                .name(id)
                .description(role + ";输入是项目描述,输出是结构化要点(最多 5 条)")
                .inlineAgentsBody("你是一个尽调分析师,专注 " + 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 决策。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值