用 LangChain4j 从零实现 RAG:基于 PDF 文档的智能问答系统
在大语言模型时代,让 AI 能够理解并基于本地文档回答问题的 RAG(检索增强生成)技术成为热门。本文将结合实际代码,详细介绍如何使用 LangChain4j 框架快速实现一个基于 PDF 文档的 RAG 系统,让 AI 能够 "读懂" 你的本地文档并精准回答相关问题。
在大语言模型时代,让 AI 能够理解并基于本地文档回答问题的 RAG(检索增强生成)技术成为热门。本文将结合实际代码,详细介绍如何使用 LangChain4j 框架快速实现一个基于 PDF 文档的 RAG 系统,让 AI 能够 "读懂" 你的本地文档并精准回答相关问题。
什么是 RAG?为什么选择 LangChain4j?
RAG(Retrieval-Augmented Generation,检索增强生成)是一种将外部知识检索与大语言模型生成相结合的技术。它解决了大语言模型 "知识过时" 和 "幻觉生成" 的问题,通过在生成回答前检索相关文档内容,让 AI 基于真实可信的来源生成答案。
LangChain4j 是 Java 生态中优秀的大语言模型应用开发框架,它提供了简洁的 API 封装,简化了 RAG 流程中文档处理、嵌入生成、向量存储、检索匹配等核心环节的实现,让开发者可以用最少的代码搭建生产级 RAG 系统。
实战:用 LangChain4j 实现 PDF 文档问答
环境准备:核心依赖
首先需要在pom.xml
中引入 LangChain4j 的核心依赖,包括框架核心、内存向量存储、文档解析器和大语言模型集成(这里以 OpenAI 为例):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
<version>1.1.0-beta7</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-easy-rag</artifactId>
<version>1.1.0-beta7</version>
</dependency>
核心组件配置:搭建 RAG 基础框架
我们需要配置三个核心组件:向量存储(用于存储文档嵌入)、嵌入模型(将文本转换为向量)、RAG 聊天助手(整合检索与生成)。以下是 Spring 环境下的配置类实现:
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.InMemoryEmbeddingStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RAGConfig {
// 1. 配置嵌入模型(将文本转换为向量)
@Bean
public OpenAiEmbeddingModel embeddingModel() {
return OpenAiEmbeddingModel.withApiKey("你的OpenAI API密钥");
}
// 2. 配置向量存储(存储文档向量)
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
// 实际生产环境可替换为Pinecone、Weaviate等向量数据库
return new InMemoryEmbeddingStore<>();
}
// 3. 配置大语言模型(用于生成回答)
@Bean
public ChatModel chatModel() {
return OpenAiChatModel.withApiKey("你的OpenAI API密钥")
.modelName("gpt-4o-mini") // 可替换为gpt-4等模型
.temperature(0.7); // 控制回答随机性,0表示更确定
}
// 4. 配置RAG聊天助手(整合检索与生成)
@Bean(name = "ragChatAssistant")
public ChatMemoryAssistant ragChatAssistant(
EmbeddingStore<TextSegment> embeddingStore,
ChatModel chatModel) {
// 创建内容检索器(从向量存储中检索相关文档)
EmbeddingStoreContentRetriever contentRetriever = EmbeddingStoreContentRetriever.from(
embeddingStore,
embeddingModel(), // 用于将查询转换为向量
3 // 每次检索返回3个最相关的文档片段
);
// 构建RAG聊天助手
return AiServices.builder(ChatMemoryAssistant.class)
.chatModel(chatModel) // 生成回答的大模型
.contentRetriever(contentRetriever) // 检索相关文档
.chatMemory(MessageWindowChatMemory.withMaxMessages(50)) // 保留对话历史
.build();
}
}
关键组件说明:
EmbeddingStore
:存储文档的向量表示,这里使用内存存储(适合演示),生产环境建议使用分布式向量数据库。EmbeddingModel
:将文本(文档片段和用户查询)转换为向量,实现语义匹配。ChatModel
:大语言模型,基于检索到的文档生成自然语言回答。ChatMemoryAssistant
:LangChain4j 提供的接口式助手,自动处理检索 - 生成流程,支持对话记忆。
文档处理:解析 PDF 并存入向量存储
接下来需要实现文档的加载、解析和嵌入存储。以下是控制器中处理 PDF 文档并提供问答接口的代码:
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.parser.apache.tika.ApacheTikaDocumentParser;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@RestController
@Slf4j
public class RAGController {
// 注入RAG聊天助手
@Resource
private ChatMemoryAssistant ragChatAssistant;
// 注入向量存储
@Resource
private EmbeddingStore<TextSegment> embeddingStore;
/**
* 加载PDF文档并执行RAG问答
*/
@GetMapping("/rag/query")
public String ragQuery(@RequestParam String query) {
try {
// 1. 读取本地PDF文件(这里以"Java开发错误码.pdf"为例)
FileInputStream fileInputStream = new FileInputStream(
"src/main/resources/static/Java开发错误码.pdf"
);
// 2. 使用Apache Tika解析PDF文档(支持多种格式:PDF/Word/Excel等)
Document document = new ApacheTikaDocumentParser().parse(fileInputStream);
// 3. 将文档分块并存入向量存储
// 自动分块(默认按字符长度分块,可自定义分块策略)
EmbeddingStoreIngestor.ingest(document, embeddingStore);
log.info("文档解析完成,已存入向量存储");
// 4. 调用RAG助手生成回答(自动检索相关文档)
String answer = ragChatAssistant.chat(query);
log.info("RAG回答:{}", answer);
return answer;
} catch (FileNotFoundException e) {
log.error("文档未找到", e);
return "文档不存在,请检查路径";
} catch (Exception e) {
log.error("RAG处理失败", e);
return "处理失败:" + e.getMessage();
}
}
}
文档处理流程解析:
- 文档加载:通过
FileInputStream
读取本地 PDF 文件(支持其他格式如 Word、TXT 等)。 - 文档解析:使用
ApacheTikaDocumentParser
解析文档内容(Tika 支持多种格式,无需单独处理 PDF 解析逻辑)。 - 文档分块:
EmbeddingStoreIngestor
自动将文档分割为适合嵌入的小片段(默认策略:每块 200 字符,重叠 0 字符,可自定义)。 - 嵌入存储:分块后的文本片段通过嵌入模型转换为向量,存入
EmbeddingStore
。
定义聊天助手接口
最后需要定义ChatMemoryAssistant
接口,LangChain4j 会通过动态代理自动实现接口逻辑:
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
public interface ChatMemoryAssistant {
// 系统提示:告诉AI如何使用检索到的文档回答问题
@SystemMessage("""
你是一个基于文档的问答助手。请根据提供的文档内容回答用户问题。
如果文档中没有相关信息,请明确说明"文档中未找到相关内容",不要编造答案。
回答要简洁明了,基于文档事实。
""")
String chat(@UserMessage String query);
}
接口说明:
@SystemMessage
:定义 AI 的角色和行为准则,这里要求 AI 严格基于检索到的文档回答。@UserMessage
:标记用户输入的查询参数。- LangChain4j 会自动将检索到的文档内容作为上下文传入大模型,生成符合系统提示的回答。
运行与测试
-
准备工作:
- 替换代码中的 OpenAI API 密钥(可在 OpenAI 官网申请)。
- 将 PDF 文档放入
src/main/resources/static
目录(或修改代码中的文件路径)。
-
启动应用:运行 Spring Boot 主类,访问接口
http://localhost:8080/rag/query?query=你的问题
。 -
示例:
- 若 PDF 中包含 "错误码 1001 表示参数无效" 的内容,查询
http://localhost:8080/rag/query?query=错误码A0001是什么意思
,会返回基于文档的准确回答。
- 若 PDF 中包含 "错误码 1001 表示参数无效" 的内容,查询
优化与扩展方向
-
替换向量存储:将
InMemoryEmbeddingStore
替换为生产级向量数据库(如 Pinecone、Milvus、Weaviate),支持大规模文档存储。 -
自定义分块策略:默认分块可能不适合长文档,可自定义分块器:
DocumentSplitter splitter = new CharacterDocumentSplitter( 500, // 块大小 50, // 块重叠 "\n" // 分隔符 ); EmbeddingStoreIngestor.builder() .documentSplitter(splitter) .embeddingStore(embeddingStore) .build() .ingest(document);
-
使用本地模型:若需隐私保护,可替换为本地嵌入模型(如 BGE)和大语言模型(如 Llama 3):
// 本地嵌入模型 EmbeddingModel embeddingModel = new BgeSmallEnV15QuantizedEmbeddingModel(); // 本地大语言模型 ChatModel chatModel = new Llama3ChatModel(...);
-
添加文档元数据:解析文档时可添加元数据(如作者、日期),检索时支持过滤:
Document document = Document.from(text, Map.of("source", "Java开发手册"));
总结
本文通过实际代码演示了如何用 LangChain4j 快速搭建 RAG 系统,核心流程包括:文档解析→分块→嵌入存储→检索→生成回答。LangChain4j 通过封装复杂的底层逻辑,让开发者只需关注业务需求,大幅降低了 RAG 的实现门槛。
无论是企业内部知识库问答、产品手册查询还是法律文档分析,这种架构都能快速适配,为 AI 应用注入 "读懂本地文档" 的能力。

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)