工具和MCP调用
请关注微信公众号:阿呆-bot
1. 工程结构概览
Spring AI 提供了完整的工具调用(Tool Calling)能力,让 AI 模型可以调用外部服务。同时,Spring AI 还支持 MCP(Model Context Protocol),这是一个标准化的工具协议。- spring-ai-model/
- ├── tool/ # 工具调用核心
- │ ├── ToolCallback.java # 工具回调接口
- │ ├── ToolDefinition.java # 工具定义
- │ ├── method/ # 方法工具
- │ │ └── MethodToolCallback.java
- │ ├── function/ # 函数工具
- │ │ └── FunctionToolCallback.java
- │ └── resolution/ # 工具解析
- │ ├── ToolCallbackResolver.java
- │ └── SpringBeanToolCallbackResolver.java
- │
- └── model/tool/ # 工具调用管理
- ├── ToolCallingManager.java
- └── DefaultToolCallingManager.java
- mcp/ # MCP 协议支持
- ├── common/ # MCP 核心
- │ ├── AsyncMcpToolCallback.java
- │ ├── SyncMcpToolCallback.java
- │ ├── AsyncMcpToolCallbackProvider.java
- │ └── SyncMcpToolCallbackProvider.java
- └── mcp-annotations-spring/ # MCP 注解支持
- └── annotation/spring/
复制代码 2. 技术体系与模块关系
工具调用和 MCP 的关系:
3. 关键场景示例代码
3.1 方法工具
使用 @Tool 注解定义工具:- @Service
- public class WeatherService {
- @Tool(name = "get_weather", description = "获取天气信息")
- public String getWeather(String city) {
- // 调用天气 API
- return weatherApi.getWeather(city);
- }
-
- @Tool(name = "get_forecast", description = "获取天气预报")
- public WeatherForecast getForecast(
- String city,
- int days,
- ToolContext context // 可选:获取工具上下文
- ) {
- // 可以从 context 中获取对话历史等
- return weatherApi.getForecast(city, days);
- }
- }
复制代码 3.2 函数工具
使用函数式接口定义工具:- FunctionToolCallback<String, String> weatherTool =
- FunctionToolCallback.builder("get_weather",
- (String city) -> weatherApi.getWeather(city))
- .description("获取天气信息")
- .build();
复制代码 3.3 MCP 工具
MCP 工具通过 MCP 客户端自动发现:- // MCP 工具会自动从 MCP 服务器发现
- // 无需手动定义,通过 AsyncMcpToolCallbackProvider 提供
- ChatClient chatClient = ChatClient.builder(chatModel)
- .defaultAdvisors(
- // MCP 工具会自动注册
- )
- .build();
复制代码 3.4 工具调用流程
工具调用是自动的:- // 1. 定义工具
- @Tool(name = "search_docs", description = "搜索文档")
- public String searchDocs(String query) {
- return docService.search(query);
- }
- // 2. 使用 ChatClient(工具会自动发现)
- ChatClient chatClient = ChatClient.builder(chatModel)
- .build();
- // 3. 模型会自动调用工具
- String response = chatClient.prompt()
- .user("帮我搜索 Spring AI 的文档")
- .call()
- .content();
- // 模型会自动调用 search_docs 工具
复制代码 4. 核心时序图
4.1 工具调用完整流程
4.2 MCP 工具发现流程
5. 入口类与关键类关系
6. 关键实现逻辑分析
6.1 工具注册机制
Spring AI 支持多种工具注册方式:
方式一:@Tool 注解(推荐)- @Service
- public class MyService {
- @Tool(name = "my_tool", description = "我的工具")
- public String myTool(String input) {
- return "处理结果: " + input;
- }
- }
复制代码 MethodToolCallbackProvider 会自动扫描所有 @Tool 注解的方法:- public class MethodToolCallbackProvider implements ToolCallbackProvider {
- @Override
- public ToolCallback[] getToolCallbacks() {
- return toolObjects.stream()
- .flatMap(toolObject ->
- Stream.of(ReflectionUtils.getDeclaredMethods(toolObject.getClass()))
- .filter(this::isToolAnnotatedMethod)
- .map(method -> MethodToolCallback.builder()
- .toolDefinition(ToolDefinitions.from(method))
- .toolMethod(method)
- .toolObject(toolObject)
- .build())
- )
- .toArray(ToolCallback[]::new);
- }
- }
复制代码 方式二:手动注册- ToolCallback tool = FunctionToolCallback.builder("my_tool",
- (String input) -> "结果: " + input)
- .build();
- ToolCallingChatOptions options = ToolCallingChatOptions.builder()
- .withToolCallbacks(tool)
- .build();
复制代码 方式三:MCP 自动发现
MCP 工具通过 AsyncMcpToolCallbackProvider 自动发现:- public class AsyncMcpToolCallbackProvider implements ToolCallbackProvider {
- @Override
- public ToolCallback[] getToolCallbacks() {
- // 从 MCP 客户端获取工具列表
- List<Tool> mcpTools = mcpClient.listTools();
-
- return mcpTools.stream()
- .map(tool -> AsyncMcpToolCallback.builder()
- .mcpClient(mcpClient)
- .tool(tool)
- .build())
- .toArray(ToolCallback[]::new);
- }
- }
复制代码 6.2 工具发现机制
ToolCallbackResolver 负责解析工具:- public class DelegatingToolCallbackResolver implements ToolCallbackResolver {
- private final List<ToolCallbackResolver> resolvers;
-
- @Override
- public ToolCallback resolve(String toolName) {
- // 按顺序尝试每个解析器
- for (ToolCallbackResolver resolver : resolvers) {
- ToolCallback tool = resolver.resolve(toolName);
- if (tool != null) {
- return tool;
- }
- }
- return null;
- }
- }
复制代码 SpringBeanToolCallbackResolver 从 Spring 容器中查找:- public class SpringBeanToolCallbackResolver implements ToolCallbackResolver {
- @Override
- public ToolCallback resolve(String toolName) {
- // 1. 检查缓存
- ToolCallback cached = cache.get(toolName);
- if (cached != null) {
- return cached;
- }
-
- // 2. 从 Spring 容器中查找 Bean
- try {
- Object bean = applicationContext.getBean(toolName);
- ResolvableType toolType = resolveBeanType(bean);
-
- // 3. 构建 ToolCallback
- ToolCallback tool = buildToolCallback(toolName, toolType, bean);
-
- // 4. 缓存
- cache.put(toolName, tool);
- return tool;
- } catch (Exception e) {
- return null;
- }
- }
- }
复制代码 6.3 工具调用执行
DefaultToolCallingManager 负责执行工具调用:- public class DefaultToolCallingManager implements ToolCallingManager {
- @Override
- public ToolExecutionResult executeToolCalls(Prompt prompt, ChatResponse response) {
- // 1. 提取工具调用请求
- AssistantMessage assistantMessage = extractToolCalls(response);
-
- // 2. 构建工具上下文
- ToolContext toolContext = buildToolContext(prompt, assistantMessage);
-
- // 3. 执行每个工具调用
- List<ToolResponse> toolResponses = new ArrayList<>();
- for (ToolCall toolCall : assistantMessage.getToolCalls()) {
- // 3.1 解析工具回调
- ToolCallback callback = resolveToolCallback(toolCall.getName());
-
- // 3.2 执行工具
- String result = callback.call(toolCall.getArguments(), toolContext);
-
- // 3.3 构建响应
- toolResponses.add(new ToolResponse(toolCall.getId(), result));
- }
-
- // 4. 构建工具响应消息
- ToolResponseMessage toolResponseMessage =
- new ToolResponseMessage(toolResponses);
-
- // 5. 构建对话历史
- List<Message> conversationHistory = buildConversationHistory(
- prompt.getInstructions(),
- assistantMessage,
- toolResponseMessage
- );
-
- return ToolExecutionResult.builder()
- .conversationHistory(conversationHistory)
- .returnDirect(shouldReturnDirect())
- .build();
- }
- }
复制代码 6.4 MCP 工具适配
MCP 工具通过 AsyncMcpToolCallback 适配到 Spring AI:- public class AsyncMcpToolCallback implements ToolCallback {
- @Override
- public String call(String toolInput, ToolContext toolContext) {
- // 1. 解析工具输入
- Map<String, Object> arguments = jsonToMap(toolInput);
-
- // 2. 转换工具上下文
- McpMeta mcpMeta = toolContextToMcpMetaConverter.convert(toolContext);
-
- // 3. 构建 MCP 请求
- CallToolRequest request = CallToolRequest.builder()
- .name(tool.name()) // 使用原始工具名
- .arguments(arguments)
- .meta(mcpMeta)
- .build();
-
- // 4. 调用 MCP 客户端
- CallToolResult response = mcpClient.callTool(request)
- .onErrorMap(exception ->
- new ToolExecutionException(getToolDefinition(), exception))
- .block();
-
- // 5. 处理错误
- if (response.isError()) {
- throw new ToolExecutionException(getToolDefinition(),
- new IllegalStateException("Error: " + response.content()));
- }
-
- // 6. 返回结果
- return toJsonString(response.content());
- }
- }
复制代码 7. MCP 协议集成
7.1 MCP 是什么
MCP(Model Context Protocol)是一个标准化的协议,用于让 AI 模型访问外部工具和数据源。它定义了:
- 工具发现:服务器可以暴露可用的工具
- 工具调用:客户端可以调用工具
- 资源访问:客户端可以访问服务器资源
7.2 MCP 工具提供者
AsyncMcpToolCallbackProvider 负责从 MCP 服务器发现工具:- public class AsyncMcpToolCallbackProvider implements ToolCallbackProvider {
- @Override
- public ToolCallback[] getToolCallbacks() {
- // 1. 从 MCP 客户端获取工具列表
- List<Tool> tools = mcpClient.listTools();
-
- // 2. 转换为 Spring AI ToolCallback
- return tools.stream()
- .map(tool -> AsyncMcpToolCallback.builder()
- .mcpClient(mcpClient)
- .tool(tool)
- .toolNamePrefixGenerator(prefixGenerator)
- .build())
- .toArray(ToolCallback[]::new);
- }
- }
复制代码 7.3 MCP 工具动态更新
MCP 支持工具的动态添加和删除:- // MCP 客户端监听工具变更事件
- mcpClient.onToolsChanged(event -> {
- // 重新获取工具列表
- List<Tool> newTools = mcpClient.listTools();
-
- // 更新工具提供者
- toolCallbackProvider.updateTools(newTools);
- });
复制代码 8. 外部依赖
8.1 工具调用
- Spring Framework:IoC 容器和反射
- Jackson:JSON 处理(工具 Schema 生成)
- Swagger Annotations:Schema 生成
8.2 MCP
- MCP Java SDK:MCP 协议实现
- Reactor Core:响应式支持(AsyncMcpToolCallback)
9. 工程总结
Spring AI 的工具调用和 MCP 能力设计有几个亮点:
统一的工具抽象。所有工具(方法、函数、MCP)都实现 ToolCallback 接口,这让工具调用变得统一和透明。不管工具来自哪里,调用方式都一样。
灵活的注册机制。支持注解、手动注册、MCP 自动发现等多种方式,适应不同的使用场景。想用注解?加个 @Tool 就行。想手动注册?创建 ToolCallback 就行。
智能的工具发现。通过 ToolCallbackResolver 链,可以按顺序尝试多个解析器,支持 Spring Bean、静态工具、MCP 工具等多种来源。找不到工具?换个解析器试试。
MCP 协议集成。通过 MCP 适配器,Spring AI 可以无缝集成 MCP 服务器提供的工具,支持工具的动态发现和更新。MCP 服务器添加了新工具?Spring AI 会自动同步。
工具上下文传递。工具可以接收 ToolContext,获取对话历史、用户信息等上下文,这让工具可以做出更智能的决策。比如根据用户历史记录,提供个性化服务。
总的来说,Spring AI 的工具调用和 MCP 能力既强大又灵活。统一的抽象让工具调用变得简单,灵活的机制让系统可以适应各种场景。这种设计让 Spring AI 既能支持简单的本地工具,也能支持复杂的 MCP 服务器工具。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |