多智能体 MultiAgent
Multi-agent 将复杂的应用程序分解为多个协同工作的专业化 Agent。与依赖单个 Agent 处理所有步骤不同,Multi-agent 架构允许你将更小、更专注的 Agent 组合成协调的工作流。
Multi-agent系统在以下情况下很有用:
- 单个Agent拥有太多工具,难以做出正确的工具选择决策
- 上下文或记忆增长过大,单个Agent难以有效跟踪
- 任务需要专业化(例如:规划器、研究员、数学专家)
Multi-agent模式
main 分支当前可确认的 Multi-agent 模式如下:
| 模式 | 工作原理 | 控制流 | 使用场景 |
|---|---|---|---|
| Agent as Tool | 控制器 Agent 将其他 Agent 包装为工具调用。工具 Agent 不直接与用户对话,只执行任务并返回结果。 | 集中式:由控制器 Agent 选择工具。 | 分层编排、控制器/工作 Agent 风格应用。 |
| SequentialAgent | 多个 Agent 按固定顺序执行,前一个 Agent 的 outputKey 可作为后续 Agent 的占位符输入。 | 固 定顺序。 | 写作 -> 评审 -> 翻译等流水线。 |
| ParallelAgent | 多个 Agent 并行处理同一输入,再通过 MergeStrategy 合并结果。 | 扇出/聚合。 | 多路检索、多专家并行评审。 |
| LlmRoutingAgent | 使用 LLM 根据用户输入和子 Agent 描述选择一个子 Agent。 | 单次动态路由。 | 跨领域专家选择。 |
| LoopAgent | 使用 LoopMode 或自定义 LoopStrategy 重复执行一个子 Agent。 | 循环。 | 迭代润色、批量处理 JSON 数组。 |
选择模式
| 问题 | Agent as Tool | FlowAgent |
|---|---|---|
| 需要集中控制工作流程? | ✅ 是 | ❌ 否 |
| 需要固定流程、并行或路由? | ❌ 有限 | ✅ 是 |
| 希望子 Agent 作为工具被模型按需调用? | ✅ 是 | ❌ 否 |
你可以混合使用两种模式:例如在
SequentialAgent的某个步骤中运行一个带有AgentTool的ReactAgent。
关于 Agent-as-tool 模式的使用请查看 ToolsAsAgent 文档。
自定义Agent上下文
Multi-agent设计的核心是上下文工程——决定每个Agent看到什么信息 。ARGI 为你提供细粒度的控制:
- 将对话或状态的哪些部分传递给每个Agent
- 为子Agent定制专门的提示
- 包含/排除中间推理
- 为每个Agent自定义输入/输出格式
系统的质量在很大程度上取决于上下文工程。目标是确保每个Agent都能访问执行任务所需的正确数据,无论它是作为工具还是作为活动Agent。
Instruction 占位符
在 Multi-agent 系统中,instruction 支持使用占位符来动态引用状态中的数据。这是实现 Agent 之间数据传递的关键机制。
支持的占位符
| 占位符 | 说明 | 使用场景 |
|---|---|---|
{input} | 用户输入的原始内容 | 第一个Agent或需要用户输入的 Agent |
{outputKey} | 引用其他Agent通过 outputKey 存储的输出 | 顺序执行中,后续Agent引用前面Agent的输出 |
{stateKey} | 引用状态中的任意键值 | 访问状态中的任何数据 |
占位符工作原理
- 自动替换:系统会在执行 Agent 的 instruction 时,自动将占位符替换为对应的实际值
- 状态查找:占位符会从当前状态(
OverAllState)中查找对应的值 - 类型安全:占位符的值会被转换为字符串并插入到 instruction 中
使用示例
// 第一个Agent:使用 {input} 获取用户输入
ReactAgent writerAgent = ReactAgent.builder()
.name("writer_agent")
.instruction("你是一个知名的作家。请根据用户的提问进行回答:{input}。")
.outputKey("article")
.build();
// 第二个Agent:使用 {article} 引用第一个Agent的输出
ReactAgent reviewerAgent = ReactAgent.builder()
.name("reviewer_agent")
.instruction("请对文章进行评审修正:\n{article},最终返回评审修正后的文章内容")
.outputKey("reviewed_article")
.build();
最佳实践
- 明确命名:使用有意义的
outputKey,便于后续Agent引用 - 占位符格式:使用
{keyName}格式,确保与outputKey一致 - 错误处理:如果占位符对应的值不存在,系统会保留原始占位符文本
- 多值引用:可以在一个 instruction 中使用多个占位符
💡 提示:占位符机制使得 Agent 之间的数据传递变得简单直观,无需手动管理状态传递逻辑。
Flow Agent
💡 重要参数说明:在多 Agent 模式下,以下参数对于控制 Agent 行为和上下文传递至关重要:
instruction:用于在当前 Agent 节点处插入新的问题说明,引导模型和流程运行。支持使用占位符(如{input}、{outputKey}等)来动态引用状态中的数据,实现 Agent 之间的数据传递。
returnReasoningContent:控制子 Agent 的上下文是否返回父流程中。如果设置为false,则其他 Agent 不会有机会看到这个子 Agent 内部的推理过程,它们只能看到这个 Agent 输出的内容(比如通过outputKey引用)。这对于减少上下文大小、提高效率非常有用。
includeContents:父流程中可能包含非常多子 Agent 的推理过程、每个子 Agent 的输出等。includeContents用来控制当前子 Agent 执行时,是只基于自己的instruction给到的内容工作,还是会带上所有父流程的上下文。设置为false可以让子 Agent 专注于自己的任务,不受父流程复杂上下文的影响。
outputKey:指定输出内容的键名,可被后续 Agent 通过占位符引用(如{outputKey})。使用有意义的outputKey名称,便于后续 Agent 引用和状态管理。
systemPrompt和instruction(Routing):LlmRoutingAgent支持定制systemPrompt和instruction,用于覆盖默认实现,控制路由行为。systemPrompt定义路由决策的整体框架,instruction提供具体的路由指导。
顺序执行(Sequential Agent)
在顺序执行模式中,多个Agent按预定义的顺序依次执行。每个Agent的输出成为下一个Agent的输入。
流程:
- Agent A处理初始输入
- Agent A的输出传递给Agent B
- Agent B处理并传递给Agent C
- 最后一个Agent返回最终结果

