LangChain4j RAG 检索增强生成

学习时间:2026/4/4
技术栈:Spring Boot 4.0.5 + LangChain4j 1.12.2 + 通义千问模型

一、什么是 RAG?

RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合信息检索和文本生成的 AI 技术。

解决的问题

问题 传统 LLM RAG 方案
知识时效性 训练数据截止 可检索实时数据
幻觉问题 可能编造信息 基于真实文档回答
私有数据 无法访问 可接入私有知识库
成本 每次训练成本高 只需更新向量库

工作原理

用户提问 → 向量化 → 向量数据库检索 → 获取相关知识 → LLM 生成答案

二、文本向量化

2.1 Embedding 模型

QwenEmbeddingModel embeddingModel = QwenEmbeddingModel.builder()
        .apiKey(System.getenv("ALI_AI"))
        .build();

Response<Embedding> embed = embeddingModel.embed("你好,我是ZHECSDN");

System.out.println(embed.content().vector().length);  // 向量维度
System.out.println(embed.content());  // 向量内容

核心概念

  • Embedding:将文本转换为高维向量
  • 语义相似性:语义相近的文本,向量距离更近
  • 向量维度:通义千问 embedding 模型输出 1536 维向量

2.2 向量存储与检索

// 1. 创建内存向量数据库
InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();

// 2. 准备文本片段并嵌入
TextSegment segment1 = TextSegment.from("预订航班规则...");
Embedding content1 = embeddingModel.embed(segment1).content();
embeddingStore.add(content1, segment1);

// 3. 向量检索
Embedding searchVector = embeddingModel.embed("退票多少钱?").content();

EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
        .queryEmbedding(searchVector)
        .maxResults(1)           // 返回最相关的 1 条
        .minScore(0.6)           // 最小相似度阈值, 取值范围[0,1]
        .build();

EmbeddingSearchResult<TextSegment> searched = embeddingStore.search(searchRequest);

searched.matches().forEach(match -> {
    System.out.println(match.score());          // 相似度分数
    System.out.println(match.embedded().text()); // 匹配的文本
});

三、ELP 流程详解

ELP 是 RAG 的三个核心步骤:

  • Extract(提取):从文档中提取文本
  • Load(加载):将文本加载到系统中
  • Process(处理):分割、向量化、存储

3.1 文档加载与解析

// 声明文本解析器
TextDocumentParser textDocumentParser = new TextDocumentParser();

// 从 classpath 加载文档
Document document = ClassPathDocumentLoader.loadDocument(
    "rag/terms-of-service.txt", 
    textDocumentParser
);

支持的文档格式

模块 解析器 支持格式
核心模块 TextDocumentParser txt, md, html
apache-pdfbox ApachePdfBoxDocumentParser PDF
apache-poi ApachePoiDocumentParser doc, docx, xls, xlsx, ppt, pptx
apache-tika ApacheTikaDocumentParser 几乎所有文件

3.2 文档分割策略

为什么需要分割?

  • 大文本超出模型上下文窗口限制
  • 提高检索精度
  • 降低计算成本

三种分割器

// 1. 按字符分割(不推荐,可能断句)
DocumentByCharacterSplitter characterSplitter = new DocumentByCharacterSplitter(
    100,  // 每段最长字数
    10    // 重叠字数
);

// 2. 按正则表达式分割
DocumentByRegexSplitter regexSplitter = new DocumentByRegexSplitter(
    "\\n\\d+\\.",  // 匹配换行 + 数字 + 点
    "\n",          // 分隔符
    70,            // 最大长度
    10,            // 重叠长度
    new DocumentByCharacterSplitter(100, 10)
);

// 3. 按句子分割(推荐,保证语义完整)
DocumentBySentenceSplitter sentenceSplitter = new DocumentBySentenceSplitter(
    100,  // 最大长度
    30    // 重叠长度
);

// 分割文本
List<TextSegment> segments = regexSplitter.split(document);

分割器选择经验值

场景 分块策略 参考值
微博/短文本 句子级分割 100-200
学术论文 段落级分割 300-500
法律合同 条款级分割 200-400
长篇小说 章节级分割 500-1000

分割注意事项

  • ❌ 分块过细:破坏上下文连贯性,增加计算成本
  • ❌ 分块过宽:可能超出模型限制,降低匹配度
  • ✅ 首要原则:保证句子完整性!

3.3 向量化与存储

// 1. 创建 Embedding 模型
QwenEmbeddingModel embeddingModel = QwenEmbeddingModel.builder()
        .apiKey(System.getenv("ALI_AI"))
        .build();

// 2. 批量嵌入所有文本片段
List<Embedding> embeddings = embeddingModel.embedAll(segments).content();

// 3. 存储到向量数据库
InMemoryEmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
embeddingStore.addAll(embeddings, segments);

3.4 检索增强生成

