【SpringAIAlibaba新手村系列】(18)Agent 智能体与今日菜单应用

第十八章 Agent 智能体与今日菜单应用

版本标注

  • Spring AI: 1.1.2
  • Spring AI Alibaba: 1.1.2.0

章节定位

  • 本章在 Agent 入口上使用 ReactAgent
  • 同时把本地菜单工具与外部 MCP 工具合并注册,形成"本地能力 + 外部能力"的组合示例。

s01 > s02 > s03 > s04 > s05 > s06 > s07 > s08 > s09 > s10 > s11 > s12 > s13 > s14 > s15 > s16 > s17 > [ s18 ]

一、本章要做什么

这一章的目标不是再做一个"只有本地工具"的 Agent,而是把两类工具放进同一个 ReactAgent

  1. 本地工具:菜单推荐能力。
  2. 外部工具:通过 MCP Client 自动发现到的第三方工具。

这样可以直接验证:Agent 在一次对话里,可以同时调度本地 @Tool 和外部 MCP 工具。

二、和前面 ChatModel / ChatClient 的区别

前面章节里,ChatModel / ChatClient 更偏"发起一次对话调用"。

本章里的 ReactAgent 更偏"执行任务":

  1. 理解用户意图。
  2. 判断要调用哪个工具。
  3. 调用工具并观察结果。
  4. 基于结果组织最终答案。

对于简单问题,这三者体感差异可能不大;但一旦涉及多工具组合,ReactAgent 的优势会更明显。

三、Saa18 当前可运行代码

3.1 配置类:合并本地工具与 MCP 工具

ini 复制代码
package cn.edu.nnu.opengms.config;

import cn.edu.nnu.opengms.service.MenuTools;
import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.support.ToolCallbacks;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.stream.Stream;

@Configuration
public class DashScopeConfig {
    @Bean
    public ReactAgent menuAgent(ChatModel chatModel, MenuTools menuTools, ToolCallbackProvider mcpTools)
    {
        ToolCallback[] localTools = ToolCallbacks.from(menuTools);
        ToolCallback[] externalTools = mcpTools.getToolCallbacks();

        ToolCallback[] allTools = Stream.concat(Arrays.stream(localTools), Arrays.stream(externalTools))
                .toArray(ToolCallback[]::new);

        return ReactAgent.builder()
                .name("menu-agent")
                .description("根据用户问题推荐菜单、解释菜品或查询天气")
                .model(chatModel)
                .tools(allTools)
                .build();
    }
}

这段代码是本章核心。

它做了三件事:

  1. ToolCallbacks.from(menuTools):加载本地菜单工具。
  2. mcpTools.getToolCallbacks():加载外部 MCP 工具。
  3. 合并后通过 .tools(allTools) 注册到同一个 Agent。

这就是"本地 + 外部"组合能力的关键实现。

3.2 本地工具类:菜单推荐

kotlin 复制代码
package cn.edu.nnu.opengms.service;

import org.springframework.ai.tool.annotation.Tool;
import org.springframework.stereotype.Service;

@Service
public class MenuTools {
    @Tool(description = "根据口味推荐菜单")
    public String recommendMenu(String taste) {
        if (taste == null || taste.isBlank()) {
            return "请先告诉我口味偏好(甜/咸/辣)。";
        }

        if (taste.equalsIgnoreCase("甜")) {
            return "推荐菜单:蛋挞、奶茶、甜甜圈";
        } else if (taste.equalsIgnoreCase("咸")) {
            return "推荐菜单:炸鸡、薯条、汉堡";
        } else if (taste.equalsIgnoreCase("辣")) {
            return "推荐菜单:麻辣香锅、辣子鸡、火锅";
        } else {
            return "抱歉,暂时没有相关口味的菜单推荐。";
        }
    }

