吃透 Spring AI Alibaba 多智能体|四大协同模式+完整代码

当一个Agent要处理很多复杂的事情,就会出现效果不佳的情况,这时候Multi-Agent就可以将复杂任务进行拆分,更好的完成我们的任务。

本文基于Spring AI Alibaba框架,详解Multi-Agent的核心概念、占位符用法,以及顺序执行、并行执行、路由调度、监督者管控四大核心模式,搭配完整可运行的代码示例,快速上手多智能体开发。

一、Multi-Agent 核心概念

官方对Multi-Agent的定义清晰直白:

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

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

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

二、指令占位符(Instruction)用法

支持使用占位符来动态引用状态中的数据。比如AgentB需要使用AgentA处理后的数据,就需要通过Instruction来获取

1、支持的占位符

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

2、占位符工作原理

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

三、公共代码(ChatModel获取)

我先把获取ChatModel这个公共代码放在这里,后面就不重复写进来了

默认模型qwen-plus

java 复制代码
public static ChatModel getChatModel() {

    DashScopeApi dashScopeApi = DashScopeApi.builder()
            .apiKey(System.getenv("AliQwen_API"))
            .build();

    return DashScopeChatModel.builder()
            .dashScopeApi(dashScopeApi)
            .defaultOptions(DashScopeChatOptions.builder()
                    // Note: model must be set when use options build.
                    .model(DashScopeChatModel.DEFAULT_MODEL_NAME)
                    .temperature(0.5)
                    .maxToken(1000)
                    .build())
            .build();
}

四、顺序执行(Sequential Agent)

顾名思义,多个Agent按照顺序依次执行,上一个Agent的输出结果可以传递给下一个Agent

1. 执行流程

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

2. 示例代码

java 复制代码
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.graph.NodeOutput;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.agent.flow.agent.SequentialAgent;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import com.alibaba.cloud.ai.graph.streaming.StreamingOutput;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.model.ChatModel;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import com.alibaba.cloud.ai.graph.OverAllState;


public class SequentialAgentTest {

    public static void main(String[] args) throws GraphRunnerException, IOException {

        ChatModel chatModel = getChatModel();
        // 创建专业化的子Agent
        ReactAgent writerAgent = ReactAgent.builder()
                .name("writer_agent")
                .model(chatModel)
                .description("专业写作Agent")
                .instruction("你是一个知名的作家,擅长写作和创作。请根据用户的提问进行回答:{input}。")
                .outputKey("article")
                .build();

        ReactAgent translateAgent = ReactAgent.builder()
                .name("translate_agent")
                .model(chatModel)
                .description("专业翻译Agent")
                .instruction("""
                         你是一个知名的翻译官,擅长对文章翻译。
                         待翻译文章:
                        {article}
                        最终只返回翻译后的文章。""")
                .outputKey("reviewed_article")
                .build();

        // 创建顺序Agent
        SequentialAgent blogAgent = SequentialAgent.builder()
                .name("blog_agent")
                .description("根据用户给定的主题写一篇文章,然后将文章交给翻译员进行翻译")
                .subAgents(List.of(writerAgent, translateAgent))
                .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());
                }
            });
        }
}

3. 运行结果

java 复制代码
原始文章: 晨光初染窗棂,茶烟袅袅浮起,如一段未写完的旧信。院中老槐静立,枝桠间漏下碎金,在青砖上缓缓游移。风来,几片薄叶旋落,无声栖于石阶,像时光轻轻踮脚走过。邻家孩童追着纸鸢跑远,笑声清亮,撞碎一巷薄雾。我凝望这寻常片刻------原来人间至味,并非惊雷烈酒,而是晨光、微风、落叶与未凉的茶,在素常里酿出微光。
翻译后文章: Dawn's first light gently tints the window frame; tea steam rises in delicate, lingering wisps---like an unfinished old letter. In the courtyard, an ancient locust tree stands still, its branches filtering golden shards of sunlight that slowly drift across the bluish-gray bricks. A breeze stirs: a few slender leaves spiral down, settling silently on the stone steps---as if time itself tiptoed past. A neighbor's child chases a kite down the lane, laughter bright and clear, shattering the morning mist. Gazing upon this ordinary moment, I realize: life's truest flavor lies not in thunderclaps or strong wine, but in dawn light, soft wind, falling leaves, and tea still warm---subtle radiance brewed quietly in the everyday.

