Spring-AI-第2篇-ChatClient 实战:使用 DeepSeek 完成第一次 AI 对话

本文是「Spring AI 从入门到实战」专栏第 2 篇。上一节梳理了 ChatModelChatClientPromptChatResponse,这一节开始真正动手:搭建一个最小可运行的 Spring Boot 项目,通过 Spring AI 调用 DeepSeek。

一、本文要完成什么

我们将实现一条完整的调用链:浏览器向 Spring Boot 接口发送问题,应用使用 ChatClient 调用 DeepSeek,并把模型生成的文本返回给浏览器。

text 复制代码
客户端请求
   ↓
ChatController
   ↓
ChatClient
   ↓
ChatModel
   ↓
DeepSeek API
   ↓
模型回答

完成后,你会掌握:

  • 使用 BOM 管理 Spring AI 依赖版本;
  • 通过 OpenAI 兼容接口连接 DeepSeek;
  • 安全地配置 API Key;
  • 注入 ChatClient.Builder 并完成同步调用;
  • 定位 401、404 和自动配置失败等常见问题。

二、项目环境与版本说明

组件 本文使用版本或方案
JDK 17
Spring Boot 3.5.15
Spring AI 1.1.8
构建工具 Maven
模型服务 DeepSeek API
模型 deepseek-v4-flash
接入方式 OpenAI 兼容接口

本文保留课程项目使用的 Spring AI 1.1.8 稳定分支,便于代码复现。Spring AI 目前也有 2.x 稳定版本,但跨大版本可能涉及依赖基线和 API 调整,不建议在一篇入门示例中混用两套写法。

DeepSeek 已更新模型命名。旧教程常见的 deepseek-chat 已不再是当前推荐模型名,本文按官方最新文档使用 deepseek-v4-flash。如果你使用的是其他时间点的账号或接口,请以 DeepSeek 控制台实际提供的模型列表为准。

2.1 准备工作

2.1.1 什么是DeepSeek

DeepSeek 是一款由深度求索所开发的 AI 人工智能大模型,其基于深度学习和多模态数据融合技术,采用先进的 Transformer 架构和跨模态协同算法,可实现对复杂文档和图像的自动化解析与结构化信息提取。

依托于最新推出的"深度思考"模式(R1),这款AI大模型在极低成本下实现了与国际顶尖模型ChatGPT-o1相媲美的性能表现,其中文理解与输出能力更是远超ChatGPT、Claude等顶尖模型。再加上极具竞争力的API定价和全面开源的策略,让这款AI大模型成功在国际上火爆出圈

如果说AI是一个广泛的概念,那么DeepSeek就是是AI领域中的一个具体产品。

DeepSeek的特点‌:

  • 成本‌:DeepSeek致力于降低AI应用的成本。通过采用先进的技术和独特的模型架构,DeepSeek在保持高性能的同时,显著降低了推理和训练的成本。
  • 性能‌:DeepSeek在性能上表现出色。它使用强化学习技术训练,推理过程中包含大量反思与验证,能够处理更加复杂的数据和任务。在一些benchmark测试中,其性能与OpenAI的模型相当,但推理成本远低于同类产品。
  • 功能‌:DeepSeek擅长处理数学、编程和复杂逻辑推理等任务。它的推理能力源于深度思考特性,推理长度与准确率呈正相关。此外,DeepSeek还支持多模态信息处理,能够应对更加多样化的应用场景。
  • 应用领域‌:DeepSeek在多个领域展现出巨大的应用潜力。无论是在医疗、教育、交通等传统领域,还是在智能制造、智慧城市等新兴领域,DeepSeek都有望发挥重要作用。

综上所述,AI是一个广泛的概念,涵盖了人工智能领域的所有技术和应用。而DeepSeek则是AI领域中的一个具体产品,它在成本、性能、功能和应用领域等方面都有着独特的特点和优势。两者之间的关系可以理解为:DeepSeek是AI领域中的一个具体实现和优秀代表。

如何使用Java集成DeepSeek:

DeepSeek 作为一款卓越的国产 AI 模型,越来越多的公司考虑在自己的应用中集成。对于 Java 应用来说,我们可以借助 Spring AI 集成 DeepSeek,非常简单方便!

2.1.2 DeepSeek开放平台创建API KEY

  • 进入API开放平台,注册用户
  • 创建API key

  • 根据自己需要,自行充值

三、为什么可以使用 OpenAI Starter 调用 DeepSeek

本文引入的是 Spring AI 的 OpenAI 模型 Starter:

xml 复制代码
<artifactId>spring-ai-starter-model-openai</artifactId>

