一文讲透 RAG 核心术语:Embedding、Chunk、Vector DB、BM25、Reranker 到底是什么


上一篇我写 RAG,不想把它讲成“给 AI 接一个知识库”。

因为知识库只是资料放在哪里,RAG 真正要解决的是:当 AI 给出一个答案时,我们能不能知道它依据了哪段材料、有没有遗漏限制条件、能不能在证据不足时拒答。

但如果继续往下讲 RAG,很快就会遇到一堆术语:

Embedding、Chunk、Vector DB、BM25、Reranker、Citation、Faithfulness、RAG Eval……

这些词如果直接堆出来,文章会很像技术名词表。读者看完还是不知道:它们到底在 RAG 系统里解决什么问题?

所以这一篇不写代码,不写复杂架构,只做一件事:

把 RAG 里的核心术语翻译成人话,并说明每个组件在“证据链”里负责什么。

如果把 RAG 看成一条可信回答链路,它大概是这样:

原始文档
  ↓
清洗 / 解析
  ↓
Chunking
  ↓
Embedding
  ↓
向量检索 / BM25 检索
  ↓
Hybrid Search
  ↓
RRF 融合排序
  ↓
Reranker 精排
  ↓
Final Evidence
  ↓
LLM 基于证据生成回答
  ↓
Citation / Faithfulness / Abstention
  ↓
RAG Eval

这条链路看起来很长,但它其实只服务一个目标:

让 AI 的回答从“看起来对”,走向“有证据、可追溯、可验证”。

image.png

1. Document:原始资料

Document,就是进入知识库的原始资料。它可以是公司制度 PDF、产品说明书、客服 SOP、GitHub README、技术文档、Markdown 博客、简历、订单规则、FAQ,也可以是数据库里的业务记录。

Document 解决的是 RAG 里最基础的问题:

系统到底从哪里拿事实?

如果没有外部资料,模型只能依赖参数记忆。它可能知道一些通用知识,但不知道你的公司政策、项目文档、订单状态、内部流程、用户简历。

所以 Document 是 RAG 的原料。

但原始文档不能直接塞给模型。原因很简单:

  • 太长。
  • 太乱。
  • 格式复杂。
  • 版本不清楚。
  • 里面可能有页眉、页脚、目录、广告、水印、重复段落。
  • 有些信息已经过期。
  • 有些信息不属于当前用户或当前租户。

所以进入 RAG 系统的第一步,不是 embedding,也不是向量库,而是文档治理:这份文档是谁的、从哪里来、什么时候更新、属于哪个业务线、是否有效、用户有没有权限看。

一句话总结:
Document 是 RAG 的事实来源,但原始文档本身还不是可用证据。

2. Chunk:证据片段

Chunk,就是把大文档切成一小段一小段,方便检索和引用。

很多人会把 chunking 理解成“把长文切短”,比如每 500 tokens 切一段,重叠 50 tokens。

这个理解太粗。

真正好的 chunk,不只是短,而是要成为一个“证据单元”。

比如一份退款政策里有这样一段:

定制商品非质量问题不支持七天无理由退货。若商品存在质量问题,用户需在签收后 7 日内提交图片或视频证据,客服审核后进入售后流程。

如果你把它切成两段:

  • 第一段只保留“定制商品非质量问题不支持七天无理由退货”。
  • 第二段只保留“用户需在签收后 7 日内提交证据”。

那模型可能在回答时丢掉条件,或者误解适用范围。

所以 chunk 的目标不是平均切短,而是:

把文档切成能被检索、被引用、被验证的最小证据单元。

好的 chunk 不只包含正文,还应该带上能追溯和过滤的信息,比如标题、章节、来源、页码、版本、所属租户、更新时间和权限范围。

比如:

{
  "content"
  "source"
  "section"
  "page"
  "tenantId"
  "version"
  "updatedAt"
}

这才是一个对 RAG 友好的 chunk。

一句话总结:

Chunk 不是把文档切短,而是把文档切成 AI 能使用、用户能追溯的证据片段。

3. Embedding:把文本变成语义坐标

Embedding 是 RAG 里最常被提到的词。

简单说,Embedding 就是把一段文本变成一串数字,也就是向量。

为什么要这么做?

因为计算机不能直接理解“这两句话意思很接近”。它需要一种可以计算的表示方式。

比如用户问:

出差住酒店最多能报销多少钱?

