乐于分享
好东西不私藏

Spring AI 整合 Ollama 实现工具调用:从入门到实战全解

Spring AI 整合 Ollama 实现工具调用:从入门到实战全解

场景

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:  port886spring:  ai:    ollama:      base-url: http://localhost:11434      chat:        model: qwen2.5:7b-instruct        options:          temperature0.7          num-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 {    @Bean    public 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<StringstreamChat(@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 日志可观察工具调用过程