惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

U
Unit 42
C
Cybersecurity and Infrastructure Security Agency CISA
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Know Your Adversary
Know Your Adversary
S
Securelist
I
Intezer
AWS News Blog
AWS News Blog
L
LINUX DO - 热门话题
P
Privacy International News Feed
Recent Announcements
Recent Announcements
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
博客园 - 聂微东
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Attack and Defense Labs
Attack and Defense Labs
N
News and Events Feed by Topic
The GitHub Blog
The GitHub Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
Schneier on Security
Schneier on Security
N
Netflix TechBlog - Medium
爱范儿
爱范儿
B
Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
CERT Recently Published Vulnerability Notes
Hacker News: Ask HN
Hacker News: Ask HN
Google DeepMind News
Google DeepMind News
Engineering at Meta
Engineering at Meta
Blog — PlanetScale
Blog — PlanetScale
WordPress大学
WordPress大学
S
Secure Thoughts
K
Kaspersky official blog
N
News | PayPal Newsroom
O
OpenAI News
Last Week in AI
Last Week in AI
C
Check Point Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Cyberwarzone
Cyberwarzone
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tor Project blog
大猫的无限游戏
大猫的无限游戏
Vercel News
Vercel News
D
Docker
Hugging Face - Blog
Hugging Face - Blog
T
Threat Research - Cisco Blogs
Cisco Talos Blog
Cisco Talos Blog
The Register - Security
The Register - Security
博客园 - 司徒正美
Martin Fowler
Martin Fowler
人人都是产品经理
人人都是产品经理
P
Palo Alto Networks Blog

博客园 - work hard work smart

使用 LangChain + Hugging Face 构建文本向量化服务 SQLAlchemy 使用详解 Python 中使用 Elasticsearch 的完整指南 Qdrant 向量数据库使用指南 OpenEvals 快速入门:LLM 评估指南 DeepEval 快速入门:LLM 应用评估指南 LangSmith 批量评估完全指南 Qwen-Agent 入门指南:快速构建智能体应用 LangSmith 集成实战:从追踪到评估的完整指南 初识 go-zero:一款让你写后端更规范、更高效的 Go 微服务框架 RAG 中为什么需要 Rerank,以及如何使用 Rerank 如何使用 Elasticsearch 进行全文检索和向量检索 MinerU Docker 部署指南 5 分钟上手:为 Cline 配置一个免费的 MCP 天气服务 Neo4j 图数据库安装与 Spring Boot 集成实战指南 LangFuse 实战指南:用 @observe 三行代码给 LLM 应用加上全链路追踪 Function Call 深度解析:让大模型从"嘴炮"到"实干"的技术革命 Spring AI 提示词模板实战:告别硬编码,实现提示词工程化管理 LangChain4j 实战指南:用 Java 轻松构建 AI 应用 Spring AI 对话短期记忆实战:让大模型拥有"记忆力" Spring AI 提示词工程实战:让大模型更懂你的意图 Spring AI ChatClient 深度解析:优雅构建大模型应用的利器 Spring AI Alibaba DashScopeChatModel 实战 Spring 中 SSE 流式输出的多种实现方式详解 OpenSandbox 实战指南:为 AI Agent 构建安全的代码执行沙箱 在本机启动 LangGraph 开发服务器:完整指南 DeepAgents中Backend的奥秘:让AI Agent拥有文件操作能力 为什么选择 Go 开发 Web 接口?从入门到实践 智能搜索DeepAgent笔记 RAG学习笔记2--系统查询流程 RAG学习笔记1--系统文件导入流程 百炼 WebSearch 快速入门指南 Python 连接 MongoDB 完整指南:从连接配置到增删改查实战 一行命令搞定 MongoDB 开发环境:Docker Compose 部署 + 可视化管理 使用 Attu 可视化管理 Milvus 向量数据库 在 Windows Docker 中快速安装 Milvus 2.5.6 minio使用 Spark 集群搭建 hadoop集群安装 Spring AI Alibaba 入门实战 Windows 安装 OpenClaw 实战指南 MyBatis 核心流程和原理 Idea中安装Claude code插件 Spark 编程 使用Matplotlib 绘制直方图 Flink安装部署 Flume安装 查找导致cpu过高的代码方法 JVisualVM监控远程Java进程 jmap jacoco多模块生成java单元测试报告实践 arthas 使用demo LockSupport Exchanger CyclicBarrier CountDownLatch 手把手教你用python开始第一个机器学习项目
LangChain4j RAG 核心组件与组合方式
work hard work smart · 2026-06-20 · via 博客园 - work hard work smart