实际调用的却是 DeepSeek。这是因为 DeepSeek 提供了 OpenAI 兼容格式的 API。我们只需要替换 base-url、API Key 和模型名称,就可以让 Spring AI 的 OpenAI 模型实现连接 DeepSeek。

这是一种"OpenAI 兼容接入方案",并不表示 DeepSeek 是 OpenAI 模型。

四、创建 Maven 工程

4.1 父工程配置

父工程通过 Spring AI BOM 统一管理各个 Spring AI 模块的版本:

xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 关键:父工程继承SpringBoot父 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.15</version>
        <relativePath/>
    </parent>

    <groupId>org.xingyue.ai</groupId>
    <artifactId>spring-ai-learning</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>springai-quickstart</module>
    </modules>

    <properties>
        <java.version>17</java.version>
        <spring-ai.version>1.1.8</spring-ai.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!-- 统一管理SpringAI版本,子模块不用写version -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>${spring-ai.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

使用 BOM 后,子模块引入 Spring AI 组件时不需要逐个填写版本号,也能降低模块版本不一致的风险。

4.2 子模块依赖

xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.xingyue.ai</groupId>
        <artifactId>spring-ai-learning</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <artifactId>springai-quickstart</artifactId>

    <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>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

两个核心依赖分别负责:

  • spring-boot-starter-web:提供 Web 接口能力;
  • spring-ai-starter-model-openai:自动配置 OpenAI 风格的聊天模型实现。

五、安全配置 DeepSeek API Key

5.1 使用环境变量保存密钥

在系统环境变量中添加:

text 复制代码
变量名:DEEPSEEK_API_KEY
变量值:你在 DeepSeek 平台创建的 API Key

设置完成后,重新启动 IDE 或终端,让新的环境变量对 Java 进程生效。

不要把真实 API Key 写进博客、提交到 Git 仓库或放入前端代码。截图中如果包含密钥,也必须先打码。

5.2 编写 application.properties

properties 复制代码
server.port=9999
spring.application.name=spring-ai-learning

spring.ai.openai.api-key=${DEEPSEEK_API_KEY}
spring.ai.openai.base-url=https://api.deepseek.com
spring.ai.openai.chat.options.model=deepseek-v4-flash
spring.ai.openai.chat.options.temperature=0.7

配置项说明:

配置项 作用
api-key 从环境变量读取访问凭证
base-url 将请求地址切换到 DeepSeek
model 指定当前使用的 DeepSeek 模型
temperature 调整输出的随机性和多样性

temperature 越低,输出通常越稳定;数值越高,输出通常越多样。但它不是回答质量的直接开关,并且不同模型对该参数的支持范围可能不同。

六、创建启动类

java 复制代码
package org.xingyue.ai;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringAiApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringAiApplication.class, args);
    }
}

应用启动时,Spring Boot 会根据依赖和配置自动创建聊天模型以及 ChatClient.Builder 等 Bean。

七、使用 ChatClient 完成第一次对话

java 复制代码
package org.xingyue.ai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/ai")
public class ChatController {

    private final ChatClient chatClient;

    public ChatController(ChatClient.Builder builder) {
        this.chatClient = builder.build();
    }

    @GetMapping("/chat")
    public String chat(
            @RequestParam(defaultValue = "请介绍一下 Spring AI")
            String message) {

        return chatClient.prompt()
                .user(message)
                .call()
                .content();
    }
}

这里采用构造器注入,依赖关系更加清晰,字段也可以声明为 final

调用链可以拆解为:

java 复制代码
chatClient.prompt()    // 开始构建本次 Prompt
        .user(message) // 添加 User Message
        .call()        // 同步调用模型
        .content();    // 读取生成文本

八、启动并测试

启动应用后,在浏览器访问:

text 复制代码
http://localhost:9999/ai/chat?message=请介绍一下Spring%20AI

也可以使用命令行测试:

bash 复制代码
curl --get "http://localhost:9999/ai/chat" \
  --data-urlencode "message=请用三句话介绍 Spring AI"

如果能够正常看到模型回答,就说明以下环节已经打通:

  • Spring Boot 应用启动成功;
  • API Key 环境变量能够读取;
  • DeepSeek 地址和模型名称配置正确;
  • Spring AI 已完成模型客户端自动配置;
  • ChatClient 已成功调用模型。

九、一次请求在程序中如何执行

text 复制代码
GET /ai/chat
   ↓
Spring MVC 将 message 参数交给 Controller
   ↓
ChatClient 将字符串封装为 User Message 和 Prompt
   ↓
