不用Python!Java+Spring AI 3.x本地RAG系统搭建实战

文章目录

无意间发现了一个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提供了PgVectorStoreOllamaChatModel的官方 starter,配置比写Hello World还简单。


环境准备:喝杯咖啡的时间就搞定

先别急着写代码,把基础设施搭好。你需要:

  1. Java 21(Spring Boot 3.4的标配,LTS版本稳如老狗)
  2. Docker Desktop(用来跑PostgreSQL+PGVector)
  3. 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-starterspring-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()方法时,它会自动:

  1. 通过Ollama的嵌入模型把文本转成768维向量
  2. 把原文、向量、元数据一起写入PGVector
  3. 建好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机制。它会在幕后自动完成:

  1. 把用户问题向量化
  2. 去PGVector检索最相似的文档片段
  3. 把片段塞进Prompt的上下文中
  4. 调用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,只是做得太稳了,不像某些语言天天上热搜。

相关推荐
堕2742 小时前
JavaEE初阶——《多线程--. 多线程带来的的⻛险-线程安全 (重点)》
java·算法·java-ee
book123_0_992 小时前
spring 跨域CORS Filter
java·后端·spring
空空潍2 小时前
Spring AI 实战教程(一)入门示例
java·后端·spring·ai
星辰_mya2 小时前
自定义注解 + AOP:打造企业级通用组件(日志、限流、幂等)
java·开发语言·spring·面试·架构师
找了一圈尾巴2 小时前
OpenClaw 技术架构解析-网关层(下)
人工智能·架构
努力的小白o(^▽^)o2 小时前
简历中关于分类的问题
大数据·人工智能·分类
Ms_lan2 小时前
体育运动手环训练为何还需要蓝牙网关加持?
人工智能·蓝牙网关·北京桂花网·体育运动监测
polaris06302 小时前
springboot接入deepseek深度求索 java
java·spring boot·后端
skywalk81632 小时前
参考paddlex的图像识别和目标检测,做一个精简的寻物小助手的推理服务器后台
服务器·人工智能·目标检测