LangChain4j RAG 核心组件与组合方式

在使用 LangChain4j 构建 RAG 应用时,经常会看到一组组件名,比如 RetrievalAugmentorQueryTransformerQueryRouterContentRetrieverContentAggregatorContentInjector

这些组件名看起来很多,容易让人觉得框架封装很深,不知道真实原理是什么。

其实 LangChain4j 并没有改变 RAG 的本质,它只是把 RAG 的几个固定步骤抽象成了标准组件。理解这些组件之后,就能知道一次 RAG 问答到底是怎么执行的。

本文介绍 LangChain4j RAG 的核心组件,以及这些组件如何组合成一个完整的检索增强问答流程。


一、RAG 的真实执行流程

不管使用什么框架,RAG 的核心流程都差不多:

用户问题
   |
   v
问题改写 / 查询增强
   |
   v
选择合适的数据源
   |
   v
执行内容检索
   |
   v
合并、去重、重排序检索结果
   |
   v
把检索结果注入 Prompt
   |
   v
调用大模型生成答案

如果不使用框架,可能会写成类似这样的代码:

String rewrittenQuery = rewrite(userQuestion);

List<Document> vectorDocs = esVectorSearch(rewrittenQuery);
List<Document> fullTextDocs = esFullTextSearch(rewrittenQuery);
List<Document> sqlDocs = text2SqlSearch(rewrittenQuery);
List<Document> graphDocs = graphSearch(rewrittenQuery);

List<Document> finalDocs = mergeAndRerank(
        vectorDocs,
        fullTextDocs,
        sqlDocs,
        graphDocs
);

String prompt = injectContext(userQuestion, finalDocs);

String answer = llm.chat(prompt);

LangChain4j 做的事情,就是把上面这些步骤拆成标准组件,然后通过 RetrievalAugmentor 统一编排。


二、LangChain4j RAG 的整体结构

LangChain4j 中,一个完整的 RAG 流程通常由下面几个组件组成:

RetrievalAugmentor
   |
   |-- QueryTransformer
   |-- QueryRouter
   |       |
   |       |-- ContentRetriever 1
   |       |-- ContentRetriever 2
   |       |-- ContentRetriever 3
   |
   |-- ContentAggregator
   |-- ContentInjector

可以简单理解为:

组件 作用
RetrievalAugmentor RAG 总编排器,负责串起完整检索增强流程
QueryTransformer 问题改写器,对用户问题进行压缩、改写或扩展
QueryRouter 问题路由器,决定当前问题应该走哪些检索器
ContentRetriever 内容检索器,真正从 ES、数据库、向量库、图数据库等数据源检索内容
ContentAggregator 内容聚合器,对多路检索结果进行合并、去重、重排序
ContentInjector 内容注入器,把检索结果注入到最终 Prompt 中

这些组件并不是都负责搜索。真正搜索的是 ContentRetriever,其他组件负责搜索前后的流程编排。


三、RetrievalAugmentor:RAG 总编排器

RetrievalAugmentor 是 LangChain4j RAG 流程的核心入口。

它负责把问题改写、问题路由、内容检索、结果聚合和上下文注入串起来。

常见组合方式如下:

RetrievalAugmentor retrievalAugmentor = DefaultRetrievalAugmentor.builder()
        .queryTransformer(queryTransformer)
        .queryRouter(queryRouter)
        .contentAggregator(contentAggregator)
        .contentInjector(contentInjector)
        .build();

这段代码表示:

  • 使用 queryTransformer 对用户问题进行改写
  • 使用 queryRouter 决定问题应该走哪些检索器
  • 使用 contentAggregator 对多路检索结果进行聚合和重排序
  • 使用 contentInjector 把最终内容注入 Prompt
  • 使用 DefaultRetrievalAugmentor 串起完整 RAG 流程

所以 RetrievalAugmentor 本身不直接查 ES,也不直接查数据库。它更像一个流程控制器。


四、QueryTransformer:问题改写器

QueryTransformer 负责在真正检索之前,对用户原始问题进行处理。

用户的问题往往比较口语化,比如:

这个怎么弄?

如果直接拿这个问题去检索,效果可能不好。问题改写器可以结合上下文,把它改写成更适合检索的问题。

例如改写成:

如何打开汽车零重力座椅?

它的作用可以理解为:

用户原始问题
   |
   v
LLM 改写 / 压缩 / 补全
   |
   v
更适合检索的问题

在 RAG 中,问题改写很重要。因为检索效果很大程度上取决于 query 的质量。


五、QueryRouter:问题路由器

QueryRouter 负责判断一个问题应该走哪些检索器。

在简单 RAG 中,可能只有一个知识库检索器,不需要路由。

但是在复杂系统中,数据源可能有很多种:

  • ES 向量检索
  • ES 全文检索
  • 关系型数据库检索
  • 图数据库检索
  • 外部接口检索
  • 文件系统检索

这时就需要路由器判断:这个问题到底应该去哪里查?

例如可以定义三类路由策略:

路由策略 适合场景 对应检索器
knowledge_base 非结构化知识问答、文档问答、语义搜索 ES / 向量库 / 文档库检索器
relational_db 订单、车辆、用户、库存等结构化数据查询 SQL 检索器
graph_db 实体关系、路径分析、关联查询 图数据库检索器

一个简化的路由器可以这样理解:

class ExampleQueryRouter implements QueryRouter {

    private final ContentRetriever vectorRetriever;
    private final ContentRetriever fullTextRetriever;
    private final ContentRetriever sqlRetriever;
    private final ContentRetriever graphRetriever;

    @Override
    public Collection<ContentRetriever> route(Query query) {
        String strategy = classify(query.text());

        return switch (strategy) {
            case "knowledge_base" -> List.of(vectorRetriever, fullTextRetriever);
            case "relational_db" -> List.of(sqlRetriever);
            case "graph_db" -> List.of(graphRetriever);
            default -> List.of(vectorRetriever, fullTextRetriever);
        };
    }
}

这里的 classify() 可以是规则判断,也可以是调用大模型做意图识别。


六、ContentRetriever:真正执行检索的组件

ContentRetriever 是 LangChain4j RAG 中真正负责检索内容的组件。

不同数据源可以实现不同的 ContentRetriever

检索器 数据源 作用
vectorRetriever ES / 向量数据库 向量检索,召回语义相似内容
fullTextRetriever Elasticsearch 全文检索,召回关键词匹配内容
sqlRetriever 关系型数据库 通过 Text2SQL 查询结构化数据
graphRetriever 图数据库 查询实体关系、路径和图结构
apiRetriever 外部 API 调用业务系统获取实时数据

也就是说,ES 搜索只是 ContentRetriever 的一种实现。

LangChain4j 的 RAG 框架并不关心底层是 ES、MySQL、Neo4j 还是外部接口。只要它实现了 ContentRetriever 接口,就可以被接入到 RAG 流程中。


七、ES 向量检索和全文检索在 RAG 中的位置

在 RAG 系统中,ES 检索经常会分成两路:

ES 向量检索
ES 全文检索