底层 ChatModel 转换为模型服务需要的请求格式
   ↓
HTTP 客户端访问 DeepSeek API
   ↓
Spring AI 解析模型响应
   ↓
content() 取得文本并返回给浏览器

业务代码应该关注稳定的 ChatClientChatModel 抽象,不要依赖可能随版本变化的内部 HTTP 实现细节。

十一、Spring AI的聊天模型

11.1 概述

  • Spring AI的聊天模型API为开发者提供了一条便捷通道,能够将强大的AI驱动的聊天完成功能无缝集成到各类应用中。借助预先训练的语言模型,如广为人知的GPT,它能够依据用户输入生成自然流畅、类人化的回复。这一API不仅工作机制高效,而且设计理念极为先进,旨在实现简单易用与高度可移植性,让开发者能以极少的代码改动在不同AI模型间自由切换,充分契合Spring框架一贯秉持的模块化与可互换性原则。

11.2 ChatClient接口

ChatClient 是一个接口,它定义了一个与聊天服务交互的客户端。这个接口主要用于创建聊天客户端对象,设置请求规范,以及发起聊天请求。

11.2.1 实现简单的对话

1 需求

用户输入设置用户消息的内容,通过SpringBoot AI封装的方法向 AI 模型发送请求,以字符串形式返回 AI 模型的响应。

2 代码编写

编写配置方法

java 复制代码
/**
 * Spring AI 客户端配置。
 *
 * <p>集中创建应用共享的 {@link ChatClient},并设置所有对话默认使用的
 * System Prompt。</p>
 */
@Configuration(proxyBeanMethods = false)
public class ChatClientConfig {

    /**
     * 基于 Spring Boot 自动配置的 Builder 创建聊天客户端。
     *
     * @param builder Spring AI 自动配置的客户端构建器
     * @return 应用共享的聊天客户端 Bean
     */
    @Bean
    public ChatClient chatClient(ChatClient.Builder builder) {
        return builder
                .defaultSystem("你是一个专业、友好的 AI 助手")
                .build();
    }
}

配置文件

编写Controller方法
java 复制代码
/**
 * AI 对话 HTTP 接口。
 *
 * <p>仅负责接收请求参数、调用业务层并返回结果,模型调用细节由
 * {@link ChatService} 处理。</p>
 */
@RestController
public class ChatDeepSeekController {

    @Autowired
    private ChatService chatService;

    /**
     * 使用底层聊天模型生成回答。
     *
     * @param message 用户输入;未提供时使用 {@code hello}
     * @return 模型生成的文本内容
     */
    @GetMapping("/ai/generate")
    public String generate(@RequestParam(value = "message", defaultValue = "hello")
                           String message) {
        return chatService.generate(message);
    }

    /**
     * 使用 {@code ChatClient} 生成回答。
     *
     * @param message 用户输入;未提供时请求模型讲一个笑话
     * @return 模型生成的纯文本内容
     */
    @GetMapping(value = "/chat", produces = MediaType.TEXT_PLAIN_VALUE + ";charset=UTF-8")
    public String chat(@RequestParam(value = "msg", defaultValue = "给我讲个笑话")
                           String message) {
        return chatService.chat(message);
    }

    /**
     * 以 Server-Sent Events 形式流式返回模型生成的内容。
     *
     * @param message 用户输入的消息
     * @return 按生成进度持续输出的文本片段
     */
    @GetMapping(value = "/chat/stream", produces = MediaType.TEXT_PLAIN_VALUE + ";charset=UTF-8")
    public Flux<String> chatStream(@RequestParam(value = "msg") String message) {
        return chatService.chatStream(message);
    }

    @GetMapping(value = "/chat/model", produces = MediaType.TEXT_PLAIN_VALUE)
    public String myChatModel(@RequestParam("msg")String msg) {
        return chatService.myChatModel(msg);
    }

    @GetMapping(value = "/chat/model2", produces = MediaType.TEXT_PLAIN_VALUE)
    public String myChatModel2(@RequestParam("msg")String msg) {
        return chatService.myChatModel2(msg);
    }
}

编写业务实现方法

java 复制代码
/**
 * AI 对话业务的默认实现。
 *
 * <p>封装 Spring AI 模型调用细节,为 Controller 提供统一的业务入口。</p>
 */
@Service
public class ChatServiceImpl implements ChatService {

    private static final Logger log = LoggerFactory.getLogger(ChatServiceImpl.class);

    @Autowired
    private ChatClient chatClient;

    @Autowired
    private OpenAiChatModel openAiChatModel;

    @Autowired
    private ChatModel chatModel;

