欢迎光临
我们一直在努力

Spring AI 实战:Spring Boot + DeepSeek 实现第一个 AI 聊天接口

Spring AI 实战:Spring Boot + DeepSeek 实现第一个 AI 聊天接口

Spring AI 从 0 到 1 系列教程 · 第 02 章

上一章我们介绍了 Spring AI 是什么,以及为什么 Java 程序员值得学习 Spring AI。

这一章开始正式进入实战。

我们不再停留在概念层面,而是从 0 创建一个 Spring Boot 项目,接入 DeepSeek,并使用 Spring AI 提供的 ChatClient 实现一个真正可以运行的 AI 聊天接口。

本章最终效果非常简单:

用户

HTTP 请求

Spring Boot

Spring AI ChatClient

DeepSeek

AI 返回答案

最终我们可以通过接口:

POST /api/ai/chat

发送:

{
"message": "什么是 Spring AI?"
}

得到:

{
"answer": "Spring AI 是 Spring 生态面向 AI 应用开发提供的框架和抽象…"
}

这也是后续学习 RAG、Tool Calling、Agent 等高级能力的基础。


一、本章目标

完成本章之后,我们将拥有一个最基础的 Spring AI AI 聊天服务。

具体完成:

✓ 创建 Spring Boot 项目

✓ 添加 Spring AI 依赖

✓ 配置 DeepSeek

✓ 创建 ChatClient

✓ 创建 AI 聊天接口

✓ 启动项目

✓ 使用 Postman 测试

✓ 理解 ChatClient 调用流程

最终项目结构:

spring-ai-chat-demo
├── pom.xml
└── src
└── main
├── java
│ └── com.example.ai
│ ├── AiApplication.java
│ └── controller
│ └── AiChatController.java

└── resources
└── application.yml


二、先理解一下整体架构

在真正开始写代码之前,我们先搞清楚整个请求是怎么走的。

┌───────────────┐
│ 用户 │
└───────┬───────┘

│ HTTP POST

┌────────────────────┐
│ Spring Boot │
│ AiChatController │
└────────┬───────────┘


┌────────────────────┐
│ Spring AI │
│ ChatClient │
└────────┬───────────┘


┌────────────────────┐
│ Spring AI │
│ ChatModel │
└────────┬───────────┘

│ API Request

┌────────────────────┐
│ DeepSeek │
│ LLM │
└────────┬───────────┘

│ AI Response

┌────────────────────┐
│ ChatClient │
└────────┬───────────┘

┌────────────────────┐
│ Spring Boot API │
└────────┬───────────┘

用户

这里需要记住一个非常重要的关系:

Controller

ChatClient

ChatModel

DeepSeek

后面学习 Spring AI 的过程中,这几个概念会反复出现。


三、环境准备

开始之前,需要准备以下环境。

3.1 JDK

建议使用:

JDK 17+

检查 Java 版本:

java -version

例如:

java version "17.x.x"


四、创建 Spring Boot 项目

可以使用 Spring Initializr 创建项目。

项目基础信息可以设置为:

Project:
Maven

Language:
Java

Spring Boot:
当前稳定版本

Group:
com.example

Artifact:
spring-ai-chat-demo

Name:
spring-ai-chat-demo

Packaging:
Jar

Java:
17

项目创建完成之后,用 IntelliJ IDEA 打开。


五、添加 Spring AI 依赖

Spring AI 项目建议通过 Spring AI BOM 管理版本。

在 pom.xml 中加入对应的 Spring AI BOM,然后添加 OpenAI 兼容模型相关的 Starter。

一个典型配置可以写成:

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

然后添加:

<dependencies>

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

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

</dependencies>

这里需要注意:

Spring AI 的版本需要与你使用的 Spring Boot 版本保持兼容。

不同 Spring AI 版本的 Starter 名称、配置属性和 API 可能存在差异。

因此实际项目中不要机械复制旧教程里的版本号,应该以你当前使用的 Spring AI 版本官方文档为准。


六、为什么使用 OpenAI Starter?

这里可能会产生一个疑问:

“我们明明使用的是 DeepSeek,为什么添加的是 OpenAI Starter?”