这两路都属于 ContentRetriever


1. ES 向量检索

向量检索的核心流程是:

用户问题
   |
   v
embedding 模型生成问题向量
   |
   v
用问题向量到 ES dense_vector 字段中做相似度搜索
   |
   v
返回语义相似的知识片段

简化代码如下:

ContentRetriever vectorRetriever = ElasticsearchContentRetriever.builder()
        .restClient(restClient)
        .embeddingModel(embeddingModel)
        .indexName("knowledge_chunks")
        .maxResults(5)
        .minScore(0.5)
        .build();

向量检索适合处理表达不同但语义相近的问题。

例如用户问:

ES 能不能做语义搜索?

文档里写的是:

Elasticsearch 支持基于 dense_vector 的相似度召回。

关键词不完全一样,但向量检索可能仍然能召回。


2. ES 全文检索

全文检索的核心流程是:

用户问题
   |
   v
分词
   |
   v
倒排索引查找
   |
   v
BM25 等相关性评分
   |
   v
返回关键词匹配度高的知识片段

简化代码如下:

ContentRetriever fullTextRetriever = ElasticsearchContentRetriever.builder()
        .restClient(restClient)
        .indexName("knowledge_chunks")
        .maxResults(5)
        .build();

全文检索适合处理专有名词、编号、错误码、精确短语等问题。

例如:

ERROR_CODE_10086 是什么意思?

这种问题通常更依赖关键词精确匹配,全文检索会比单纯向量检索更稳定。


八、多路检索:为什么要组合多个 Retriever

单一路径检索往往不够稳定。

只用全文检索,可能遇到这些问题:

  • 同义词召回效果差
  • 用户表达和文档表达不一致时容易漏召回
  • 对自然语言问题不够友好

只用向量检索,也可能遇到这些问题:

  • 对错误码、编号、类名、方法名不够稳定
  • 结果可解释性弱
  • 依赖 embedding 模型质量

所以更常见的做法是多路检索:

用户问题
   |
   +--> ES 向量检索
   |
   +--> ES 全文检索
   |
   +--> SQL 检索
   |
   +--> 图数据库检索

然后再交给 ContentAggregator 做统一处理。


九、ContentAggregator:多路结果聚合和重排序

当一个问题走了多个检索器之后,会得到多批结果。

例如:

ES 向量检索结果
ES 全文检索结果
SQL 检索结果
图数据库检索结果

这些结果不能直接全部塞给大模型,因为可能存在:

  • 重复内容
  • 不相关内容
  • 排序不准确
  • 结果数量太多

所以需要 ContentAggregator 进行聚合。

常见处理方式包括:

  1. 合并多路结果
  2. 根据文档 ID 或 chunk ID 去重
  3. 对分数做归一化
  4. 使用 rerank 模型重新排序
  5. 过滤低分内容
  6. 截取 Top N 条结果

简化代码如下:

ContentAggregator contentAggregator = ReRankingContentAggregator.builder()
        .scoringModel(scoringModel)
        .minScore(0.6)
        .maxResults(5)
        .build();

可以理解为:

多路召回结果
   |
   v
去重 + 过滤 + rerank
   |
   v
最适合注入 Prompt 的 Top N 内容

十、ContentInjector:把检索内容注入 Prompt

ContentInjector 负责把聚合后的检索内容注入到大模型 Prompt 中。

简化代码如下:

ContentInjector contentInjector = new DefaultContentInjector();

它的作用可以理解为:

用户问题 + 检索到的知识片段
   |
   v
组装成最终 Prompt
   |
   v
发送给大模型

例如用户问题是:

如何打开零重力座椅?

检索到的知识片段是:

零重力座椅可通过中控屏座椅菜单开启,也可以通过语音助手控制。

ContentInjector 会把这些内容拼到 Prompt 中,让大模型基于资料回答,而不是完全依赖模型自身记忆。

