欢迎光临
我们一直在努力

15. LangChain rag增强

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.8max
base-url: https://llmk1s2eoitgcuz7t2g.cnbeijing.maas.aliyuncs.com/compatiblemode/v1
open-ai-embedding:
chat-model: # ⚠️ 注意:这里应该是 embedding-model,但代码中引用的是 chat-model
api-key: ******
model-name: qwen3.7textembedding
base-url: https://llmk1s2eoitgcuz7t2g.cnbeijing.maas.aliyuncs.com/compatiblemode/v1

# WebSearch 配置
websearch:
api-key: ******
engine: google

# Jina Reranker 配置
# 使用 jina 大模型时,需注意下网络,否则调不通
jina:
api-key: ******
model-name: jinarerankerv3.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) 会根据接口自动生成实现,内部流程:

  • 接收 String userMessage 参数
  • 转换为 Query 对象
  • 调用 retrievalAugmentor.augment(query) 进行 RAG 处理
  • 调用 chatModel.generate(prompt) 生成回答
  • 返回自然语言响应

  • 六、单元测试演示

    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);
    }
    }

    测试要点:

  • loadDocument():验证文档加载能力
  • splitDocument():验证文档切分效果
  • chat():验证完整的 RAG 流程是否正常工作

  • 七、踩坑总结

    在实际使用 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: skxxx

    个人收集经验:

    • 经验 1:虽然 chat-model 也能工作(只要与 Java 代码中引用的 key 一致),但从语义上讲应该是 embedding-model
    • 经验 2:Spring Boot 的配置绑定非常严格,键名拼写错误会导致绑定失败
    • 经验 3:IDEA 可以配置 YAML 提示,有助于减少这类错误

    解决方案:

    langchain4j:
    open-ai:
    chat-model:
    api-key: ******
    model-name: qwen3.8max
    open-ai-embedding:
    embedding-model: # ✅ 更准确的命名
    api-key: ******
    model-name: qwen3.7textembedding

    注意: 如果你的 Java 代码中用的是 @Value("${langchain4j.open-ai-embedding.chat-model.api-key}"),那么保持现状也可以,但要确保两处一致。

    坑 3:CustomContentRetriever 不被调用

    现象:

    在 .contentRetriever() 中定义的自定义检索逻辑,运行时从未被触发。

    原因:

    误解了 DefaultRetrievalAugmentor 的执行流程。实际上:

  • .contentRetriever() 只是设置一个属性字段
  • 真正决定使用哪个检索器的是 .queryRouter()
  • DefaultRetrievalAugmentor.process() 方法只会从 QueryRouter.route(query) 获取检索器
  • 个人收集经验:

    • 经验 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(jinarerankerv3.5)
    .timeout(Duration.ofMinutes(5))
    .build()
    ))

    优势:

    • 基于深度学习模型重新评估相关性
    • 比单纯基于向量的相似度排序更精准
    • 支持多语言场景

    注意事项:

    • 需要良好的网络连接(Jina API 在国外)
    • 会增加约 500ms-1s 的处理时间
    • 建议在生产环境配置 HTTP 代理或使用国内镜像

    九、常见问题解答(FAQ)

    Q1:为什么 .contentRetriever() 配置不生效?

    A: 这是一个常见的误解。DefaultRetrievalAugmentor 在执行时,会从 QueryRouter.route(query) 获取检索器列表,而不是使用 .contentRetriever() 设置的属性。正确的做法是将所有检索器都放入 DefaultQueryRouter 中。

    Q2:如何在 QueryRouter 中实现混合检索?

    A: 有两种方式:

  • 方式 A:在 DefaultQueryRouter 中传入自定义的 ContentRetriever,实现条件判断逻辑(本例采用)
  • 方式 B:将多个检索器直接放入 DefaultQueryRouter,框架会自动并行执行
  • 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 的依赖冲突问题
  • 配置规范:正确的 application.yml 配置方式
  • 核心组件:QueryTransformer、QueryRouter、ContentRetriever、ContentAggregator、ContentInjector 的职责和工作原理
  • 混合检索实现:在 QueryRouter 中自定义 ContentRetriever,实现向量库优先 + WebSearch 兜底的策略
  • 重排序增强:集成 Jina Rerank 提升检索质量
  • 踩坑指南:常见问题及解决方案
  • 性能优化:超时配置、批量限制处理等实战技巧
  • 延伸方向

  • 会话记忆:集成 ChatMemory 实现多轮对话
  • 缓存优化:基于 Token 计数的智能缓存
  • 流量控制:Token 预算管理、请求优先级调度
  • 自定义 QueryRouter:实现基于语义的智能路由
  • 文档持久化:探索更多向量数据库选项(Elasticsearch、Milvus 等)
  • 动态阈值调整:根据查询复杂度自适应调整混合检索阈值

  • 十一、参考资料

    官方文档

    • 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 团队提供的优质学习资料和技术分享。

    赞(0)
    未经允许不得转载:171主机测评 » 15. LangChain rag增强
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址