这是因为很多国产大模型提供了与 OpenAI API 兼容的接口。

也就是说:

Spring AI

OpenAI-compatible API

DeepSeek

因此,我们可以利用 Spring AI 的 OpenAI 模型集成能力连接 DeepSeek。

这也是一个非常实用的设计:

应用层不需要关心底层 API 的大量 HTTP 细节。


七、配置 DeepSeek

接下来配置 DeepSeek API。

在:

src/main/resources/application.yml

添加:

spring:
ai:
openai:
api-key: ${DEEPSEEK_API_KEY}
base-url: https://api.deepseek.com
chat:
options:
model: deepseekchat

这里有几个非常重要的配置。


7.1 api-key

api-key: ${DEEPSEEK_API_KEY}

不要直接把 API Key 写死在代码里面。

不推荐:

api-key: skxxxxxxxx

推荐:

api-key: ${DEEPSEEK_API_KEY}

然后通过环境变量提供:

export DEEPSEEK_API_KEY=你的API_KEY

Windows 可以使用对应的环境变量配置方式。

这样做的好处是:

代码

不会保存 Secret

Git 提交

不会意外泄露 API Key


八、base-url 是什么?

这里:

base-url: https://api.deepseek.com

表示:

Spring AI 应该把模型请求发送到哪里。

如果你使用的是 OpenAI,那么对应地址会不同。

如果使用 DeepSeek,则需要配置 DeepSeek 的 API 地址。

因此可以理解成:

ChatClient

ChatModel

base-url

DeepSeek API


九、model 是什么?

这里:

model: deepseekchat

表示:

使用哪个模型处理请求。

模型是 AI 应用非常重要的一个概念。

例如:

deepseek-chat

用于普通聊天场景。

具体可使用哪些模型,需要以 DeepSeek 当前提供的模型列表和 API 文档为准。


十、创建 Spring Boot 启动类

创建:

AiApplication.java

代码:

package com.example.ai;

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

