如果你是一个 Java 后端开发,2026 年无论如何都绕不开这三个名字:Spring AI、LangChain4j、DeepSeek。Spring AI 2.0 把 LLM 接入做成了经典的 Spring 风格,LangChain4j 在 Java 生态里提供了类似 LangChain 的编排能力,DeepSeek 则把大模型 API 的成本和效果拉到了非常有竞争力的位置。这篇文章不是概念科普,而是一套可以照着敲的保姆级流程:从创建 Spring Boot 项目、接入 DeepSeek API,到结构化输出、RAG 向量检索、批量任务和接口化,全部跑通。
默认你的环境是 JDK 17+、Spring Boot 3.x,用 Maven 管理依赖。DeepSeek 使用云端 API,不需要本地显卡,所以显存、CUDA 这些在这个教程里不是门槛;如果你要在本地跑 Qwen 或 DeepSeek 的蒸馏模型,那才需要关注 Ollama 和显存占用。文章会把云端 API 和本地模型两条路径都说清楚,你按自己的场景选。
另外,Spring AI Alibaba 值得单独拿出来看。它对 Qwen 系模型、DashScope、以及 Graph 图编排提供了更完整的支持,很多企业项目在 Spring AI 基础上直接叠加它来做私有化 AI 应用。下面按照实际开发中最常用的接入方式展开,每一步都可以直接复制到你的项目里验证。
1. 核心能力速览
| 能力项 | 说明 |
|---|---|
| 项目类型 | Java 生态大模型应用开发框架 |
| 核心功能 | 对话、流式输出、结构化输出、RAG、向量存储、Tool Calling、Agent 编排 |
| 模型接入 | DeepSeek API、OpenAI 兼容接口、Ollama 本地模型、Qwen/DashScope |
| 主要组件 | Spring AI 2.0、LangChain4j、Spring AI Alibaba |
| 推荐环境 | JDK 17+、Spring Boot 3.x、Maven 或 Gradle |
| 启动方式 | Spring Boot 标准启动,内嵌 Tomcat |
| 接口能力 | 支持将 AI 能力封装为 REST API,供前端、移动端或外部系统调用 |
| 批量任务 | 支持异步批处理、任务队列、失败重试 |
| 向量库 | 支持 Milvus、Elasticsearch、Redis、PGVector 等 |
| 是否支持本地部署 | 支持,可通过 Ollama 部署 Qwen 或 DeepSeek 蒸馏模型 |
| 适合场景 | Java 后端接入大模型、私有知识库、智能客服、AI 应用服务化 |
从这张表格能看出来,这套组合解决的不是“怎么调一个模型接口”的问题,而是“怎么把大模型能力工程化地放进 Java 后端系统”的问题。如果你之前只用 Python 写过 AI 脚本,Spring AI 2.0 会给你一套更贴近企业项目习惯的写法。
2. 技术栈分工:Spring AI、LangChain4j、DeepSeek、Spring AI Alibaba 各管什么
很多初学者容易把这四个概念混在一起。先理清分工,后面写代码才不会乱。
Spring AI 是 Spring 官方推出的 AI 框架,目标是让 Java 开发者用最小的成本接入大模型。它的核心抽象是ChatClient、EmbeddingModel、VectorStore、ToolCallback等,只要配置好模型提供方,业务代码基本不用改。Spring AI 2.0 相比 1.x 更强调模块化,模型接入、向量数据库、Agent 编排被拆分得更清楚,同时兼容了大量主流模型厂商。
LangChain4j 是 Java 生态里的 LLM 编排框架,设计灵感来自 Python 的 LangChain。它擅长做对话记忆管理、结构化输出、RAG、Tool Calling 和 Agent 流程编排。LangChain4j 和 Spring AI 不是对立关系,两者在功能上有重叠,但在工程集成上各有优势。Spring AI 更“Spring 原生”,适合深度使用 Spring Boot 的项目;LangChain4j 更灵活,RAG 和 Agent 示例也更丰富。实际项目里,有人只用其中一个,也有人在一个系统里同时引入两者,分别承担不同模块。
DeepSeek 在这套组合里是模型提供方。DeepSeek 的 API 兼容 OpenAI 协议,这意味着 Spring AI 和 LangChain4j 里现成的 OpenAI 客户端稍作配置就能对接。常用的模型名是deepseek-chat和deepseek-reasoner,前者适合通用对话,后者支持思考模式,但调用时要注意处理reasoning_content字段。
Spring AI Alibaba 是阿里开源的项目,基于 Spring AI 做了大量扩展。它的价值主要有三点:第一,对 Qwen 通义千问系列模型的接入做了封装,包括文本生成、Embedding、语音等;第二,提供 DashScope 平台的适配,企业如果已经用阿里云百炼,可以直接对接;第三,提供了 Graph 图编排模块,可以用节点和边的方式设计 AI 工作流,相当于 Java 版的轻量 LangGraph。
一句话总结分工:Spring AI 2.0 是主框架,LangChain4j 是增强型工具集,DeepSeek 是背后的模型引擎,Spring AI Alibaba 负责把阿里系能力补齐。四个组件可以组合使用,也可以按需取舍。
3. 环境准备与前置条件
在动手前,先把环境检查一遍。以下是这套教程的最小环境清单,每一项如果不满足,后面跑起来会出现各种奇怪问题。
| 检查项 | 要求 | 说明 |
|---|---|---|
| JDK | 17 及以上 | Spring Boot 3.x 强制要求 JDK 17+ |
| Spring Boot | 3.2 及以上 | 更高版本兼容性更好,推荐 3.3+ |
| 构建工具 | Maven 3.6+ 或 Gradle 7.5+ | 本文示例使用 Maven |
| DeepSeek API Key | 必选 | 在 DeepSeek 开放平台创建,充值和开通模型服务 |
| 网络 | 能访问 DeepSeek API | 国内网络可以直接访问,无需额外手段 |
| 可选组件 | Milvus、Elasticsearch、Ollama | 只有做 RAG 或本地模型时才需要 |
| 磁盘空间 | 2GB 左右 | 主要是 Maven 依赖和日志,若本地跑 Ollama 模型需额外预留 10GB+ |
DeepSeek API Key 的申请路径很简单:打开 DeepSeek 开放平台,完成注册,进入控制台创建 API Key,然后把 Key 保存到本地环境变量或配置文件中。注意 API Key 只在创建时完整展示一次,之后无法再次查看,只能重新创建。
如果你打算在本地跑 Ollama 模型,还要提前安装 Ollama 客户端,并下载对应的模型,比如qwen2.5或 DeepSeek 蒸馏版本。显存占用取决于模型大小,7B 级别模型通常需要 6GB 左右显存,小参数模型可以用 CPU 跑,但速度会明显慢。这里不展开具体数字,以你本机实际测试为准。
如果你的目标是做 RAG,需要准备向量数据库。Milvus 是比较流行的选择,本地可以用 Docker 快速起一个单机版;Elasticsearch 适合已经在用 ES 做搜索的公司,可以直接把向量索引和业务索引统一管理。两种方案后面我都会给出接入思路。
4. 搭建项目并接入 DeepSeek
4.1 创建 Spring Boot 项目
最简单的方式是去 Spring Initializr 生成一个基础项目,也可以直接用 IDE 创建。关键点是勾选 web 依赖,语言选择 Java,Boot 版本选择 3.x。
4.2 引入 Spring AI 相关依赖
DeepSeek 兼容 OpenAI 协议,所以 Spring AI 侧不需要单独的 DeepSeek starter,直接使用 OpenAI 模块,把 base-url 指向 DeepSeek 即可。先引入 BOM 管理版本,再引入具体模块。
<properties> <java.version>17</java.version> <spring-ai.version>2.0.0</spring-ai.version> </properties> <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.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> </dependency> </dependencies>上面的spring-ai.version是我给的一个示例值,实际使用时请去 Maven 中央仓库查一下当前最新稳定版本,替换成真实版本号。不要把 2.0.0 当成固定结论,Spring AI 迭代很快,版本之间可能存在 API 差异。
如果要用 LangChain4j,可以额外引入它的核心包和 OpenAI 模块。这里建议先跑通 Spring AI,再叠加 LangChain4j,避免一开始两个框架的配置互相干扰。
<dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j</artifactId> <version>${langchain4j.version}</version> </dependency> <dependency> <groupId>dev.langchain4j</groupId> <artifactId>langchain4j-open-ai</artifactId> <version>${langchain4j.version}</version> </dependency>langchain4j.version同样需要替换为实际最新版本。
4.3 配置 DeepSeek 连接
在application.yml中加入以下配置:
spring: application: name: spring-ai-demo ai: openai: base-url: https://api.deepseek.com api-key: ${DEEPSEEK_API_KEY} chat: options: model: deepseek-chat temperature: 0.7DEEPSEEK_API_KEY建议通过环境变量注入,不要硬编码在配置文件中。如果你的 DeepSeek 账号支持/v1路径,也可以把 base-url 写成https://api.deepseek.com/v1,两种写法对 OpenAI 兼容客户端来说通常都能生效。
4.4 写第一个对话接口
Spring AI 2.0 的核心对象是ChatClient。在配置类里注入ChatClient.Builder,然后构建一个全局的ChatClient实例。
package com.example.demo; import org.springframework.ai.chat.client.ChatClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AIConfig { @Bean public ChatClient chatClient(ChatClient.Builder builder) { return builder.build(); } }接着写一个 REST 接口,把对话能力暴露出去。
package com.example.demo; import org.springframework.ai.chat.client.ChatClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class ChatController { private final ChatClient chatClient; public ChatController(ChatClient chatClient) { this.chatClient = chatClient; } @GetMapping("/chat") public String chat(@RequestParam(defaultValue = "你好,请介绍一下你自己") String message) { return chatClient.prompt(message) .call() .content(); } }启动项目后访问http://127.0.0.1:8080/chat?message=你好,如果返回一段正常的中文回复,说明 Spring AI 2.0 到 DeepSeek 的链路已经通了。这是整个教程的“地基”,后面所有功能都在这个基础上扩展。
5. 功能测试:对话、流式输出与结构化输出
5.1 流式输出
普通接口一次返回全部内容,适合内部工具;但做智能客服或前端对话框时,流式输出体验更好。Spring AI 的流式输出返回Flux<String>,前端可以用 SSE 方式接收。
import org.springframework.ai.chat.client.ChatClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; @RestController public class StreamChatController { private final ChatClient chatClient; public StreamChatController(ChatClient chatClient) { this.chatClient = chatClient; } @GetMapping("/chat/stream") public Flux<String> streamChat(@RequestParam String message) { return chatClient.prompt(message) .stream() .content(); } }Vue 前端做对话页面时,可以用EventSource或fetch配合ReadableStream接收流式数据。这里给一个简单的 fetch 思路,具体封装方式看你的前端框架。
const response = await fetch('/chat/stream?message=' + encodeURIComponent(text)); const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); let result = ''; while (true) { const { done, value } = await reader.read(); if (done) break; result += decoder.decode(value, { stream: true }); }5.2 多轮对话与上下文数量限制
大模型本身是无状态的,多轮对话需要手动把历史消息传给模型。Spring AI 里有两个方案:一是自己维护消息列表,二是使用内置的ChatMemory。
用内置方案时,可以限制上下文数量,避免历史消息无限增长导致 token 费用过高。
import org.springframework.ai.chat.memory.MessageWindowChatMemory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ChatMemoryConfig { @Bean public MessageWindowChatMemory chatMemory() { return MessageWindowChatMemory.builder() .maxMessages(20) .build(); } }这里的maxMessages(20)就是控制上下文窗口条数。20 条是一个保守值,具体要看你用的模型上下文长度。如果业务场景需要更长的记忆,可以调大这个值,但要注意 token 成本会随之上升。
5.3 结构化输出
默认情况下模型返回的是纯文本,但我们经常需要把输出绑定到实体类上,比如解析一本书的信息、抽取一篇文章的标题和作者。Spring AI 支持把回复直接映射到 Java 对象。
先定义一个实体类:
package com.example.demo; public record BookInfo( String title, String author, String category, String summary ) { }然后在调用时指定目标类型:
import org.springframework.ai.chat.client.ChatClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class BookController { private final ChatClient chatClient; public BookController(ChatClient chatClient) { this.chatClient = chatClient; } @GetMapping("/parse-book") public BookInfo parseBook(@RequestParam String text) { return chatClient.prompt("请从下面的文本中抽取书籍信息,返回 JSON 格式:" + text) .call() .entity(BookInfo.class); } }结构化输出的重点在于提示词要给出明确的格式约束,实体类字段名最好用英文,并且加说明性注释,这样模型的召回率更高。如果返回结果经常解析失败,检查两个方向:一是实体类字段是否过于复杂且语义模糊,二是在提示词中补充“只返回 JSON,不要解释”之类的约束。LangChain4j 同样支持结构化输出,并且对复杂嵌套对象的容错性更好,后面章节会提到。
5.4 DeepSeek 思考模式的坑:reasoning_content 必须原样回传
如果你使用deepseek-reasoner模型,会在响应里多出一个reasoning_content字段,代表模型内部的思考过程。这是 DeepSeek 的一个特色,但也容易踩坑。
在多轮对话时,如果直接把content拼到历史消息里,把reasoning_content丢了,下一次请求可能收到 400 错误,提示思考模式下的reasoning_content必须传回 API。解决方式是把reasoning_content保存到 assistant 消息中,下一轮原样带回。
在 Spring AI 中,可以构造一个通用的消息转换工具:
import java.util.HashMap; import java.util.Map; public class DeepSeekMessageBuilder { public static Map<String, Object> assistantMessageWithReasoning(String content, String reasoningContent) { Map<String, Object> message = new HashMap<>(); message.put("role", "assistant"); message.put("content", content); if (reasoningContent != null) { message.put("reasoning_content", reasoningContent); } return message; } }核心原则是:reasoning_content和content必须绑定在同一条 assistant 消息里回传,不能拆开,也不能省略。这属于 DeepSeek 协议层的行为,不管用 Spring AI、LangChain4j 还是直接用 HTTP 客户端调用,都要遵守。
6. RAG 实战:向量存储、ES 覆盖策略、Milvus 混合检索与重排
6.1 为什么需要 RAG
大模型的知识截止时间有限,企业内部资料也无法靠训练塞进模型。RAG(检索增强生成)的思路是先把文档切块、向量化,存进向量数据库,用户提问时先检索最相关的片段,和问题一起送给模型回答。这样既控制成本,又能保证最新文档被回答到。
6.2 Qwen Embedding 接入
向量化这一步通常用专门的 Embedding 模型。这里以阿里云百炼 DashScope 的text-embedding-v3为例,在 Spring AI Alibaba 体系里,可以像配置 Chat 模型一样配置 Embedding 模型。
<dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter</artifactId> <version>${spring-ai-alibaba.version}</version> </dependency>spring: ai: dashscope: api-key: ${DASHSCOPE_API_KEY} embedding: options: model: text-embedding-v3从材料看,这是实际项目里比较常见的接入路径。如果你没有阿里云百炼的 Key,也可以使用本地 Ollama 的 embedding 模型,例如nomic-embed-text,只是召回效果和延迟会有差异。
6.3 文档写入 Milvus,混合检索加 Rerank
LangChain4j 提供了 Milvus 向量存储实现,基础用法如下:
import dev.langchain4j.store.embedding.milvus.MilvusEmbeddingStore; MilvusEmbeddingStore embeddingStore = MilvusEmbeddingStore.builder() .host("127.0.0.1") .port(19530) .collectionName("java_knowledge") .dimension(1024) .build();dimension必须和 Embedding 模型输出维度一致,不同模型维度不同,写错了写入时就会报错。写入文档后,查询时可以做混合检索,同时用关键词和向量相似度召回,再用 Rerank 模型对结果重排,把最相关的片段排到前面,这能明显提升 RAG 答案质量。
重排阶段如果使用 DashScope 服务,注意在查询链路里增加重排 API 调用,并把 TopK 结果截断后再送进 Prompt。混合检索加重的流程本身不复杂,但每一步的参数都需要观察实际返回结果来调整,不是配好就能永远最优。
6.4 ES 向量存储:重复文档怎么覆盖
用 Spring AI 把文档向量化后写入 Elasticsearch 时,很容易遇到一个现象:同一份 PDF 重复执行导入任务,ES 里会出现多条重复记录。原因在于 Spring AI 默认写入文档时,如果没有指定稳定 id,每次都会生成一个新的 UUID,重复导入自然产生新记录。
解决办法是在写入前给文档设置稳定的业务 id,比如用文件路径、文档编号或内容哈希。Spring AI 的Document构造器允许传入 id:
import org.springframework.ai.document.Document; import java.util.List; public class DocumentService { public List<Document> buildDocs(List<String> chunks) { return chunks.stream() .map(chunk -> new Document("doc-" + Integer.toHexString(chunk.hashCode()), chunk)) .toList(); } }当同一个 id 再次写入时,ES 向量库会按 id 执行 upsert 语义,覆盖旧文档而不是追加新文档。如果某个 id 对应的内容已经不存在,还需要主动删除旧向量,避免脏数据残留。
另一种更稳妥的方案是:在批量任务开头先按业务标记删除本批次对应的旧文档,再执行写入。比如每个文档写入时 metadata 里保存batchId,清理时按batchId批量删除。这个策略适合定时重建知识库的场景。
7. 接口 API 化与批量任务
7.1 封装 REST API
前面已经写了一个/chat接口,生产环境通常还会加上对话记录持久化、用户维度上下文隔离、token 用量日志。这里给出一个相对完整的接口示例,查询参数和返回结构可以按你公司规范调整。
@RestController public class ChatApiController { private final ChatClient chatClient; public ChatApiController(ChatClient chatClient) { this.chatClient = chatClient; } @PostMapping("/api/chat") public ChatResponse chat(@RequestBody ChatRequest request) { String answer = chatClient.prompt(request.messages()) .call() .content(); return new ChatResponse(answer, request.sessionId()); } public record ChatRequest(String sessionId, String message) {} public record ChatResponse(String answer, String sessionId) {} }前端 Vue 项目可以对接这个接口,也可以对接前面的流式接口。建议流式接口给终端用户,非流式接口给内部系统做异步处理。
7.2 批量任务示例
批量任务常见于文档解析、商品文案生成、评论分类等场景。原则是不要在主线程里同步循环调用模型,那样既慢又容易触发 API 限流。正确做法是异步提交 + 任务队列 + 失败重试。
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; @Service public class BatchAIService { private final ChatClient chatClient; public BatchAIService(ChatClient chatClient) { this.chatClient = chatClient; } @Async("aiTaskExecutor") public CompletableFuture<String> processOne(String prompt) { try { String result = chatClient.prompt(prompt).call().content(); return CompletableFuture.completedFuture(result); } catch (Exception e) { return CompletableFuture.failedFuture(e); } } public List<CompletableFuture<String>> processBatch(List<String> prompts) { List<CompletableFuture<String>> futures = new ArrayList<>(); for (String prompt : prompts) { futures.add(processOne(prompt)); } return futures; } }线程池建议单独配置,不要把模型调用塞进 Tomcat 的工作线程。线程池大小可以根据模型 API 的并发限制来调整,如果 DeepSeek 并发额度不高,线程数过大只会增加堆积和超时。
8. 资源占用与性能观察
这套组合的性能观察点和 Python 本地模型不同,重点不是显存,而是网络、超时、并发、token 用量。
如果你只用 DeepSeek 云端 API,本机不跑任何模型,那么资源占用主要是 JVM 内存和少量网络 IO,普通开发机完全扛得住。需要在监控面板里重点观察的是:
- API 响应延迟:DeepSeek 首次 token 时间是否稳定,高峰期是否明显变慢。
- 超时配置:默认 HTTP 超时在慢网络下容易触发 SocketTimeoutException,建议把连接超时设置为 10 秒到 30 秒之间。
- 并发控制:同一账号并发过高会触发限流,返回 429 状态码,需要在代码里做重试和退避。
- token 用量:每次请求的输入 token 和输出 token 都建议记录到日志或数据库,月底对账和成本评估都靠它。
如果你在本地用 Ollama 跑 Qwen 或 DeepSeek 蒸馏模型,那么资源和显存占用才是重点。模型加载后显存会持续占用,7B 模型大约需要 6GB 左右显存,量化版本会低一些。降低显存占用的常见手段包括:使用量化模型、关闭不用的模型、降低上下文长度、限制并发数。在 Ollama 里可以通过环境变量控制模型常驻策略,具体以 Ollama 文档为准。
下面是两个常用指标采集点:
| 指标 | 采集方式 | 用途 |
|---|---|---|
| 调用耗时 | 在 ChatClient 调用前后记时 | 判断模型响应是否稳定 |
| token 消耗 | 从响应对象中读取 usage 信息 | 成本统计和限流策略 |
| 429 重试次数 | 在重试拦截器中累积计数 | 判断并发额度是否充足 |
| JVM 内存 | Spring Boot Actuator + Prometheus | 防止内存泄漏 |
9. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 调用 DeepSeek 返回 400,提示思考模式 reasoning_content 未回传 | 多轮对话丢弃了 thinking 内容 | 查看请求日志中 assistant 消息结构 | 把 reasoning_content 拼回 assistant 消息后重试 |
| 启动后接口一直超时 | base-url 配置错误或网络不通 | 用 curl 直接测试 DeepSeek API | 确认 base-url 和 api-key 是否正确 |
| 对话结果不稳定,偶尔返回空内容 | 模型参数配置或提示词约束不够 | 查看完整响应日志 | 调整 temperature,增强提示词约束 |
| 重复导入文档后 ES 记录越来越多 | 文档未设置稳定 id | 检查 Document id 生成逻辑 | 使用业务 id 并配合删除旧批次 |
| RAG 检索结果相关度差 | 向量维度不匹配或缺少重排 | 检查 embedding 维度,打印召回结果 | 校准维度,加入 rerank 环节 |
| 批量任务跑到一半卡住 | 并发过高触发 API 限流 | 查看 429 响应统计 | 降低线程池并发,增加退避重试 |
| JDK 版本过低导致依赖冲突 | JDK 8 无法运行 Spring Boot 3 | 执行 java -version 查看版本 | 升级到 JDK 17+ |
| LangChain4j 和 Spring AI 同时使用时 Bean 冲突 | 两个框架都扫描了 OpenAI 客户端 | 查看启动日志的 Bean 冲突提示 | 配置不同的包扫描路径或排除自动配置 |
10. 最佳实践与合规建议
第一,API Key 全部走环境变量或配置中心,不要提交到 Git 仓库。一旦泄露,立刻去平台删除重建。DeepSeek 开放平台的后台可以查看用量,建议设置额度告警,防止异常调用导致费用飞涨。
第二,批量任务一定要有日志和任务表。每次任务的输入、输出、耗时、token 数记录清楚,失败任务要有重试机制。批量跑文档解析时,建议先跑 5 条样本验证效果,再放开全部任务,避免大批量失败后回滚困难。
第三,涉及 RAG 的文档导入,必须考虑数据版本管理。文档更新后,旧版本向量要及时清理或覆盖。不要长期堆积无主数据,否则检索结果会越来越差,最终影响回答准确性。
第四,合规边界要重视。如果你的业务涉及用户上传的文档、图片、录音,或者要处理他人的人脸、声音、版权内容,必须确认有合法授权。企业内部知识库接入 AI 时,要评估数据是否适合发送到第三方模型 API,敏感数据建议本地部署模型或做脱敏处理。部署测试环境时,先用脱敏数据验证,不要直接把生产数据导进去试。
第五,任何一个 AI 功能上线前,准备一套固定的验收用例。包括普通问答、多轮连续性、长文本、异常输入、空输入、重复提交等场景。模型输出有随机性,不能依赖一次测试通过就认定稳定,至少跑三到五次,观察结果波动。
11. 总结与后续方向
这套组合最值得尝试的点是:把大模型能力变成 Java 项目里的普通依赖,从配置 DeepSeek 到跑通对话接口只需要几十分钟。接下来优先验证这几个功能:流式对话是否能稳定推送、结构化输出解析是否准确、RAG 检索到你自己的文档时回答是否靠谱。
最容易踩的坑有三个:DeepSeek 思考模式下忘记回传reasoning_content、ES 写入时没设置文档 id 导致重复数据、两个 AI 框架同时引入后出现 Bean 冲突。后两者通过配置隔离和稳定 id 就能解决。
后续想继续深入,可以按这个顺序扩展:先做 Tool Calling,让模型能调用你内部的查询接口;再用 Spring AI Alibaba Graph 编排复杂的多步骤任务;最后把批量任务和定时任务结合起来,做成一个完整的知识库自动更新系统。这篇文章建议直接收藏,配置代码都是可以复制改的,真正用时拿起来就能跑。