AI项目博客
记录 AI 工程实践与大模型应用

Spring AI Alibaba 39|多智能体编排 · 交接(Handoffs):顺序执行(Sequential Agent)

Multi-agent 将复杂的应用程序分解为多个协同工作的专业化Agent。与依赖单个Agent处理所有步骤不同,Multi-agent架构允许你将更小、更专注的Agent组合成协调的工作流。

Multi-agent系统在以下情况下很有用:

  • 单个Agent拥有太多工具,难以做出正确的工具选择决策
  • 上下文或记忆增长过大,单个Agent难以有效跟踪
  • 任务需要专业化(例如:规划器、研究员、数学专家)

Spring AI Alibaba支持以下Multi-agent模式:

模式 工作原理 控制流 使用场景
Tool Calling Supervisor Agent将其他Agent作为工具调用。”工具”Agent不直接与用户对话——它们只执行任务并返回结果。 集中式:所有路由都通过调用Agent。 任务编排、结构化工作流。
Handoffs 当前的Agent决定将控制权转移给另一个Agent。活动Agent随之变更,用户可以继续与新的Agent直接交互。 去中心化:Agent可以改变当前由谁来担当活跃Agent。 跨领域对话、专家接管。
问题 工具调用 (Agent Tool) 交接(Handoffs)
需要集中控制工作流程? ✅ 是 ❌ 否
希望Agent直接与用户交互? ❌ 否 ✅ 是
专家之间复杂的、类人对话? ❌ 有限 ✅ 强

你可以混合使用两种模式——使用交接进行Agent切换,并让每个Agent将子Agent作为工具调用来执行专门任务。

关于工具调用模式的使用请查看 Agent Tool 文档。

Multi-agent设计的核心是上下文工程——决定每个Agent看到什么信息。Spring AI Alibaba 为你提供细粒度的控制:

  • 将对话或状态的哪些部分传递给每个Agent
  • 为子Agent定制专门的提示
  • 包含/排除中间推理
  • 为每个Agent自定义输入/输出格式

系统的质量在很大程度上取决于上下文工程。目标是确保每个Agent都能访问执行任务所需的正确数据,无论它是作为工具还是作为活动Agent。

在 Multi-agent 系统中,instruction 支持使用占位符来动态引用状态中的数据。这是实现 Agent 之间数据传递的关键机制。

支持的占位符

占位符 说明 使用场景
{input} 用户输入的原始内容 第一个Agent或需要用户输入的 Agent
{outputKey} 引用其他Agent通过 outputKey 存储的输出 顺序执行中,后续Agent引用前面Agent的输出
{stateKey} 引用状态中的任意键值 访问状态中的任何数据

占位符工作原理

  1. 自动替换:系统会在执行 Agent 的 instruction 时,自动将占位符替换为对应的实际值
  2. 状态查找:占位符会从当前状态(OverAllState)中查找对应的值
  3. 类型安全:占位符的值会被转换为字符串并插入到 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();

最佳实践

  1. 明确命名:使用有意义的 outputKey,便于后续Agent引用
  2. 占位符格式:使用 {keyName} 格式,确保与 outputKey 一致
  3. 错误处理:如果占位符对应的值不存在,系统会保留原始占位符文本
  4. 多值引用:可以在一个 instruction 中使用多个占位符

💡 提示:占位符机制使得 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 和 Supervisor):LlmRoutingAgent 和 SupervisorAgent 还支持定制 systemPrompt 和 instruction,用于覆盖默认实现,控制后续任务流转的行为。systemPrompt 定义路由决策的整体框架,instruction 提供具体的路由指导。

在交接模式中,Agent可以直接将控制权传递给彼此。”活动”Agent会发生变化,用户与当前拥有控制权的Agent进行交互。

流程:

  1. 当前Agent决定它需要另一个Agent的帮助
  2. 它将控制权(和状态)传递给下一个Agent
  3. 新Agent直接与用户交互,直到它决定再次交接或完成

在顺序执行模式中,多个Agent按预定义的顺序依次执行。每个Agent的输出成为下一个Agent的输入。

流程:

  1. Agent A处理初始输入
  2. Agent A的输出传递给Agent B
  3. Agent B处理并传递给Agent C
  4. 最后一个Agent返回最终结果

Spring AI Alibaba SequentialAgent

实现

import com.alibaba.cloud.ai.graph.agent.flow.agent.SequentialAgent;
import com.alibaba.cloud.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());
      }
  });
}

关键特性

  1. 按顺序执行:Agent按照 subAgents 列表中定义的顺序执行
  2. 状态传递:每个Agent的输出通过 outputKey 存储在状态中,可被后续Agent访问
  3. 消息历史:默认情况下,所有Agent共享消息历史
  4. 推理内容控制:使用 returnReasoningContents 控制是否在消息历史中包含中间推理

控制推理内容

ReactAgent writerAgent = ReactAgent.builder()
  .name("writer_agent")
  .model(chatModel)
  .returnReasoningContents(true) 
  .outputKey("article")
  .build();

ReactAgent reviewerAgent = ReactAgent.builder()
  .name("reviewer_agent")
  .model(chatModel)
  .instruction("请对文章进行评审修正:
{article},最终返回评审修正后的文章内容") 
  .includeContents(true) // 包含上一个Agent的推理内容 
  .returnReasoningContents(true) 
  .outputKey("reviewed_article")
  .build();

SequentialAgent blogAgent = SequentialAgent.builder()
  .name("blog_agent")
  .subAgents(List.of(writerAgent, reviewerAgent))
  .build();

Optional<OverAllState> result = blogAgent.invoke("帮我写一个100字左右的散文");

if (result.isPresent()) {
  // 消息历史将包含所有工具调用和推理过程
  List<Message> messages = (List<Message>) result.get().value("messages").orElse(List.of()); 
  System.out.println("消息数量: " + messages.size()); // 包含所有中间步骤
}

本文整理自 Spring AI Alibaba 官方文档《多智能体编排》:https://java2ai.com/docs/frameworks/agent-framework/advanced/multi-agent

赞(0)
未经允许不得转载:AI项目博客 » Spring AI Alibaba 39|多智能体编排 · 交接(Handoffs):顺序执行(Sequential Agent)

评论 抢沙发

AI项目博客

专注 AI 工程化落地 —— 覆盖智能体、大模型、Java AI 与 Python 的学习笔记,以及 AI 平台的项目实战记录。

关于本站文章归档

登录

找回密码

注册