--RetrievalAugmentor--LangChain4j)
高级RAG解决的痛点解决基础 RAGNaive RAG在面对复杂业务场景时暴露出的“找不到、找不准、用不好”等核心痛点我们可以把基础 RAG 的痛点归纳为三个阶段检索前提问阶段、检索中寻找阶段和检索后生成阶段。高级 RAG 正是通过引入更复杂的机制精准干预了这三个阶段。Advanced RAG流程高级 RAG 流程RetrievalAugmentor检索增强器实现高级RAG的核心就是配置RetrievalAugmentor检索增强器在配置AiServices的时候官方包里有对应的获取retrievalAugmentor方法package dev.langchain4j.service; public abstract class AiServicesT { ... public AiServicesT retrievalAugmentor(RetrievalAugmentor retrievalAugmentor) { if (this.contentRetrieverSet) { throw IllegalConfigurationException.illegalConfiguration(Only one out of [retriever, contentRetriever, retrievalAugmentor] can be set); } else { this.retrievalAugmentorSet true; this.context.retrievalAugmentor (RetrievalAugmentor)ValidationUtils.ensureNotNull(retrievalAugmentor, retrievalAugmentor); return this; } } ... }所以可以直接注入AIservice注意这里“MyAiService”必须是接口LangChain4j 内部使用了 Java 的动态代理当你调用AiServices.builder(MyService.class).build()时自动为你生成了一个代理实现类。/** LangChain4j 的 AiServices 原生支持响应式流。 如果返回值是 FluxString LangChain4j 会自动将其识别为流式传输Streaming */ public interface MyAiService{ public FluxString streamChat(自定义参数); public String chat(自定义参数); } MyAiService aiService AiServices.builder(MyAiService.class) .... .retrievalAugmentor(retrievalAugmentor)//放到这里 .build();如何配置 RetrievalAugmentorRetrievalAugmentor主要组件可以通过 LangChain4j 配合以下核心组件实现QueryTransformer优化检索词解决“用户不会提问”问题QueryRouter查询路由允许同一个系统同时向不同的介质向量库、关系型数据库、Web 搜索引擎发起检索ContentRetriever检索器ContentAggregator聚合检索结果重排序对这些杂乱的数据进行合并、去重、筛选和重新排序。ContentInjector将检索到的内容注入 prompt“高质量上下文”代码实现// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package dev.langchain4j.rag; public interface RetrievalAugmentor { AugmentationResult augment(AugmentationRequest var1); } | V public class DefaultRetrievalAugmentor implements RetrievalAugmentor{...} 上面是源码 | V RetrievalAugmentor retrievalAugmentor DefaultRetrievalAugmentor.builder() .queryRouter(...) .queryTransformer(...) .contentAggregator(...) .contentInjector(...) .build();1.QueryTransformer(优化检索词)langchain4j包中实现查询转换的接口// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package dev.langchain4j.rag.query.transformer; import dev.langchain4j.rag.query.Query; import java.util.Collection; public interface QueryTransformer { CollectionQuery transform(Query var1); }支持多种场景查询改写Query Rewriting- 把一个查询改写成另一个更好的形式查询扩展Query Expansion- 把一个查询扩展成多个相关查询查询压缩Query Compression- 从对话历史中提取核心查询查询分解Query Decomposition- 把复杂查询拆分成多个子查询代码实现//核心就是编写个专门用来优化检索词的prompt//核心就是编写个专门用来优化检索词的prompt private static final PromptTemplate LG_AGENT_PROMPT PromptTemplate.from( 编写优化检索词的提示词 ); public class MyQueryTransformer implements QueryTransformer { Override public CollectionQuery transform(Query query) { // 你的转换逻辑 ... } }MyQueryTransformer queryTransformer new MyQueryTransformer(); RetrievalAugmentor retrievalAugmentor DefaultRetrievalAugmentor.builder() .queryRouter(...) .queryTransformer(queryTransformer) // 这里 .contentAggregator(...) .contentInjector(...) .build();放进去后当用AIservice调用接口中的方法时 自动调用 queryTransformer.transform(query)2、QueryRouter(查询路由)langchain4j包里的queryRouter方法package dev.langchain4j.rag; public class DefaultRetrievalAugmentor implements RetrievalAugmentor { ... public static class DefaultRetrievalAugmentorBuilder { ... public DefaultRetrievalAugmentorBuilder queryRouter(QueryRouter queryRouter) { this.queryRouter queryRouter; return this; } ... } }接收的是QueryRouter类型的参数这是个接口package dev.langchain4j.rag.query.router; public interface QueryRouter { CollectionContentRetriever route(Query var1); }直接实现这个接口核心构建prompt让llm返回该问题属于哪种场景常见的 RAG 查询路由场景1.向量检索语义相似性、模糊匹配、概念理解2.关键词检索精确匹配、专有名词、编号、错误码3.结构化查询聚合、统计、范围查询、排序4.图查询Graph/Neo4j根据返回的场景从所有检索器CollectionContentRetriever中筛选出 对应的 检索器代码实现public class MyQueryRouter implements QueryRouter { private static final PromptTemplate QUERY_ROUTE_PROMPT PromptTemplate.from(...) Override public CollectionContentRetriever route(Query query) { //路由问题获取结果 //判断执行哪个检索器 } }RetrievalAugmentor retrievalAugmentor DefaultRetrievalAugmentor.builder() .queryRouter(new MyQueryRouter(检索器集合...)) .queryTransformer(queryTransformer) .contentAggregator(...) .contentInjector(...) .build();3.ContentAggregator聚合检索结果去重、重排序核心是RAG重排序什么是重排序重排序Reranking是在通过混合检索或其他方式获得初步检索结果候选文本块)后再通过更強的模型通常是Cross-Encoder或专用Reranker模型对这些候选文本块进行重新打分和排序将真正最相关、最有价值的内容排在前面。重排序作用过滤噪声初步检索往往会召回数十条文档其中可能混杂着相关性较低的噪声内容。提升答案精度优化上下文窗口利用率把最相关的放前面实现方式原理使用RRFReciprocal Rank Fusion倒数排名融合不看各个检索模型给出的绝对评分Score只看文档在各个检索结果列表中的相对排名Rank并通过倒数求和的方式进行多路召回结果的融合。当向DefaultContentAggregator传入多个检索器或使用了QueryTransformer导致产生了多个查询时LangChain4j 内部就会自动触发 RRF 算法为你融合排名ReRank模型基于语义模型重新打分使用深度学习模型计算相关性三种实现方式1.用云服务API egCohere2.去Hugging Face下载到本地3.将重排模型独立部署Hugging Face的TEI用哪个只用RRFDefaultContentAggregator内置RRF只用ReRank自己实现聚合器调用scoringModel二者兼得ReRankingContentAggregator项目里先用 RRF 将多路检索如向量全文的结果融合成一路再用 ReRank 模型进行高精度的深度打分。// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package dev.langchain4j.rag.content.aggregator; public interface ContentAggregator { ListContent aggregate(MapQuery, CollectionListContent var1); }package dev.langchain4j.rag.content.aggregator; public class ReRankingContentAggregator implements ContentAggregator { ... }LangChain4j 官方已经内置了ReRankingContentAggregator。 只需要直接通过ReRankingContentAggregator.builder().scoringModel(...).build()就能实现重排序。// 聚合器 ContentAggregator contentAggregator new ProgressAwareContentAggregator( ReRankingContentAggregator.builder() .scoringModel(scoringModel)//ReRank模型 .maxResults(5) .build());RetrievalAugmentor retrievalAugmentor DefaultRetrievalAugmentor.builder() .queryRouter(new MyQueryRouter(检索器集合...)) .queryTransformer(queryTransformer) .contentAggregator(contentAggregator) .contentInjector(...) .build();4、ContentInjector 将检索到的内容注入 prompt直接用的 LangChain4j 的 DefaultContentInjector。// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package dev.langchain4j.rag.content.injector; public class DefaultContentInjector implements ContentInjector { .... public DefaultContentInjector() { this(DEFAULT_PROMPT_TEMPLATE, (List)null); } public DefaultContentInjector(PromptTemplate promptTemplate, ListString metadataKeysToInclude) { this.promptTemplate (PromptTemplate)Utils.getOrDefault(promptTemplate, DEFAULT_PROMPT_TEMPLATE); this.metadataKeysToInclude Utils.copy(metadataKeysToInclude); } }只需要放进RetrievalAugmentor 里就行底层自动完成内容注入//将检索到的内容注入到 LLM 的 Prompt 中 ContentInjector contentInjector new DefaultContentInjector();RetrievalAugmentor retrievalAugmentor DefaultRetrievalAugmentor.builder() .queryRouter(new MyQueryRouter(检索器集合...)) .queryTransformer(queryTransformer) .contentAggregator(contentAggregator) .contentInjector(contentInjector) .build(); // 注入到 AI Service 中 MyAiService aiService AiServices.builder(MyAiService.class) ... .retrievalAugmentor(retrievalAugmentor) .build();