第八章 多 Agent 协作:orchestrator + workers 模式,主 Agent 主持 Subagent 群聊
"以前我们用
MsgHub.broadcast(...)让四个 agent 在同一个消息总线里自由聊天来模拟群聊 / 圆桌会议……2.0 没有 MsgHub 也能达到一模一样的效果——靠 orchestrator + workers 模式:主 agent 扮演主持人,subagent 扮演参与者,每轮由主 agent 把'上一轮的发言'喂给下一个发言者。"本章你将学到:1.x
MsgHub是怎么被 orchestrator 取代的、怎么用agent_spawn+ 状态自循环实现多 agent 群聊、以及如何避免 1.x 时代常见的"消息风暴"。
8.1 MsgHub 的角色与它的替代品
1.x 的 MsgHub 把"群聊"抽象成这样的语义:
agent_A ↘
agent_B → MsgHub → 自动推送给所有 agent
agent_C ↗
任何 agent 发的消息都会自动广播给 hub 里所有其他 agent。2.0 没有这个类——但等价的语义可以由"主 agent 当主持人"实现:
1.x MsgHub 语义 |
2.0 替代 |
|---|---|
| 多 agent 共享消息总线 | 主 agent 持有一个 Map<speaker, latest_message> 状态 |
| 任一 agent 发言自动广播 | 主 agent 轮流向每个 subagent 喂"上一个人的发言" |
hub.add(a, b, c) |
HarnessAgent.builder().subagent(a, b, c) |
hub.broadcast(msg) |
主 agent 自己写一段 prompt,循环里 spawn |
| 异步 / 多轮 | 主 agent 每轮 agent.call(...) 一次 |
⚠️ 2.0 重大变更
整个
io.agentscope.core.pipeline包(包含MsgHub、Pipelines)已被移除。MsgHub.broadcast(...)这种 1.x 代码在 2.0 编译期就会失败,需要按本章 8.5 的模式改造。
8.2 第一个群聊:四方圆桌会议
我们模拟"产品 / 技术 / 运营 / 法务"四方就一个需求各抒己见:
import io.agentscope.core.agent.RuntimeContext;
import io.agentscope.core.formatter.openai.OpenAIChatFormatter;
import io.agentscope.core.message.UserMessage;
import io.agentscope.core.model.OpenAIChatModel;
import io.agentscope.harness.HarnessAgent;
import io.agentscope.harness.agent.subagent.SubagentDeclaration;
import java.nio.file.Path;
import java.util.List;
public class Chapter08_Roundtable {
public static void main(String[] args) {
OpenAIChatModel model = OpenAIChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.baseUrl("https://api.openai.com")
.stream(true)
.formatter(new OpenAIChatFormatter())
.build();
SubagentDeclaration product = speaker("product", "产品经理", "关注用户价值与优先级");
SubagentDeclaration tech = speaker("tech", "技术负责人", "关注实现成本与稳定性");
SubagentDeclaration ops = speaker("ops", "运营负责人", "关注上线节奏与风险");
SubagentDeclaration legal = speaker("legal", "法务顾问", "关注合规与用户协议");
HarnessAgent host = HarnessAgent.builder()
.name("roundtable_host")
.sysPrompt("""
你是一个会议主持人。
1. 你管辖 4 位参与者:product / tech / ops / legal。
2. 拿到议题后,调用 agent_spawn 让 product 先发言,
然后把 product 的发言喂给 tech,再把 tech 的发言喂给 ops,
最后喂给 legal,legal 收尾。
3. 最后用一句话总结四方共识。
""")
.model(model)
.workspace(Path.of("./workspace"))
.subagent(product)
.subagent(tech)
.subagent(ops)
.subagent(legal)
.build();
host.call(
List.of(new UserMessage("user", "议题:我们打算把免费用户的 API 限速从 60/min 降到 30/min,请四方评估。")),
RuntimeContext.empty())
.block();
}
static SubagentDeclaration speaker(String id, String role, String concern) {
return SubagentDeclaration.builder()
.name(id)
.description(role + ",参与四方会议;每次发言聚焦自己的关切:" + concern)
.inlineAgentsBody("你是" + role + "。发言简洁(不超过 60 字),聚焦:" + concern)
.build();
}
}
跑一下你会看到 4 段 subagent 输出被自然串成一段"圆桌会议纪要"。
关键设计:主持人 agent 的 system prompt 里显式描述了发言顺序——
product → tech → ops → legal。这等价于 1.xMsgHub的add(a, b, c, d)之后硬编码broadcast的顺序。
8.3 多轮群聊:把"上一轮"喂回给"下一轮"
1.x MsgHub 的精髓是多轮对话——上一轮 A 的发言会自动变成 B 这轮的"上下文"。在 2.0 里这通过主 agent 自己的 AgentState 实现:每跑完一个 subagent,主 agent 在自己 call() 的上下文里就自动有了它的回复;下一轮 subagent 被 spawn 时,主 agent 的 system prompt 把"上一个发言者说了什么"显式拼进去。
// 在主 agent 的 system prompt 里加一条规则:
"""
第 N 轮发言前,先在 user 输入里写:
'以下是上一位 speaker 的发言:<上一段完整文本>'
然后再让下一个 subagent 接着说。
"""
主 agent 在每一轮会自己拼这段前缀——不需要业务代码循环。这是 HarnessAgent + agent_spawn 比硬编码 Pipeline 灵活的地方:LLM 会自己组织"上下文传递"。
8.4 防止"消息风暴"
1.x MsgHub 的一个老毛病是:4 个 agent 在 hub 里互发消息,5 轮后 token 用量爆炸。2.0 通过两个机制解决:
8.4.1 限制发言轮次
在主 agent 的 system prompt 里加:"每位参与者最多发言 1 轮"。LLM 看到这条会自己避免重复 spawn。
8.4.2 用 CompactionMiddleware 自动摘要
挂一个 CompactionMiddleware:
HarnessAgent host = HarnessAgent.builder()
...
.middleware(new CompactionMiddleware(
CompactionConfig.builder()
.triggerTokens(8000) // 上下文超过 8k token 时压缩
.keepRecentMessages(6) // 保留最近 6 条
.summaryTarget("MEMORY.md")
.build()))
.build();
当上下文超过 8k token 时自动把"早期的发言"压缩成摘要写进 workspace/MEMORY.md——下一章会详细讲。
8.5 最小迁移清单(1.x MsgHub → 2.0 orchestrator)
| 1.x 用法 | 2.0 等价 |
|---|---|
MsgHub hub = new MsgHub() |
隐式:主 agent 持有 subagent 列表 |
hub.add(a, b, c) |
HarnessAgent.builder().subagent(a, b, c) |
hub.broadcast(Msg) |
主 agent 自己组织 prompt,循环 spawn |
hub.enter().broadcastAll(...) |
主 agent 一次性发多 spawn(async) |
Pipelines.conversation([a,b,c]) |
主 agent 写"轮次规则"+ subagent 列表 |
迁移技巧:先写下"四方会议"的发言顺序,再用 system prompt 描述这个顺序——这是 1.x 写 Pipeline 时就要做的设计,2.0 把它挪到了 system prompt 里。
8.6 完整可运行示例:3 人辩论赛
public class Chapter08_Debate {
public static void main(String[] args) {
DashScopeChatModel model = DashScopeChatModel.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.modelName("qwen-plus")
.build();
SubagentDeclaration pro = debater("pro", "正方", "AI 会大幅提升生产力");
SubagentDeclaration con = debater("con", "反方", "AI 不会减少劳动时间");
SubagentDeclaration judge = SubagentDeclaration.builder()
.name("judge")
.description("辩论赛裁判;正反方发言结束后给出一句胜负判定")
.inlineAgentsBody("你是裁判,只返回'正方胜'或'反方胜',不要解释。")
.build();
HarnessAgent host = HarnessAgent.builder()
.name("debate_host")
.sysPrompt("""
你是辩论赛主持人。
流程:
1. 拿议题,先 agent_spawn pro,让正方开场
2. 把 pro 发言喂给 con,反方反驳
3. 把 con 反驳喂给 pro,正方再反驳(最多 1 轮)
4. 最后让 judge 收尾
5. 总结一句:哪个论据最有说服力
""")
.model(model)
.workspace(Path.of("./workspace"))
.subagent(pro)
.subagent(con)
.subagent(judge)
.build();
host.call(
List.of(new UserMessage("user", "辩题:未来 5 年,AI 是否会替代大部分白领工作?")),
RuntimeContext.empty())
.block();
}
static SubagentDeclaration debater(String id, String side, String stance) {
return SubagentDeclaration.builder()
.name(id)
.description(side + "辩手;坚持立场:" + stance)
.inlineAgentsBody("你是" + side + "辩手,立场:" + stance + "。发言不超过 80 字。")
.build();
}
}
8.7 本章小结
- 1.x
MsgHub/Pipelines在 2.0 中被整体移除,由SubagentDeclaration+agent_spawn替代。 - "群聊"在 2.0 里是 orchestrator + workers 模式:主 agent 当主持人,system prompt 描述发言顺序。
- 多轮群聊靠"主 agent 自己的 AgentState"自动保留上下文,不再需要共享消息总线。
CompactionMiddleware+ 限制发言轮次是防止 token 爆炸的两道保险。