这也是 RAG 能减少幻觉的关键步骤。


十一、组件组合后的完整执行链路

把这些组件组合起来后,完整流程可以画成这样:

用户问题
   |
   v
QueryTransformer
问题改写 / 查询增强
   |
   v
QueryRouter
判断应该走哪些检索器
   |
   +------------------------------+
   |                              |
   v                              v
ContentRetriever              ContentRetriever
ES 向量检索                    ES 全文检索
   |                              |
   +--------------+---------------+
                  |
                  v
        ContentAggregator
        多路结果聚合、过滤、rerank
                  |
                  v
        ContentInjector
        把检索结果注入 Prompt
                  |
                  v
        ChatModel / StreamingChatModel
        大模型生成答案

如果问题需要查结构化数据,可以路由到 SQL 检索器。

如果问题需要查实体关系,可以路由到图数据库检索器。

如果问题需要查文档知识库,可以路由到向量检索和全文检索。


十二、AiServices 如何使用 RetrievalAugmentor

构建好 RetrievalAugmentor 之后,需要把它交给 LangChain4j 的 AI Service。

示例代码如下:

Assistant assistant = AiServices.builder(Assistant.class)
        .chatModel(chatModel)
        .chatMemoryProvider(chatMemoryProvider)
        .systemMessageProvider(memoryId -> "你是一个专业助手,请基于资料回答问题。")
        .retrievalAugmentor(retrievalAugmentor)
        .build();

这里的关键是:

.retrievalAugmentor(retrievalAugmentor)

它表示:在调用大模型之前,先执行 RAG 检索增强流程。

也就是说,大模型最终看到的不是单纯的用户问题,而是类似这样的内容:

系统提示词
+ 用户问题
+ 检索到的相关资料
+ 历史会话记忆

然后再生成最终答案。

如果使用流式模型,也可以替换成:

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

十三、不要被框架封装迷惑

LangChain4j 的组件名很多,但真实原理并不复杂。

可以把它还原成普通代码:

Query transformedQuery = queryTransformer.transform(originalQuery);

Collection<ContentRetriever> retrievers = queryRouter.route(transformedQuery);

List<Content> contents = new ArrayList<>();
for (ContentRetriever retriever : retrievers) {
    contents.addAll(retriever.retrieve(transformedQuery));
}

List<Content> finalContents = contentAggregator.aggregate(transformedQuery, contents);

Prompt prompt = contentInjector.inject(finalContents, originalQuery);

String answer = chatModel.chat(prompt);

框架只是帮我们把这套流程标准化了。

真正需要关注的是:

  1. 问题有没有被正确改写
  2. 路由器有没有选对检索器
  3. 检索器底层查的是什么数据源
  4. 多路结果有没有正确合并和重排序
  5. 注入到 Prompt 的内容是否准确、足够、不过量

十四、总结

LangChain4j RAG 的核心不是某一个搜索引擎,而是一套检索增强生成的流程抽象。

它把 RAG 拆成了几个核心组件:

QueryTransformer:问题改写
QueryRouter:问题路由
ContentRetriever:内容检索
ContentAggregator:结果聚合和重排序
ContentInjector:上下文注入
RetrievalAugmentor:统一编排

其中,ES 搜索只是 ContentRetriever 的一种实现。

在真实应用中,ES 通常可以分成两路:

ES 向量检索:负责语义相似召回
ES 全文检索:负责关键词匹配召回

它们可以和 SQL 检索、图数据库检索、外部 API 检索一起,由 QueryRouter 选择,再由 RetrievalAugmentor 串联成完整的 RAG 流程。

所以理解 LangChain4j RAG 的关键是:

不要先看框架名字,而是先还原真实流程。

只要抓住这条主线:

改写问题 -> 路由检索器 -> 执行检索 -> 聚合重排 -> 注入 Prompt -> 大模型回答

再复杂的 LangChain4j RAG 封装,也就能看明白了。