RAG

LangChain4J中的Modular RAG支持

除了Spring AI中提供了模块化RAG的支持,其实LangChain4J中也有,甚至功能更加强大。 LangChain4J中提供了RetrievalAugmentor接口,他有一个默认的实现DefaultRetrievalAug…

TL;DR

除了Spring AI中提供了模块化RAG的支持,其实LangChain4J中也有,甚至功能更加强大。 LangChain4J中提供了RetrievalAugmentor接口,他有一个默认的实现DefaultRetrievalAug…

除了Spring AI中提供了模块化RAG的支持,其实LangChain4J中也有,甚至功能更加强大。 LangChain4J中提供了RetrievalAugmentor接口,他有一个默认的实现DefaultRetrievalAugmentor,就是和Spring AI中的RetrievalAugmentationAdvisor类似的存在。 这里面分别支持查询转换器、查询路由器、内容聚合器、以及内容注入器。

基本用法

DefaultRetrievalAugmentor augmentor = DefaultRetrievalAugmentor.builder()
// 1. ContentRetriever - 从向量数据库或其他数据源检索内容(必需)
.contentRetriever(EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore) // 向量数据库
        .embeddingModel(embeddingModel) // 向量模型
        .maxResults(5)                 // 返回Top-K结果
        .minScore(0.7)               // 最小相似度阈值
        .build())

// 2. QueryTransformer - 查询转换器(可选)
.queryTransformer(queryTransformer)

// 3. QueryRouter - 查询路由器(可选)
.queryRouter(queryRouter)

// 4. ContentAggregator - 内容聚合器(可选)
.contentAggregator((contentAggregator)

// 5. ContentInjector - 内容注入器(可选)
.contentInjector(contentInjector)

.build();

然通过把DefaultRetrievalAugmentor注入到AiServices中:

AiServices.builder(LangChainAiService.class)
        .chatModel(chatModel)
        .chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(10))
        .retrievalAugmentor(DefaultRetrievalAugmentor.builder().build())
        .build();

ContentRetriever

在上面我们介绍DefaultRetrievalAugmentor的时候,从他的成员变量来看,并没有ContentRetriever,但是这个东西也是必须要有的,只不过ContentRetriever可以被包在QueryRouter中,因为路由我们前面讲过,有一个很重要的目的就是找到合适的检索器(比如不同的数据源) 可以通过DefaultRetrievalAugmentorBuilder的源码发现,当我们构造ContentRetriever的时候,其实他是通过构造了一个对应的QueryRouter实现的。

EmbeddingStoreContentRetriever

EmbeddingStoreContentRetriever 是 LangChain4j 框架中专门用于从向量数据库检索相关内容的核心组件。它实现了 ContentRetriever 接口,是 RAG 系统中最常用的检索器。和Spring AI中的VectorStoreDocumentRetriever功能类似。

EmbeddingStoreContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
    // ========== 必需参数 ==========
    .embeddingStore(embeddingStore)     // 向量数据库实例
    .embeddingModel(embeddingModel)     // 向量模型(用于查询向量化)

    // ========== 可选参数 ==========
    .maxResults(5)                      // 返回Top-K结果,默认3
    .minScore(0.7)                      // 最小相似度阈值(0.0-1.0),低于此分数的结果会被过滤

    .build();

所必须的参数是embeddingStore和embeddingModel。即一个向量存储和一个向量模型。这也是我们前面讲RAG的时候重点提到的两个东西了。老朋友了。

EmbeddingStore