文档里写的是:

差旅住宿报销标准:一线城市 600 元/晚,其他城市 400 元/晚。

这两句话用词不完全一样。

用户说的是“出差”“住酒店”“最多能报销多少钱”,文档写的是“差旅”“住宿”“报销标准”。如果只靠关键词,系统不一定能稳定命中。但从语义上看,它们问的其实是同一类问题。

Embedding 的作用,就是把这些文本映射到一个向量空间里。你可以把它理解成“语义坐标”。

  • 意思接近的文本,坐标距离更近。
  • 意思不相关的文本,坐标距离更远。

所以在 RAG 里,Embedding 解决的是:

让系统可以计算用户问题和文档片段之间的语义相似度。

具体流程分成两个阶段。

第一阶段是文档入库,也就是提前处理知识库:

原始文档
  ↓
切成 chunk
  ↓
每个 chunk 做 embedding
  ↓
得到每个 chunk 的向量
  ↓
把 chunk 原文 + 向量 + metadata 存入数据库

比如文档被切成三个 chunk:

chunk_001:差旅住宿报销标准:一线城市 600 元/晚,其他城市 400 元/晚。
chunk_002:交通费报销需提供发票。
chunk_003:餐饮补贴按城市等级计算。

系统会把每个 chunk 都转成向量。真实的向量通常有几百到几千维,这里只用简化数字演示:

chunk_001 embedding = [0.12, -0.44, 0.87, ...]
chunk_002 embedding = [0.31, 0.22, -0.10, ...]
chunk_003 embedding = [-0.18, 0.62, 0.40, ...]

这些数字不是给人看的,而是给系统计算相似度用的。

第二阶段是用户提问,也就是在线检索:

用户问题
  ↓
问题也做 embedding
  ↓
得到 query 向量
  ↓
拿 query 向量去数据库里查相似 chunk
  ↓
返回最相似的 topK 个 chunk
  ↓
把这些 chunk 原文交给 LLM 生成回答

比如用户问:

出差住酒店最多能报销多少钱?

系统会把这个问题也转成向量:

query embedding = [0.10, -0.41, 0.83, ...]

然后系统会比较:

query embedding 和 chunk_001 embedding 距离很近
query embedding 和 chunk_002 embedding 距离较远
query embedding 和 chunk_003 embedding 距离较远

所以它会优先召回 chunk_001:

差旅住宿报销标准:一线城市 600 元/晚,其他城市 400 元/晚。

最后,LLM 不是凭空回答,而是基于召回的 chunk 生成:

根据差旅住宿报销标准,一线城市住宿最高可报销 600 元/晚,其他城市最高可报销 400 元/晚。

所以 Embedding 不是直接回答问题,它只负责把“可能相关的证据”找出来。

你可以把它理解成 RAG 检索层的第一步:

文档 chunk 先变成向量
用户问题也变成向量
系统比较两边向量的距离
距离越近,说明语义越相关
然后取回对应 chunk 原文
再交给大模型生成回答

但这里有一个非常重要的边界:

Embedding 解决的是语义相似,不等于事实正确。

  • 相似,不代表能回答。
  • 相关,不代表完整。
  • 语义接近,不代表证据足够。

比如用户问:

SKU-A1937 是否支持德国仓发货?

这个问题最关键的是两个精确信息:

SKU-A1937
德国仓

系统必须找到同时和这两个条件相关的内容。

如果只靠 Embedding,它可能召回这些看起来相近的内容:

SKU-A1938 支持德国仓发货。
SKU-A1937 支持法国仓发货。
德国仓发货规则说明。

这些内容都“相关”,但不一定能回答用户的问题。

因为用户问的不是“德国仓规则是什么”,也不是“类似 SKU 怎么发货”,而是:

SKU-A1937 这个具体商品,是否支持德国仓发货?

这种问题不能只靠语义相似,还需要 BM25 / 关键词检索、metadata filter,甚至直接查业务数据库。

所以不要把 Embedding 当成语义魔法。它只是 RAG 检索系统的一部分。

一句话总结:

Embedding 是 RAG 检索层的语义匹配器:它把文档片段和用户问题都变成向量,通过相似度找到可能相关的候选证据。但它只能说明“语义接近”,不能保证证据完整、事实正确、权限合规,也不能替代关键词检索和业务数据查询。

4. Vector DB:存向量、查相似

