java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring AI Ollama工具调用

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

作者:霸道流氓气质

在大模型应用开发中,工具调用(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工具调用的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文