Spring AI整合Ollama实现工具调用的实战全解

 更新时间:2026年05月13日 09:33:27   作者:霸道流氓气质  
在大模型应用开发中,工具调用(Tool Calling / Function Calling)是实现智能 Agent 的核心能力,本文将基于 Spring AI + Ollama,从基础环境搭建、工具的定义与注册、完整项目实现到常见问题排查,系统性地讲解如何实现本地大模型的工具调用,需要的朋友可以参考下

场景

在大模型应用开发中,工具调用(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();
}

实现

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: 886
spring:
  ai:
    ollama:
      base-url: http://localhost:11434
      chat:
        model: qwen2.5:7b-instruct
        options:
          temperature: 0.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;

@Service
public 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;

@Configuration
public 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(@RequestBody ChatRequest 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(@RequestParam String 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 日志可观察工具调用过程

以上就是Spring AI整合Ollama实现工具调用的实战全解的详细内容,更多关于Spring AI Ollama工具调用的资料请关注脚本之家其它相关文章!

相关文章

  • 在Java中使用OpenCV实践

    在Java中使用OpenCV实践

    用户分享了在Java项目中集成OpenCV4.10.0的实践经验,涵盖库简介、Windows安装、依赖配置及灰度图测试,强调其在图像处理领域的多功能性,并计划后续探索AI结合应用
    2025-07-07
  • Java中的static--静态变量你了解吗

    Java中的static--静态变量你了解吗

    Java 中被 static 修饰的成员称为静态成员或类成员。它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享。静态成员可以使用类名直接访问,也可以使用对象名进行访问,.下面我们来详细了解一下吧
    2021-09-09
  • Java中int与Integer的区别详解及常见问题解决

    Java中int与Integer的区别详解及常见问题解决

    在Java编程语言中int和Integer虽然都用于表示数值,但它们之间存在着显著的区别,这篇文章主要介绍了Java中int与Integer的区别详解及常见问题的相关资料,需要的朋友可以参考下
    2025-07-07
  • java实现python session功能代码实例

    java实现python session功能代码实例

    这篇文章主要介绍了java实现python session功能代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Java之ThreadLocal使用常见和方式案例讲解

    Java之ThreadLocal使用常见和方式案例讲解

    这篇文章主要介绍了Java之ThreadLocal使用常见和方式案例讲解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • Springboot如何基于assembly服务化实现打包

    Springboot如何基于assembly服务化实现打包

    这篇文章主要介绍了Springboot如何基于assembly服务化实现打包,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • Java微信获取用户资料报错48001解决办法

    Java微信获取用户资料报错48001解决办法

    这篇文章主要介绍了Java微信获取用户资料报错48001的解决办法,这个问题大家在工作可能经常会遇到,文中通过示例代码将解决的办法介绍的非常详细,需要的朋友可以参考下
    2025-09-09
  • SpringAop日志找不到方法的处理

    SpringAop日志找不到方法的处理

    这篇文章主要介绍了SpringAop日志找不到方法的处理方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • MyBatis中动态SQL语句@Provider的用法

    MyBatis中动态SQL语句@Provider的用法

    本文主要介绍了MyBatis中动态SQL语句@Provider的用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • JDK + IDEA + Maven安装与完整配置指南(含图文)

    JDK + IDEA + Maven安装与完整配置指南(含图文)

    在开发Java应用程序时,我们通常需要配置Java开发工具包(JDK),以便能够在我们的集成开发环境(IDE)中编写和运行Java代码,这篇文章主要介绍了JDK+IDEA+Maven安装与完整配置的相关资料,需要的朋友可以参考下
    2026-05-05

最新评论