有了 embedding 之后,需要一个地方存这些向量,并支持按相似度检索。

这就是 Vector DB。

常见选择包括 PGVector、Milvus、Qdrant、Weaviate、Pinecone,也可以使用 Elasticsearch / OpenSearch 的向量检索能力。

Vector DB 的基本工作方式是:

  • 文档被切成 chunk。
  • 每个 chunk 被 embedding 成向量。
  • 向量和 chunk 一起存入数据库。
  • 用户提问时,问题也被 embedding 成向量。
  • 系统查找和问题向量最相似的 chunk。
  • 把这些 chunk 交给大模型生成答案。

基本流程:

chunk 文本
  ↓
embedding 模型
  ↓
向量
  ↓
Vector DB
  ↓
相似度检索
  ↓
topK chunks

如果你用 Java / Spring Boot / PostgreSQL 技术栈,PGVector 是一个很适合入门和工程落地的选择。它是 PostgreSQL 的向量相似搜索扩展,可以让你在 PostgreSQL 里存向量、建索引、做相似度查询。

对个人项目和中小型应用来说,PGVector 的优势是工程成本低:document、chunk、metadata、tenant_id 可以和业务数据放在同一个 PostgreSQL 里,也方便接入 Spring AI 的 VectorStore 抽象,不需要一开始就维护单独的向量数据库集群。

但 Vector DB 不是 RAG 的全部。

很多人做 RAG 的第一个误区就是:

我接了向量数据库,所以我有 RAG 了。

不一定。

如果你没有好的 chunk,没有 metadata filter,没有 citation,没有拒答,没有 eval,那它只是一个“向量检索 + Prompt”demo。

用一个生活类比:

假设你有一个图书馆。

  • Document 是一本本书。
  • Chunk 是书里被裁出来的一小段内容。
  • Embedding 是给每一段内容贴一个“语义坐标”。
  • Vector DB 是图书馆的“语义索引系统”。
  • 用户问题也会被贴一个“语义坐标”。
  • 系统就看:用户问题这个坐标,离哪些内容的坐标最近。
  • 最近的几段,就是候选证据。

所以 Vector DB 不是“知识库本身”的全部,它只是知识库里的一个检索组件。

一句话总结:

Vector DB 负责把 chunk 的语义坐标存起来,并在用户提问时找出最相似的候选证据;但证据是否完整、是否有权限、是否支持答案,还要靠 chunk 质量、metadata filter、reranker、citation、faithfulness 和 eval。

5. topK:到底取多少条证据

topK 是一个很小但很重要的参数。

它表示:检索时取前 K 条结果。

比如:

topK = 5

意思是:系统会取最相似的 5 个 chunk 放进上下文。

很多人会以为 topK 越大越好,因为取更多证据似乎更安全。

但真实情况不是这样。

  • topK 太小,可能漏掉关键证据。
  • topK 太大,可能引入噪声,污染上下文。
  • 无关 chunk 进入 prompt 后,模型可能把错误信息也编进答案。
  • 上下文越长,成本越高,延迟越大。

比如用户问住宿报销标准,topK 太小可能只拿到金额,漏掉“必须提供发票”;topK 太大又可能把交通费、餐饮补贴、加班餐费一起塞进上下文,污染回答。

如果 topK 太小,比如 topK = 1:

只取第 1 条 chunk

好处是上下文很干净,成本低,速度快。

但风险是:如果第 1 条不完整,系统就漏掉关键条件。

比如第 1 条只说:

一线城市住宿最高 600 元/晚。

但第 4 条才说:

报销时必须提供住宿发票,且需经过部门负责人审批。

如果 topK = 1,模型只能看到第一条,就可能回答不完整。

这叫:漏召回

如果 topK 太大,比如 topK = 20:

取前 20 条 chunk

看起来证据更多,好像更安全。

但问题是,前 20 条里很可能混进很多“看起来相关但其实没用”的内容:

差旅住宿标准
交通费规则
餐饮补贴
出差审批
酒店协议
员工福利
加班餐费
团队建设报销……

这些内容一起塞进 Prompt,模型可能被干扰。

用户问的是“住宿最高报销多少”,但上下文里混入“餐饮补贴”“交通费”“加班餐费”,模型就可能把不相关规则也带进答案。

这叫:噪声污染上下文

所以 topK 的本质是一个平衡:

topK 太小:容易漏掉关键证据
topK 太大:容易引入无关噪声