    @Tool(description = "根据天气状况和温度推荐菜单,参数示例:weather=小雨, temperature=12")
    public String recommendByWeather(String weather, Integer temperature) {
        if (weather == null || weather.isBlank() || temperature == null) {
            return "请提供完整信息,例如:weather=小雨, temperature=12。";
        }

        String w = weather.toLowerCase();

        if (temperature <= 5) {
            return "当前" + weather + ",约" + temperature + "度,推荐暖身菜单:羊肉汤、番茄牛腩、砂锅米线。";
        }

        if (temperature <= 15) {
            if (w.contains("雨") || w.contains("雪")) {
                return "当前" + weather + ",约" + temperature + "度,推荐热汤类:酸辣汤面、菌菇鸡汤、馄饨。";
            }
            return "当前" + weather + ",约" + temperature + "度,推荐家常热菜:土豆炖牛肉、青椒肉丝、米饭。";
        }

        if (temperature <= 25) {
            if (w.contains("雨")) {
                return "当前" + weather + ",约" + temperature + "度,推荐温和口味:鲜虾粥、番茄鸡蛋面、清蒸鱼。";
            }
            if (w.contains("晴")) {
                return "当前" + weather + ",约" + temperature + "度,推荐轻食搭配:鸡胸沙拉、玉米浓汤、全麦三明治。";
            }
            return "当前" + weather + ",约" + temperature + "度,推荐均衡菜单:宫保鸡丁、时蔬、紫菜蛋花汤。";
        }

        if (w.contains("雨") || w.contains("闷")) {
            return "当前" + weather + ",约" + temperature + "度,推荐清爽低负担:绿豆粥、凉拌鸡丝、蒸南瓜。";
        }

        return "当前" + weather + ",约" + temperature + "度,推荐夏季清凉菜单:凉面、手撕鸡、冬瓜排骨汤。";
    }
}

这个版本比"甜咸辣"单一推荐更适合测试 Agent 的决策路径,尤其是当问题里同时出现天气和温度时。

3.3 控制器:统一入口

kotlin 复制代码
package cn.edu.nnu.opengms.controller;

import com.alibaba.cloud.ai.graph.agent.ReactAgent;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MenuController {
    @Resource(name = "menuAgent")
    private ReactAgent menuAgent;

    @GetMapping(value = "/eatAgent")
    public String eatAgent(@RequestParam(name = "msg", defaultValue = "今天吃什么") String msg) throws GraphRunnerException {
        return menuAgent.call(msg).getText();
    }
}

这一层保持简单:把用户输入交给 Agent,后续工具决策由 Agent 运行期处理。

四、application.yml 与依赖

4.1 当前配置

yaml 复制代码
server:
  port: 8001

spring:
  application:
    name: Saa09

  ai:
    dashscope:
      api-key: ${DASHSCOPE_API_KEY}

    mcp:
      client:
        request-timeout: 20s
        toolcallback:
          enabled: true
        stdio:
          servers-configuration: classpath:/mcp-server.json5

说明:

  1. 本章除了模型 API Key,还需要 MCP Client 配置。
  2. servers-configuration 指向外部 MCP 服务清单文件。

4.2 关键依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.cloud.ai</groupId>
    <artifactId>spring-ai-alibaba-agent-framework</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>

前者提供 Agent 运行能力,后者提供外部 MCP 工具接入能力。

五、测试建议

启动后可先测:

bash 复制代码
http://localhost:8001/eatAgent?msg=我想吃辣的
http://localhost:8001/eatAgent?msg=今天小雨12度,推荐晚饭
http://localhost:8001/eatAgent?msg=今天的南京天气适合吃什么?

观察点:

  1. 是否会触发菜单推荐工具。
  2. 当问题涉及天气时,是否能利用外部工具结果再给菜单建议。
  3. 返回是否明显比纯对话更"任务化"。

六、本章小结

当前 Saa18 的价值在于跑通了一个实用结构:

  1. ReactAgent 作为统一执行入口。
  2. 本地 MenuTools 提供业务逻辑。
  3. ToolCallbackProvider 注入外部 MCP 工具。
  4. 在一个 Agent 中完成"本地能力 + 外部能力"的协同调用。

这个结构是后续扩展多工具、多步骤 Agent 的基础。

本章重点

  1. 读懂本章不是单工具示例,而是工具合并示例。
  2. 理解 .tools(allTools) 里的本地与外部工具来源。
  3. 用更真实菜单逻辑验证 Agent 的任务执行能力。

📝 编辑者 :Flittly

📅 更新时间 :2026年4月

🔗 相关资源Spring AI 官方文档 | Spring AI Alibaba

相关推荐
木井巳2 小时前
【递归算法】目标和
java·算法·leetcode·决策树·深度优先
亦暖筑序2 小时前
手写 Spring AI Agent:让大模型自主规划任务,ReAct 模式全流程拆解
java·人工智能·spring
敖正炀2 小时前
ReentrantLock 与 synchronized对比
java
XiYang-DING2 小时前
【Java】二叉搜索树(BST)
java·开发语言·python
weixin_437957612 小时前
Mysql安装不成功
java
Lyyaoo.2 小时前
【JAVA基础面经】进程安全问题(synchronized and volatile)
java·开发语言·jvm
Andya_net2 小时前
Java | 基于 Feign 流式传输操作SFTP文件传输
java·开发语言·spring boot
_Evan_Yao2 小时前
别让“规范”困住你:前后端交互中的方法选择与认知突围
java·后端·交互·restful
星乐a3 小时前
String vs StringBuilder vs StringBuffer深度解析
java