关于 langchain4j-rag-implementation-patterns
面向使用 LangChain4j 构建 RAG 应用的开发者,提供文档摄取、向量检索和聊天问答的实现模式。内容涵盖混合搜索、分层 RAG 与验证实践。
主要功能
- 01文档加载、切分与嵌入
- 02向量检索及元数据筛选
- 03混合搜索与重排建议
- 04聊天文档问答模式
- 05摄取和检索验证
适用场景
- 01构建 PDF、文本或网页问答
- 02为助手接入企业或外部知识
- 03在文档库中实现语义搜索
- 04按领域整理知识并提供来源
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill langchain4j-rag-implementation-patterns安装后在 Claude Code 中输入/langchain4j-rag-implementation-patterns确认已加载。
附带文件references/examples.mdreferences/references.md
详细介绍
LangChain4j RAG 实现模式
概述
使用 LangChain4j 实现 RAG 系统:包括文档摄取管道、嵌入存储,以及用于文档对话和知识增强型 AI 应用的向量搜索。
何时使用此技能
- 构建文档对话系统,或针对 PDF、文本文件或网页的文档问答系统
- 创建可访问公司知识库或外部来源的 AI 助手
- 对文档存储库实现语义搜索或混合搜索
- 利用经过整理的知识和来源归属信息构建特定领域的 AI
说明
初始化 RAG 项目
创建包含所需依赖项的新 Spring Boot 项目:
pom.xml:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.8.0</version>
</dependency>
设置文档摄取
配置文档加载和处理,并进行验证:
验证检查点:摄取完成后,确认嵌入数量与分段数量一致,并使用示例查询测试检索。
@Configuration
public class RAGConfiguration {
@Bean
public EmbeddingModel embeddingModel() {
return OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("text-embedding-3-small")
.build();
}
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
return new InMemoryEmbeddingStore<>();
}
}
创建文档摄取服务:
@Service
@RequiredArgsConstructor
public class DocumentIngestionService {
private final EmbeddingModel embeddingModel;
private final EmbeddingStore<TextSegment> embeddingStore;
public void ingestDocument(String filePath, Map<String, Object> metadata) {
Document document = FileSystemDocumentLoader.loadDocument(filePath);
document.metadata().putAll(metadata);
DocumentSplitter splitter = DocumentSplitters.recursive(
500, 50, new OpenAiTokenCountEstimator("text-embedding-3-small")
);
List<TextSegment> segments = splitter.split(document);
List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
embeddingStore.addAll(embeddings, segments);
// Validation: verify embedding count matches segments
if (embeddings.size() != segments.size()) {
throw new IllegalStateException("Embedding count mismatch: expected " + segments.size() + ", got " + embeddings.size());
}
}
public boolean validateIngestion(String testQuery) {
// Validation: test retrieval with sample query
Embedding queryEmbedding = embeddingModel.embed(testQuery).content();
List<EmbeddingMatch<TextSegment>> results = embeddingStore.search(
EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(1)
.build()
).matches();
return !results.isEmpty();
}
}
配置内容检索
配置带筛选功能的内容检索:
验证检查点:配置完成后,使用已知查询测试检索,确认可以搜索到嵌入。
@Configuration
public class ContentRetrieverConfiguration {
@Bean
public ContentRetriever contentRetriever(
EmbeddingStore<TextSegment> embeddingStore,
EmbeddingModel embeddingModel) {
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(5)
.minScore(0.7)
.build();
}
}
创建支持 RAG 的 AI 服务
定义包含上下文检索的 AI 服务:
interface KnowledgeAssistant {
@SystemMessage("""
You are a knowledgeable assistant with access to a comprehensive knowledge base.
When answering questions:
1. Use the provided context from the knowledge base
2. If information is not in the context, clearly state this
3. Provide accurate, helpful responses
4. When possible, reference specific sources
5. If the context is insufficient, ask for clarification
""")
String answerQuestion(String question);
}
@Service
@RequiredArgsConstructor
public class KnowledgeService {
private final KnowledgeAssistant assistant;
public KnowledgeService(ChatModel chatModel, ContentRetriever contentRetriever) {
this.assistant = AiServices.builder(KnowledgeAssistant.class)
.chatModel(chatModel)
.contentRetriever(contentRetriever)
.build();
}
public String answerQuestion(String question) {
return assistant.answerQuestion(question);
}
}
示例
基本文档处理
public class BasicRAGExample {
public static void main(String[] args) {
var embeddingStore = new InMemoryEmbeddingStore<TextSegment>();
var embeddingModel = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("text-embedding-3-small")
.build();
var ingestor = EmbeddingStoreIngestor.builder()
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
ingestor.ingest(Document.from("Spring Boot is a framework for building Java applications with minimal configuration."));
var retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.build();
}
}
多领域助手
interface MultiDomainAssistant {
@SystemMessage("""
You are an expert assistant with access to multiple knowledge domains:
- Technical documentation
- Company policies
- Product information
- Customer support guides
Tailor your response based on the type of question and available context.
Always indicate which domain the information comes from.
""")
String answerQuestion(@MemoryId String userId, String question);
}
分层 RAG
@Service
@RequiredArgsConstructor
public class HierarchicalRAGService {
private final EmbeddingStore<TextSegment> chunkStore;
private final EmbeddingStore<TextSegment> summaryStore;
private final EmbeddingModel embeddingModel;
public String performHierarchicalRetrieval(String query) {
List<EmbeddingMatch<TextSegment>> summaryMatches = searchSummaries(query);
List<TextSegment> relevantChunks = new ArrayList<>();
for (EmbeddingMatch<TextSegment> summaryMatch : summaryMatches) {
String documentId = summaryMatch.embedded().metadata().getString("documentId");
List<EmbeddingMatch<TextSegment>> chunkMatches = searchChunksInDocument(query, documentId);
chunkMatches.stream()
.map(EmbeddingMatch::embedded)
.forEach(relevantChunks::add);
}
return generateResponseWithChunks(query, relevantChunks);
}
}
最佳实践
文档分段
- 对大多数应用,使用递归拆分,将文本分为 500-1000 个 token 的块
- 在块之间保留 20-50 个 token 的重叠,以保留上下文
- 拆分时考虑文档结构(标题、段落)
- 使用感知 token 的拆分器,以优化嵌入生成
元数据策略
- 添加丰富的元数据,以支持筛选和来源归属:
- 用于多租户的用户和租户标识符
- 文档类型和类别分类
- 创建和修改时间戳
- 版本和作者信息
- 保密级别和访问权限标签
查询处理
- 实现查询预处理和清理
- 考虑扩展查询,以提高召回率
- 根据用户上下文应用动态筛选
- 使用重排序来提升结果质量
性能优化
- 缓存重复查询的嵌入
- 批量操作时使用批量嵌入生成
- 为大型结果集实现分页
- 对耗时较长的操作考虑异步处理
常见模式
简单 RAG 管道
@RequiredArgsConstructor
@Service
public class SimpleRAGPipeline {
private final EmbeddingModel embeddingModel;
private final EmbeddingStore<TextSegment> embeddingStore;
private final ChatModel chatModel;
public String answerQuestion(String question) {
Embedding queryEmbedding = embeddingModel.embed(question).content();
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(3)
.build();
List<TextSegment> segments = embeddingStore.search(request).matches().stream()
.map(EmbeddingMatch::embedded)
.collect(Collectors.toList());
String context = segments.stream()
.map(TextSegment::text)
.collect(Collectors.joining("\n\n"));
return chatModel.generate(context + "\n\nQuestion: " + question + "\nAnswer:");
}
}
混合搜索(向量 + 关键词)
@Service
@RequiredArgsConstructor
public class HybridSearchService {
private final EmbeddingStore<TextSegment> vectorStore;
private final FullTextSearchEngine keywordEngine;
private final EmbeddingModel embeddingModel;
public List<Content> hybridSearch(String query, int maxResults) {
// Vector search
List<Content> vectorResults = performVectorSearch(query, maxResults);
// Keyword search
List<Content> keywordResults = performKeywordSearch(query, maxResults);
// Combine and re-rank using RRF algorithm
return combineResults(vectorResults, keywordResults, maxResults);
}
}
故障排除
验证失败
嵌入数量不匹配:当分段数量 != 嵌入数量时抛出。检查拆分器配置和模型是否可用。
检索结果为空:调用 validateIngestion(testQuery) 验证可以搜索到嵌入。检查文档是否已成功摄取。
检索分数偏低:确认 minScore 阈值(默认值为 0.7)对于你的用例而言不会过高。使用已知查询进行测试。
常见问题
检索结果不理想
- 检查文档块大小和重叠设置
- 验证嵌入模型兼容性
- 确保元数据筛选条件没有过于严格
- 考虑添加重排序步骤
- 运行验证,确认嵌入存在
性能缓慢
- 为频繁查询使用缓存的嵌入
- 优化向量存储的数据库索引
- 为大型数据集实现分页
- 批量操作时考虑异步处理
内存使用量高
- 对大型数据集使用基于磁盘的嵌入存储
- 实现适当的分页和筛选
- 定期清理未使用的嵌入
- 监控并优化块大小
限制和警告
- 嵌入模型成本:为大型文档集合生成嵌入可能成本高昂;请实现缓存和批处理。
- 向量存储的可扩展性:内存存储仅适用于开发;生产环境请使用持久化存储(Pinecone、Qdrant、Redis)。
- 分块大小的权衡:较小的分块能提高精度,但会丢失上下文;较大的分块能保留上下文,但可能引入噪声。
- 数据过期:源文档变更后,缓存的嵌入会过期;请实现更新策略。
- 令牌限制:RAG 上下文窗口有长度限制;通常,标准模型的限制允许放入 3-5 个检索到的分块。
- 幻觉风险:RAG 能减少幻觉,但无法消除幻觉;请始终根据来源验证关键回答。
- 延迟:向量搜索和嵌入生成会增加延迟;实时应用可考虑异步处理。
- 元数据筛选:限制过严的筛选条件可能导致没有结果;请实现回退策略。
- 多租户:确保正确隔离元数据,防止租户间数据泄露。
参考资料
- API 参考 - 完整的 API 文档和接口
- 示例 - 可用于生产环境的示例和模式
- LangChain4j 官方文档
评论
支持 Markdown