EmbeddingStore默认的只有InMemoryEmbeddingStore,但是可以通过增加依赖的方式导入更多的实现,如以下这么多实现(具体的适用方式,在这个链接中都有:https://github.com/langchain4j/langchain4j/tree/main/docs/docs/integrations/embedding-stores ): 比如pgvector,需要依赖:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-pgvector</artifactId>
    <version>1.10.0-beta18</version>
</dependency>

然后通过以下方式创建:

EmbeddingStore<TextSegment> embeddingStore = PgVectorEmbeddingStore.builder()
        .host("localhost")                           // Required: Host of the PostgreSQL instance
        .port(5432)                                  // Required: Port of the PostgreSQL instance
        .database("postgres")                        // Required: Database name
        .user("my_user")                             // Required: Database user
        .password("my_password")                     // Required: Database password
        .table("my_embeddings")                      // Required: Table name to store embeddings
        .dimension(embeddingModel.dimension())       // Required: Dimension of embeddings
        .build();

EmbeddingModel

embeddingModel也一样,也有很多种实现,比如openai的,比如ollama的,也通过扩展的方式可以配置进来。(https://github.com/langchain4j/langchain4j/tree/main/docs/docs/integrations/embedding-models ) 如:

// OpenAI Embedding
EmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
    .apiKey(System.getenv("OPENAI_API_KEY"))
    .modelName("text-embedding-3-small")  // 或 text-embedding-3-large
    .build();

WebSearchContentRetriever

WebSearchContentRetriever 是 LangChain4j 框架中用于从互联网搜索引擎检索实时信息的 RAG 组件。它允许 AI 应用获取最新的网络信息,而不仅仅依赖于预先存储的向量数据库。

//使用 Google Custom Search
WebSearchEngine googleSearchEngine = GoogleCustomSearchEngine.builder()
    .apiKey(System.getenv("GOOGLE_API_KEY"))
    .csi(System.getenv("GOOGLE_SEARCH_ENGINE_ID"))  // Custom Search Engine ID
    .build();

WebSearchContentRetriever googleRetriever = WebSearchContentRetriever.builder()
    .webSearchEngine(googleSearchEngine)
    .maxResults(5)
    .build();

可以看到,必要的参数是一个webSearchEngine。 同理,webSearchEngine也给了一些可以用的扩展(https://github.com/langchain4j/langchain4j/tree/main/docs/docs/integrations/web-search-engines ): 使用方法: 到tavily网站上创建一个账号,使用google账号可以直接登录:https://app.tavily.com/home ,登录后就有一个api key可以直接用了。 然后在代码中实现:

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-web-search-engine-tavily</artifactId>
            <version>1.8.0-beta15</version>
            <exclusions>
                <exclusion>
                    <groupId>dev.langchain4j</groupId>
                    <artifactId>*</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
package cn.hollis.llm.HelloLlm.langchain4j.controller;

import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.rag.DefaultRetrievalAugmentor;
import dev.langchain4j.rag.content.retriever.WebSearchContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.web.search.tavily.TavilyWebSearchEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/websearch")
public class WebSearchController {

    @Autowired
    OpenAiChatModel chatModel;

    @GetMapping("/search")
    public String webSearch() {
        // 1. 配置搜索引擎
        TavilyWebSearchEngine searchEngine = TavilyWebSearchEngine.builder()
                .apiKey("替换成你自己的key")
                .includeAnswer(true)
                .searchDepth("advanced")
                .build();

        // 2. 配置 Web 搜索检索器
        WebSearchContentRetriever webRetriever = WebSearchContentRetriever.builder()
                .webSearchEngine(searchEngine)
                .maxResults(5)
                .build();

        // 3. 配置 RetrievalAugmentor
        DefaultRetrievalAugmentor augmentor = DefaultRetrievalAugmentor.builder()
                .contentRetriever(webRetriever)
                .build();

        // 5. 创建 AI Service
        interface WebSearchAssistant {
            String chat(String userMessage);
        }

        WebSearchAssistant assistant = AiServices.builder(WebSearchAssistant.class)
                .chatModel(chatModel)
                .retrievalAugmentor(augmentor)
                .build();

        // 6. 使用 - 获取实时信息
        String answer = assistant.chat("2025年人工智能领域有哪些重大突破?");
        return answer;
    }

}

即可得到结果:

QueryTransformer

QueryTransformer这个在Spring AI中也有,这个是他关于功能的介绍,可以看到这里面提到的一些查询改写的方式,我们前面基本都讲过了。 但是并没有全都是现,默认值给了CompressingQueryTransformer和ExpandingQueryTransformer。

CompressingQueryTransformer

这个和Spring AI中的CompressionQueryTransformer功能基本类似,通过他的提示词你就能知道了,他就是实现的我们前面见过的所谓"富化"的能力。

ExpandingQueryTransformer

这个其实就是我们前面见过的提示词的分解,把一个提示词拆分成多个提示词。但是他的目标是将单个用户查询扩展为多个语义相关的查询,从不同角度检索文档,提高召回率。

QueryRouter

前面介绍ContentRetriever的时候提到了QueryRouter,他的作用就是把不同的用户请求路由给不同的ContentRetriever。 入参是用户查询,出参是ContentRetriever的列表: langchain4j中给提供了两个router实现,分别是DefaultQueryRouter和LanguageModelQueryRouter。 DefaultQueryRouter比较简单,就是直接无脑把所有查询都路由给提前配置好的一批ContentRetriever: 不需要介绍再多了,当我们构造DefaultRetrievalAugmentor的时候,如果只通过contentRetriever创建而不用router的时候,他就会使用默认的DefaultQueryRouter把我们传入的contentRetriever包一下。

混合检索:向量数据库 + Web 搜索

import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.rag.query.router.QueryRouter;

// 1. 向量数据库检索器
EmbeddingStoreContentRetriever vectorRetriever =
    EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .maxResults(3)
        .build();

// 2. Web 搜索检索器
WebSearchContentRetriever webRetriever =
    WebSearchContentRetriever.builder()
        .webSearchEngine(tavilyEngine)
        .maxResults(3)
        .build();

// 3. 配置查询路由器 - 智能选择检索方式
QueryRouter queryRouter = query -> {
    String queryText = query.text().toLowerCase();

    // 判断是否需要实时信息
    if (queryText.contains("最新") ||
        queryText.contains("今天") ||
        queryText.contains("现在") ||
        queryText.contains("当前")) {
        return webRetriever;  // 使用Web搜索
    } else {
        return vectorRetriever;  // 使用向量数据库
    }
};

// 4. 使用路由器集成
DefaultRetrievalAugmentor augmentor = DefaultRetrievalAugmentor.builder()
    .queryRouter(queryRouter)
    .build();

LanguageModelQueryRouter

LanguageModelQueryRouter 是 LangChain4j 中基于语言模型的智能查询路由器,根据查询类型、意图或特征,将查询分发到不同的检索器,实现多数据源智能检索。适合以下场景: - 多种数据库并存(向量库、图数据库、关系型数据库) - 不同领域的知识库(技术文档、业务规则、实时信息) - 检索策略差异(语义检索、精确匹配、关系查询) 如:

import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.rag.DefaultRetrievalAugmentor;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStore;

public class QueryRoutingExample {

    public static void main(String[] args) {
        // 1. 初始化 ChatModel
        OpenAiChatModel chatModel = OpenAiChatModel.builder()
            .apiKey(System.getenv("OPENAI_API_KEY"))
            .modelName("gpt-4")
            .build();

        // 2. 创建不同类型的检索器

        // 向量检索器 - 用于语义搜索
        ContentRetriever vectorRetriever = EmbeddingStoreContentRetriever.builder()
            .embeddingStore(vectorEmbeddingStore)
            .embeddingModel(embeddingModel)
            .maxResults(5)
            .build();

        // 图数据库检索器 - 用于关系查询
        ContentRetriever graphRetriever = new GraphDatabaseContentRetriever(
            neo4jDriver
        );

        // 关系数据库检索器 - 用于结构化查询
        ContentRetriever relationalRetriever = new RelationalDatabaseContentRetriever(
            dataSource
        );

        // Web 搜索检索器 - 用于实时信息
        ContentRetriever webRetriever = WebSearchContentRetriever.builder()
            .webSearchEngine(tavilyEngine)
            .maxResults(5)
            .build();

        // 3. 配置路由器
        LanguageModelQueryRouter router = LanguageModelQueryRouter.builder()
            .chatModel(chatModel)
            .retriever("VECTOR", vectorRetriever)
            .retriever("GRAPH", graphRetriever)
            .retriever("RELATIONAL", relationalRetriever)
            .retriever("WEB", webRetriever)
            .defaultRetriever(vectorRetriever)
            .build();

        // 4. 集成到 RAG
        DefaultRetrievalAugmentor augmentor = DefaultRetrievalAugmentor.builder()
            .queryRouter(router)
            .build();

        // 5. 创建 AI Service
        interface Assistant {
            String chat(String message);
        }

        Assistant assistant = AiServices.builder(Assistant.class)
            .chatModel(chatModel)
            .retrievalAugmentor(augmentor)
            .build();

        // 6. 使用示例

        // 路由到向量检索器
        String answer1 = assistant.chat("RAG 技术的优势是什么?");

        // 路由到图检索器
        String answer2 = assistant.chat("刘备和张飞是什么关系?");

        // 路由到关系数据库检索器
        String answer3 = assistant.chat("2024年第一季度销售额是多少?");

        // 路由到 Web 搜索
        String answer4 = assistant.chat("今天北京的天气如何?");
    }
}

ContentAggregator

ContentAggregator这个功能是spring ai中没有的,就是我们前面讲过的重排序。 通过文档可以看到,他提供了我们前面在重排序章节介绍过的RRF和ReRank模型两种实现方式。

DefaultContentAggregator

DefaultContentAggregator 是 ContentAggregator 的默认实现,它用的就是我们介绍过的RRF重排序

✅RAG优化技术:重排序

什么是重排序? 重排序(Reranking)是在通过混合检索(或其他方式)获得初步检索结果(候选文本块)后,再通过更强的模型(通常是 Cross-Encoder 或专用 Reranker 模型)对这些候选文本块进行重新打分和排序,将真正最相 LLMentor

ReRankingContentAggregator

ReRankingContentAggregator使用更精细的模型(如 Cross-Encoder)对候选文档与查询的相关性进行重新评分和排序。 可以选择的排序模型有以下这几个(https://github.com/langchain4j/langchain4j/tree/main/docs/docs/integrations/scoring-reranking-models ): 比如使用jina:

<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-jina</artifactId>
    <version>1.10.0-beta18</version>
</dependency>
ScoringModel scoringModel = JinaScoringModel.builder()
    .apiKey(System.getenv("JINA_API_KEY"))
    .modelName("jina-reranker-v2-base-multilingual")
    .build();

ContentAggregator contentAggregator = ReRankingContentAggregator.builder()
    .scoringModel(scoringModel)
    ...
    .build();

RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
    ...
    .contentAggregator(contentAggregator)
    .build();

return AiServices.builder(Assistant.class)
    .chatModel(...)
    .retrievalAugmentor(retrievalAugmentor)
    .build();

ContentInjector

ContentInjector这个就是RAG中的那个上下文融合的过程,即将检索到的文档和用户消息融到一个提示词中。 默认有一个DefaultContentInjector,代码也很简单,就是把userMessage和文档内容拼到一起。

总结

以上,就是langchain4j给我们提供的一系列RAG的各种组件,我们可以任意组装他们,在langchain中也提供了一些默认的实现和扩展,当然你可以可以自己重写他们,自定义你自己的比如问题改写器、查询路由器等等。 通过对比spring ai和langchain4j,你会发现,其实在rag这块,langchain4j的能力更强一些,实现更加丰富一点。

版本提示

模型、框架与接口会持续变化。涉及版本号、参数与生产配置时,请在实践前对照对应官方文档。

LLMentor系统化学习大模型应用工程

内容来自个人课程知识库备份,并经过结构化整理。技术版本持续演进,生产使用前请结合官方文档验证。