第4集:让AI学会看文档:Spring AI RAG入门实战

上集回顾:老张给客服AI装上了"海马体",多轮对话终于连贯了。但新问题来了------用户问"你们ERP系统的功能有哪些?"AI傻眼了:"我不知道你们公司有什么系统..."


一、故事继续:知识鸿沟

周一早上,张姐又来了:

"老张,有个大客户在咨询咱们的ERP系统,AI怎么啥都不知道?客户都快跑了!"

老张一看后台:

复制代码
用户:你们的ERP系统支持什么功能?
AI:抱歉,我不了解贵公司的产品...

老张的顿悟:"AI虽然会聊天、有记忆,但它从来没读过我们的文档!它不知道我们公司是做什么的!"

这就好比你有个聪明的秘书,但他从没看过公司的产品手册------你让他回答业务问题,他只能瞎猜。


二、技术引入:什么是RAG?

2.1 RAG是什么?

RAG = Retrieval-Augmented Generation(检索增强生成)

传统大模型 RAG增强
只靠训练数据回答 先查资料,再生成答案
不知道公司内部信息 能基于公司文档回答
幻觉问题严重 有资料可查,有据可依
知识更新需重新训练 上传新文档即可

老张的类比:"RAG就像开卷考试------以前AI是闭卷,现在允许它翻书了!"

2.2 RAG的工作流程

复制代码
用户提问
    ↓
① 检索:在知识库中找相关资料
    ↓
② 增强:把资料塞进Prompt
    ↓
③ 生成:AI基于资料生成答案
    ↓
返回答案(带来源引用)

三、第一步:文档解析

3.1 Spring AI的DocumentReader

Spring AI 通过 Apache Tika 提供了统一的多格式解析器 TikaDocumentReader,一份代码就能读 PDF / Word / TXT / Markdown / HTML:

java 复制代码
// 一份代码通吃所有格式(PDF、Word、TXT、MD、HTML)
DocumentReader reader = new TikaDocumentReader(resource);
List<Document> documents = reader.read();

// 如果是纯 PDF,也可以用更细的 PagePdfDocumentReader / ParagraphPdfDocumentReader
// DocumentReader pdfReader = new PagePdfDocumentReader(resource);

⚠️ 代码验证说明 :早期版本有 PdfReaderWordDocumentReader 等独立类,Spring AI 1.0 起统一收敛为 TikaDocumentReader(按页/按段拆分可配 ExtractedTextFormatter)。本教程统一用 TikaDocumentReader,避免类名随版本变动。

3.2 实战:解析PDF

java 复制代码
@Service
public class DocumentService {
    
    public List<Document> parsePdf(String filePath) {
        Resource resource = new FileSystemResource(filePath);
        
        // 统一用 TikaDocumentReader 解析(PDF/Word/TXT 都支持)
        DocumentReader reader = new TikaDocumentReader(resource);
        
        // 解析并返回文档列表
        return reader.read();
    }
}

老张的发现:"原来Spring AI已经封装好了各种解析器,跟Spring Boot自动装配一样省心!"


四、第二步:文本分块

4.1 为什么要分块?

直接扔整个PDF给AI?不行!

问题 原因
Token限制 大模型有输入长度上限
检索精度 整篇文档太粗,定位不准
语义完整 需要按段落/句子切分

4.2 TokenTextSplitter

java 复制代码
// Spring AI 1.0:TokenTextSplitter 构造参数为
// (chunkSize, minChunkSizeChars, maxChunkSizeChars, overlap, maxNumChunks)
TextSplitter splitter = new TokenTextSplitter(
    500,   // 每个 chunk 最大 500 个 token
    100,   // 最小 chunk 字符数
    800,   // 最大 chunk 字符数
    50,    // 重叠 50 个 token(保持上下文连贯)
    10000  // 最大 chunk 数量上限
);

// 分块
List<Document> chunks = splitter.apply(documents);

老张的比喻:"就像把一本书切成章节,每章几百字,方便查找和记忆。"


五、第三步:向量化

5.1 EmbeddingModel

把文字转成向量(数字列表),这样计算机才能"理解"语义:

java 复制代码
@Service
public class EmbeddingService {
    
    @Autowired
    private EmbeddingModel embeddingModel;
    
    public float[] embed(String text) {
        // 调用智谱Embedding-2模型
        EmbeddingResponse response = embeddingModel.call(text);
        return response.getResults().get(0).getEmbedding();
    }
}

输出示例

复制代码
原文:"退货政策是什么?"

向量:[0.023, -0.156, 0.789, ...](1536维)

5.2 语义相似度

复制代码
"退货政策"的向量  ≈  "退款规定"的向量  →  相似度0.85
"订单查询"的向量  ≠  "退货政策"的向量  →  相似度0.32

