SpringAI-DeepSeek-Java开发者大模型入门指南
Spring AI + DeepSeek:Java开发者的大模型入门指南
前言:作为一名写了5年Java的后端开发,最近在研究大模型应用开发。发现一个事实——Java开发者做大模型应用,比你想象的简单得多。 这篇文章从0到1讲清楚Spring AI怎么接入DeepSeek,中间踩的坑和解决方案也一并记录了。
一、为什么Java开发者也能做大模型应用?
很多人一提到大模型应用开发,第一反应就是Python。确实,Python生态在AI领域很强。但实际情况是:
大模型落地最缺的不是会写Python的人,而是能把AI集成到企业业务系统里的工程师。
而企业业务系统,Java占了大半壁江山。
Spring AI的出现就是为了解决这个问题——让Java开发者用熟悉的Spring Boot方式,就能接入大模型能力。 不需要学Python,不需要换框架,加个依赖、改个配置就能跑。
| 对比 | Python方案 | Spring AI方案 |
|---|---|---|
| 框架 | LangChain / LlamaIndex | Spring AI |
| 语言 | Python | Java |
| 与Spring集成 | 需要额外封装 | 原生集成 |
| 切换模型 | 改代码 | 改配置文件 |
| 适合谁 | Python开发者 | Java/Spring开发者 |
你会Spring Boot,你就能用Spring AI。
二、Spring AI是什么?
Spring AI是Spring官方推出的AI应用开发框架。简单说就是:Spring Boot + 大模型。
它帮你封装了:
- 大模型调用(对话、Embedding)
- 向量数据库对接(Chroma、Milvus、Redis等)
- 工具调用(Function Calling)
- 对话记忆(ChatMemory)
- 提示词模板管理(PromptTemplate)
核心好处:切换模型只需要改配置文件,代码不用动。
比如你项目里用DeepSeek,明天领导说换通义千问,只需要改application.yml,Java代码一行不改。
三、DeepSeek是什么?为什么选它?
DeepSeek是国内的一家AI公司,做了一个很猛的大语言模型。选它的理由很实际:
| 理由 | 说明 |
|---|---|
| 兼容OpenAI格式 | API调用方式和OpenAI一样,Spring AI原生支持 |
| 成本低 | 输入1元/百万token,输出2元/百万token,比GPT便宜很多 |
| 国内访问快 | 不用翻墙,API稳定 |
| 效果好 | 在中文场景下表现很强,性价比极高 |
| 有免费额度 | 新用户注册有赠送,够你学习和测试用 |
便宜、好用、不用翻墙,Java开发者接入成本最低的大模型之一。
四、快速开始:30分钟跑通第一个对话
4.1 环境准备
你需要:
- JDK 17+
- Maven 3.6+
- IDEA(或其他Java IDE)
- DeepSeek API Key(去 https://platform.deepseek.com/ 注册)
4.2 创建项目
用Spring Initializr(https://start.spring.io/)生成项目:
Project: Maven
Language: Java
Spring Boot: 3.5.x
Group: com.example
Artifact: ai-demo
Dependencies: Spring Web
4.3 添加Spring AI依赖
打开pom.xml,加入Spring AI的BOM和DeepSeek依赖:
<properties>
<java.version>17</java.version>
<spring-ai.version>1.1.8</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-deepseek</artifactId>
</dependency>
</dependencies>
4.4 配置application.yml
spring:
ai:
deepseek:
api-key: sk-你的DeepSeek密钥
base-url: https://api.deepseek.com
4.5 写一个Controller
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final ChatClient chatClient;
public ChatController(ChatClient.Builder chatClientBuilder) {
this.chatClient = chatClientBuilder.build();
}
@GetMapping("/ask")
public String ask(@RequestParam String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
}
4.6 启动测试
mvn spring-boot:run
浏览器打开:
http://localhost:8080/api/chat/ask?question=你好,请用一句话介绍Java
看到DeepSeek返回文字 = 接入成功! 🎉
整个过程就这几步,不需要装Python,不需要学新框架。Spring Boot开发者看到这段代码应该很亲切——就是标准的Controller + 依赖注入。
五、进阶:Function Calling(让模型调你的代码)
5.1 什么是Function Calling?
普通对话只能问大模型"知道的"东西。但如果你想让它查数据库、调接口、算数据,就需要Function Calling。
通俗理解:你告诉大模型"我有哪些工具",大模型自己决定什么时候用哪个。
流程是这样的:
你定义工具 + 写好描述
↓
Spring AI把工具描述发给大模型
↓
用户提问:"今天北京天气怎么样?"
↓
大模型分析:这个问题需要调 getWeather 工具
↓
大模型返回:请调用 getWeather,参数是 {city: "北京"}
↓
Spring AI自动执行你的Java方法
↓
返回结果给大模型
↓
大模型组织最终回答
5.2 代码实现
创建一个工具类,模拟天气查询和数据库查询:
@Component
public class AppTools {
@Tool(description = "根据城市名称查询当前天气信息")
public String getWeather(@ToolParam(description = "城市名称,如北京、上海") String city) {
// 实际开发中这里调天气API,这里模拟返回
Map<String, String> mockData = Map.of(
"北京", "晴,温度28°C,湿度45%",
"上海", "多云,温度26°C,湿度65%",
"广州", "阵雨,温度30°C,湿度80%"
);
return mockData.getOrDefault(city, "暂无该城市天气数据");
}
@Tool(description = "查询员工的部门信息,根据工号返回所在部门")
public String queryDepartment(@ToolParam(description = "员工工号") String empId) {
// 实际开发中这里查数据库,这里模拟返回
if ("1001".equals(empId)) return "研发部";
if ("1002".equals(empId)) return "市场部";
return "未找到该员工信息";
}
}
然后在调用时加上 .tools(tools):
@GetMapping("/ask-with-tools")
public String askWithTools(@RequestParam String question) {
return chatClient.prompt()
.user(question)
.tools(appTools)
.call()
.content();
}
测试:
# 模型自动调用 getWeather
http://localhost:8080/api/chat/ask-with-tools?question=今天北京天气怎么样?
# 模型自动调用 queryDepartment
http://localhost:8080/api/chat/ask-with-tools?question=工号1001的员工在哪个部门?
大模型自动判断该调哪个工具,参数也自动传对。 这就是Function Calling的魔力。
5.3 关键点
@Tool(description = "xxx") 里的description是给大模型看的"说明书"。description写得好不好,直接决定模型能不能正确调用你的工具。 写得太模糊,模型可能调错;写得太长,模型可能理解不了。
5.4 实际开发建议
- 工具方法的返回值要尽量简洁,别把整个对象返回,大模型不需要那么多信息
- description要写清楚输入输出,比如"根据工号查询部门"比"查数据库"好得多
- 多个工具的description要有区分度,不然模型可能选错
六、进阶:RAG知识库问答
6.1 为什么需要RAG?
大模型有个致命问题——幻觉。你问它你公司内部的信息,它不知道就编一个看起来很真的答案。
RAG(Retrieval Augmented Generation,检索增强生成)的思路是:
你的文档 → 切成小段 → 转成向量 → 存起来
用户提问 → 也转成向量 → 找最相似的几段 → 喂给大模型 → 基于真实文档回答
大模型不再是"凭空回答",而是"看着你的文档回答"。
6.2 一个实际场景:技术博客搜索助手
假设你有很多技术博客文章(Markdown或TXT格式),你想做一个"技术问答机器人"——用户问"Spring Boot怎么配置多数据源",系统能从你的博客里找到相关内容,基于真实文章回答。
这就是RAG能做的事情。
6.3 整体架构
┌──────────────────────────────────────────────┐
│ 文档导入阶段 │
│ │
│ 技术博客文章(MD/TXT) │
│ ↓ │
│ 文本切片 (TokenTextSplitter) │
│ ↓ │
│ 向量化 (Ollama nomic-embed-text) │
│ ↓ │
│ 存入向量数据库 (Chroma) │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ 问答阶段 │
│ │
│ 用户提问: "Redis缓存穿透怎么解决?" │
│ ↓ │
│ 问题向量化 │
│ ↓ │
│ 向量检索 Top-5 │
│ ↓ │
│ 拼接上下文 + Prompt │
│ ↓ │
│ 大模型回答: 基于你的博客文章给出解答 │
└──────────────────────────────────────────────┘
6.4 核心组件
1)Embedding模型:把文字变成数字
计算机不懂数字,Embedding模型干的事情就是:
"Redis缓存穿透解决方案" → [0.82, 0.15, 0.93, 0.41, ...]
变成数字后就能算"两段话有多像"。
2)向量数据库:存储和检索向量
普通数据库用关键字搜索,向量数据库用"语义相似度"搜索。搜"缓存雪崩",即使文章里写的是"Redis大面积失效",也能找到,因为它们在语义上是相似的。
3)文本切片:把长文章切成小段
太长的文章作为一个向量,检索时匹配不精确。切成小段后,每段只包含一个知识点,检索更精准。
6.5 代码实现
依赖(在pom.xml中添加):
<!-- Ollama Embedding -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
<!-- Chroma向量数据库 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-chroma</artifactId>
</dependency>
配置(application.yml):
spring:
ai:
ollama:
base-url: http://localhost:11434
embedding:
options:
model: nomic-embed-text
vectorstore:
chroma:
client:
host: http://localhost:8000
collection-name: blog-search
RAG服务核心代码:
@Service
public class BlogSearchService {
private final VectorStore vectorStore;
private final ChatClient chatClient;
public BlogSearchService(VectorStore vectorStore, ChatClient.Builder builder) {
this.vectorStore = vectorStore;
this.chatClient = builder.build();
}
// 导入博客文章
public void importBlog(String title, String content) {
Map<String, Object> metadata = Map.of("title", title);
Document doc = new Document(content, metadata);
vectorStore.add(List.of(doc));
}
// 基于博客内容问答
public String searchAndAnswer(String question) {
// 1. 从向量库检索相关文章片段
SearchRequest request = SearchRequest.query(question)
.withTopK(5); // 取最相关的5段
List<Document> results = vectorStore.similaritySearch(request);
// 2. 拼接上下文
String context = results.stream()
.map(Document::getText)
.collect(Collectors.joining("\n\n---\n\n"));
// 3. 用Prompt组装
String systemPrompt = "你是一个技术博客助手。请基于以下博客文章内容回答用户问题。\n"
+ "要求:\n"
+ "1. 只基于提供的文章内容回答\n"
+ "2. 如果文章中没有相关信息,请说明'现有文章中未找到相关内容'\n"
+ "3. 回答时标注信息来源的文章标题\n";
String userMessage = "文章内容:\n" + context + "\n\n用户问题:" + question;
// 4. 调用大模型
return chatClient.prompt()
.system(systemPrompt)
.user(userMessage)
.call()
.content();
}
}
这段代码是RAG的核心逻辑,建议仔细看。 整个流程就四步:检索→拼接→组装Prompt→调用模型。
七、进阶:多轮对话记忆
7.1 为什么需要?
没有对话记忆的话,每次提问都是独立的:
用户:我之前问过Redis缓存的问题
AI:好的,请问你想了解什么?
用户:刚才那个问题的解决方案里,布隆过滤器具体怎么用?
AI:布隆过滤器是一种……(但我不知道你之前问的是什么)← 尴尬了
7.2 Spring AI的ChatMemory
Spring AI提供了ChatMemory接口,实现多轮对话记忆:
// 用Map存储每个用户的对话历史
private final Map<String, ChatMemory> userMemories = new ConcurrentHashMap<>();
@GetMapping("/ask-memory")
public String askWithMemory(@RequestParam String userId,
@RequestParam String question) {
// 每个用户用userId区分
ChatMemory memory = userMemories
.computeIfAbsent(userId, k -> new InMemoryChatMemory());
return chatClient.prompt()
.user(question)
.chatMemory(memory) // 加上记忆
.call()
.content();
}
就这么简单,加一行 .chatMemory(memory) 就支持多轮对话了。
7.3 注意事项
- InMemoryChatMemory:存在内存里,重启就没了。学习阶段够用,生产环境建议用Redis或数据库持久化。
- 记忆窗口:对话太多会撑爆token,可以用
MessageWindowChatMemory限制保留最近N条对话。 - 用户隔离:不同用户用不同的userId,不然会串对话。
八、踩坑记录
学习过程中遇到的几个坑,记录一下:
坑1:Spring AI版本和Spring Boot版本不兼容
现象:启动报各种奇怪的NoSuchBeanDefinitionException
解决:Spring AI 1.0.x 需要 Spring Boot 3.x。版本对照表:
| Spring AI | Spring Boot |
|---|---|
| 1.0.x | 3.2.x |
| 1.1.x | 3.4.x / 3.5.x |
建议:用最新的稳定版本组合,别混着用。
坑2:DeepSeek API Key格式
现象:401 Unauthorized
解决:确认api-key格式是 sk-xxx,不是 Bearer sk-xxx。Spring AI会自动加Bearer前缀。
坑3:Chroma连接不上
现象:Connection refused
解决:
- 确认Chroma服务在运行:
docker ps | grep chroma - 确认端口放通:云服务器安全组要开放8000端口
- 确认Chroma绑定的是0.0.0.0而不是127.0.0.1
坑4:Ollama Embedding模型没下载
现象:模型找不到
解决:
ollama pull nomic-embed-text
ollama list # 确认列表里有这个模型
坑5:TokenTextSplitter切片后检索不准确
现象:用户问Redis,检索出来的却是MySQL的文章
原因:切片太大,一个切片里混了好几个技术点
解决:调小切片大小。我用的是1000token/段,重叠100token。重叠是为了保证相邻切片之间的上下文连续性。具体参数要根据你的文章长度和内容密度来调。
坑6:多轮对话token超限
现象:聊了几轮后报"maximum context length"错误
原因:历史对话太长,加上当前问题和检索结果,超过了模型的上下文窗口
解决:用MessageWindowChatMemory限制只保留最近10条对话:
ChatMemory memory = MessageWindowChatMemory.builder()
.maxMessages(10)
.build();
九、Java开发者的大模型技术栈
总结一下,Java开发者做大模型应用需要掌握的技术栈:
┌─────────────────────────────────────────────┐
│ 应用层 │
│ Spring Boot + Spring AI │
├─────────────────────────────────────────────┤
│ 模型层 │
│ DeepSeek / 通义千问 / OpenAI │
├─────────────────────────────────────────────┤
│ 能力层 │
│ RAG | Function Calling | ChatMemory │
│ PromptTemplate | Embedding │
├─────────────────────────────────────────────┤
│ 存储层 │
│ Chroma/Milvus (向量) | Redis (缓存) │
│ MySQL (业务数据) │
├─────────────────────────────────────────────┤
│ 基础设施 │
│ Docker | Linux | Nginx │
└─────────────────────────────────────────────┘
你会发现,这里面大部分东西Java开发者都会。 Spring Boot、MySQL、Redis、Docker——这些是你的优势,不是障碍。
十、下一步学什么?
入门之后,可以继续深入这些方向:
| 方向 | 说明 | 难度 |
|---|---|---|
| 混合检索 | 向量检索 + 关键词检索(BM25)结合 | ⭐⭐ |
| Reranker | 对检索结果二次排序,提高准确率 | ⭐⭐⭐ |
| Agent架构 | ReAct模式,让大模型自主决策执行步骤 | ⭐⭐⭐ |
| MCP协议 | 标准化的工具调用协议 | ⭐⭐ |
| 模型微调 | Fine-tuning,让模型适应特定领域 | ⭐⭐⭐⭐ |
总结
Java开发者做大模型应用,核心路径就一条:
Spring Boot → Spring AI → 接大模型 → 加RAG → 加工具 → 加记忆
每一步都是在你已有的Spring知识体系上叠加AI能力,不需要推倒重来。
最大的门槛不是技术,是迈出第一步。
本文代码示例基于 Spring AI 1.1.8 + Spring Boot 3.5 + DeepSeek API。
如有问题,欢迎在评论区交流。
更多推荐




所有评论(0)