RAG API知识点梳理

RAG API文档地址


1. 先对比一下:简单 RAG 和 Core RAG API 的区别

你现在可能已经会这种简单写法:

ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .maxResults(3)
        .minScore(0.7)
        .build();

Assistant assistant = AiServices.builder(Assistant.class)
        .chatLanguageModel(chatModel)
        .contentRetriever(contentRetriever)
        .build();

这种方式的流程大概是:

用户问题
  ↓
去向量库查相关内容
  ↓
把查到的内容塞进 Prompt
  ↓
交给大模型回答

它很好用,但问题是:
你很难细粒度控制下面这些步骤:

  • 用户问题要不要改写?
  • 要不要根据不同问题查不同知识库?
  • 要不要同时查多个知识库?
  • 查出来的内容要不要去重、重排、过滤?
  • 查出来的内容以什么格式塞进 Prompt?
  • 要不要把元数据,比如文件名、页码、链接一起塞进去?

所以 LangChain4j 提供了 Core RAG API


2. Core RAG API 的整体流程

Core RAG API 的核心管道可以理解成这样:

用户问题 UserMessage
        ↓
QueryTransformer:把用户问题转换成一个或多个检索 Query
        ↓
QueryRouter:决定每个 Query 应该去哪些 Retriever 查
        ↓
ContentRetriever:真正去查知识库、向量库、搜索引擎
        ↓
ContentAggregator:合并、去重、排序、筛选查到的内容
        ↓
ContentInjector:把内容注入到 Prompt/UserMessage
        ↓
LLM 生成回答

LangChain4j 里把这个整体过程封装成一个东西:

RetrievalAugmentor

它是 Core RAG API 的核心入口。


3. RetrievalAugmentor:RAG 增强器,总指挥

它是干什么的?

RetrievalAugmentor 可以理解为:

在用户消息交给大模型之前,先帮你完成检索、整理、注入上下文的全过程。

简单说,它就是 RAG 流程的“总控制器”。


在 AiServices 里面怎么用?

简单 RAG 是这样:

AiServices.builder(Assistant.class)
        .chatLanguageModel(chatModel)
        .contentRetriever(contentRetriever)
        .build();

而 Core RAG API 通常是这样:

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

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

也就是说:

contentRetriever(...)

适合简单场景。

retrievalAugmentor(...)

适合你要自定义完整 RAG 流程的场景。


4. Query:检索用的问题

它是干什么的?

Query 表示“用于检索的问题”。

注意,它不一定等于用户原始问题。

用户原始问题可能是:

它支持哪些数据库?

但这个问题单独拿出去查知识库,效果可能很差,因为“它”指的是什么不清楚。

如果结合聊天历史,真正应该检索的问题可能是:

LangChain4j 支持哪些向量数据库?

这就是 Query 的作用。


通俗理解

用户说的话是:

UserMessage

检索系统真正拿去查的是:

Query

两者不一定一样。


5. QueryTransformer:把用户问题改造成检索问题

它是干什么的?

QueryTransformer 的作用是:

把用户输入转换成一个或多个适合检索的 Query。


为什么需要它?

因为用户问问题经常不完整。

比如多轮对话:

用户:LangChain4j 的 RAG 是什么?
AI:RAG 是检索增强生成……
用户:那它怎么接入 Spring Boot?

第二个问题:

那它怎么接入 Spring Boot?

如果直接拿去向量库检索,效果可能不好。

因为“它”是谁?
向量库不知道。

更好的检索问题应该是:

LangChain4j 的 RAG 怎么接入 Spring Boot?

这就是 QueryTransformer 可以做的事情。


常见用法 1:默认转换

默认情况下,它基本就是把用户问题包装成 Query

用户问题:
LangChain4j 如何使用 RAG?

转换后:
Query("LangChain4j 如何使用 RAG?")

适合简单单轮问答。


常见用法 2:压缩/改写问题

比如:

聊天历史:
用户:我想学习 LangChain4j 的 RAG
AI:可以,RAG 包括 indexing 和 retrieval
用户:核心 API 是什么?

用户真实想问的是:

LangChain4j RAG 的核心 API 是什么?

这类场景可以用“查询压缩”或“问题改写”。

它会借助大模型把上下文和当前问题合并成一个更完整的检索问题。


常见用法 3:扩展成多个 Query

用户问:

Spring Boot 中怎么使用 LangChain4j RAG?

可以扩展成多个检索问题:

Query 1:Spring Boot 集成 LangChain4j RAG
Query 2:LangChain4j AiServices retrievalAugmentor 用法
Query 3:LangChain4j ContentRetriever Spring Boot 示例

这样可以提高召回率。


你可以把它理解成

QueryTransformer = 检索前的问题优化器

它负责让“用户随口问的问题”变成“适合知识库搜索的问题”。


6. QueryRouter:决定去哪里查

它是干什么的?

QueryRouter 的作用是:

决定每个 Query 应该交给哪些 ContentRetriever 去检索。


为什么需要它?

因为你可能不止一个知识库。

比如你的系统里有:

产品文档知识库
订单系统知识库
售后政策知识库
代码文档知识库

用户问:

怎么申请退款?

应该去:

售后政策知识库

用户问:

OrderService 的 createOrder 方法有什么限制?

应该去:

代码文档知识库

这就是 QueryRouter 的作用。


简单情况

如果你只有一个向量库,那么路由很简单:

所有 Query 都去同一个 ContentRetriever

比如:

QueryRouter queryRouter = new DefaultQueryRouter(contentRetriever);

大概意思是:

不管用户问什么,都去这个知识库查

多知识库情况

比如你有两个 retriever:

ContentRetriever productDocRetriever;
ContentRetriever orderDocRetriever;

可以让 QueryRouter 决定:

产品相关问题 → productDocRetriever
订单相关问题 → orderDocRetriever

通俗理解

QueryRouter = 检索路由器

类似 Spring MVC 里面的路由:

请求进来 → 判断该交给哪个 Controller

在 RAG 里是:

问题进来 → 判断该查哪个知识库

7. ContentRetriever:真正负责查资料

它是干什么的?

ContentRetriever 是真正执行检索的组件。

它接收一个 Query,返回一批 Content

Query
  ↓
ContentRetriever
  ↓
List<Content>

你之前用过的 EmbeddingStoreContentRetriever 就是它的一种实现

例如:

ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
        .embeddingStore(embeddingStore)
        .embeddingModel(embeddingModel)
        .maxResults(5)
        .minScore(0.7)
        .build();

它的作用是:

把用户问题转成向量
    ↓
去向量数据库查相似内容
    ↓
返回最相关的几个文本片段

重要参数

1. embeddingStore

你的向量库。

可以是:

  • InMemoryEmbeddingStore
  • Milvus
  • Qdrant
  • Weaviate
  • Pinecone
  • PGVector
  • Elasticsearch
  • Redis
  • 等等

2. embeddingModel

用来把问题转成向量的模型。

例如:

OpenAiEmbeddingModel

或者:

BgeSmallEnV15QuantizedEmbeddingModel

注意:
你索引文档时用的 embedding model,和查询时用的 embedding model,最好保持一致。

否则向量空间不一致,检索效果会下降。


3. maxResults

最多返回多少条内容。

例如:

.maxResults(5)

意思是最多找 5 个最相关片段。

不是越多越好。
太多会导致 Prompt 很长,大模型反而抓不到重点。


4. minScore

最低相似度分数。

例如:

.minScore(0.7)

意思是相似度低于 0.7 的内容不要。

如果设置太高,可能查不到内容。
如果设置太低,可能塞进去很多无关内容。


通俗理解

ContentRetriever = 知识库查询器

它就是负责“查资料”的。


8. Content:检索出来的内容

它是干什么的?

Content 表示检索结果。

它里面通常包含:

文本内容
元数据
分数信息

比如检索出来一段内容:

LangChain4j supports RAG through ContentRetriever and RetrievalAugmentor.

它可能还带有 metadata:

source = rag.md
page = 3
url = https://docs.langchain4j.dev/tutorials/rag

为什么 Content 很重要?

因为最终要塞进 Prompt 的就是这些 Content

例如:

用户问题:
LangChain4j 的 Core RAG API 包括哪些组件?

检索出来的 Content:
1. RetrievalAugmentor is the core abstraction...
2. QueryTransformer transforms user message into queries...
3. QueryRouter routes queries to retrievers...

然后这些内容会被注入到 Prompt 里,让大模型基于它回答。


9. ContentAggregator:合并、去重、排序检索结果

它是干什么的?

ContentAggregator 的作用是:

把多个 Query、多个 Retriever 查出来的结果合并成最终要给大模型的上下文。


为什么需要它?

假设你用了 QueryTransformer,把一个问题扩展成 3 个 Query:

Query 1
Query 2
Query 3

然后每个 Query 又查了 5 条内容。

那么总共可能得到:

3 × 5 = 15 条 Content

