LangChain4j RAG 增强实现详解:QueryTransformer、ContentRetriever、QueryRouter 全解析
开篇导读
在构建基于大模型的智能问答系统时,如何让 AI 的回答更准确、更相关,是每个开发者面临的核心挑战。这就是检索增强生成(RAG, Retrieval-Augmented Generation)技术的价值所在——通过从外部知识库中检索相关信息,再结合用户的查询进行回答,可以显著提升 AI 输出的质量和可信度。
本文档基于 langchain4j-16-rag-enhance 模块,深入讲解 LangChain4j 框架中 RAG 增强的完整实现方案。你将学到:
- 五大核心组件的工作原理:QueryTransformer(查询优化)、QueryRouter(路由决策)、ContentRetriever(智能检索)、ContentAggregator(结果聚合)、ContentInjector(Prompt 组装)
- 混合检索实战:在 QueryRouter 中自定义 ContentRetriever,实现向量库优先、WebSearch 兜底的智能检索策略
- 重排序增强:集成 Jina Reranker 提升检索结果的相关性评分
- 配置管理规范:正确配置 application.yml、避免 Bean 冲突、处理超时和批量限制
- 踩坑总结:Bean 冲突、配置命名错误、CustomContentRetriever 不被调用等问题的根源和解决方案
- 性能调优建议:参数配置、超时设置、Token 管理等最佳实践
无论你是在学习 LangChain4j 的初学者,还是希望在生产环境中优化 RAG 系统的开发者,本文档都提供了从原理到实践的完整指南。
一、依赖配置与启动类
pom.xml 完整配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.study.ai</groupId>
<artifactId>study-ai</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>langchain4j-16-rag-enhance</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>langchain4j-16-rag-basis</name>
<description>LangChain4j 学习入门 – 使用 OpenAI SDK</description>
<dependencies>
<!– Spring Boot Web 支持 –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!– Spring Boot Test –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!– LangChain4j Core:核心功能库 –>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<!– langchain4j-open-ai:用于构建 OpenAiChatModel/OpenAiEmbeddingModel,不提供自动配置 –>
<!– 注意:不要使用 langchain4j-open-ai-spring-boot-starter,会自动创建 Bean 导致冲突 –>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!– Qdrant:向量数据库,存储和检索文本向量 –>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-qdrant</artifactId>
</dependency>
<!– WebSearch (SearchApi):集成网络搜索能力 –>
<!– 登录 https://www.searchapi.io/ 获取 API Key –>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-web-search-engine-searchapi</artifactId>
</dependency>
<!– Jina Reranker:用于结果重排序,提升检索质量 –>
<!– 登录 https://jina.ai/reranker 获取 API Key –>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-jina</artifactId>
</dependency>
</dependencies>
</project>
关键点说明:
- 不推荐使用 Spring Boot Starter:langchain4j-open-ai-spring-boot-starter 会自动创建 openAiChatModel Bean,与手动配置的 Bean 冲突
- 使用基础包 + 手动@Bean:当需要使用自定义配置(如阿里云兼容接口)时,应该移除 starter,改用基础包 + 手动构建 Bean
- Jina Reranker:新增的重排序能力,可显著提升搜索结果的相关性,但需要注意网络连接问题
Application.java 启动类
package com.study.ai.langchain4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Spring Boot 启动类
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
二、application.yml 配置
完整的配置文件(已脱敏)
langchain4j:
open-ai:
chat-model:
api-key: ******
model-name: qwen3.8–max
base-url: https://llm–k1s2eoitgcuz7t2g.cn–beijing.maas.aliyuncs.com/compatible–mode/v1
open-ai-embedding:
chat-model: # ⚠️ 注意:这里应该是 embedding-model,但代码中引用的是 chat-model
api-key: ******
model-name: qwen3.7–text–embedding
base-url: https://llm–k1s2eoitgcuz7t2g.cn–beijing.maas.aliyuncs.com/compatible–mode/v1
# WebSearch 配置
websearch:
api-key: ******
engine: google
# Jina Reranker 配置
# 使用 jina 大模型时,需注意下网络,否则调不通
jina:
api-key: ******
model-name: jina–reranker–v3.5
配置要点:
| chat-model.model-name | 对话模型名称 | 使用阿里云通义千问 qwen3.8-max |
| embedding-model.model-name | 嵌入模型名称 | 使用 qwen3.7-text-embedding |
| base-url | API 地址 | 必须为兼容 OpenAI 协议的地址 |
| timeout | 超时时间 | RAG 场景建议设置为 5-10 分钟 |
| websearch.engine | 搜索引擎类型 | 支持 google、bing 等多种引擎 |
| jina.model-name | Reranker 模型名称 | jina-reranker-v3.5 支持多语言 |
注意: 虽然 application.yml 中写的是 open-ai-embedding.chat-model,但在 ChatConfig.java 中也是通过 @Value("${langchain4j.open-ai-embedding.chat-model.api-key}") 引用的,所以保持一致即可。不过从语义上讲,应该改为 embedding-model 更准确。
三、核心配置类详解
ChatConfig.java 完整代码
package com.study.ai.langchain4j.config;
import com.study.ai.langchain4j.service.ChatAssistant;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.jina.JinaScoringModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.rag.DefaultRetrievalAugmentor;
import dev.langchain4j.rag.content.Content;
import dev.langchain4j.rag.content.aggregator.ReRankingContentAggregator;
import dev.langchain4j.rag.content.injector.DefaultContentInjector;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.rag.content.retriever.WebSearchContentRetriever;
import dev.langchain4j.rag.query.Query;
import dev.langchain4j.rag.query.router.DefaultQueryRouter;
import dev.langchain4j.rag.query.transformer.CompressingQueryTransformer;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.qdrant.QdrantEmbeddingStore;
import dev.langchain4j.web.search.searchapi.SearchApiWebSearchEngine;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
import java.util.List;
/**
* 配置 ChatModel
*/
@Configuration
public class ChatConfig {
@Value("${langchain4j.open-ai.chat-model.api-key}")
private String apiKey;
@Value("${langchain4j.open-ai.chat-model.model-name}")
private String modelName;
@Value("${langchain4j.open-ai.chat-model.base-url}")
private String baseUrl;
@Value("${langchain4j.open-ai-embedding.chat-model.api-key}")
private String apiKeyEmbedding;
@Value("${langchain4j.open-ai-embedding.chat-model.model-name}")
private String modelNameEmbedding;
@Value("${langchain4j.open-ai-embedding.chat-model.base-url}")
private String baseUrlEmbedding;
@Value("${websearch.api-key}")
private String webSearchApiKey;
@Value("${websearch.engine}")
private String webSearchEngine;
@Value("${jina.api-key}")
private String jinaApiKey;
@Value("${jina.model-name}")
private String jinaModelName;
/**
* 配置对话模型
*/
@Bean
public ChatModel chatModel() {
return OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.baseUrl(baseUrl)
.timeout(Duration.ofMinutes(5)) // RAG 场景需要较长的超时时间
.build();
}
/**
* 配置嵌入模型
*/
@Bean
public EmbeddingModel embeddingModel() {
return OpenAiEmbeddingModel.builder()
.apiKey(apiKeyEmbedding)
.modelName(modelNameEmbedding)
.baseUrl(baseUrlEmbedding)
.timeout(Duration.ofMinutes(5)) // 嵌入模型也需要超时配置
// 阿里云 embedding 接口单次最多接受 20 条文本,超过会报 "batch size should not be larger than 20"
// 设置此参数后,框架会自动把大批量切成每 20 条一组分多次调用
.maxSegmentsPerBatch(20)
.build();
}
/**
* 配置 Qdrant 客户端
*/
@Bean
public QdrantClient qdrantClient() {
QdrantGrpcClient.Builder grpcClientBuilder = QdrantGrpcClient.newBuilder("127.0.0.1", 6334, false);
return new QdrantClient(grpcClientBuilder.build());
}
/**
* 配置 Qdrant 向量存储
*/
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
return QdrantEmbeddingStore.builder()
.host("127.0.0.1")
.port(6334)
.collectionName("test")
.build();
}
/**
* 构建 AI 助手(包含 RAG 增强器)
*/
@Bean
public ChatAssistant chatAssistant(ChatModel chatModel,
EmbeddingStore<TextSegment> embeddingStore,
EmbeddingModel embeddingModel) {
// 提取公共组件便于复用
// 向量库检索器
EmbeddingStoreContentRetriever storeContentRetriever =
new EmbeddingStoreContentRetriever(embeddingStore, embeddingModel);
// WebSearch 引擎配置
SearchApiWebSearchEngine searchEngine = SearchApiWebSearchEngine.builder()
.apiKey(webSearchApiKey)
.engine(webSearchEngine)
.build();
// WebSearch 检索器
WebSearchContentRetriever webSearchContentRetriever =
WebSearchContentRetriever.builder()
.webSearchEngine(searchEngine)
.maxResults(3)
.build();
// 检索增强器:这是 RAG 系统的核心组件
DefaultRetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
// ==================== QueryTransformer 查询转换器 ====================
// 源码位置:dev.langchain4j.rag.query.transformer
// 将问题进行润色处理,优化查询语句以提高检索精度
// CompressingQueryTransformer 会调用 LLM 压缩和优化问题文本
.queryTransformer(new CompressingQueryTransformer(chatModel))
// 如果不需压缩,可使用 DefaultQueryTransformer() 不做任何处理
// ==================== ContentRetriever 内容检索器配置误区 ====================
// 【重要】.contentRetriever() 只是设置一个属性字段,真正被调用的检索器来自 .queryRouter()!
// 这段代码永远不会被执行:
// .contentRetriever(storeContentRetriever) // 向量库
// .contentRetriever(webSearchContentRetriever) // WebSearch
// .contentRetriever(new ContentRetriever() { // 混合模式(同时使用向量库 + WebSearch):永远也不会调用,因为 .contentRetriever 只是设置一个属性,并不会立即执行
// @Override
// public List<Content> retrieve(Query query) {
// // ← 这些代码不会被调用
// List<Content> result = storeContentRetriever.retrieve(query);
// return result;
// }
// })
// ==================== QueryRouter 查询路由器 ====================
// 这是检索器的唯一来源!DefaultQueryRouter 会返回所有注册的检索器集合
// 【关键实现】在本例中,我们自定义了一个 ContentRetriever 放入 DefaultQueryRouter
// 实现混合检索逻辑:优先向量库检索,不足 10 条时再补充 WebSearch
// 源码位置:dev.langchain4j.rag.DefaultRetrievalAugmentor.process 方法
// 框架在 execute 时会调用 queryRouter.route(query),然后对返回的检索器执行 retrieve()
.queryRouter(new DefaultQueryRouter(
// storeContentRetriever, // 向量库 ← 这些注释的代码不会生效
// webSearchContentRetriever // WebSearch ← 这些注释的代码不会生效
// 【核心实现】混合模式(同时使用向量库 + WebSearch)
// 通过在 DefaultQueryRouter 中传入自定义的 ContentRetriever,
// 可以实现复杂的检索逻辑控制
new ContentRetriever() {
@Override
public List<Content> retrieve(Query query) {
// 第一步:优先从向量库检索
List<Content> retrieve = storeContentRetriever.retrieve(query);
// 第二步:判断向量库结果数量是否足够
// 如果 >= 10 条,直接返回,不再调用 WebSearch
if (retrieve.size() >= 10) {
return retrieve;
}
// 第三步:如果向量库结果不足 10 条,则调用 WebSearch 补充
retrieve = webSearchContentRetriever.retrieve(query);
return retrieve;
}
}
))
// ==================== ContentAggregator 内容聚合器 ====================
// 负责合并、去重、排序多个检索器的结果
// 【重要升级】使用 ReRankingContentAggregator 替代 DefaultContentAggregator
// 通过 JinaScoringModel 进行深度学习重排序,可显著提升检索相关性
// 缺点:会增加 ~500ms-1s 的处理时间,且需要良好的网络连接(Jina API 在国外)
.contentAggregator(new ReRankingContentAggregator(
// Jina 评分模型
JinaScoringModel.builder()
.apiKey(jinaApiKey)
.modelName(jinaModelName)
.timeout(Duration.ofMinutes(5))
.build()
))
// ==================== ContentInjector 内容注入器 ====================
// 将精选的内容格式化并组装成最终发送给 LLM 的 Prompt
.contentInjector(new DefaultContentInjector())
.build();
// 构建 AI Services
return AiServices.builder(ChatAssistant.class)
.chatModel(chatModel)
// 注册检索增强器
.retrievalAugmentor(retrievalAugmentor)
.build();
}
}
关键组件职责解析:
QueryTransformer:查询文本优化
- CompressingQueryTransformer:调用 LLM 压缩和优化查询
- DefaultQueryTransformer:不做处理,直接返回原始查询
QueryRouter:路由决策(本例的独特实现)
- 创新点:在 DefaultQueryRouter 中传入自定义的 ContentRetriever
- 混合策略:先查向量库,不足 10 条时再用 WebSearch 补充
- 这种方式比简单地将多个检索器放入 Router 更灵活可控
ContentRetriever:实际检索执行
- EmbeddingStoreContentRetriever:向量库检索
- WebSearchContentRetriever:网络搜索
- 自定义实现:在 QueryRouter 中的 ContentRetriever 实现了混合逻辑
ContentAggregator:结果聚合
- ReRankingContentAggregator:使用 Jina Rerank 进行智能重排序(推荐)
- 比普通排序更精准,能显著提升相关性
ContentInjector:Prompt 组装
- 将筛选后的内容包装成 LLM 可用的格式
四、业务接口/实体类
ChatAssistant.java 接口定义
package com.study.ai.langchain4j.service;
/**
* AI 助手接口
* 通过 AiServices 动态实现,无需手动编写实现类
*/
public interface ChatAssistant {
/**
* 聊天方法
* 用户传入自然语言问题,系统会自动进行 RAG 增强后回答
*
* @param userMessage 用户的问题
* @return AI 生成的回答
*/
String chat(String userMessage);
}
工作原理:
AiServices.builder(ChatAssistant.class) 会根据接口自动生成实现,内部流程:
六、单元测试演示
ApplicationTests.java 测试用例
package com.study.ai.langchain4j;
import com.study.ai.langchain4j.service.ChatAssistant;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.loader.UrlDocumentLoader;
import dev.langchain4j.data.document.parser.TextDocumentParser;
import dev.langchain4j.data.document.splitter.DocumentByCharacterSplitter;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.rag.query.Query;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class ApplicationTests {
@Autowired
private ChatAssistant chatAssistant;
/**
* 测试加载器:UrlDocumentLoader
* 从指定 URL 加载文档内容
*/
@Test
void loadDocument() {
// 从指定的 URL 加载网页内容
String url = "https://blog.csdn.net/qq_15720875/article/details/164136437?spm=1001.2014.3001.5501";
TextDocumentParser textDocumentParser = new TextDocumentParser();
Document document = UrlDocumentLoader.load(url, textDocumentParser);
// 添加自定义元数据,在向量化存储时可用于过滤
document.metadata().put("author", "peixin");
System.out.println(document);
}
/**
* 测试分割器:DocumentByCharacterSplitter
* 按字符数切分文档,避免片段过大或语义断裂
*/
@Test
void splitDocument() {
// 从指定的 URL 加载
String url = "https://blog.csdn.net/qq_15720875/article/details/164136437?spm=1001.2014.3001.5501";
TextDocumentParser textDocumentParser = new TextDocumentParser();
Document document = UrlDocumentLoader.load(url, textDocumentParser);
// 按字符数递归切分:每片最大 500 字符,最小重叠 0 字符
List<TextSegment> split = new DocumentByCharacterSplitter(500, 0).split(document);
System.out.println(split);
}
/**
* 测试 RAG 问答功能
* 验证检索增强生成是否正常工作
*/
@Test
void chat() {
// 简单的字符串查询,包含 URL 链接让检索更丰富
String chat = chatAssistant.chat("我是刚接触 Langchain 的小白,第一节课我应该从哪里开始学?最好含有 URL 链接");
System.out.println("查询结果:" + chat);
}
}
测试要点:
七、踩坑总结
在实际使用 LangChain4j RAG 增强功能的过程中,我遇到了以下几个典型问题,现将解决方案整理如下,供后续参考。
坑 1:Bean 冲突报错
现象:
java.lang.IllegalStateException: Failed to load ApplicationContext
No qualifying bean of type 'dev.langchain4j.model.chat.ChatModel' available: expected single matching bean but found 2: chatModel,openAiChatModel
原因:
使用了 langchain4j-open-ai-spring-boot-starter 依赖,该 Starter 会自动创建 openAiChatModel Bean,与手动配置的 chatModel Bean 发生冲突。
个人收集经验:
- 经验 1:任何情况下都要注意 Spring Boot Starter 的自动配置行为
- 经验 2:当需要自定义配置(如阿里云兼容接口)时,Starter 可能不适用
- 经验 3:可以通过 @ConditionalOnMissingBean 注解控制 Bean 的创建时机
解决方案:
<!– ❌ 不要用这个 –>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
</dependency>
<!– ✅ 改用基础包 –>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
同时在配置类中手动创建 Bean:
@Bean
public ChatModel chatModel() {
return OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.baseUrl(baseUrl)
.timeout(Duration.ofMinutes(5))
.build();
}
坑 2:配置命名错误
现象:
嵌入式模型无法正确初始化,或者运行时出现找不到配置的错误。
原因:
在 application.yml 中使用了错误的配置键名:
langchain4j:
open-ai-embedding:
chat-model: # ❌ 语义上应该是 embedding-model
api-key: sk–xxx
个人收集经验:
- 经验 1:虽然 chat-model 也能工作(只要与 Java 代码中引用的 key 一致),但从语义上讲应该是 embedding-model
- 经验 2:Spring Boot 的配置绑定非常严格,键名拼写错误会导致绑定失败
- 经验 3:IDEA 可以配置 YAML 提示,有助于减少这类错误
解决方案:
langchain4j:
open-ai:
chat-model:
api-key: ******
model-name: qwen3.8–max
open-ai-embedding:
embedding-model: # ✅ 更准确的命名
api-key: ******
model-name: qwen3.7–text–embedding
注意: 如果你的 Java 代码中用的是 @Value("${langchain4j.open-ai-embedding.chat-model.api-key}"),那么保持现状也可以,但要确保两处一致。
坑 3:CustomContentRetriever 不被调用
现象:
在 .contentRetriever() 中定义的自定义检索逻辑,运行时从未被触发。
原因:
误解了 DefaultRetrievalAugmentor 的执行流程。实际上:
个人收集经验:
- 经验 1:阅读源码很重要,很多看似直观的配置实际有隐藏逻辑
- 经验 2:框架的路由机制优先于单独的配置项
- 经验 3:如果要实现混合检索,应该将所有检索器都放入 QueryRouter
解决方案:
正确的做法是在 DefaultQueryRouter 中传入自定义的 ContentRetriever:
.queryRouter(new DefaultQueryRouter(
new ContentRetriever() {
@Override
public List<Content> retrieve(Query query) {
// 自定义检索逻辑
List<Content> vectorResults = storeContentRetriever.retrieve(query);
if (vectorResults.size() >= 10) {
return vectorResults;
}
// 不足 10 条时用 WebSearch 补充
return webSearchContentRetriever.retrieve(query);
}
}
))
八、优化建议
8.1 查询优化策略
方案 A:启用 CompressingQueryTransformer
.queryTransformer(new CompressingQueryTransformer(chatModel))
优点:
- 优化查询语句,去除冗余信息
- 提高检索准确性
- 节省 Token 消耗
缺点:
- 额外调用一次 LLM,增加耗时
- 约 1-2 秒延迟
适用场景: 查询复杂、需要精准匹配的场景
方案 B:使用 DefaultQueryTransformer
.queryTransformer(new DefaultQueryTransformer()) // 不做任何处理
优点:
- 零额外开销
- 响应速度快
缺点:
- 保留原始查询中的噪音
- 可能影响检索质量
适用场景: 简单查询、对实时性要求高的场景
8.2 检索参数调优
| minScore | 0.6-0.8 | 相似度阈值 | 精确匹配用 0.8+,宽泛检索用 0.6+ |
| maxResults | 3-5 | 每个检索器最多返回 | 根据上下文窗口大小调整 |
| Aggregator.limit | 3-5 | 最终结果数量 | 平衡信息量和 Token 成本 |
8.3 超时配置优化
.timeout(Duration.ofMinutes(5)) // RAG 场景推荐 5-10 分钟
原因分析:
- 向量检索:~500ms-1s
- LLM 压缩查询:~1-2s(如启用)
- LLM 生成:~2-5s
- 总耗时:3-8 秒
建议:
- 本地开发:5 分钟足够
- 生产环境:建议 10 分钟,防止长时间查询超时
8.4 批量处理优化
.maxSegmentsPerBatch(20) // 阿里云 embedding API 限制
背景:
阿里云 embedding 接口单次最多接受 20 条文本,超过会报错:
batch size should not be larger than 20
框架处理:
设置该参数后,框架会自动把大批量切成每 20 条一组分多次调用,无需手动处理。
8.5 混合检索策略优化
当前实现的混合检索策略是:向量库优先,不足 10 条时用 WebSearch 补充。
这种方式的优缺点:
优点:
- 优先使用本地知识库,响应快、成本低
- WebSearch 作为兜底,避免无结果的情况
- 灵活可控,可根据实际情况调整阈值
改进建议:
8.6 Jina Rerank 重排序优化
使用 ReRankingContentAggregator 配合 JinaScoringModel 可以显著提升检索质量:
.contentAggregator(new ReRankingContentAggregator(
JinaScoringModel.builder()
.apiKey(jinaApiKey)
.modelName(jina–reranker–v3.5)
.timeout(Duration.ofMinutes(5))
.build()
))
优势:
- 基于深度学习模型重新评估相关性
- 比单纯基于向量的相似度排序更精准
- 支持多语言场景
注意事项:
- 需要良好的网络连接(Jina API 在国外)
- 会增加约 500ms-1s 的处理时间
- 建议在生产环境配置 HTTP 代理或使用国内镜像
九、常见问题解答(FAQ)
Q1:为什么 .contentRetriever() 配置不生效?
A: 这是一个常见的误解。DefaultRetrievalAugmentor 在执行时,会从 QueryRouter.route(query) 获取检索器列表,而不是使用 .contentRetriever() 设置的属性。正确的做法是将所有检索器都放入 DefaultQueryRouter 中。
Q2:如何在 QueryRouter 中实现混合检索?
A: 有两种方式:
Q3:Bean 冲突怎么办?
A: 移除 langchain4j-open-ai-spring-boot-starter 依赖,改用基础包 langchain4j-open-ai,然后手动在配置类中使用 @Bean 创建所需的服务实例。
Q4:Token 预估不准怎么办?
A: 使用安全系数法预留余量,或使用动态截断策略。更高级的做法是建立 Token 预算管理系统,每日配额限制、分类统计使用。
Q5:QueryTransformer 的作用是什么?
A: CompressingQueryTransformer 会调用 LLM 优化查询文本,减少噪音;DefaultQueryTransformer 不做处理,适合对延迟敏感的场景。
Q6:为什么检索结果有时不准确?
A: 可能的原因包括:
- 文档切分粒度不合适
- 相似度阈值过低或过高
- 向量模型选择不当
- 检索源单一,缺乏多样性
建议通过调试工具查看实际分数分布,逐步调整参数。
Q7:RAG 流程的整体耗时是多少?
A: 正常情况下为 3-8 秒:
- 向量检索:~500ms-1s
- LLM 压缩查询:~1-2s(如启用)
- LLM 生成:~2-5s
建议在 application.yml 中设置 timeout: PT5M 或更长。
Q8:Jina Rerank 调用失败怎么办?
A: 检查网络连接是否正常,Jina API 需要访问国外服务器。可以尝试配置 HTTP 代理,或使用其他 Rerank 服务作为替代。
Q9:混合检索的阈值(10 条)如何确定?
A: 阈值需要根据实际场景调整:
- 高阈值(如 15-20):尽量使用本地知识库,减少对外部搜索的依赖
- 低阈值(如 5-8):更愿意补充外部信息,提高召回率
- 建议:先用默认值 10 试运行,然后根据实际查询结果调整
十、总结与下一步
已掌握知识点
通过本文档的学习,您已经掌握了:
延伸方向
十一、参考资料
官方文档
- LangChain4j 官方文档:https://docs.langchain4j.dev/
- Qdrant 向量数据库:https://qdrant.tech/
- SearchApi WebSearch:https://www.searchapi.io/
- Jina Reranker:https://jina.ai/reranker
pig4cloud 学习资料
感谢 pig4cloud 提供的系统化的 LangChain4j 学习资源,本文档部分内容参考自以下教程:
- RAG API 增强:https://javaai.pig4cloud.com/docs/15-rag-api2
- Reranker 重排序:https://javaai.pig4cloud.com/docs/17-rag-reranking
GitHub 源码
- DefaultRetrievalAugmentor:https://raw.githubusercontent.com/langchain4j/langchain4j/main/langchain4j-core/src/main/java/dev/langchain4j/rag/DefaultRetrievalAugmentor.java
- DefaultQueryRouter:https://raw.githubusercontent.com/langchain4j/langchain4j/main/langchain4j-core/src/main/java/dev/langchain4j/rag/query/router/DefaultQueryRouter.java
作者签名
8 年 Java 开发者自学转型 AI Agent,专注 Java/Spring AI + LangChain4j 技术栈。
致谢声明
感谢 pig4cloud 团队提供的优质学习资料和技术分享。




