Spring AI 从入门到实战:用 Java 实现大模型对话与 Tool Calling

大模型接入 Java 项目并不难,真正麻烦的是:不同模型的请求格式不同、流式响应处理复杂、工具调用还要自己维护参数解析和执行循环。

Spring AI 的价值,就是为 Java 开发者提供一套相对统一的抽象。我们可以继续使用熟悉的 Spring Boot、依赖注入和注解,把大模型能力接入现有系统。

本文通过一个"天气助手"示例,快速实现两项能力:

  • 使用 ChatClient 完成大模型对话;

  • 使用 @Tool 让模型调用 Java 方法查询天气。

一、Spring AI 解决了什么问题?

如果直接调用模型厂商的 HTTP 接口,我们通常要处理请求体、响应解析、流式输出、工具参数、上下文和异常。更换模型时,还可能重新适配一套接口。

Spring AI 对这些能力进行了统一封装,核心包括:

  • ChatModel:屏蔽不同聊天模型的调用差异;

  • ChatClient:提供类似 Spring WebClient 的流式 API;

  • Tool Calling:把 Java 方法暴露给大模型选择和调用;

  • Advisors:以拦截器方式扩展记忆、RAG、日志等能力;

  • Vector Store:对接向量数据库,构建知识库问答;

  • MCP:以标准协议连接外部工具和资源。

需要注意:Spring AI 不是一个大模型,也不会替代业务代码。它更像 Java 应用和模型服务之间的适配层。

二、创建 Spring Boot 项目

pom.xml 中导入 Spring AI BOM,并添加 Web 和模型 Starter。下面以 OpenAI 兼容模型为例:

复制代码
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>2.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-starter-model-openai</artifactId>
    </dependency>
</dependencies>

然后在 application.yml 中配置模型:

复制代码
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: your-model-name
          temperature: 0.2

API Key 不要直接写进配置文件并提交到 Git,推荐通过环境变量或密钥管理服务注入。

三、使用 ChatClient 实现基础对话

Spring Boot 会根据模型 Starter 自动配置 ChatClient.Builder。我们可以将其注入 Controller:

复制代码
@RestController
@RequestMapping("/ai")
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder builder) {
        this.chatClient = builder
                .defaultSystem("你是一个严谨的 Java 技术助手,请简洁回答问题。")
                .build();
    }

    @GetMapping("/chat")
    public String chat(@RequestParam String message) {
        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

访问:

复制代码
GET /ai/chat?message=什么是依赖注入

调用链很直观:Controller 接收问题,ChatClient 构造 Prompt 并调用模型,最后从响应中取出文本内容。

但普通对话只能依赖模型已有知识。如果用户询问实时天气、订单状态或数据库数据,模型本身无法得到最新结果。这时就需要 Tool Calling。

四、使用 @Tool 声明 Java 工具

先定义一个天气工具。为了让示例可以独立运行,这里使用模拟数据;实际项目中可替换为第三方天气接口。

复制代码
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

@Component
public class WeatherTools {

    @Tool(description = "查询指定城市的当前天气")
    public WeatherResult getCurrentWeather(
            @ToolParam(description = "城市名称,例如杭州、北京") String city) {

        if (city == null || city.isBlank()) {
            throw new IllegalArgumentException("城市名称不能为空");
        }

        // 实际项目中在这里调用天气 API
        return new WeatherResult(city.trim(), 28, "晴", "东南风2级");
    }

    public record WeatherResult(
            String city,
            int temperature,
            String condition,
            String wind) {
    }
}

@Tool 告诉 Spring AI:这个方法可以作为工具提供给模型。description 非常重要,因为模型会根据工具名称、说明和参数结构判断是否调用它。

@ToolParam 则补充参数语义。描述越清楚,模型生成错误参数的概率越低。

接着把工具注册到本次调用:

复制代码
@RestController
@RequestMapping("/ai")
public class WeatherController {

    private final ChatClient chatClient;
    private final WeatherTools weatherTools;

    public WeatherController(ChatClient.Builder builder,
                             WeatherTools weatherTools) {
        this.chatClient = builder.build();
        this.weatherTools = weatherTools;
    }

    @GetMapping("/weather")
    public String weather(@RequestParam String question) {
        return chatClient.prompt()
                .system("你是天气助手。涉及实时天气时必须使用工具,不要编造数据。")
                .user(question)
                .tools(weatherTools)
                .call()
                .content();
    }
}

现在请求:

复制代码
GET /ai/weather?question=杭州今天天气怎么样,适合跑步吗

模型会识别出需要实时天气,生成类似 getCurrentWeather(city="杭州") 的工具调用。Spring AI 执行 Java 方法,再把结果交给模型组织为自然语言回答。

五、Tool Calling 的完整执行链路

很多初学者会误以为:大模型看到 @Tool 后直接执行了 Java 代码。实际流程并不是这样。

  1. 应用把工具名称、描述和参数 Schema 一起发送给模型;

  2. 模型判断是否需要工具,并返回工具名和 JSON 参数;

  3. Spring AI 根据工具名定位并执行本地 Java 方法;

  4. 工具返回结构化结果;

  5. Spring AI 将结果作为工具响应再次发送给模型;

  6. 模型结合工具结果生成最终回答。

因此,模型负责"做决策和填参数",Java 应用负责"真正执行"。ChatClient 默认可通过框架托管方式完成这一循环,我们不需要手动解析每一次工具调用。

这也意味着:工具调用是否安全,不能只靠 Prompt。权限校验、参数校验和执行限制必须放在 Java 代码中。

六、Spring AI 和 LangChain4j 怎么选?

二者都能在 Java 中接入大模型、RAG 和工具调用,没有绝对优劣。

如果项目本身就是 Spring Boot,希望复用自动配置、Bean 管理、Advisor 和 Spring 生态,Spring AI 通常更自然。若更看重声明式 AI Service、框架独立性或现有 LangChain4j 组件,也可以选择 LangChain4j。

比"选哪个框架"更重要的是:模型调用、工具执行和业务服务之间要保持清晰边界。业务逻辑不应全部堆进 Controller,也不应与某个模型 SDK 强绑定。

七、总结

使用 Spring AI 实现 Tool Calling,核心只有三步:

  1. 通过 ChatClient 接入大模型;

  2. 使用 @Tool@ToolParam 描述 Java 工具;

  3. 在调用时通过 .tools(...) 将工具提供给模型。

但真正上线时,重点不是"模型成功调用了一次工具",而是这次调用是否可校验、可超时、可审计、可重试,并且不会绕过业务权限。

Spring AI 降低了 Java 接入大模型的门槛,却不会替我们解决所有工程问题。把模型当作不确定的决策组件,把 Java 服务当作可靠的执行边界,才是 Tool Calling 能稳定落地的关键。

参考资料

相关推荐
智塑未来1 小时前
发那科又叫法兰克?译名误区拆解,数控自动化龙头全维度解析
大数据·人工智能·自动化
网易云信1 小时前
立即下载!帝王蟹(ClawHive)桌面客户端正式上线!
人工智能·agent
windliang1 小时前
Claude Code 源码分析(六):上下文的发现、注入与压缩
前端·javascript·人工智能
evans在进步1 小时前
LeetCode 189 轮转数组:三次反转原地解决,图解 Java 实现
java·算法·leetcode
龍德明宇1 小时前
AI不会疼-龍德明宇
人工智能·算法·大语言模型llm·负主体性·ai存在论
(轻舟已过万重山)1 小时前
第27章 框架实操:用 LangChain/LlamaIndex 搭建完整 RAG 系统
人工智能·ai·langchain
️学习的小王2 小时前
智能文档助手:基于RAG的本地化文档问答系统实战指南
人工智能·python·机器学习
zhangfeng11332 小时前
CodeBuddy 是否支持 SDD(Spec-Driven Development 规范驱动开发
人工智能·驱动开发
阿里云大数据AI技术2 小时前
基于阿里云EMR Serverless StarRocks提效多模态工单标注和舆情研判
人工智能