所以 topK 不是越大越好,而是要和 chunk 质量、检索质量、reranker、上下文窗口一起调。

比如:

  • naive RAG 可能直接取 top5。
  • Hybrid Search 可能先召回 top50。
  • Reranker 再从 top50 里选 top5。
  • 最终只把最可靠的 3–5 个 chunk 放进 prompt。

topK也分两种,第一种是:召回阶段的 topK

它的目标是“不要漏”。

比如:

Vector Search 先召回 top50
BM25 也召回 top50

这时候 topK 可以大一点,因为只是候选池,还没直接塞进 Prompt。

第二种是:最终上下文的 topK

它的目标是“少噪声”。

比如 reranker 从 top50 里重新排序,最后只选:

final topK = 3 或 5

这几条才会真正进入 Prompt,让 LLM 生成答案。

所以完整流程是:

用户问题
  ↓
向量检索 / BM25 检索
  ↓
先多召回一些候选证据,比如 top50
  ↓
Reranker 重排
  ↓
最终只选 top3~top5
  ↓
放进 Prompt
  ↓
LLM 生成答案

一句话总结:

topK 决定有多少候选证据进入下一步,太少会漏召回,太多会污染上下文。

6. Similarity Threshold:相似度阈值

Similarity Threshold,就是相似度低于某个分数的结果不要。

比如:

similarityThreshold = 0.75

意思是:相似度低于 0.75 的 chunk 不进入上下文。

它的作用是减少无关内容进入 prompt。

但这个参数也不能迷信。

  • 阈值太高,可能把有用证据过滤掉。
  • 阈值太低,可能放进很多噪声。
  • 不同 embedding 模型、不同业务问题、不同 query 长度都会影响分数分布,所以 threshold 不能照抄,需要靠 eval 调。

Similarity Threshold 可以理解成:检索结果的最低及格线

Similarity Threshold 的本质是一个平衡:

阈值太高:结果更干净,但可能漏掉有用证据
阈值太低:结果更多,但可能引入噪声

它和 topK 的区别也要分清。

topK 控制的是:

最多取几条

Similarity Threshold 控制的是:

低于多少分不要

比如:

topK = 5
similarityThreshold = 0.75

意思不是“无论如何取 5 条”,而是:

先按相似度排序最多取前 5 条但低于 0.75 的不要

假设结果是:

0.91:chunk A
0.86:chunk B
0.79:chunk C
0.68:chunk D
0.62:chunk E

虽然 topK = 5,但因为 threshold = 0.75,最后只保留:

chunk A
chunk B
chunk C

所以可以这样理解:

topK 是数量上限
threshold 是质量底线

一句话总结:

topK 决定“最多拿几条”,Similarity Threshold 决定“太不像的不要”。

7. BM25 / Lexical Search:关键词检索不是过时技术

BM25 或 lexical search,可以简单理解成关键词检索。

它不像 embedding 那样理解语义,而是更关注词面命中。

比如:

SKU-A1937
HTTP 401
退款政策第 7 条
tenant_id
RetrievalAugmentationAdvisor
PGVector

这些查询不需要先“理解语义”,而是要精确命中。

如果用户问“SKU-A1937 是否支持德国仓发货”,系统就应该优先找到包含 SKU-A1937 的文档或表格。

如果用户问“Spring AI 的 RetrievalAugmentationAdvisor 怎么用”,系统就应该优先命中官方文档里包含这个类名的片段。

所以 BM25 / lexical search 没有过时。

它解决的是向量检索不擅长的问题:

  • 编号。
  • 错误码。
  • 字段名。
  • 类名。
  • 方法名。
  • 产品型号。
  • 政策条款。
  • 固定术语。
  • 短 query。
  • 中英混合表达。

这也是为什么很多生产 RAG 系统会做 Hybrid Search,而不是只做向量检索。

BM25 / Lexical Search 这段的核心意思是:

不要以为 RAG 只靠 Embedding。Embedding 擅长找“意思相近”的内容,但 BM25 擅长找“字面上必须命中”的内容。

你不需要记 BM25 的公式,只要理解它比普通关键词匹配更会衡量词的重要性和匹配强度,特别适合编号、类名、字段名、错误码、政策条款这类必须精确命中的内容。

你只要理解:BM25 更重视词面命中,尤其适合查精确词。

如果用 Embedding,系统可能觉得这些内容相关:

HTTP 403 权限错误
HTTP 401 未认证
HTTP 500 服务异常

但如果用户明确问 HTTP 401,那系统就必须优先命中包含 HTTP 401 的片段。

这就是 BM25 的价值。

它不是过时技术,而是在 RAG 里补 Embedding 的短板。

更具体一点,Embedding 容易在这些场景失手:

比如用户问“退款政策第 7 条怎么说?”,Embedding 可能召回退款政策总则、退款流程、售后说明,但不一定精确命中“第 7 条”。BM25 会更关注“第 7 条”这个词面。

一句话总结:

Embedding 找语义相似,BM25 / lexical search 找精确命中。

8. Hybrid Search:两路一起找证据

Hybrid Search,就是混合检索。

最常见的是:

Vector Search + BM25 / Lexical Search

也就是:

向量检索负责找语义相关。
关键词检索负责找精确命中。
两路结果合并后再排序。

它解决的是一个非常现实的问题:

单一路检索器容易漏证据。

比如:

用户问:

我的简历里有没有能支撑 RAG evaluation 的证据?

简历里可能没写 “RAG evaluation”,但写了:

设计了 evidence guard、citation check、unsupported claim detection,用于限制 AI 生成中的无证据扩写。

这个时候向量检索有价值。

但如果用户问:

我的项目有没有写 PGVector?

那就应该精确命中 PGVector 这个词,关键词检索更重要。

所以 Hybrid Search 不是炫技,而是降低漏召回。

基本流程是:

用户问题
  ↓
Vector Recall:找语义相关
  +
Lexical Recall:找精确命中
  ↓
融合排序/去重/重排
  ↓
候选证据

Vector Search 像一个懂意思的人:
“你虽然没说 evidence guard,但我知道它和 RAG evaluation 有关。”

BM25 像一个认真查关键词的人:
“你问 PGVector,我就必须找到 PGVector 这个词。”

一句话总结:

Hybrid Search = 语义检索负责“意思相近”,关键词检索负责“原词命中”。两路一起召回,可以降低关键证据被漏掉的概率。

9. RRF:把多路检索结果合并

Hybrid Search 会产生两张排行榜,RRF 的作用就是把这两张排行榜合并成一张总榜。

做完 Hybrid Search 后,会出现一个新问题:

  • Vector Search 有一组结果。
  • BM25 / Lexical Search 有一组结果。
  • 这两组结果怎么合并?

最直接的想法是把分数加起来。

但这通常不严谨。

因为向量相似度和 BM25 分数不是同一种分数。它们来自不同算法,尺度不同,不能简单相加。

这时候可以用 RRF。

RRF,全称 Reciprocal Rank Fusion,中文可以理解成“倒数排名融合”。

它不直接比较原始分数,而是看排名。

公式大概是:

RRF score = Σ 1 / (k + rank)

不用被公式吓到,它的意思很简单:

  • 如果一个 chunk 在向量检索里排得很靠前,在关键词检索里也排得靠前,那它更可能重要。
  • 如果一个 chunk 只在某一路检索里非常靠前,它也有机会被保留下来。
  • RRF 关心的是“排第几”,不是原始分数是多少。

举个简单例子:

Chunk A:向量检索第 1,关键词检索第 5
Chunk B:向量检索第 20,关键词检索第 1
Chunk C:向量检索第 3,关键词检索没有召回

RRF 会综合这些排名,而不是强行比较“向量相似度 0.82”和“BM25 分数 12.7”谁更大。

RRF 最适合解决的问题是:

Vector Search 和 BM25 的分数不能直接加,但它们的排名可以融合。

你可以把它放回整个 RAG 流程:

用户问题
  ↓
Vector Search 返回一组排行榜
  ↓
BM25 返回一组排行榜
  ↓
RRF 根据“排名”融合两组结果
  ↓
得到候选证据总榜
  ↓
Reranker 再精排
  ↓
选出 Final Evidence

这里还要分清 RRF 和 Reranker:

RRF:用排名规则快速融合多路检索结果
Reranker:用模型进一步判断 query 和 chunk 是否真的相关

一句话总结:

RRF 是把 Vector Search 和 BM25 的结果合并成一张更合理的候选证据排行榜。

10. Reranker:最终复核候选证据

Retriever 是粗筛,Reranker 是复核。

  • 检索器先找出一批候选 chunk,比如 top50 或 top100。
  • Reranker 再判断这些 chunk 和当前问题到底有多相关。
  • 最后只选最适合回答问题的几个 chunk 进入 prompt。