老张的理解:"意思相近的文字,向量距离就近;意思无关的,距离就远。AI就是靠这个'理解'文字!"


六、第四步:存入向量库

6.1 主流向量库对比

向量库 优点 缺点 适用场景
Redis 快、简单 非专用 开发测试
PgVector PostgreSQL扩展 需PostgreSQL 中小型项目
Milvus 性能好 部署复杂 大规模生产
Chroma 轻量本地 功能有限 个人项目

6.2 Redis向量库(推荐入门)

xml 复制代码
<!-- 依赖 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-vector-store-redis</artifactId>
</dependency>
yaml 复制代码
# 配置
spring:
  ai:
    vectorstore:
      redis:
        host: localhost
        port: 6379
        index-name: spring-ai-index
        prefix: "spring-ai:"

6.3 存储文档

java 复制代码
@Service
public class KnowledgeBaseService {
    
    @Autowired
    private VectorStore vectorStore;
    
    @Autowired
    private TextSplitter splitter;
    
    @Autowired
    private EmbeddingModel embeddingModel;
    
    public void addDocument(Document doc) {
        // 1. 分块
        List<Document> chunks = splitter.apply(Collections.singletonList(doc));
        
        // 2. 生成向量并存储
        vectorStore.add(chunks);
    }
}

七、第五步:检索增强生成

7.1 使用QuestionAnswerAdvisor

Spring AI内置了RAG助手,一行代码搞定:

java 复制代码
@Service
public class RagChatService {
    
    @Autowired
    private ChatClient chatClient;
    
    @Autowired
    private VectorStore vectorStore;
    
    public String chatWithRag(String question) {
        return chatClient.prompt()
            .user(question)
            .advisors(new QuestionAnswerAdvisor(vectorStore))  // 添加RAG助手
            .call()
            .content();
    }
}

老张的惊喜:"就一行?不需要手写检索逻辑?Spring AI太贴心了!"

7.2 完整流程演示

java 复制代码
// 1. 上传文档到知识库
KnowledgeBaseService.addDocument(new Document(
    "我们的ERP系统支持:采购管理、销售管理、库存管理、财务管理..."
));

// 2. 用户提问
String answer = ragChatService.chatWithRag("你们的ERP支持什么功能?");

// 3. AI回答(基于文档)
/*
根据我们的产品文档,我们的ERP系统主要支持以下功能:
1. 采购管理:供应商管理、采购订单、入库管理
2. 销售管理:客户管理、销售订单、出库管理
3. 库存管理:仓库管理、库存调拨、盘点管理
4. 财务管理:应收应付、成本核算、报表分析
*/

八、效果对比

场景 无RAG 有RAG
问公司产品 瞎编或说不知道 准确引用文档
问内部流程 通用回答 基于内部资料
知识更新 需重新训练 上传新文档
幻觉问题 严重 大幅降低

张姐的评价:"现在AI回答都有依据了,客户也放心了!"


九、下一集预告

RAG跑通了,但老张发现一个问题:检索质量不稳定。有时能召回正确答案,有时却找到了无关内容。

第5集《向量数据库是什么?AI的第二大脑》将深入讲解:Embedding原理、向量相似度计算、以及如何调优检索效果。


📦 完整代码

GitHub分支:chapter04-rag-intro


💬 互动环节

老兵问答

你的项目中有需要接入AI知识库的场景吗?

A. 已有,正在做

B. 计划做,还没开始

C. 暂时没有

D. 其他(评论区聊聊)

下周三晚9点,我们继续!


作者:Java老兵搞AI | 关注我,看Java如何玩转AI

相关推荐
“AI国潮设计-小江”1 小时前
【SDXL实战】Python自动化生成3D潮汕美食IP,附ComfyUI工作流与商用变现思路
开发语言·人工智能·python·prompt·aigc
墨染天姬1 小时前
[AI]BERT 详解:从起源到实战
人工智能
qyr67891 小时前
全球无硅导热垫片市场调研分析
大数据·人工智能·能源·无硅导热垫片
可乐配鸡翅1 小时前
day seven 猜数字小游戏
java
张小凡vip1 小时前
Java Web 设置 Session 超时时间:如何让 Session 永不失效
java·spring boot
浪里摸鱼1 小时前
Java 泛型快速学习指南(面向接口扫描场景)
java
盼小辉丶1 小时前
PyTorch强化学习实战——分布式策略梯度
人工智能·pytorch·深度学习·强化学习
qq7422349841 小时前
OpenCV 之外的另一半工具箱:Supervision 视觉工程实战
人工智能·opencv·计算机视觉
doiito(Do It Together)1 小时前
【Agent Harness】Gliding Horse 最新进化:从“能学习”到“可验证的自主进化”
人工智能·rust·系统架构·开源