第十八章 Agent 智能体与今日菜单应用版本标注Spring AI:1.1.2Spring 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本地工具菜单推荐能力。外部工具通过 MCP Client 自动发现到的第三方工具。这样可以直接验证Agent 在一次对话里可以同时调度本地Tool和外部 MCP 工具。二、和前面ChatModel / ChatClient的区别前面章节里ChatModel/ChatClient更偏“发起一次对话调用”。本章里的ReactAgent更偏“执行任务”理解用户意图。判断要调用哪个工具。调用工具并观察结果。基于结果组织最终答案。对于简单问题这三者体感差异可能不大但一旦涉及多工具组合ReactAgent的优势会更明显。三、Saa18 当前可运行代码3.1 配置类合并本地工具与 MCP 工具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(); } }这段代码是本章核心。它做了三件事ToolCallbacks.from(menuTools)加载本地菜单工具。mcpTools.getToolCallbacks()加载外部 MCP 工具。合并后通过.tools(allTools)注册到同一个 Agent。这就是“本地 外部”组合能力的关键实现。3.2 本地工具类菜单推荐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小雨, temperature12) public String recommendByWeather(String weather, Integer temperature) { if (weather null || weather.isBlank() || temperature null) { return 请提供完整信息例如weather小雨, temperature12。; } 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 控制器统一入口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 当前配置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说明本章除了模型 API Key还需要 MCP Client 配置。servers-configuration指向外部 MCP 服务清单文件。4.2 关键依赖dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-agent-framework/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-client/artifactId /dependency前者提供 Agent 运行能力后者提供外部 MCP 工具接入能力。五、测试建议启动后可先测http://localhost:8001/eatAgent?msg我想吃辣的 http://localhost:8001/eatAgent?msg今天小雨12度推荐晚饭 http://localhost:8001/eatAgent?msg今天的南京天气适合吃什么观察点是否会触发菜单推荐工具。当问题涉及天气时是否能利用外部工具结果再给菜单建议。返回是否明显比纯对话更“任务化”。六、本章小结当前Saa18的价值在于跑通了一个实用结构ReactAgent作为统一执行入口。本地MenuTools提供业务逻辑。ToolCallbackProvider注入外部 MCP 工具。在一个 Agent 中完成“本地能力 外部能力”的协同调用。这个结构是后续扩展多工具、多步骤 Agent 的基础。本章重点读懂本章不是单工具示例而是工具合并示例。理解.tools(allTools)里的本地与外部工具来源。用更真实菜单逻辑验证 Agent 的任务执行能力。编辑者Flittly更新时间2026年4月相关资源Spring AI 官方文档 | Spring AI Alibaba