Spring AI系列之Tool Calling实战指南
文章目录 什么是Tool Calling核心流程图️ 方案一本地Tool Calling推荐入门1. 项目依赖2. 配置文件3. 定义工具类核心4. Controller层调用5. 测试验证 方案二MCP协议工具调用企业级MCP架构图 两种方案对比⚠️ 最佳实践 什么是Tool CallingTool Calling工具调用是AI Agent的核心能力允许大语言模型LLM在需要时调用外部工具/函数来获取实时数据或执行操作。核心流程图流程说明定义工具将Java方法注册为工具包含名称、描述、参数模式AI决策模型分析用户意图决定是否需要调用工具执行工具Spring AI自动分发并执行对应的工具方法结果返回将工具执行结果传回模型生成最终回复️ 方案一本地Tool Calling推荐入门1. 项目依赖dependencies!-- Spring Boot Starter --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!-- Spring AI OpenAI Starter --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-model-openai/artifactId/dependency/dependenciesdependencyManagementdependenciesdependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-bom/artifactIdversion1.0.0-M5/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagement2. 配置文件# application.ymlspring:ai:openai:api-key:your-api-keybase-url:https://api.siliconflow.cnchat:options:model:moonshotai/Kimi-K2-Thinkingtemperature:0.73. 定义工具类核心使用Tool注解声明式定义工具 获取当前日期时间的工具类packagecom.example.ai.tool;importorg.springframework.ai.tool.annotation.Tool;importorg.springframework.stereotype.Component;importjava.time.LocalDate;importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;ComponentpublicclassTimeTools{Tool(description获取用户所在时区的当前日期和时间用于回答时间相关问题)publicStringgetCurrentTime(){returnLocalDateTime.now().atZone(java.time.ZoneId.systemDefault()).toString();}}数学运算的工具类packagecom.example.ai.tool;importlombok.extern.slf4j.Slf4j;importorg.springframework.ai.tool.annotation.Tool;importorg.springframework.ai.tool.annotation.ToolParam;importorg.springframework.stereotype.Component;importjavax.script.ScriptEngine;importjavax.script.ScriptEngineManager;importjava.util.regex.Pattern;/** * 数学计算工具支持加减乘除及括号运算 * 注意Java 17 已移除 Nashorn JS 引擎使用自定义表达式解析器替代 */ComponentSlf4jpublicclassCalcTools{// 安全正则只允许数字 运算符privatestaticfinalPatternSAFE_EXPRPattern.compile([0-9\\-*/().\\s]);Tool(description计算数学表达式支持加减乘除及括号例如 1020*3 或 (1020)*3)publicStringcalculate(ToolParam(description数学表达式例如 1020*3 或 (1020)*3)Stringexpr){try{if(!SAFE_EXPR.matcher(expr).matches()){return非法表达式仅支持数字 - * / ( );}ScriptEngineManagermanagernewScriptEngineManager();ScriptEngineenginemanager.getEngineByName(graal.js);if(enginenull){log.error(错误找不到 graal.js 引擎请确认依赖已正确添加);return;}Objectresultengine.eval(expr);// 使用 Number 接口安全转换避免直接强转 doubledoublenumericResult((Number)result).doubleValue();return计算结果:numericResult;}catch(Exceptione){log.error(计算失败,e);return计算失败e.getMessage();}}}因为是jdk17版本所以引入graal.js引擎maven配置文件加上dependencygroupIdorg.graalvm.js/groupIdartifactIdjs/artifactIdversion24.1.2/version/dependencydependencygroupIdorg.graalvm.js/groupIdartifactIdjs-scriptengine/artifactIdversion24.1.2/version/dependency查询天气的工具类packagecom.example.ai.tool;importcom.fasterxml.jackson.databind.ObjectMapper;importlombok.extern.slf4j.Slf4j;importorg.springframework.ai.tool.annotation.Tool;importorg.springframework.ai.tool.annotation.ToolParam;importorg.springframework.stereotype.Component;importorg.springframework.web.reactive.function.client.WebClient;importjava.util.Map;/** * 天气查询工具通过聚合数据天气 API 获取实时天气信息 */ComponentSlf4jpublicclassWeatherTools{privatefinalWebClientwebClient;privatefinalObjectMapperobjectMappernewObjectMapper();publicWeatherTools(WebClient.BuilderwebClientBuilder){this.webClientwebClientBuilder.build();}/** * 免费天气接口无需 API Key国内直接访问支持全国城市 */Tool(description查询中国城市的实时天气返回温度、天气状况、风向风速)publicStringgetWeather(ToolParam(description中文城市名称例如北京、上海、长沙、深圳)Stringcity){try{StringapiKey4efc59bb794a071dcabf21fc0583dffd;StringurlString.format(http://apis.juhe.cn/simpleWeather/query?key%scity%s,apiKey,city);returnwebClient.get().uri(url).retrieve().bodyToMono(String.class).block();}catch(Exceptione){log.error(查询天气服务异常,e);return天气查询服务异常请稍后再试;}}}4. Controller层调用packagecom.example.ai.controller;importcom.example.ai.tool.CalcTools;importcom.example.ai.tool.TimeTools;importcom.example.ai.tool.WeatherTools;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;RestControllerpublicclassToolCallingController{privatefinalChatClientchatClient;privatefinalTimeToolstimeTools;privatefinalCalcToolscalcTools;privatefinalWeatherToolsweatherTools;publicToolCallingController(ChatClient.Builderbuilder,TimeToolstimeTools,CalcToolscalcTools,WeatherToolsweatherTools){this.chatClientbuilder.build();this.timeToolstimeTools;this.calcToolscalcTools;this.weatherToolsweatherTools;}/** * Tool Calling 接口支持时间查询、数学计算、天气查询 * * param msg 用户问题 * return AI 回答 */GetMapping(/ai)publicStringcallTool(RequestParamStringmsg){// 注册所有工具AI 根据问题自动选择合适的工具调用returnchatClient.prompt(msg).tools(timeTools,calcTools,weatherTools).call().content();}}5. 测试验证# 测试1查询时间会触发getCurrentDateTime工具curlhttp://localhost:8080/api?msg现在几点了明天是几号# 测试2简单数学运算curlhttp://localhost:8080/ai?msg1020*3 等于多少# 测试2查询实时天气curlhttp://localhost:8080/ai?msg北京天气执行逻辑解析步骤动作说明1用户提问“现在几点了”2LLM分析识别需要当前时间信息3工具调用自动调用getCurrentDateTime()4结果返回工具返回时间字符串5生成回复LLM基于工具结果生成自然语言回答 方案二MCP协议工具调用企业级MCPModel Context Protocol是Anthropic推出的开放协议标准化AI工具集成 。MCP架构图 两种方案对比特性本地Tool CallingMCP协议复杂度⭐ 简单⭐⭐⭐ 较复杂适用场景单体应用、快速原型微服务、企业级集成工具复用仅限当前应用跨应用、跨语言共享生态兼容Spring AI专属支持Claude、Cursor、Cline等部署方式嵌入式独立Server/Client模式推荐阶段开发测试生产环境⚠️ 最佳实践工具描述要清晰Tool的description直接影响LLM的决策准确性参数类型明确使用具体类型而非String让Spring AI自动生成Schema错误处理工具方法内做好异常捕获返回友好的错误信息权限控制敏感操作如转账、删除需增加人工确认环节日志记录开启logging.level.org.springframework.aiDEBUG查看工具调用详情通过以上方案您可以快速构建具备Tool Calling能力的Spring Boot AI应用。建议从本地Tool Calling开始入门熟悉后再迁移到MCP架构以获得更好的扩展性。