4. 关键特性

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

五、并行执行(Parallel Agent)

当不考虑智能体的执行顺序时,可以使用Parallel Agent,多个智能体接收相同的输出进行处理,最后将结果汇总

1. 执行流程

  1. 输入同时发送给所有Agent
  2. 所有Agent并行处理
  3. 结果被合并成单一输出

2. 示例代码

java 复制代码
public static void main(String[] args) throws GraphRunnerException {

      ChatModel chatModel = getChatModel();
      // 创建多个专业化Agent
      ReactAgent proseWriterAgent = ReactAgent.builder()
              .name("prose_writer_agent")
              .model(chatModel)
              .description("专门写散文的AI助手")
              .instruction("你是一个知名的散文作家,擅长写优美的散文。" +
                      "用户会给你一个主题:{input},你只需要创作一篇100字左右的散文。")
              .outputKey("prose_result")
              .build();

      ReactAgent poemWriterAgent = ReactAgent.builder()
              .name("poem_writer_agent")
              .model(chatModel)
              .description("专门写现代诗的AI助手")
              .instruction("你是一个知名的现代诗人,擅长写现代诗。" +
                      "用户会给你的主题是:{input},你只需要创作一首现代诗。")
              .outputKey("poem_result")
              .build();

      ReactAgent summaryAgent = ReactAgent.builder()
              .name("summary_agent")
              .model(chatModel)
              .description("专门做内容总结的AI助手")
              .instruction("你是一个专业的内容分析师,擅长对主题进行总结和提炼。" +
                      "用户会给你一个主题:{input},你只需要对这个主题进行简要总结。")
              .outputKey("summary_result")
              .build();

      // 创建并行Agent
      ParallelAgent parallelAgent = ParallelAgent.builder()
              .name("parallel_creative_agent")
              .description("并行执行多个创作任务,包括写散文、写诗和做总结")
              .mergeOutputKey("merged_results")
              .subAgents(List.of(proseWriterAgent, poemWriterAgent, summaryAgent))
              .mergeStrategy(new CustomMergeStrategy())
              .build();

      // 使用
      Optional<OverAllState> result = parallelAgent.invoke("以'西湖'为主题");

      if (result.isPresent()) {
          OverAllState state = result.get();

          // 访问各个Agent的输出
          state.value("prose_result").ifPresent(r ->
                  System.out.println("散文: " + r));
          state.value("poem_result").ifPresent(r ->
                  System.out.println("诗歌: " + r));
          state.value("summary_result").ifPresent(r ->
                  System.out.println("总结: " + r));

          // 访问合并后的结果
          state.value("merged_results").ifPresent(r ->
                  System.out.println("合并结果: " + r));
      }
  }

3. 自定义合并策略

通过自定义合并策略来控制组合多个Agent的输出:

java 复制代码
public class CustomMergeStrategy implements ParallelAgent.MergeStrategy {

    @Override
    public Object merge(Map<String, Object> mergedState, OverAllState state) {
        // 从每个Agent的状态中提取输出
        state.data().forEach((key, value) -> {

            // 检查key不为null且以"_result"结尾
            if (key != null && key.endsWith("_result")) {
                String resultText = "";
                if (value instanceof GraphResponse graphResponse) {
                    if (graphResponse.resultValue().isPresent()) {
                        HashMap messageMap = (HashMap) graphResponse.resultValue().get();
                        AssistantMessage assistantMessage = (AssistantMessage) messageMap.get(key);
                        resultText = assistantMessage.getText();
                    }
                } else if (value != null) {
                    resultText = value.toString();
                }
                Object existing = mergedState.get("all_results");
                if (existing == null) {
                    mergedState.put("all_results", resultText);
                }
                else {
                    mergedState.put("all_results", existing + "\n\n---\n\n" + resultText);
                }
            }
        });
        return mergedState;
    }
}

4. 输出结果

