LangChain4j全集-01-RAG知识梳理
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 就会容易很多。
更多推荐
所有评论(0)