// 1. 创建聊天模型
ChatModel qwenModel = QwenChatModel.builder()
        .apiKey(System.getenv("ALI_AI"))
        .modelName("qwen-max")
        .build();

// 2. 创建内容检索器
EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .maxResults(5)      // 返回最相关的 5 条
        .minScore(0.6)      // 最小相似度
        .build();

// 3. 构建 AI 助手(集成 RAG)
public interface Assistant {
    String chat(@UserMessage String message);
}

Assistant assistant = AiServices.builder(Assistant.class)
        .chatModel(qwenModel)
        .contentRetriever(contentRetriever)  // 关键:添加内容检索器
        .build();

// 4. 使用 RAG 进行问答
String answer = assistant.chat("退费费用?");
System.out.println(answer);

3.5 RAG 工作流程图

用户提问:"退费费用?"
    ↓
1. 问题向量化
    ↓
2. 向量数据库检索(返回 top 5 相关文档片段)
    ↓
3. 将检索到的文档片段 + 用户问题一起发送给 LLM
    ↓
4. LLM 基于检索到的知识生成答案
    ↓
AI 回复:"根据服务条款,取消费用为:经济舱 75 元..."

四、Spring Boot 集成

4.1 应用启动时加载 RAG 数据

@SpringBootApplication
public class Langchain4jSpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(Langchain4jSpringBootApplication.class, args);
    }

    @Bean
    CommandLineRunner insertTermsOfServiceToVectorStore(
            QwenEmbeddingModel qwenEmbeddingModel,
            EmbeddingStore<TextSegment> embeddingStore) {
        return args -> {
            // 加载文件
            Document document = ClassPathDocumentLoader.loadDocument(
                "rag/terms-of-service.txt",
                new TextDocumentParser()
            );
            
            // 分割文件 - 使用句子分割器
            DocumentBySentenceSplitter splitter = new DocumentBySentenceSplitter(100, 20);
            List<TextSegment> segments = splitter.split(document);
            
            // 向量化并存储
            List<Embedding> embeddings = qwenEmbeddingModel.embedAll(segments).content();
            embeddingStore.addAll(embeddings, segments);
            
            System.out.println("RAG 数据加载完成,共 " + segments.size() + " 个片段");
        };
    }
}

4.2 AiConfig 配置

@Configuration
public class AiConfig {

    public interface Assistant {
        String chat(@UserMessage String message);
    }

    @Bean
    public EmbeddingStore<TextSegment> embeddingStore() {
        return new InMemoryEmbeddingStore<>();
    }

    @Bean
    public Assistant assistant(ChatModel qwenChatModel,
                              QwenEmbeddingModel embeddingModel,
                              EmbeddingStore<TextSegment> embeddingStore) {
        
        // 创建内容检索器
        EmbeddingStoreContentRetriever contentRetriever = 
            EmbeddingStoreContentRetriever.builder()
                .embeddingStore(embeddingStore)
                .embeddingModel(embeddingModel)
                .maxResults(5)
                .minScore(0.6)
                .build();
        
        return AiServices.builder(Assistant.class)
                .chatModel(qwenChatModel)
                .contentRetriever(contentRetriever)
                .build();
    }
}

五、向量数据库选型

类型 代表产品 适用场景
内存型 InMemoryEmbeddingStore 测试、小规模应用
云原生 Pinecone、Weaviate、Milvus Cloud 生产环境、大规模数据
自托管 Milvus、Chroma、Qdrant 数据敏感、需要私有部署
混合型 Elasticsearch + 向量插件 已有 ES 集群

六、最佳实践

6.1 提升检索质量

  1. 优化分块策略

    • 保证句子完整性
    • 适当的重叠(10%-20%)保持上下文连贯
  2. 调整检索参数

    EmbeddingStoreContentRetriever retriever = 
        EmbeddingStoreContentRetriever.builder()
            .maxResults(5)      // 根据任务复杂度调整
            .minScore(0.6)     // 平衡召回率和准确率
            .build();
    
  3. 元数据过滤

    TextSegment segment = TextSegment.from("文本内容");
    segment.metadata().put("category", "航空政策");
    
    // 检索时过滤
    Filter filter = Filter.eq("category", "航空政策");
    

6.2 RAG 应用场景

场景 说明 示例
智能客服 基于企业知识库回答 航空客服、电商客服
文档问答 对长篇文档进行问答 合同审查、论文阅读
代码助手 基于代码库回答问题 内部 API 文档查询
知识管理 企业知识库智能检索 员工手册、技术规范

七、总结

RAG 是企业级 AI 应用的核心技术:

  • 知识增强:基于私有文档回答问题
  • 减少幻觉:答案来自真实文档
  • 实时更新:只需更新向量库
  • 向量检索:语义相似度匹配

相关笔记:

  1. LangChain4j 入门指南
  2. LangChain4j 声明式 AI 服务开发
  3. LangChain4j 对话记忆与多用户隔离
  4. LangChain4j Function Call 工具调用
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