java 复制代码
合并结果: {all_results=《曲径证词》

粉墙是未拆封的宣纸,  
苔痕在青砖缝里写小楷------  
一笔,就洇开三百年雨。  

假山不假:它用太湖石的嶙峋,  
把整座江南叠进一拳掌中;  
游鱼在漏窗格子里游成篆字,  
而影子,在池底临摹另一座园林。  

你数过九曲桥的弯吗?  
每一道折,都把直路还给流水,  
把时间还给回廊的弧度。  
当夕光斜切过飞檐,  
瓦上霜色忽然浮起------  
原来最深的幽静,  
是光在转身时,  
轻轻合拢的门。  

(石阶微凉,而月光正从花窗进来,  
替所有未出口的留白,  
落款。)

---

苏州园林是中国古典私家园林的杰出代表,以"咫尺乾坤"的造园理念,融合诗、书、画、印等艺术形式,追求自然意趣与人文精神的统一。其典型特征包括精巧的布局(如借景、框景、对景)、丰富的建筑元素(亭、台、楼、阁、廊、舫)、写意的山水营造(旱园水做、石峰点景)、细腻的装饰工艺(花窗、铺地、彩绘、木雕)以及深厚的文化内涵(隐逸思想、文人审美)。代表园林有拙政园、留园、网师园、狮子林等,1997年被联合国教科文组织列入《世界遗产名录》。

---

。。。。不粘贴出来了

六、智能路由(LlmRoutingAgent)

路由模式中,使用大语言模型(LLM)动态决定将请求路由到哪个子Agent。这种模式非常适合需要智能选择不同专家Agent的场景。

1.执行流程

  1. 路由Agent接收用户输入
  2. LLM分析输入并决定最合适的子Agent
  3. 选中的子Agent处理请求
  4. 结果返回给用户

2. 示例代码

java 复制代码
public static void main(String[] args) {

    ChatModel chatModel = getChatModel();
    ReactAgent proseWriterAgent = ReactAgent.builder()
            .name("prose_writer_agent")
            .model(chatModel)
            .description("Can write prose articles.")
            .instruction("You are a renowned writer skilled in writing prose. Please respond to the following request: {input}")
            .outputKey("prose_article")
            .build();

    ReactAgent poemWriterAgent = ReactAgent.builder()
            .name("poem_writer_agent")
            .model(chatModel)
            .description("Can write modern poetry.")
            .instruction("You are a famous poet skilled in modern poetry. Please use tools to respond to the following request: {input}")
            .outputKey("poem_article")
            .tools(List.of(createPoetToolCallback()))
            .build();

    LlmRoutingAgent blogAgent = LlmRoutingAgent.builder()
            .name("blog_agent")
            .model(chatModel)
            .description("Can write articles or poems based on user-provided topics.")
            .subAgents(List.of(proseWriterAgent, poemWriterAgent))
            .build();

    try {

        GraphRepresentation representation = blogAgent.getGraph().getGraph(GraphRepresentation.Type.PLANTUML);
        System.out.println(representation.content());

        Optional<OverAllState> result = blogAgent.invoke("帮我写一个100字左右的现代诗");
        blogAgent.invoke("帮我写一个100字左右的现代诗");
        Optional<OverAllState> result3 = blogAgent.invoke("帮我写一个100字左右的现代诗");


        OverAllState state = result.get();
        OverAllState state3 = result3.get();

        AssistantMessage poemContent = (AssistantMessage) state.value("poem_article").get();
        AssistantMessage poemContent3 = (AssistantMessage) state3.value("poem_article").get();

        System.out.println(result.get());
        System.out.println("------------------");
        System.out.println(result3.get());
    }
    catch (CompletionException | GraphRunnerException e) {
        e.printStackTrace();
    }
}

3. 输出结果

java 复制代码
10:45:58.958 [main] INFO com.alibaba.cloud.ai.graph.agent.flow.node.RoutingNode -- RoutingAgent blog_agent routed to single sub-agent poem_writer_agent.
Poet tool called : 100字左右的现代诗
10:46:03.509 [main] INFO com.alibaba.cloud.ai.graph.agent.flow.node.RoutingNode -- RoutingAgent blog_agent routed to single sub-agent poem_writer_agent.
Poet tool called : 100字左右的现代诗
10:46:08.768 [main] INFO com.alibaba.cloud.ai.graph.agent.flow.node.RoutingNode -- RoutingAgent blog_agent routed to single sub-agent poem_writer_agent.
Poet tool called : 帮我写一个100字左右的现代诗
{"OverAllState":{"data":{"_graph_execution_id_":"438452b3-d336-4581-99ac-690e56564841","input":"帮我写一个100字左右的现代诗","messages":[{"messageType":"USER","metadata":{"messageType":"USER"},"media":[],"text":"帮我写一个100字左右的现代诗"},{"messageType":"USER","metadata":{"messageType":"USER"},"rendered":false,"text":"You are a famous poet skilled in modern poetry. Please use tools to respond to the following request: {input}"},{"messageType":"ASSISTANT","metadata":{"search_info":"","role":"ASSISTANT","messageType":"ASSISTANT","finishReason":"STOP","id":"08c74cd3-a22f-476e-b9dd-52506b5642be","reasoningContent":""},"toolCalls":[],"media":[],"text":"在城市的缝隙里,  \n一束光悄悄发芽,  \n穿过钢筋水泥的沉默,  \n在风中轻轻说话。  \n\n夜色如墨,却不再黑,  \n星星点亮了每一个角落,  \n我站在时间的边缘,  \n等一朵云,轻轻落下。  \n\n------这是属于你的一首现代诗,简洁而有呼吸感,愿它在喧嚣中为你留出一片静默与微光。"}],"poem_article":{"messageType":"ASSISTANT","metadata":{"search_info":"","role":"ASSISTANT","messageType":"ASSISTANT","finishReason":"STOP","id":"08c74cd3-a22f-476e-b9dd-52506b5642be","reasoningContent":""},"toolCalls":[],"media":[],"text":"在城市的缝隙里,  \n一束光悄悄发芽,  \n穿过钢筋水泥的沉默,  \n在风中轻轻说话。  \n\n夜色如墨,却不再黑,  \n星星点亮了每一个角落,  \n我站在时间的边缘,  \n等一朵云,轻轻落下。  \n\n------这是属于你的一首现代诗,简洁而有呼吸感,愿它在喧嚣中为你留出一片静默与微光。"}}}}
------------------
省略。。

4. 自定义提示词

LlmRoutingAgent支持使用SystemPrompt指定系统提示词,下面摘抄自官方示例:

text 复制代码
final String ROUTING_SYSTEM_PROMPT = """
你是一个智能的内容路由Agent,负责根据用户需求将任务路由到最合适的专家Agent。

## 你的职责
1. 仔细分析用户输入的意图和需求
2. 根据任务特性,选择最合适的专家Agent
3. 确保路由决策准确、高效

## 可用的子Agent及其职责

### writer_agent
- **功能**: 擅长创作各类文章,包括散文、诗歌等文学作品
- **适用场景**:
* 用户需要创作新文章、散文、诗歌等原创内容
* 简单的写作任务
- **输出**: writer_output

### reviewer_agent
- **功能**: 擅长对文章进行评论、修改和润色
- **适用场景**:
* 用户需要修改、评审或优化现有文章
* 需要提高文章质量
- **输出**: reviewer_output

### translator_agent
- **功能**: 擅长将文章翻译成各种语言
- **适用场景**:
* 用户需要将内容翻译成其他语言
* 多语言转换需求
- **输出**: translator_output

## 决策规则

1. **写作任务**: 如果用户需要创作新内容,选择 writer_agent
2. **修改任务**: 如果用户需要修改或优化现有内容,选择 reviewer_agent
3. **翻译任务**: 如果用户需要翻译内容,选择 translator_agent

## 响应格式
只返回Agent名称(writer_agent、reviewer_agent、translator_agent),不要包含其他解释。
""";

LlmRoutingAgent routingAgent = LlmRoutingAgent.builder()
.name("content_routing_agent")
.description("根据用户需求智能路由到合适的专家Agent")
.model(chatModel)
.systemPrompt(ROUTING_SYSTEM_PROMPT)
.subAgents(List.of(writerAgent, reviewerAgent, translatorAgent))
.build();

七、监督者(SupervisorAgent)

SupervisorAgent 是多智能体系统的 "大脑 / 协调者",核心职责:

  • 接收用户请求,理解并拆解复杂任务
  • 决策调度:根据任务类型,选择最合适的子智能体(如写作、翻译、搜索等)
  • 循环执行:多次调用不同子智能体,完成多步骤任务
  • 结果整合:汇总子智能体输出,形成最终答案

1. 执行流程

  1. 监督者Agent接收用户输入或前序Agent的输出
  2. LLM分析当前状态并决定最合适的子Agent
  3. 选中的子Agent处理任务
  4. 子Agent执行完成后返回监督者
  5. 监督者 根据结果决定:
    • 继续路由到另一个子Agent(多步骤任务)
    • 返回 FINISH 完成任务

2. 示例代码

javav 复制代码
static final String SUPERVISOR_SYSTEM_PROMPT = """
            你是一个智能的内容管理监督者,负责协调和管理多个专业Agent来完成用户的内容处理需求。

            ## 你的职责
            1. 分析用户需求,将其分解为合适的子任务
            2. 根据任务特性,选择合适的Agent进行处理
            3. 监控任务执行状态,决定是否需要继续处理或完成任务
            4. 当所有任务完成时,返回FINISH结束流程

            ## 可用的子Agent及其职责

            ### writer_agent
            - **功能**: 擅长创作各类文章,包括散文、诗歌等文学作品
            - **适用场景**: 
            * 用户需要创作新文章、散文、诗歌等原创内容
            * 简单的写作任务,不需要后续评审或修改
            - **输出**: writer_output

            ### translator_agent
            - **功能**: 擅长将文章翻译成各种语言
            - **适用场景**: 当文章需要翻译成其他语言时
            - **输出**: translator_output

            ## 决策规则

            1. **单一任务判断**:
             - 如果用户只需要简单写作,选择 writer_agent
             - 如果用户需要翻译,选择 translator_agent

            2. **多步骤任务处理**:
             - 如果用户需求包含多个步骤(如"先写文章,然后翻译"),需要分步处理
             - 先路由到第一个合适的Agent,等待其完成
             - 完成后,根据剩余需求继续路由到下一个Agent
             - 直到所有步骤完成,返回FINISH

            3. **任务完成判断**:
             - 当用户的所有需求都已满足时,返回FINISH

            ## 响应格式
            只返回Agent名称(writer_agent、translator_agent)或FINISH,不要包含其他解释。
            """;
            
public static void main(String[] args) throws GraphRunnerException, IOException {

    ChatModel chatModel = getChatModel();

    // 创建专业化的子Agent
    ReactAgent writerAgent = ReactAgent.builder()
            .name("writer_agent")
            .model(chatModel)
            .description("擅长创作各类文章,包括散文、诗歌等文学作品")
            .outputKey("writer_output")
            .build();

    ReactAgent translatorAgent = ReactAgent.builder()
            .name("translator_agent")
            .model(chatModel)
            .description("擅长将文章翻译成各种语言")
            .outputKey("translator_output")
            .build();

    // 创建监督者Agent
    SupervisorAgent supervisorAgent = SupervisorAgent.builder()
            .name("content_supervisor")
            .description("内容管理监督者")
            .systemPrompt(SUPERVISOR_SYSTEM_PROMPT)
            .mainAgent(writerAgent)
            .model(chatModel)
            .subAgents(List.of(writerAgent, translatorAgent))
            .build();

    // 使用 - 监督者会根据任务自动路由并支持多步骤处理
    Flux<NodeOutput> flux = supervisorAgent.stream("先帮我写一篇关于春天的短文,然后将文章翻译成英文");

    flux.subscribe(chunk -> {
        if (chunk instanceof StreamingOutput<?> streamingOutput) {
            String newContent = "";
            Message message = streamingOutput.message();
            if (message instanceof AssistantMessage assistantMessage) {
                Object finishReason = message.getMetadata().get("finishReason");
                if (finishReason == null) {
                    newContent = assistantMessage.getText();
                }
                if (finishReason != null && !finishReason.toString().equals("STOP")) {

                    newContent = assistantMessage.getText();
                }
            }
            System.out.println(newContent);
        }
    });

    System.in.read();
}

3. 输出结果

java 复制代码
11:06:21.373 [main] INFO com.alibaba.cloud.ai.graph.agent.flow.node.MainAgentNodeAction -- Invoking mainAgent 'writer_agent' compiled graph with threadId: Optional[subgraph_writer_agent]
  
Agent output text: **中文短文:春天的信使**

当冬寒悄然退去,大地便轻轻舒展腰身------春天来了。  
柳枝最先醒来,在微风中抽出嫩黄的新芽,像一串串小小的音符,轻轻摇曳在清冽的空气里。桃花、杏花、梨花次第绽放,粉的娇羞,白的澄澈,红的热烈,把山坡、小院、河岸染成流动的锦缎。泥土松软温润,蚯蚓在深处翻动,草尖顶开枯叶,怯生生地探出一点新绿。  

清晨,鸟鸣清亮如洗;午后,阳光温柔似蜜,晒得人懒洋洋地想打个盹;傍晚,归燕掠过屋檐,衔来南方的暖意与旧年的故事。孩子们脱下厚衣,在田野里奔跑,纸鸢乘着东风扶摇直上,仿佛把整个童年的欢笑都放飞到了云朵之间。  

春天从不喧哗,却用最细腻的笔触,把希望写进每一片叶脉、每一滴露珠、每一双仰望天空的眼睛里。它提醒我们:凋零不是终点,而是生命在静默中积蓄力量,只为一次更盛大的重逢。

---

**English Translation: The Herald of Spring**

As winter's chill quietly retreats, the earth gently stretches its limbs---spring has arrived.  
The willow branches are the first to awaken, sprouting tender yellow buds in the breeze---like tiny musical notes swaying softly in the crisp, clear air. Peach blossoms, apricot flowers, and pear blossoms bloom in gentle succession: pink ones blush with shy charm, white ones gleam with serene purity, and red ones blaze with quiet passion---painting hillsides, courtyards, and riverbanks with a flowing, living tapestry. The soil grows soft and warm; earthworms stir beneath the surface, while fresh green shoots push through last year's dry leaves, timidly raising their heads.  

At dawn, birdsong rings out, clear and cleansing; at noon, sunlight pours down like golden honey---so warm and gentle it lulls one into drowsy contentment; by evening, swallows glide home across rooftops, carrying southern warmth and stories from seasons past. Children shed their heavy coats and race across open fields; kites soar high on the east wind, lifting childhood laughter all the way up into the clouds.  

Spring never shouts---it speaks instead in whispers, using the finest brushstroke to inscribe hope into every leaf vein, every dewdrop, and every pair of eyes gazing upward toward the sky. It reminds us: decay is never an end, but rather life's quiet season of gathering strength---preparing, always, for a more magnificent reunion.

八、多种Agent混合使用

实际业务中,往往会将多种Agent模式组合使用,打造完整的工作流。以下以电商订单智能处理为例,融合并行查询、智能分析、路由处理、顺序执行,实现全自动售后处理。

1. 示例代码

java 复制代码
public static void main(String[] args) throws GraphRunnerException {

    ChatModel chatModel = getChatModel();
    // 1. 创建并行查询Agent(同时查用户信息 + 订单信息)
    ReactAgent userQueryAgent = ReactAgent.builder()
            .name("user_query")
            .model(chatModel)
            .description("查询用户信息、会员等级、历史行为")
            .instruction("根据用户ID查询用户信息:{input}")
            .outputKey("user_info")
            .build();

    ReactAgent orderQueryAgent = ReactAgent.builder()
            .name("order_query")
            .model(chatModel)
            .description("查询订单状态、物流、商品信息")
            .instruction("根据订单号查询订单详细信息:{input}")
            .outputKey("order_info")
            .build();

    // 并行执行:同时查用户+订单,大幅提速
    ParallelAgent queryAgent = ParallelAgent.builder()
            .name("parallel_query")
            .description("并行查询用户信息与订单信息")
            .subAgents(List.of(userQueryAgent, orderQueryAgent))
            .mergeOutputKey("query_data")
            .build();

    // 2. 智能分析Agent(分析问题类型:退款/换货/补发/咨询)
    ReactAgent analysisAgent = ReactAgent.builder()
            .name("order_analysis")
            .model(chatModel)
            .description("分析用户问题、订单状态,给出处理建议")
            .instruction("""
                      分析以下查询数据,判断用户需求类型:
                      1. 未发货仅退款 → 退款
                      2. 已收货质量问题 → 换货
                      3. 少发/漏发 → 补发
                      4. 其他 → 人工客服
                      数据:{query_data}
                    """)
            .outputKey("analysis_result")
            .build();

    // 3. 路由处理Agent(根据分析结果,自动选择处理方式)
    ReactAgent refundAgent = ReactAgent.builder()
            .name("refund_process")
            .model(chatModel)
            .description("自动生成退款方案")
            .instruction("""
                      根据订单与分析结果生成退款处理方案:
                      订单信息:{order_info}
                      分析结果:{analysis_result}
                    """)
            .outputKey("refund_solution")
            .build();

    ReactAgent exchangeAgent = ReactAgent.builder()
            .name("exchange_process")
            .model(chatModel)
            .description("自动生成换货方案")
            .instruction("""
                      根据订单与分析结果生成换货处理方案:
                      订单信息:{order_info}
                      分析结果:{analysis_result}
                    """)
            .outputKey("exchange_solution")
            .build();

    ReactAgent resendAgent = ReactAgent.builder()
            .name("resend_process")
            .model(chatModel)
            .description("自动生成补发方案")
            .instruction("""
                      根据订单与分析结果生成补发处理方案:
                      订单信息:{order_info}
                      分析结果:{analysis_result}
                    """)
            .outputKey("resend_solution")
            .build();

    // LLM智能路由:自动选最合适的处理Agent
    LlmRoutingAgent processAgent = LlmRoutingAgent.builder()
            .name("process_router")
            .description("根据分析结果智能路由到对应处理流程")
            .model(chatModel)
            .subAgents(List.of(refundAgent, exchangeAgent, resendAgent))
            .build();

    // 4. 组合成完整工作流(顺序执行)
    SequentialAgent orderWorkflow = SequentialAgent.builder()
            .name("ecommerce_order_workflow")
            .description("电商订单智能处理全流程:并行查询 → 智能分析 → 路由处理")
            .subAgents(List.of(queryAgent, analysisAgent, processAgent))
            .build();

    // 使用:传入用户问题 + 订单号
    Optional<OverAllState> result = orderWorkflow.invoke("订单号:123456,我要退款,商品还没发货");

    System.out.println(result.get());
}

2. 业务流程图

九、总结

Spring AI Alibaba的Multi-Agent架构,通过分工协作,旨在解决单个Agent的能力瓶颈。四种核心模式各有侧重,适配不同场景:

  • 顺序执行:适合流水线、有先后依赖的任务
  • 并行执行:适合无依赖、需提速的批量任务
  • 智能路由:适合任务类型多变、需智能分流的场景
  • 监督者模式:适合复杂长流程、多步骤协作任务

文中代码已上传GitHub,地址:

github.com/Jucunqi/spr...

相关推荐
IT_陈寒9 小时前
Vue的响应式把我坑惨了,原来问题出在这
前端·人工智能·后端
shark22222229 小时前
能懂!基于Springboot的用户增删查改(三层设计模式)
spring boot·后端·设计模式
IGAn CTOU10 小时前
王炸级更新!Spring Boot 3.4 正式发布,新特性真香!
java·spring boot·后端
柯西劝我别收敛10 小时前
Koordinator-Scheduler 调度器源码解析
后端·云原生
tycooncool10 小时前
Spring中的IOC详解
java·后端·spring
3037810 小时前
消息推送削峰落地方案
后端
爱敲代码的小黄10 小时前
我重新梳理了一遍 RAG,终于明白它不只是接个向量库
后端·面试·agent
亦暖筑序11 小时前
Spring AI Alibaba 报错合集:我踩过的那些坑
java·后端
石榴树下的七彩鱼11 小时前
OCR 识别不准确怎么办?模糊 / 倾斜 / 反光图片优化实战(附完整解决方案 + 代码示例)
图像处理·人工智能·后端·ocr·api·文字识别·图片识别
卜夋12 小时前
Rust 学习笔记 - Day 6: 引用与借用
后端·rust