    @Override
    public String generate(String message) {
        String response = this.openAiChatModel.call(message);
        log.info("response : {}", response);
        return response;
    }

    @Override
    public String chat(String message) {
        return chatClient.prompt()
                .user(message)
                // 非流式输出 call:等待大模型把回答结果全部生成后输出给用户;
                .call()
                .content();
    }

    @Override
    public Flux<String> chatStream(String message) {
        return chatClient.prompt()
                .user(message)
                // 流式输出stream:逐个字符输出,一方面符合大模型生成方式的本质,另一方面当模型推理效率不是很高时,流式输出比起全部生成后再输出大大提高用户体验。
                .stream()
                .content();
    }

    @Override
    public String myChatModel(String msg) {
        return chatModel.call(msg);
    }

    @Override
    public String myChatModel2(String msg) {
        ChatResponse call = chatModel.call(
                new Prompt(msg,
                        OpenAiChatOptions.builder()
                                .model("deepseek-chat")
                                .temperature(0.8)
                                .build()
                )
        );
        return call.getResult().getOutput().getText();
    }
}
3 测试结果
4 总结
text 复制代码
ChatClient 接口提供了构建和配置聊天客户端对象的灵活性,以及发起和处理聊天请求的能力。用户可以通过 ChatClient.Builder 来定制客户端的行为,然后使用 prompt() 和 prompt(Prompt prompt) 方法设置请求规范,最后通过 call() 方法发起聊天请求。

十一、常见问题排查

10.1 找不到 ChatClient.Builder

优先检查:

  • Spring AI Starter 是否正确引入;
  • Spring AI 与 Spring Boot 版本是否兼容;
  • 是否排除了聊天模型自动配置;
  • 配置文件是否位于 src/main/resources

10.2 返回 401 或认证失败

检查环境变量名称是否与 ${DEEPSEEK_API_KEY} 完全一致,并确认 IDE 是在环境变量设置完成后重新启动的。

10.3 返回 404 或提示模型不存在

依次检查:

  • base-url 是否为 https://api.deepseek.com
  • 模型名是否为当前账户可用的模型;
  • 是否仍在使用已经过期的旧模型名;
  • 当前 Spring AI 版本是否使用了不同的配置属性名称。

10.4 为什么不直接注入 OpenAiChatModel

直接注入具体实现也可以运行,但会增加业务代码对厂商实现的依赖。使用 ChatClient.BuilderChatModel 接口,更符合面向抽象编程的思路。

10.5 生产接口适合使用 GET 吗

本篇为了方便演示使用 GET。真实聊天内容可能很长,也可能包含敏感数据,不适合全部出现在 URL 中。生产应用通常更适合使用 POST 和 JSON 请求体,并增加参数校验、鉴权、限流与日志脱敏。

十二、本文总结

本篇完成了第一个可运行的 Spring AI 项目,并明确了五个关键点:

  1. 通过 OpenAI 兼容接口可以使用 Spring AI 调用 DeepSeek。
  2. API Key 应通过环境变量注入,不能硬编码到项目中。
  3. ChatClient 提供了适合业务开发的链式 API。
  4. call() 是同步调用,会等待模型生成完整回答。
  5. 示例中的 GET 便于学习,生产项目还需要完善安全和接口设计。

下一篇将在这个项目上增加 System Prompt,为 AI 助手设置稳定的角色和回答规范。

参考资料

相关推荐
ajassi200025 分钟前
AI语音智能体开发日记(十五)智能体LCD屏幕GIF动画显示方案——从GIF到BMP的完整实战
人工智能·ai·ai编程
悲且狂32 分钟前
SpringBoot项目改造注意事项(旧项目框架复用)
java·spring boot·后端
Dfreedom.35 分钟前
目标检测后处理核心:NMS非极大值抑制详解
图像处理·人工智能·深度学习·目标检测·目标跟踪
枫叶丹437 分钟前
实时语音 Agent:从语音机器人到连续协作界面
人工智能·chatgpt·机器人·语音识别·agent·codex
戴西软件1 小时前
戴西iDWS.3DViz Suite数据轻量化可视化软件,从传统桌面软件向云端协同的重大突破
大数据·运维·网络·人工智能·机器学习·3d
AIkk861 小时前
2026年AI证件照工具功能速览:三款实用方案对比
人工智能
ReleaseU1 小时前
Harness + MCP:打通企业工具链的最后一步
人工智能·大模型
衡石科技1 小时前
衡石科技携手超聚变联合发布HENGSHI BOX,引领私域ChatBI规模化落地
大数据·人工智能·科技