为什么要这样做?

因为召回阶段追求“不要漏”。
重排阶段追求“更准确”。

  • 如果一开始就只取 top5,很可能漏掉关键证据。
  • 如果把 top50 全部塞进 prompt,又会污染上下文。
  • 所以常见做法是:先多召回,再精排。

典型流程:

用户问题
  ↓
Vector Search / BM25 先召回 top50
  ↓
RRF 把多路结果融合成候选列表
  ↓
Reranker 逐条判断:这个 chunk 到底能不能回答这个问题?
  ↓
重新排序
  ↓
只选 top3 / top5 放进 Prompt
  ↓
LLM 基于最终证据生成答案

Reranker 和 Embedding 的区别非常重要。

Embedding 的做法一般是:

把 query 单独变成向量
把 chunk 单独变成向量
然后计算两个向量距离

它更像是快速粗筛:

这个问题和这个 chunk 的语义大概像不像?

Reranker 的做法通常是:

把 query 和 chunk 放在一起让模型直接判断它们的相关性

它问的是更细的问题:

这个 chunk 是否真的能回答当前 query?
这个 chunk 是强相关、弱相关,还是只是沾边?
这个 chunk 是否包含用户问题需要的关键条件?

举个例子。

用户问:

退款政策第 7 条怎么说?

前面检索可能召回:

A:退款政策总则
B:退款申请流程
C:第 7 条:定制商品非质量问题不支持七天无理由退货
D:售后审核要求
E:退货运费说明

Embedding 可能觉得 A、B、D、E 都和“退款政策”相关。

但 Reranker 会更容易判断:

用户问的是“第 7 条”
C 直接包含“第 7 条”
所以 C 应该排第一

这就是 reranker 的价值:它不是只看大概相关,而是更细地判断“能不能支撑这个问题”。

一句话总结:

Reranker 是 final context 之前的最后一道证据复核:它决定哪些候选 chunk 真正有资格进入大模型上下文。

11. Metadata Filter:只在正确范围里检索

很多 RAG demo 会直接在所有文档里检索,但生产系统不能这样做。

Metadata,就是文档或 chunk 附带的信息。

比如:

{
  "tenantId"
  "sourceType"
  "language"
  "version"
  "status"
  "updatedAt"
}

Metadata Filter 就是按这些字段过滤。

为什么它重要?

因为不是所有文档都应该被检索。

用户问退款政策时,系统要先判断:

  • 是不是当前商家的政策?
  • 是不是当前语言?
  • 是不是当前版本?
  • 是不是 active 状态?
  • 是不是当前用户有权限访问?
  • 是不是对应业务线?

如果不做 metadata filter,系统可能召回:

  • 旧版本政策。
  • 其他租户文档。
  • 测试文档。
  • 英文文档。
  • 无权限文档。
  • 已废弃规则。

这不是回答不准的问题,而是系统边界问题。

RAG 检索时,不能在所有文档里乱找。它必须先限定范围,只在“当前用户应该看的、当前业务应该用的、当前版本有效的文档”里检索。

Chunk 本身是正文,比如:

定制商品非质量问题不支持七天无理由退货。

Metadata 是这段 chunk 身上的标签,比如:

{
  "tenantId"
  "sourceType"
  "language"
  "version"
  "status"
  "updatedAt"
}

这些标签不是给大模型看的废信息,而是给系统检索时做过滤用的。

也就是说,系统不是直接问:

哪些 chunk 和用户问题最相似?

而应该先问:

在当前商家 merchant_001 的 active 中文退款政策里,哪些 chunk 和用户问题最相似?

这就是 Metadata Filter。

一句话总结:

Metadata Filter 决定“哪些资料有资格参与检索”;Embedding / BM25 决定“这些资料里哪些最相关”。

12. Tenant Filter:多租户系统的硬隔离

Tenant Filter 可以理解成 Metadata Filter 里最不能出错的一种。

Metadata Filter 是范围控制,Tenant Filter 是权限隔离。

如果一个系统服务多个公司、多个商家、多个团队,每个组织就是一个 tenant。

比如:

  • 商家 A 有自己的退款政策。
  • 商家 B 有自己的退款政策。
  • 商家 C 有自己的商品知识库。

用户来自商家 A,那么系统只能检索商家 A 的文档。

