006-Spring AI Alibaba Tool Calling 功能完整案例

本案例展示了 Spring AI Alibaba 中 Tool Calling 功能的四种不同实现方式,通过四个独立的示例来演示如何将外部工具集成到 AI 应用中,增强 AI 的能力。
1. 案例目标
我们将创建一个包含四种不同 Tool Calling 实现方式的 Web 应用:
- TimeController:演示如何将方法作为工具使用 (Methods as Tools)
- AddressController:演示如何使用 MethodToolCallback 将方法作为工具
- BaiduTranslateController:演示如何通过函数名将函数作为工具使用 (Function as Tools - Function Name)
- WeatherController:演示如何使用 FunctionCallBack 将函数作为工具
2. 技术栈与核心依赖
- Spring Boot 3.x
- Spring AI Alibaba (用于对接阿里云 DashScope 通义大模型)
- Maven (项目构建工具)
- 百度翻译 API (提供翻译功能)
- 百度地图 API (提供地址信息查询功能)
- Weather API (提供天气信息查询功能)
- 时间服务 (提供时间查询功能)
在 pom.xml 中,你需要引入以下核心依赖:
<dependencies><!-- Spring Web 用于构建 RESTful API --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring AI Alibaba 核心启动器,集成 DashScope --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId></dependency><!-- 百度翻译工具 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-tool-calling-baidutranslate</artifactId></dependency><!-- 天气查询工具 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-tool-calling-weather</artifactId></dependency><!-- 百度地图工具 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-tool-calling-baidumap</artifactId></dependency><!-- 时间工具 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-tool-calling-time</artifactId></dependency><!-- GitHub 工具包 --><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-tool-calling-githubtoolkit</artifactId></dependency>
</dependencies>
3. 项目配置
在 src/main/resources/application.yml 文件中,配置你的 API Key。
spring:ai:alibaba:toolcalling:baidu:translate:enabled: trueapp-id: ${BAIDU_TRANSLATE_APP_ID}secret-key: ${BAIDU_TRANSLATE_SECRET_KEY}map:enabled: trueapiKey: ${BAIDU_MAP_API_KEY}time:enabled: trueweather:enabled: trueapi-key: ${WEATHER_API_KEY}dashscope:api-key: ${AI_DASHSCOPE_API_KEY}
重要提示:请将上述环境变量设置为你从相应服务提供商获取的有效 API Key。你也可以直接将其写在配置文件中,但这不推荐用于生产环境。
4. 编写 Java 代码
4.1 主应用程序类
package com.alibaba.cloud.ai.toolcall;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class ToolCallingApplication {public static void main(String[] args) {SpringApplication.run(ToolCallingApplication.class, args);}
}
4.2 TimeController - Methods as Tools
package com.alibaba.cloud.ai.toolcall.controller;import com.alibaba.cloud.ai.toolcall.component.TimeTools;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/time")
public class TimeController {private final ChatClient dashScopeChatClient;private final TimeTools timeTools;public TimeController(ChatClient chatClient, TimeTools timeTools) {this.dashScopeChatClient = chatClient;this.timeTools = timeTools;}/*** 不使用工具的普通聊天*/@GetMapping("/chat")public String simpleChat(@RequestParam(value = "query", defaultValue = "请告诉我现在北京时间几点了") String query) {return dashScopeChatClient.prompt(query).call().content();}/*** 使用方法作为工具*/@GetMapping("/chat-tool-method")public String chatWithTimeFunction(@RequestParam(value = "query", defaultValue = "请告诉我现在北京时间几点了") String query) {return dashScopeChatClient.prompt(query).tools(timeTools).call().content();}
}
4.3 TimeTools 组件
package com.alibaba.cloud.ai.toolcall.component;import com.alibaba.cloud.ai.toolcalling.time.GetTimeByZoneIdService;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;public class TimeTools {private final GetTimeByZoneIdService timeService;public TimeTools(GetTimeByZoneIdService timeService) {this.timeService = timeService;}@Tool(description = "Get the time of a specified city.")public String getCityTime(@ToolParam(description = "Time zone id, such as Asia/Shanghai") String timeZoneId) {return timeService.apply(new GetTimeByZoneIdService.Request(timeZoneId)).description();}
}
4.4 AddressController - Methods as Tools with MethodToolCallback
package com.alibaba.cloud.ai.toolcall.controller;import com.alibaba.cloud.ai.toolcall.component.AddressInformationTools;
import com.alibaba.cloud.ai.toolcalling.baidumap.BaiduMapSearchInfoService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.definition.ToolDefinition;
import org.springframework.ai.tool.method.MethodToolCallback;
import org.springframework.ai.util.json.schema.JsonSchemaGenerator;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.lang.reflect.Method;@RestController
@RequestMapping("/address")
public class AddressController {private final ChatClient dashScopeChatClient;private final AddressInformationTools addressTools;public AddressController(ChatClient chatClient, AddressInformationTools addressTools) {this.dashScopeChatClient = chatClient;this.addressTools = addressTools;}/*** 不使用工具的普通聊天*/@GetMapping("/chat")public String chat(@RequestParam(value = "address", defaultValue = "北京") String address) throws JsonProcessingException {BaiduMapSearchInfoService.Request query = new BaiduMapSearchInfoService.Request(address);return dashScopeChatClient.prompt(new ObjectMapper().writeValueAsString(query)).call().content();}/*** 使用 MethodToolCallback 将方法作为工具*/@GetMapping("/chat-method-tool-callback")public String chatWithBaiduMap(@RequestParam(value = "address", defaultValue = "北京") String address) throws JsonProcessingException {Method method = ReflectionUtils.findMethod(AddressInformationTools.class, "getAddressInformation", String.class);if (method == null) {throw new RuntimeException("Method not found");}return dashScopeChatClient.prompt(address).toolCallbacks(MethodToolCallback.builder().toolDefinition(ToolDefinition.builder().description("Search for places using Baidu Maps API "+ "or Get detail information of a address and facility query with baidu map or "+ "Get address information of a place with baidu map or "+ "Get detailed information about a specific place with baidu map").name("getAddressInformation").inputSchema(JsonSchemaGenerator.generateForMethodInput(method)).build()).toolMethod(method).toolObject(addressTools).build()).call().content();}
}
4.5 AddressInformationTools 组件
package com.alibaba.cloud.ai.toolcall.component;import com.alibaba.cloud.ai.toolcalling.baidumap.BaiduMapSearchInfoService;public class AddressInformationTools {private final BaiduMapSearchInfoService service;public AddressInformationTools(BaiduMapSearchInfoService service) {this.service = service;}public String getAddressInformation(String address) {return service.apply(new BaiduMapSearchInfoService.Request(address)).message();}
}
4.6 BaiduTranslateController - Function as Tools with Function Name
package com.alibaba.cloud.ai.toolcall.controller;import com.alibaba.cloud.ai.toolcalling.baidutranslate.BaiduTranslateService;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/translate")
public class BaiduTranslateController {private final ChatClient dashScopeChatClient;public BaiduTranslateController(ChatClient chatClient, BaiduTranslateService baiduTranslateService) {this.dashScopeChatClient = chatClient;}/*** 不使用工具的普通聊天*/@GetMapping("/chat")public String simpleChat(@RequestParam(value = "query", defaultValue = "帮我把以下内容翻译成英文:你好,世界。") String query) {return dashScopeChatClient.prompt(query).call().content();}/*** 使用函数名将函数作为工具*/@GetMapping("/chat-tool-function-callback")public String chatTranslateFunction(@RequestParam(value = "query", defaultValue = "帮我把以下内容翻译成英文:你好,世界。") String query) {return dashScopeChatClient.prompt(query).toolNames("baiduTranslate").call().content();}
}
4.7 WeatherController - Function as Tools with FunctionCallBack
package com.alibaba.cloud.ai.toolcall.controller;import com.alibaba.cloud.ai.toolcalling.weather.WeatherService;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.function.FunctionToolCallback;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/weather")
public class WeatherController {private final ChatClient dashScopeChatClient;private final WeatherService weatherService;public WeatherController(ChatClient chatClient, WeatherService weatherService) {this.dashScopeChatClient = chatClient;this.weatherService = weatherService;}/*** 不使用工具的普通聊天*/@GetMapping("/chat")public String simpleChat(@RequestParam(value = "query", defaultValue = "请告诉我北京1天以后的天气") String query) {return dashScopeChatClient.prompt(query).call().content();}/*** 使用 FunctionCallBack 将函数作为工具*/@GetMapping("/chat-tool-function-name")public String chatWithWeatherFunction(@RequestParam(value = "query", defaultValue = "请告诉我北京1天以后的天气") String query) {return dashScopeChatClient.prompt(query).toolCallbacks(FunctionToolCallback.builder("getWeather", weatherService).description("Use api.weather to get weather information.").inputType(WeatherService.Request.class).build()).call().content();}
}
5. 运行与测试
- 启动应用:运行你的 Spring Boot 主程序。
- 使用浏览器或 API 工具(如 Postman, curl)进行测试。
测试 1:时间工具 - 不使用工具
访问以下 URL,询问当前时间,但不使用工具。
GET http://127.0.0.1:8080/time/chat
预期响应:
AI 会基于其内置知识回答,可能无法提供准确的当前时间。
测试 2:时间工具 - 使用方法作为工具
访问以下 URL,询问当前时间,并使用方法作为工具。
GET http://127.0.0.1:8080/time/chat-tool-method
预期响应:
AI 会调用 TimeTools 中的 getCityTime 方法获取准确的当前时间并返回。
测试 3:地址工具 - 不使用工具
访问以下 URL,查询北京的信息,但不使用工具。
GET http://127.0.0.1:8080/address/chat?address=北京
预期响应:
AI 会基于其内置知识回答,可能无法提供详细的地址信息。
测试 4:地址工具 - 使用 MethodToolCallback
访问以下 URL,查询北京的信息,并使用 MethodToolCallback。
GET http://127.0.0.1:8080/address/chat-method-tool-callback?address=北京
预期响应:
AI 会调用 AddressInformationTools 中的 getAddressInformation 方法,通过百度地图 API 获取北京的详细信息并返回。
测试 5:翻译工具 - 不使用工具
访问以下 URL,请求翻译,但不使用工具。
GET http://127.0.0.1:8080/translate/chat?query=帮我把以下内容翻译成英文:你好,世界。
预期响应:
AI 会基于其语言能力尝试翻译,但可能不够准确。
测试 6:翻译工具 - 使用函数名
访问以下 URL,请求翻译,并使用函数名作为工具。
GET http://127.0.0.1:8080/translate/chat-tool-function-callback?query=帮我把以下内容翻译成英文:你好,世界。
预期响应:
AI 会调用百度翻译 API 进行准确的翻译,并返回结果。
测试 7:天气工具 - 不使用工具
访问以下 URL,查询天气,但不使用工具。
GET http://127.0.0.1:8080/weather/chat?query=请告诉我北京1天以后的天气
预期响应:
AI 会基于其内置知识回答,可能无法提供准确的天气预报。
测试 8:天气工具 - 使用 FunctionCallBack
访问以下 URL,查询天气,并使用 FunctionCallBack。
GET http://127.0.0.1:8080/weather/chat-tool-function-name?query=请告诉我北京1天以后的天气
预期响应:
AI 会调用天气 API 获取准确的天气预报信息并返回。
6. 实现思路与扩展建议
实现思路
本案例的核心思想是"工具集成"。通过将外部服务(如时间服务、地图服务、翻译服务、天气服务)作为工具集成到 AI 应用中,扩展 AI 的能力边界。这使得:
- 功能增强:AI 可以访问实时数据和服务,提供更准确、更及时的回答。
- 灵活性高:可以根据需要选择不同的工具集成方式,适应不同的使用场景。
- 可扩展性强:可以轻松添加新的工具,不断扩展 AI 的能力。
四种 Tool Calling 方式对比
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Methods as Tools | 简单方法调用 | 实现简单,代码直观 | 灵活性较低 |
| MethodToolCallback | 需要自定义工具定义 | 可以自定义工具描述和输入模式 | 实现稍复杂 |
| Function as Tools - Function Name | 已注册的函数 | 简单易用,只需函数名 | 需要预先注册函数 |
| FunctionCallBack | 需要自定义函数回调 | 灵活性高,可自定义描述和输入类型 | 实现最复杂 |
扩展建议
- 工具注册中心:可以设计一个工具注册中心,统一管理和发现可用的工具。
- 工具权限控制:为不同用户或角色分配不同的工具访问权限,增强安全性。
- 工具调用链:支持多个工具的链式调用,实现更复杂的业务逻辑。
- 工具调用监控:添加工具调用的监控和日志记录,便于问题排查和性能优化。
- 工具版本管理:支持工具的版本管理,便于工具的升级和回滚。
- 自定义工具开发:根据业务需求开发自定义工具,扩展 AI 的专业领域能力。
7. 相关资源
- 更多可用工具可以参考 工具文档
- MCP 风格的工具请参考 spring-ai-alibaba-mcp-example
- Spring AI 工具详细信息请参考 spring-ai-tools
- 百度翻译 API 访问文档:https://api.fanyi.baidu.com/product/113
- 百度地图 API 文档:https://lbs.baidu.com/faq/api
- 天气预报 API 访问文档:https://www.weatherapi.com/docs/
