场景
SpringAI+Ollama本地模型实现快速对话入门实例:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/160983728
在上面基础上实现tool工具调用示例。
在大模型应用开发中,工具调用(Tool Calling / Function Calling)是实现智能 Agent 的核心能力。
通过工具调用,大模型可以自主决定何时调用外部工具来获取实时信息、执行计算或操作外部系统。
Spring AI 作为 Java 生态中的 AI 集成框架,提供了一套优雅的 API 来定义和管理工具,
而 Ollama 则让开发者可以在本地运行强大的开源大模型。
本文将基于 Spring AI + Ollama,从基础环境搭建、工具的定义与注册、完整项目实现到常见问题排查,
系统性地讲解如何实现本地大模型的工具调用,并提供可直接运行的完整代码示例。
工具调用的工作流程
在 Ollama + Spring AI 的场景下,工具调用的完整流程如下:
定义工具:通过 @Tool 注解或编程式 API 将 Java 方法标记为可调用的工具。
注册工具:在 ChatClient 构建时将工具注入,Spring AI 会自动生成符合 OpenAI 规范的 JSON Schema。
模型决策:当用户提问时,Ollama 模型评估是否需要调用工具,如果需要,则返回工具名称和参数。
执行与反馈:Spring AI 自动执行对应的 Java 方法,并将结果回传给模型。
生成回答:模型根据工具执行结果生成最终的自然语言回答。
模型兼容性要求
并非所有 Ollama 模型都支持工具调用。必须使用原生支持 Function Calling 的模型,否则 LLM 将直接忽略工具列表,
只返回纯文本回答。
可以通过 ollama list 查看已下载的模型,通过 ollama pull <模型名> 下载新模型。
两种工具定义方式
Spring AI 提供了两种工具定义方式,可根据场景灵活选择。
使用 @Tool 注解(推荐)
在 Spring 管理的 Bean 方法上添加 @Tool 注解,Spring AI 会自动将其包装为 ToolCallback。
编程式 API(无需注解)
使用 MethodToolCallback 构建工具回调,适合动态创建或无法修改已有类的场景。
import org.springframework.ai.tool.MethodToolCallback;import org.springframework.ai.tool.ToolCallback;public ToolCallback dynamicTool(Object target) {return MethodToolCallback.builder().method("methodName", target).description("工具描述").build();}
注:
博客:https://blog.csdn.net/badao_liumang_qizhi
实现
pom.xml 依赖配置
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.3</version> <!-- 降级为稳定版,解决冲突 --></parent><groupId>com.example</groupId><artifactId>spring-ai-ollama-tool</artifactId><version>1.0</version><properties><java.version>17</java.version><spring-ai.version>1.1.2</spring-ai.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring AI Ollama 核心 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-ollama</artifactId><version>${spring-ai.version}</version></dependency></dependencies><repositories><repository><id>spring-milestones</id><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository></repositories>
application.yml 配置
server:port: 886spring:ai:ollama:base-url: http://localhost:11434chat:model: qwen2.5:7b-instructoptions:temperature: 0.7num-ctx: 4096 # 上下文窗口大小logging:level:org.springframework.ai.chat.client: DEBUG # 查看工具调用详情
工具服务类(含 @Tool 注解)
package com.badao.ai.service;import org.springframework.ai.tool.annotation.Tool;import org.springframework.ai.tool.annotation.ToolParam;import org.springframework.stereotype.Service;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;@Servicepublic class ToolService {/*** 获取当前日期和时间*/@Tool(description = "获取当前系统的日期和时间,返回格式化后的时间字符串")public String getCurrentDateTime() {System.out.println("获取当前日期和时间工具被调用");return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));}/*** 查询指定城市的天气(模拟)*/@Tool(description = "查询指定城市的天气信息")public String getWeather(@ToolParam(description = "城市名称") String city) {System.out.println("查询指定城市的天气信息工具被调用");return String.format("城市:%s,天气:晴,温度:22°C ~ 28°C,湿度:45%%,风力:3级", city);}/*** 计算两个数的和*/@Tool(description = "计算两个数字的和")public double add(@ToolParam(description = "第一个加数") double a,@ToolParam(description = "第二个加数") double b) {System.out.println("计算两个数字的和工具被调用");return a + b;}}
ChatClient 配置类
注意:在 Spring AI 1.1.2 中,@Tool 标注的方法不会自动生成 ToolCallbackProvider,我们需要手动注入工具服务类。
package com.badao.ai.config;import com.badao.ai.service.ToolService;import org.springframework.ai.chat.client.ChatClient;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class ChatConfig {@Beanpublic ChatClient chatClient(ChatClient.Builder chatClientBuilder,ToolService toolService) { // ✅ 直接注入工具类return chatClientBuilder.defaultTools(toolService) // ✅ 使用 defaultTools.build();}}
控制器
package com.badao.ai.controller;import org.springframework.ai.chat.client.ChatClient;import org.springframework.web.bind.annotation.*;@RestController@RequestMapping("/api")public class ToolChatController {private final ChatClient chatClient;public ToolChatController(ChatClient chatClient) {this.chatClient = chatClient;}/*** 通用对话接口,AI 会自动判断是否需要调用工具*/@PostMapping("/chat")public ChatResponse chat(@RequestBodyChatRequest request) {String result = chatClient.prompt().user(request.getMessage()).call().content();return new ChatResponse(200, "success", result);}/*** 流式输出对话(支持打字机效果)*/@GetMapping(value = "/stream", produces = org.springframework.http.MediaType.TEXT_EVENT_STREAM_VALUE)public reactor.core.publisher.Flux<String> streamChat(@RequestParamString msg) {return chatClient.prompt().user(msg).stream().content();}// 请求体public record ChatRequest(String message) {public String getMessage() {return message;}}// 响应体public record ChatResponse(int code, String msg, String data) {}}
测试验证
测试天气工具调用

调用计算器
常见问题与解决方案
1、找不到 ToolCallbackProvider Bean
报错信息:
Could not autowire. No beans of 'ToolCallbackProvider' type found.
原因:仅使用 @Tool 注解时,Spring AI 不会自动创建 ToolCallbackProvider Bean。
解决:直接注入工具服务类 ToolService,使用 .defaultTools(toolService) 注册工具(参考上文中 ChatConfig 的写法)。
2、找不到 spring-ai-starter-model-ollama 依赖
报错信息:
Could not find artifact org.springframework.ai:spring-ai-ollama-spring-boot-starter:pom:1.1.2
原因:错误的 artifactId。
解决:在 Spring AI 1.1.2 中,正确的依赖名为 spring-ai-starter-model-ollama。
3、模型从不调用工具,只返回文字回答
原因:当前模型不支持 Function Calling(如 llama2、早期 qwen 等)。
解决:更换为原生支持工具调用的模型,如 qwen2.5:7b、llama3.1:8b、mistral:7b。
关键知识点总结
@Tool 注解 将方法标记为工具,description 用于告知 LLM 何时调用
@ToolParam 注解 描述工具方法参数的含义,帮助 LLM 准确填充参数
ChatClient.defaultTools() 将包含 @Tool 方法的类注入 ChatClient,使其具备工具调用能力
模型兼容性 必须使用原生支持 Function Calling 的模型
JSON Schema 自动生成 Spring AI 会根据 Java 方法签名和注解自动生成符合 OpenAI 规范的 Schema
日志调试 开启 org.springframework.ai.chat.client 的 DEBUG 日志可观察工具调用过程
夜雨聆风