不能靠 prompt 说:

请你只回答当前商家的内容。

这不够。

真正的 tenant filter 应该在数据库查询、检索条件、权限系统里生效。

比如:

WHERE

如果 tenant filter 漏了,后果不是“回答不够好”,而是“数据越权”。

一句话总结:

Tenant Filter 不是 Prompt 约束,而是数据访问控制。

13. Citation:答案来自哪里,但不代表答案一定被支持

Citation,就是引用来源。

它告诉用户:

  • 这个答案来自哪篇文档。
  • 来自哪个 chunk。
  • 来自哪一页。
  • 来自哪个章节。
  • 原文片段是什么。

比如:

{
  "answer"
  "citation"
    "document"
    "section"
    "page"
    "quote"
  }
}

Citation 的价值是让答案可追溯。

但要注意:

有引用不等于可信。

引用只能说明系统给了来源。
它不能自动说明答案真的被来源支持。

比如原文说:

定制商品非质量问题不支持七天无理由退货。

模型回答:

所有跨境商品都不支持退货。

这个答案可能也带了引用,但它扩大了原文范围,所以不可信。

一句话总结:

Citation 是可信的起点,不是终点。

14. Faithfulness / Groundedness:答案是否忠于证据

Faithfulness 和 Groundedness 经常一起出现。

你可以先不用纠结二者的边界,它们都在问一个核心问题:

模型说的话,证据里到底有没有?

如果证据说:

候选人参与了 Spring Boot 后端开发,并接入了 Redis 限流。

模型改写成:

主导设计高并发 AI Agent 平台,使用 Redis、RocketMQ、PGVector 构建生产级 RAG 系统。

这就是典型不 faithful。

因为模型加了很多证据里没有的东西。

这在 AI 简历、项目包装、求职材料里尤其危险。它不是简单“润色”,而是把没有证据的经历写成了事实。

所以 Faithfulness / Groundedness 不是看答案是否流畅,也不是看答案是否有引用,而是看:

答案里的每个关键 claim 是否被证据支持。

你可以把它拆成 claim 检查:

Claim 1:主导设计高并发 AI Agent 平台证据支持?没有。
Claim 2:使用 Redis证据支持?有。
Claim 3:使用 RocketMQ证据支持?没有。
Claim 4:使用 PGVector证据支持?没有。
Claim 5:构建生产级 RAG 系统证据支持?没有。

所以 Faithfulness 检查的不是“这句话写得好不好”,而是:

每一个关键 claim 是否有证据支撑?
有没有夸大?
有没有扩展范围?
有没有补充证据里没有的技术?
有没有把参与说成主导?
有没有把 demo 说成生产级?

这也是为什么 Faithfulness 不能只看语言是否流畅,也不能只看答案是否带了引用。

因为模型最容易出现的问题就是:它可以把错误答案说得非常自然。

一个不 faithful 的答案可能具备这些表象:

语言很流畅结构很清楚看起来专业甚至带了引用

但只要答案里的关键结论没有被证据支持,它仍然不可信。

一句话总结:

Citation 问的是“答案挂了哪个来源”,Faithfulness 问的是“这个来源到底支不支持答案”。有引用只是把答案和资料连起来;Faithfulness 才是在检查这条连接是不是真的成立。

15. Abstention:证据不足时,系统应该拒答

Abstention,就是拒答。

但这里的拒答不是“模型不会”,而是“系统知道不该答”。

什么时候应该拒答?

  • 没有检索到证据。
  • 证据之间互相冲突。
  • 用户没有权限访问相关资料。
  • 问题超出知识库范围。
  • 答案需要实时订单状态,但当前只有静态政策文档。
  • 检索结果只支持一部分结论,不支持完整回答。

比如用户问:

这个订单还能退吗?

如果系统只检索到通用退款政策,但没有订单状态、商品类型、物流节点、是否定制商品这些信息,就不应该直接回答“可以退”或“不可以退”。

更好的回答是:

当前知识库只包含通用退款政策,无法确认该订单是否符合退款条件。需要查询订单状态、商品类型和物流信息后才能判断。

这就是可信 RAG 的边界感。

一句话总结:

可信 RAG 不应该永远给答案。它必须能识别证据不足、权限不足、信息缺失和结论无法成立的情况。

16. RAG Eval:证明系统真的变好了