@SpringBootApplication
public class AiApplication {

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

这是标准的 Spring Boot 启动类。

启动:

mvn spring-boot:run

如果看到:

Started AiApplication

说明 Spring Boot 已经启动成功。


十一、创建 ChatClient

接下来进入 Spring AI 最核心的一步。

我们需要创建:

ChatClient

可以使用 Spring AI 自动配置的 ChatClient.Builder 创建:

package com.example.ai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/ai")
public class AiChatController {

private final ChatClient chatClient;

public AiChatController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
}

这里发生了什么?

Spring Boot 启动时会根据我们配置的模型自动创建相关 AI 组件。

然后 Spring AI 提供:

ChatClient.Builder

我们通过:

chatClientBuilder.build();

得到:

ChatClient

于是:

Spring Boot

自动配置

ChatClient.Builder

ChatClient


十二、实现第一个 AI 聊天接口

接下来添加:

@PostMapping("/chat")
public String chat(@RequestParam String message) {

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

完整代码:

package com.example.ai.controller;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/ai")
public class AiChatController {

private final ChatClient chatClient;

public AiChatController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}

@PostMapping("/chat")
public String chat(@RequestParam String message) {

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

现在我们的第一个 AI 接口就完成了。


十三、这几行代码到底做了什么?

第一次看到:

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

可能会觉得:

“这么简单?”

没错,Spring AI 的目标之一就是把底层复杂度封装起来。

我们拆开来看。


13.1 prompt()

chatClient.prompt()

表示:

创建一次 AI 请求。

可以理解成:

ChatClient

创建 Prompt 请求


13.2 user()

.user(message)

表示:

设置用户发送给 AI 的消息。

例如:

message = "什么是 Spring AI?"

最终形成:

User Message

什么是 Spring AI?


13.3 call()

.call()

表示:

真正执行模型调用。

前面的:

prompt()
user()

主要是在构建请求。

到了:

call()

才真正发起调用。

整体过程:

prompt()

构建 Prompt

user()

添加 User Message

call()

调用 DeepSeek


13.4 content()

最后:

.content()

表示:

获取模型返回的文本内容。

所以整个代码可以翻译成人话:

创建一次 AI 请求

告诉 AI 用户的问题

发送请求

获取 AI 返回的文本


十四、启动项目

启动:

mvn spring-boot:run

或者直接使用 IntelliJ IDEA 启动:

AiApplication

Run

默认情况下:

http://localhost:8080


十五、使用 Postman 测试

发送:

POST http://localhost:8080/api/ai/chat?message=什么是Spring%20AI?

如果配置正确,你应该能够得到类似:

Spring AI 是 Spring 生态面向 AI 应用开发提供的框架和抽象……

这意味着:

Spring Boot

Spring AI

DeepSeek

AI

已经完整打通。


十六、使用 curl 测试

也可以直接使用:

curl -X POST \\
"http://localhost:8080/api/ai/chat?message=请介绍一下Spring%20AI"

如果调用成功,就会直接看到模型返回结果。


十七、目前的接口有什么问题?

虽然我们的接口已经可以运行,但是它还比较简陋。

现在请求:

POST /api/ai/chat?message=你好

返回:

你好!有什么可以帮助你的吗?

这对于 Demo 足够了。

但是如果是真正的后端项目,我们一般不会让接口直接返回一个字符串。

更合理的是:

{
"message": "你好",
"answer": "你好!有什么可以帮助你的吗?"
}

所以我们可以定义请求对象。


十八、定义 ChatRequest

创建:

ChatRequest.java
package com.example.ai.dto;

public record ChatRequest(
String message
) {
}

然后修改 Controller:

@PostMapping("/chat")
public String chat(@RequestBody ChatRequest request) {

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

请求:

{
"message": "什么是 Spring AI?"
}

这样更符合 REST API 的开发习惯。


十九、进一步封装 Service

随着项目越来越复杂,我们不建议把 AI 调用逻辑全部放到 Controller。

更合理的结构:

Controller

Service

ChatClient

DeepSeek

创建:

AiChatService.java
package com.example.ai.service;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;

@Service
public class AiChatService {

private final ChatClient chatClient;

public AiChatService(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}

public String chat(String message) {

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

Controller:

package com.example.ai.controller;

import com.example.ai.dto.ChatRequest;
import com.example.ai.service.AiChatService;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/ai")
public class AiChatController {

private final AiChatService aiChatService;

public AiChatController(AiChatService aiChatService) {
this.aiChatService = aiChatService;
}

@PostMapping("/chat")
public String chat(@RequestBody ChatRequest request) {

return aiChatService.chat(request.message());
}
}

这样结构就变成:

HTTP

Controller

Service

ChatClient

ChatModel

DeepSeek

这才是更接近真实项目的写法。


二十、为什么要进行 Controller / Service 分层?

因为 AI 应用后面会越来越复杂。

现在:

chat(message)

以后可能变成:

chat()
├── Prompt
├── Memory
├── Advisor
├── RAG
├── Tool Calling
├── Logging
└── Exception Handling

如果全部写在 Controller:

Controller

大量 AI 业务逻辑

代码很容易失控。

所以:

Controller

只负责 HTTP

Service

负责业务

Spring AI

负责 AI 能力

职责更加清晰。


二十一、完整项目结构

现在我们的项目可以整理成:

spring-ai-chat-demo

├── pom.xml

└── src
└── main
├── java
│ └── com.example.ai
│ │
│ ├── AiApplication.java
│ │
│ ├── controller
│ │ └── AiChatController.java
│ │
│ ├── service
│ │ └── AiChatService.java
│ │
│ └── dto
│ └── ChatRequest.java

└── resources
└── application.yml

虽然项目很小,但已经有一个基本的分层结构。


二十二、完整请求流程

现在重新看一次整个流程:

用户

│ POST

┌────────────────────┐
│ AiChatController │
└─────────┬──────────┘


┌────────────────────┐
│ AiChatService │
└─────────┬──────────┘


┌────────────────────┐
│ ChatClient │
└─────────┬──────────┘


┌────────────────────┐
│ ChatModel │
└─────────┬──────────┘


┌────────────────────┐
│ DeepSeek │
└─────────┬──────────┘


AI Response


用户

这张图非常重要。

后面我们学习 Spring AI 的其他能力,本质上都是在这个基础上不断扩展。


二十三、到这里,我们真正学到了什么?

表面上看,这一章只是写了一个:

/api/ai/chat

但实际上我们已经建立了 Spring AI 的第一个核心认知:

Spring Boot

Spring AI

ChatClient

ChatModel

LLM

同时理解了:

prompt()
user()
call()
content()

分别承担什么作用。


二十四、为什么不直接使用 RestClient?

这是一个非常值得思考的问题。

当然可以。

你完全可以自己:

RestClient

HTTP

DeepSeek API

但是随着项目变复杂,你还需要自己处理:

模型适配
消息结构
Streaming
Tool Calling
Structured Output
Embedding
Vector Store
RAG

Spring AI 的价值就在这里。

它不是让:

“调用一个 API”

变得多么神奇。

而是希望:

把 AI 应用开发过程中大量重复的基础能力进行抽象,让开发者可以把更多精力放在业务本身。


二十五、常见问题

问题 1:启动时报 API Key 错误

例如:

401 Unauthorized

首先检查:

echo $DEEPSEEK_API_KEY

确认环境变量是否存在。

然后检查:

spring:
ai:
openai:
api-key: ${DEEPSEEK_API_KEY}

是否配置正确。


问题 2:模型不存在

如果出现类似:

model not found

检查:

model: deepseekchat

是否仍然是当前 DeepSeek API 支持的模型名称。

模型名称会随着模型服务商的产品变化,因此应以当前官方模型列表为准。


问题 3:为什么 DeepSeek 使用 OpenAI Starter?

因为 DeepSeek 提供了 OpenAI 兼容接口。

因此 Spring AI 可以使用 OpenAI 模型集成能力连接 DeepSeek。

需要注意:

OpenAI Starter 并不意味着你必须使用 OpenAI 模型。

这里主要使用的是兼容的 API 接口规范。


问题 4:为什么不把 API Key 写在 application.yml?

不推荐:

api-key: skxxxx

因为:

Git

提交代码

API Key 泄露

更推荐:

api-key: ${DEEPSEEK_API_KEY}

使用环境变量或者安全的 Secret 管理系统。


二十六、本章总结

这一章我们从 0 开始创建了一个 Spring AI 项目,并成功完成:

Spring Boot

Spring AI

ChatClient

DeepSeek

AI Response

我们还学习了:

ChatClient
ChatModel
Prompt
User Message
call()
content()

并最终实现了:

POST /api/ai/chat

可以把用户问题发送给 DeepSeek,并获得 AI 返回结果。


二十七、但是,现在的 AI 还非常“笨”

目前我们只是:

用户

问题

DeepSeek

答案

它还不知道:

你的身份
你的业务
你的公司
你的知识库
你的数据库
你的系统能力

例如用户问:

“我们公司的退款规则是什么?”

现在的 AI 很可能无法回答。

那么怎么办?

我们需要学习:

Prompt

通过 System Prompt,我们可以告诉 AI:

你是谁?

你的职责是什么?

你应该如何回答?

你不能回答什么?

回答需要遵循什么格式?

再进一步,我们还可以让 AI:

读取公司文档

查询数据库

调用 Java 方法

检索知识库

这时候 AI 才真正开始进入企业业务系统。


二十八、下一章:Prompt

下一章我们继续学习 Spring AI 中非常重要的一个概念:

《Spring AI Prompt 实战:System Prompt、User Prompt 与 PromptTemplate》

我们将解决一个实际问题:

现在用户输入:

介绍一下 Java

AI 会直接回答。

但是如果我们希望:

你是一名 Java 高级工程师。

回答必须使用中文。

回答需要包含:

1. 概念
2. 原理
3. 示例
4. 常见问题

应该怎么做?

下一章我们就从:

Prompt

System Message

User Message

PromptTemplate

动态参数

开始深入 Spring AI 的 Prompt 体系。

到这里,我们才算真正开始进入 Spring AI AI 应用开发。

赞(0)
未经允许不得转载:171主机测评 » Spring AI 实战:Spring Boot + DeepSeek 实现第一个 AI 聊天接口
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址