文章目录
-
- 前言
- RAG是个啥?说白了就是个超级图书管理员
- 技术选型:为什么要用这套组合拳?
- 环境准备:喝杯咖啡的时间就搞定
- [项目搭建:Spring Initializr走你](#项目搭建:Spring Initializr走你)
- 配置文件:把散落的珠子串起来
- 核心代码:Document入库与RAG问答
- 跑起来!见证奇迹的时刻
- 踩坑实录:我掉过的坑你别再掉
- 进阶玩法:让AI调用你的业务方法
- [总结:Java AI生态的黄金时代真的来了](#总结:Java AI生态的黄金时代真的来了)
无意间发现了一个CSDN大神的人工智能教程,忍不住分享一下给大家。很通俗易懂,重点是还非常风趣幽默,像看小说一样。床送门放这了👉 http://blog.csdn.net/jiangjunshow
前言
谁说Java不能做AI?Spring AI 3.x来砸场子了
兄弟们,我是真受不了那个风气------一提到AI就是Python,好像Java程序员只能老老实实写CRUD似的。前段时间我去参加一个技术沙龙,刚说我是做Java的,旁边一个戴黑框眼镜的哥们儿立马露出怜悯的表情:"哦...Java啊...现在AI时代了,你们是不是挺难的?"
难个锤子!我当场就想掏出手机给他看我笔记本上跑的本地大模型。Java不仅能做AI,而且做得贼溜,特别是Spring AI 3.x出来后,搭一套企业级的RAG(检索增强生成)系统比泡碗方便面还简单。
今天咱们就手撕一套零Python、纯Java、完全本地部署的RAG系统。不用买OpenAI的会员,不用啃英文文档,甚至不用联网------把你的公司内部文档扔进去,它就能变成一个懂业务的AI助手。而且这套系统跑在Spring Boot 3.4上,跟你现有的微服务架构无缝衔接。
RAG是个啥?说白了就是个超级图书管理员
很多教程一上来就扔术语,什么"向量空间"、"语义检索"、"嵌入模型",听得人头大。我用个接地气的比喻给你讲清楚:
想象你去图书馆问管理员:"我想找讲Spring Boot事务管理的书。"
普通AI(比如裸奔的ChatGPT)就像个没进过图书馆的网红学者,他只能凭记忆瞎编:"Spring Boot事务管理啊,那个...可能要用@Transactional注解吧...具体细节我也不太清楚。"
RAG系统则是个正经图书管理员,他先听懂你的问题,然后冲进书库(向量数据库)把《Spring Boot实战》《Java事务处理内幕》这类相关书籍抽出来,翻开对应章节,最后拿着这些资料告诉你:"根据第3章第5节,你要在方法上加@Transactional,还要注意默认只对RuntimeException回滚..."
Spring AI 3.x就是帮你培养这个图书管理员的工具包,而且全免费、全本地、全Java!
技术选型:为什么要用这套组合拳?
在动手之前,咱们得把武器选明白。Spring AI 3.x(目前里程碑版本是1.0.0-M6)支持的向量库很多:Redis、PostgreSQL/pgvector、MongoDB、Elasticsearch...为什么我选Ollama + PGVector?
- Ollama这玩意儿就是本地大模型的"应用商店",一条命令
ollama pull qwen2.5就能把通义千问下载到你电脑上,完全离线运行,数据不出本机,老板再也不用担心我把客户隐私发到OpenAI了。 - PGVector是PostgreSQL的向量扩展,把关系数据库和向量检索二合一。这意味着你不需要额外维护一个Milvus或Pinecone,直接用你熟悉的PostgreSQL就能存向量数据,事务、备份、权限管理全是现成的。
而且这套组合对Java极度友好------Spring AI提供了PgVectorStore和OllamaChatModel的官方 starter,配置比写Hello World还简单。
环境准备:喝杯咖啡的时间就搞定
先别急着写代码,把基础设施搭好。你需要:
- Java 21(Spring Boot 3.4的标配,LTS版本稳如老狗)
- Docker Desktop(用来跑PostgreSQL+PGVector)
- Ollama(去官网下载,Windows/macOS/Linux都支持)
首先把PGVector拉起来,新建一个docker-compose.yml:
yaml
version: '3.8'
services:
postgres:
image: ankane/pgvector:latest
container_name: pgvector-springai
environment:
POSTGRES_DB: vectordb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
ports:
- "5433:5432"
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
注意我把端口映射到5433,避免跟你本地已有的PostgreSQL冲突。执行docker compose up -d,数据库就启动了。
接着装Ollama并拉取模型:
bash
# 安装Ollama后,拉取中文友好的千问模型
ollama pull qwen2.5:7b
# 再拉一个轻量级嵌入模型(把文字转成向量的)
ollama pull nomic-embed-text
这里有个坑:嵌入模型的维度必须跟PGVector表结构匹配 。nomic-embed-text生成768维向量,如果你后面看到expected 1536 dimensions, not 768这种报错,就知道是这里没对齐。
项目搭建:Spring Initializr走你
打开 Spring Initializr,选:
- Project: Maven
- Language: Java
- Spring Boot: 3.4.3(目前稳定版)
- Java: 21
依赖项勾选:
- Spring Web
- Spring Data JDBC(PGVector底层用它)
- PostgreSQL Driver
然后手动在pom.xml里加入Spring AI的依赖(因为它还没进Maven中央仓库,需要声明仓库):
xml
21
1.0.0-M6
org.springframework.ai
spring-ai-pgvector-store-spring-boot-starter
org.springframework.ai
spring-ai-pdf-document-reader
org.springframework.ai
spring-ai-tika-document-reader
看到没,spring-ai-ollama-spring-boot-starter和spring-ai-pgvector-store-spring-boot-starter这两个starter就是Spring AI 3.x的魔法所在------它把Ollama和PGVector的复杂交互全封装了,你只需写业务代码。
配置文件:把散落的珠子串起来
application.yml是整套系统的神经中枢:
yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5433/vectordb
username: postgres
password: password
ai:
ollama:
base-url: http://localhost:11434
chat:
model: qwen2.5:7b
options:
temperature: 0.7
embedding:
model: nomic-embed-text
options:
temperature: 0.0
vectorstore:
pgvector:
index-type: HNSW # 高性能近似最近邻搜索
distance-type: COSINE_DISTANCE
dimensions: 768 # 必须跟nomic-embed-text匹配!
initialize-schema: true # 自动建表,懒人福音
max-document-batch-size: 1000
server:
port: 8080
重点看initialize-schema: true,这会让Spring AI自动在PostgreSQL里创建vector_store表,包含id、content、metadata、embedding四个字段。如果没开这个,你得手写SQL建表,且embedding字段的维度必须严格匹配,不然直接报错。
核心代码:Document入库与RAG问答
现在写业务逻辑。首先我们要解决"图书上架"问题------把PDF文档切分、向量化、存进数据库。
文档导入服务
java
@Service
public class DocumentService {
private final VectorStore vectorStore;
private final ResourceLoader resourceLoader;
public DocumentService(VectorStore vectorStore, ResourceLoader resourceLoader) {
this.vectorStore = vectorStore;
this.resourceLoader = resourceLoader;
}
/**
* 加载PDF并入库 - 相当于图书管理员把新书编码上架
*/
public String ingestDocument(String filePath) throws IOException {
// 1. 读取PDF
Resource resource = resourceLoader.getResource("classpath:" + filePath);
PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(resource);
List documents = pdfReader.get();
// 2. 切分文档(避免一次塞太多token)
TokenTextSplitter textSplitter = new TokenTextSplitter(
1000, // 每块最大token数
200, // 重叠token数(保持上下文连贯)
10, // 最小字符数
10000, // 最大字符数
true // 保留缩进
);
List chunks = textSplitter.apply(documents);
// 3. 自动向量化并存储(Spring AI幕后完成)
vectorStore.add(chunks);
return "成功导入 " + chunks.size() + " 个文档片段";
}
}
VectorStore接口是Spring AI的神来之笔。调用add()方法时,它会自动:
- 通过Ollama的嵌入模型把文本转成768维向量
- 把原文、向量、元数据一起写入PGVector
- 建好HNSW索引加速后续检索
RAG问答接口
java
@RestController
@RequestMapping("/api/chat")
public class RagController {
private final ChatClient chatClient;
private final VectorStore vectorStore;
public RagController(ChatClient.Builder chatClientBuilder, VectorStore vectorStore) {
this.vectorStore = vectorStore;
// 关键:配置Advisor实现自动RAG
this.chatClient = chatClientBuilder
.defaultAdvisors(new QuestionAnswerAdvisor(vectorStore))
.build();
}
@PostMapping
public String chat(@RequestBody String question) {
return chatClient.prompt()
.user(question)
.call()
.content();
}
}
看到QuestionAnswerAdvisor了吗?这就是Spring AI 3.x的"大杀器"------Advisor机制。它会在幕后自动完成:
- 把用户问题向量化
- 去PGVector检索最相似的文档片段
- 把片段塞进Prompt的上下文中
- 调用Ollama生成答案
你不需要手写检索逻辑,不需要拼Prompt,Spring AI全包了!
跑起来!见证奇迹的时刻
启动应用前,先在src/main/resources下放一个测试PDF,比如《Spring Boot官方文档.pdf》。然后写一个初始化类:
java
@Component
public class DataInitializer implements ApplicationRunner {
@Autowired
private DocumentService documentService;
@Override
public void run(ApplicationArguments args) throws Exception {
// 项目启动时自动加载文档(生产环境建议改成接口触发)
String result = documentService.ingestDocument("Spring Boot官方文档.pdf");
System.out.println("文档初始化:" + result);
}
}
启动Spring Boot,你会看到控制台输出:
文档初始化:成功导入 47 个文档片段
然后测试RAG效果:
bash
curl -X POST http://localhost:8080/api/chat \
-H "Content-Type: text/plain" \
-d "Spring Boot怎么配置数据库连接池?"
如果一切正常,AI会基于你上传的PDF内容回答,而不是瞎编。你可以对比删掉QuestionAnswerAdvisor后的效果------那才是真正的"幻觉大师"。
踩坑实录:我掉过的坑你别再掉
第一坑:维度不匹配地狱
如果你把dimensions配成1536(OpenAI的默认值),但用nomic-embed-text(768维),会报:
ERROR: expected 1536 dimensions, not 768
解决方案:严格对照嵌入模型的文档,nomic-embed-text是768,mofanke/dmeta-embedding-zh是1024,all-minilm是384。
第二坑:中文分词导致的检索失效
Spring AI默认的TokenTextSplitter对中文处理比较粗暴,可能把"事务管理"切成"事"、"务管"、"理"。建议引入更聪明的分词器,或者调小chunkSize到500左右。
第三坑:Ollama模型没拉取
如果报model not found,先执行ollama list确认模型已下载。Spring AI 3.x支持自动拉取(pull-policy: if_not_present),但第一次启动会很慢。
第四坑:PGVector版本太老
确保用ankane/pgvector镜像,普通PostgreSQL镜像没有向量扩展,会报pgvector extension not found。
进阶玩法:让AI调用你的业务方法
Spring AI 3.x还支持Function Calling,让AI不仅能读文档,还能调用你的Java方法。比如:
java
@FunctionalInterface
public interface WeatherService {
@Tool(description = "获取指定城市的实时天气")
String getWeather(String city);
}
// 然后在ChatClient配置时加入
chatClientBuilder.defaultFunctions("weatherService")
这样当你问"今天适合出门吗?",AI会主动调用你的getWeather方法获取实时数据,再给出建议。
总结:Java AI生态的黄金时代真的来了
写到这里,我突然想起五年前用DL4J做深度学习的日子------那叫一个痛苦,API反人类,文档稀烂,还得跟Python脚本来回传数据。现在的Spring AI 3.x简直是降维打击:标准化的ChatClient接口、开箱即用的Vector Store实现、声明式的Advisor机制,让你用纯Java就能搭出生产级的RAG系统。
这套方案的优势再强调一遍:
- 零Python:全Java团队维护无压力
- 零费用:Ollama+PGVector全开源
- 零网络:内网部署,数据不出域
- 全Spring:跟你现有的UserDetailsService、事务管理无缝集成
下次再有人问你"Java能不能做AI",直接把这篇文章拍他脸上。咱们Java程序员不是不能做AI,只是做得太稳了,不像某些语言天天上热搜。