实现
import io.github.agentic.ai.graph.agent.flow.agent.SequentialAgent;
import io.github.agentic.ai.graph.OverAllState;
// 创建专业化的子Agent
ReactAgent writerAgent = ReactAgent.builder()
.name("writer_agent")
.model(chatModel)
.description("专业写作Agent")
.instruction("你是一个知名的作家,擅长写作和创作。请根据用户的提问进行回答:{input}。")
.outputKey("article")
.build();
ReactAgent reviewerAgent = ReactAgent.builder()
.name("reviewer_agent")
.model(chatModel)
.description("专业评审Agent")
.instruction("你是一个知名的评论家,擅长对文章进行评论和修改。" +
"对于散文类文章,请确保文章中必须包含对于西湖风景的描述。待评论文章:
{article}" +
"最终只返回修改后的文章,不要包含任何评论信息。")
.outputKey("reviewed_article")
.build();
// 创建顺序Agent
SequentialAgent blogAgent = SequentialAgent.builder()
.name("blog_agent")
.description("根据用户给定的主题写一篇文章,然后将文章交给评论员进行评论")
.subAgents(List.of(writerAgent, reviewerAgent))
.build();
// 使用
Optional<OverAllState> result = blogAgent.invoke("帮我写一个100字左右的散文");
if (result.isPresent()) {
OverAllState state = result.get();
// 访问第一个Agent的输出
state.value("article").ifPresent(article -> {
if (article instanceof AssistantMessage) {
System.out.println("原始文章: " + ((AssistantMessage) article).getText());
}
});
// 访问第二个Agent的输出
state.value("reviewed_article").ifPresent(reviewedArticle -> {
if (reviewedArticle instanceof AssistantMessage) {
System.out.println("评审后文章: " + ((AssistantMessage) reviewedArticle).getText());
}
});
}