问题来了:

  • 有些内容可能重复
  • 有些内容相关性不高
  • 有些内容顺序不合理
  • 最终不可能全部塞给大模型

所以需要 ContentAggregator 进行整理。


它一般做什么?

1. 合并

把多个检索结果放到一起。

Retriever A 的结果
Retriever B 的结果
Retriever C 的结果
        ↓
合并

2. 去重

多个 Query 可能查到同一段内容。

Query 1 查到 文档片段 A
Query 2 也查到 文档片段 A

这种情况就需要去重。


3. 排序

把更相关的内容排在前面。


4. 截断

最终只保留最有用的一部分。

比如最终只保留前 5 条。


5. 重排 rerank

有些高级场景会用专门的 reranker 模型重新排序。

比如第一次向量检索召回 20 条:

粗筛:向量库查 top 20

然后用 rerank 模型重新判断相关性:

精排:reranker 选 top 5

这样效果通常比单纯向量相似度更好。


通俗理解

ContentAggregator = 检索结果整理器

它负责从一堆查到的资料里面挑出最适合塞给大模型的内容。


10. ContentInjector:把检索结果塞进 Prompt

它是干什么的?

ContentInjector 的作用是:

把最终筛选好的 Content 注入到用户消息或 Prompt 中。


RAG 最关键的一步

大模型本身不知道你的私有知识库内容。

所以你要把检索出来的内容变成类似这样的 Prompt:

请根据下面的资料回答用户问题。

资料:
1. LangChain4j 的 RetrievalAugmentor 是 RAG 的核心组件。
2. QueryTransformer 用于将用户问题转换成检索 Query。
3. QueryRouter 用于决定去哪个 ContentRetriever 检索。

用户问题:
LangChain4j 的 Core RAG API 有哪些?

然后再交给大模型。

这个“把资料拼进 Prompt”的动作,就是 ContentInjector 做的。


默认注入方式

默认情况下,它会把内容追加到用户消息中。

大概类似:

用户原始问题:
LangChain4j 的 Core RAG API 是什么?

增强后的问题:
LangChain4j 的 Core RAG API 是什么?

请使用以下信息回答:
[检索内容 1]
[检索内容 2]
[检索内容 3]

可以自定义注入模板

你可以控制注入格式,比如:

你是一个企业知识库助手。
请只根据 <资料> 中的信息回答问题。
如果资料中没有答案,请回答“不知道”。

<资料>
{{contents}}
</资料>

<问题>
{{userMessage}}
</问题>

这种方式在企业系统里很常用。


为什么要自定义 ContentInjector?

因为不同业务对回答要求不同。

比如客服系统:

只能根据知识库回答,不能编造。

可以在模板里写:

如果资料中没有明确答案,请不要猜测。

比如技术文档助手:

回答时附带来源。

可以把 metadata 里的文件名、URL 一起注入。


通俗理解

ContentInjector = Prompt 拼装器

它负责把检索结果包装成大模型能看懂的上下文。


11. DefaultRetrievalAugmentor:默认的 RAG 编排器

它是干什么的?

DefaultRetrievalAugmentor 是 LangChain4j 提供的默认实现。

你不需要自己实现整个 RetrievalAugmentor,可以用它的 builder 组装各个组件:

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

如果你只配置 ContentRetriever

你也可以写得比较简单:

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

这样 LangChain4j 会帮你用默认的:

默认 QueryTransformer
默认 QueryRouter
默认 ContentAggregator
默认 ContentInjector

你可以逐步替换

比如一开始你只替换检索器:

DefaultRetrievalAugmentor.builder()
        .contentRetriever(contentRetriever)
        .build();

后来发现多轮问题效果不好,你再加 QueryTransformer:

DefaultRetrievalAugmentor.builder()
        .queryTransformer(queryTransformer)
        .contentRetriever(contentRetriever)
        .build();

再后来你有多个知识库,再加 QueryRouter:

DefaultRetrievalAugmentor.builder()
        .queryTransformer(queryTransformer)
        .queryRouter(queryRouter)
        .contentAggregator(contentAggregator)
        .contentInjector(contentInjector)
        .build();

这就是 Core RAG API 的灵活性。


12. 用一个完整例子串起来

假设你在 Spring Boot 里做一个“公司内部文档助手”。

你有两个知识库:

1. 技术文档知识库
2. 人事制度知识库

用户问:

我入职多久可以休年假?

Core RAG API 的流程是:


第一步:QueryTransformer

把用户问题转换成检索 Query:

Query("公司员工入职多久可以休年假?")

如果是多轮对话,还会结合上下文改写。


第二步:QueryRouter

判断这个问题应该去哪查:

这是人事制度问题
    ↓
路由到 人事制度知识库 Retriever

不会去技术文档知识库查。


第三步:ContentRetriever

从人事制度知识库查资料:

查到:
1. 员工连续工作满一年后享受带薪年假。
2. 新入职员工年假按照入职时间折算。
3. 具体天数根据累计工作年限确定。

第四步:ContentAggregator

整理结果:

去掉重复内容
按相关性排序
保留最相关的 3 条

第五步:ContentInjector

拼成 Prompt:

请根据以下资料回答问题。

资料:
1. 员工连续工作满一年后享受带薪年假。
2. 新入职员工年假按照入职时间折算。
3. 具体天数根据累计工作年限确定。

问题:
我入职多久可以休年假?

第六步:LLM 回答

大模型基于资料回答:

根据公司制度,员工通常连续工作满一年后可以享受带薪年假。
如果是新入职员工,年假可能会按照入职时间进行折算,具体天数还要结合累计工作年限确定。

13. 各核心组件一句话总结

组件 作用 通俗理解
RetrievalAugmentor RAG 总流程控制器 总指挥
DefaultRetrievalAugmentor 默认 RAG 编排实现 官方提供的标准流水线
Query 用于检索的问题 真正拿去查知识库的问题
QueryTransformer 改写、压缩、扩展用户问题 检索前的问题优化器
QueryRouter 决定 Query 去哪些 Retriever 知识库路由器
ContentRetriever 从知识库中检索内容 查资料的人
Content 检索出来的资料片段 查到的资料
ContentAggregator 合并、去重、排序、过滤内容 资料整理器
ContentInjector 把资料塞进 Prompt Prompt 拼装器

14. 你作为 Spring Boot 开发者应该怎么理解它?

可以类比成一个后端请求处理链。

Controller 接收用户问题
        ↓
QueryTransformer 类似参数规范化
        ↓
QueryRouter 类似路由选择 Service
        ↓
ContentRetriever 类似 Repository 查询数据库
        ↓
ContentAggregator 类似聚合查询结果
        ↓
ContentInjector 类似 DTO/Prompt 组装
        ↓
ChatModel 类似最终业务处理器

如果你之前只会简单 RAG,那么你现在可以这样理解:


简单 RAG

我只指定一个 ContentRetriever,其他交给框架默认处理

适合:

  • 单知识库
  • 单轮问答
  • 对检索结果要求不复杂
  • demo 或内部简单工具

Core RAG API

我自己控制查询改写、路由、检索、聚合、注入

适合:

  • 多知识库
  • 多轮对话
  • 企业文档问答
  • 需要来源引用
  • 需要精确控制 Prompt
  • 需要 rerank
  • 需要减少幻觉
  • 需要按业务类型选择不同知识库

15. 学习建议

你可以按这个顺序学:

第一步:先熟练 ContentRetriever

重点掌握:

EmbeddingStoreContentRetriever

因为它是最常用的向量检索组件。

你需要理解:

embeddingModel
embeddingStore
maxResults
minScore

第二步:学 RetrievalAugmentor

把简单 RAG 改成:

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

然后接到 AiServices:

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

第三步:学 ContentInjector

这是最容易看到效果的。

你可以自定义 Prompt,让模型:

只根据资料回答
不知道就说不知道
回答时带来源

第四步:学 QueryTransformer

解决多轮对话里的问题。

比如:

它怎么配置?
这个支持国产模型吗?
刚才那个能不能部署到内网?

这种问题都需要结合上下文改写。


第五步:学 QueryRouter

当你有多个知识库时再学它。

比如:

技术文档库
业务规则库
合同库
客服 FAQ 库

这时候 QueryRouter 就很重要。


第六步:学 ContentAggregator / Rerank

当你发现检索出来内容太杂时,再重点研究它。

尤其是:

先召回多一点,再 rerank 精排

这在生产系统里很常见。


16. 最核心的一句话

LangChain4j 的 Core RAG API 本质上就是把 RAG 拆成了这几步:

问题优化 → 选择知识库 → 检索资料 → 整理资料 → 注入 Prompt → 大模型回答

对应到组件就是:

QueryTransformer
QueryRouter
ContentRetriever
ContentAggregator
ContentInjector
RetrievalAugmentor

如果你理解了这条链路,后面的高级 RAG 就会容易很多。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