RAG Eval,就是评测 RAG 系统是不是真的有效,要用一组可重复的测试问题,检查系统到底坏在哪个环节。

很多 demo 的评测方式是:

  • 问几个问题。
  • 看起来回答不错。
  • 觉得系统可以上线。

这很危险。

因为 RAG 的错误可能发生在多个环节:

  • 文档解析错。
  • chunk 切坏了。
  • embedding 召回错。
  • BM25 没命中。
  • RRF 排序不好。
  • reranker 选错证据。
  • final context 被噪声污染。
  • 模型没有忠实使用证据。
  • 引用不支持答案。
  • 该拒答时没有拒答。

所以 eval 的价值不是打一个漂亮分数,而是定位系统坏在哪里。

常见评测维度包括:

  • retrieval recall:该召回的证据有没有召回。
  • context precision:召回的上下文有多少真的有用。
  • faithfulness:答案是否忠于证据。
  • answer relevance:答案是否回应问题。
  • citation accuracy:引用是否真的支持答案。
  • abstention accuracy:该拒答时有没有拒答。

RAG 不是一个单点功能,而是一条链路:

文档解析
  ↓
chunk 切分
  ↓
embedding / BM25 召回
  ↓
RRF / Reranker 排序
  ↓
final context 选择
  ↓
LLM 生成回答
  ↓
citation 引用
  ↓
faithfulness 检查
  ↓
abstention 拒答

这条链路任何一环出问题,最后答案都可能错。

一句话总结:

没有 Eval,你只能凭感觉调 RAG。
有了 Eval,你才能知道问题到底出在检索、排序、上下文选择、生成、引用,还是拒答边界。
到这一步,RAG 才开始从 demo 接近工程系统。

17. 把这些词放回一条证据链里

现在再回头看这些术语,它们其实不是孤立概念。

  • Document 是原料。
  • Chunk 是证据单元。
  • Embedding 是语义坐标。
  • Vector DB 是语义检索工具。
  • BM25 / Lexical Search 是精确词面检索工具。
  • Hybrid Search 是双路召回。
  • RRF 是多路排序融合。
  • Reranker 是候选证据复核。
  • Metadata Filter 是检索范围控制。
  • Tenant Filter 是数据隔离。
  • Citation 是来源标记。
  • Faithfulness / Groundedness 是答案是否忠于证据。
  • Abstention 是边界控制。
  • RAG Eval 是质量证明。

它们共同组成的是:

问题
  ↓
检索正确范围内的证据
  ↓
选择最能支撑答案的证据
  ↓
基于证据生成回答
  ↓
标记引用来源
  ↓
检查答案是否忠于证据
  ↓
证据不足时拒答
  ↓
用 eval 证明系统是否变好

这就是我理解的可信 RAG。

  • 它不是“向量库 + Prompt”。
  • 也不是“把 PDF 丢进去让 AI 聊天”。
  • 它是一套把问题、证据、生成、引用、拒答、评测串起来的工程系统。

18. 下一篇:从 0 到 1 搭一个个人技术资产知识库

下一篇,我会开始写保姆级实战:

从 0 到 1 搭一个个人技术资产知识库:Spring Boot + Spring AI + PGVector 保姆级教程。

这次不做泛泛的“PDF 聊天机器人”,而是用自己的真实技术资产作为知识库来源:

  • 个人博客文章

  • GitHub README

  • 项目文档

  • 技术复盘

  • Markdown 笔记

目标也不是一上来做完整企业级平台,而是搭出一个最小可信 RAG 骨架:

  • 文档从哪里来

  • chunk 怎么切

  • embedding 怎么入库

  • PGVector 怎么检索

  • metadata 怎么过滤

  • 回答怎么带 citation

  • 证据不足怎么拒答

  • retrieval trace 怎么记录

  • 最小 eval case 怎么设计

它还不是完整企业级知识库,但会保留企业级系统最关键的边界意识:来源、权限、版本、证据、引用、拒答和评测。

最后回到一句话:

RAG 的目标不是让 AI 更会说,而是让 AI 的回答更值得被信任。

参考资料

我是 Ryan,一个专注于可信 AI 应用工程的开发者,技术博客:yanxai.com。相比让 AI 生成更多内容,我更关心它的回答是否有证据,过程是否可追溯,结果是否经得起验证。


文章作者: Ryan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ryan !

评论

有问题欢迎留言,看到都会回~

  大纲
 目录