RAG 检索基础:多路表示、向量数据库与索引

文本经过清洗、分片和向量化之后,还需要解决两个问题:用什么表示判断内容相关,以及怎样在大量资料中快速找到这些内容;整段语义、精确词项和 token 之间的细粒度关系,是不同的匹配信号;向量数据库与索引则决定这些信号如何被保存和检索

从 Dense、Sparse、BM25 到 ColBERT,再到近似最近邻和结构化索引,核心都是在信息保留、查询成本与知识组织之间取舍

一、Embedding 的多路输出

部分模型能够从同一段文本中产生多种表示;例如 bge-m3 同时支持稠密向量、稀疏词项权重与 ColBERT 式多向量输出,各路保留的信息并不相同

输出 表示形式 主要用途
Dense 每段文本一个固定维度向量;bge-m3 的稠密向量为 1024 维 匹配整体语义
Sparse 以词表位置为维度,只记录非零词项及权重 提供词项匹配信号
ColBERT 式多向量 每个有效 token 保留一个向量 比较细粒度语义关系

稀疏表示的非零项数量随文本而变,50---200 项可以是一种文本规模下的示例,不能当成固定输出长度;多向量的维度也要以模型配置为准,不能把所有 ColBERT 模型都写成 1024 维;相关输出见 bge-m3 模型说明

图中的词组与向量条用于示意,不代表某个 tokenizer 的实际切分或真实模型输出

Dense:把整段文本压缩成一个向量

从文本到向量:池化做了什么

Transformer 编码器通常先输出一个形状为 seq_len × hidden_dim 的矩阵;seq_len 是 tokenizer 实际产生的序列长度,hidden_dim 是每个 token 的表示维度;例如,序列有 512 个 token、隐藏维度为 1024,输出便是 512 × 1024

"如何部署 RAG 系统" 可以用四个词组来说明处理过程,但真实 token 数要由模型的 tokenizer 计算;中文词、英文缩写和空格都可能影响切分,不能直接把四个词组当成四个真实 token

要得到整段文本的单一向量,还需要池化:

  • CLS 池化 :取特定起始位置的向量作为整段表示;它是否能有效汇聚语义,取决于模型的训练方式,而非只要存在 [CLS] 就自动成立
  • 平均池化:对有效 token 的表示求平均,通常需要排除 padding;它是另一种汇聚方式,不能笼统认为一定更稳定或完全不受位置影响

如果一段文本有 128 个 token,每个 token 为 1024 维,那么池化前有 128 × 1024 = 131072 个数值,池化后剩下 1024 个;这里的 128∶1 是表示元素数量之比,不是严格的信息量度量;它说明了 Dense 的取舍:整段表示便于检索,但 token 级匹配细节不再单独保存

例如,"如何部署系统" 可能匹配到没有相同措辞的 "安装步骤如下",因为两者语义接近;但查询 processPayment 函数 时,单靠整体语义可能把 "支付处理模块设计" 排在前面,却没有准确找出包含函数标识符的代码块

从向量到召回:相似度怎样计算

余弦相似度关注向量方向;欧氏距离同时受到方向与模长影响,二者适合哪一种场景,应依据模型训练时使用的度量判断;不能把向量模长直接解释为文本长度,也不能断言欧氏距离必然给出错误排序

先看点积;对于两个三维向量:

复制代码
A = [0.12, -0.34, 0.56]
B = [0.10, -0.31, 0.52]

A · B = 0.12 × 0.10 + (-0.34) × (-0.31) + 0.56 × 0.52
      = 0.012 + 0.1054 + 0.2912
      = 0.4086

高维向量的算法相同,都是对应元素相乘后求和;余弦相似度再除以两个向量的模长乘积:

复制代码
cos(A, B) = (A · B) / (|A| × |B|)

|A| = √(0.12² + (-0.34)² + 0.56²)
    = √0.4436 ≈ 0.6660

|B| = √(0.10² + (-0.31)² + 0.52²)
    = √0.3765 ≈ 0.6136

cos(A, B) ≈ 0.9998
cosine distance = 1 - cosine similarity ≈ 0.0002

模长是向量的几何长度,不是元素数量;余弦相似度的范围为 [-1, 1],1 表示方向一致,0 表示正交,-1 表示方向相反;相应的余弦距离 1 - cosine similarity 范围为 [0, 2],越小表示方向越接近;这些是几何含义,不能把 -1 直接等同于自然语言中的 "语义对立"

这里使用完整的三维示例计算结果;如果展示的是带省略号的高维向量,就不能仅用已展示的三个元素验证整条向量的相似度

使用 normalize_embeddings=True 等配置进行 L2 归一化后,非零向量的模长变为 1:

复制代码
归一化后的余弦相似度 = 点积
归一化后的余弦距离 = 1 - 点积

这样可以直接使用点积比较方向,避免未归一化点积中模长对得分的影响;代价是丢弃模长所携带的信号,因此是否归一化应遵循模型的使用方式;对于单位向量,欧氏距离与余弦相似度也具有对应关系,可以产生相同的近邻排序

检索时,把问题编码为向量,与知识库向量比较,按距离从小到大取前 K 个,就是 Top-K 召回

方面 Dense 的特点
语义匹配 能利用训练得到的语义关系,匹配 "部署" 和 "安装" 等不同表达
精确匹配 函数名、型号等精确标识符可能需要词项检索补充
可解释性 很难直接指出某一个词对最终相似度贡献多少
预计算 文档向量可以提前生成;查询时主要编码问题
查询成本 单次向量比较简单,但全库检索耗时还取决于数量、维度和索引

Sparse:为词项保留可检索的权重

Sparse 表示可以理解为一个很长、但绝大多数位置为零的向量;维度对应词表中的固定位置,只有部分词项携带权重;实际存储时可以保存 "词项 ID---权重" 对,而不必写出所有零

仍以 "如何部署 RAG 系统" 为例,用简化词项展示:

复制代码
输入文本 → Tokenizer → 上下文编码 → 词项权重

词项       示例词表位置       示例权重
如何          1234             0.35
系统          2345             0.28
部署          5678             0.82
RAG           8901             0.91

稀疏表示:{1234: 0.35, 2345: 0.28, 5678: 0.82, 8901: 0.91}

这些位置和权重只是示意,不是实际词表记录或推理结果;对于约 25 万规模的词表,即使只保留少量非零项,仍然可以按词项位置进行比较

以 bge-m3 的词项权重思路看,编码器先得到每个 token 的上下文向量,再经线性映射和非负激活获得标量权重;重复词项还需要聚合;映射参数通过训练学习,因此同一个词在不同上下文中可能获得不同权重

例如,"部署" 比 "系统" 更能区分当前问题,"RAG" 也可能比 "如何" 更有用;Sparse 不必固定遵守这个排序,而是由模型根据上下文给出权重

需要区分 "词项权重包含上下文" 与" 不同词项可以直接匹配";bge-m3 的稀疏路以词项重合为基础,仅仅提高 "部署" 的权重,并不会自动让它和不同词表位置的 "安装" 产生点积;同样,多语言模型不意味着纯稀疏匹配自动获得任意跨语言对齐能力

BM25 与中文分词器:

神经词项权重与统计词项权重:

稀疏检索还有一条传统路径:BM25;它不需要通过神经网络生成词项权重,而是利用词频、文档频率和文档长度计算相关性

TF-IDF 的直觉是:一个词在当前文档中越常见、在整个语料库中越少见,就越能代表这篇文档;使用原始词频的简单版本会受到词频线性增长和文档长度的影响;BM25 则在稀有词加权之外,引入词频饱和与长度校正;不同 TF-IDF 实现也可能使用对数词频和归一化,不能把这些局限概括为所有 TF-IDF 的必然行为

比较项 Sparse embedding BM25
权重来源 模型学习到的上下文权重 语料统计与评分公式
查询端 需要模型编码;与 Dense 同时使用时可能共享编码器计算 分词与查索引,不需要神经模型推理
可解释性 能查看词项权重,但权重来源仍依赖模型 可以分解 IDF、词频和长度项
索引维护 同步更新词项记录及对应文档 同步更新倒排记录、文档频率、长度等统计
精确匹配 受词表切分和词项重合影响 受分析器和分词结果影响
多语言 依赖模型词表与训练,不保证跨词项匹配 需要适合语言的分词或分析策略

例如,神经稀疏表示可以给出 {部署: 0.82, 系统: 0.28},BM25 则依据对应词的 IDF、出现次数和文档长度计算贡献;二者的数值来源不同,不能直接比较大小

BM25 公式与参数:

一种常见的 BM25 形式为:

复制代码
BM25(q, d) = Σ_i IDF(q_i) ×
             [f(q_i, d) × (k1 + 1)] /
             [f(q_i, d) + k1 × (1 - b + b × |d| / avgdl)]

其中 f(q_i, d) 是查询词在文档中的出现次数,|d| 是文档长度,avgdl 是语料中的平均文档长度

IDF 控制词的区分度 ;设总文档数为 N,包含该词的文档数为 df,经典形式之一是:

复制代码
IDF(q_i) = ln[(N - df(q_i) + 0.5) / (df(q_i) + 0.5)]

这个版本在 df > N/2 时会出现负值,因此不能据此说 "所有文档都包含某词时,IDF 接近零";Lucene 使用带 1 + 的非负形式,高频词在这一形式下才会获得接近零的权重:

复制代码
IDF(q_i) = ln[1 + (N - df(q_i) + 0.5) / (df(q_i) + 0.5)]

k1 控制词频饱和 ;某词出现 3 次可能说明相关,出现 30 次却不意味着相关性变为十倍;k1=0 时,命中词不再因重复出现而继续增加词频得分;取 1.2 或 2.0 会形成不同的饱和曲线,较大的值允许词频继续发挥更大作用

b 控制文档长度校正b=0 忽略长度,b=1 完全使用公式中的长度比校正;Lucene 的默认值为 k1=1.2b=0.75;当 chunk 长度都接近 512 token 时,长度差异较小,b 的影响可能减弱;公式与默认值见 Lucene BM25Similarity 文档

停用词与中文分词:

"的、了、在、是" 等高频词可以通过停用词表处理;中文停用词集合 收录了多个来源的词表,包括常被称作哈工大、百度停用词表的版本;使用时仍要检查过滤规则是否伤害实际查询

低频词同样需要结合业务判断;不能统一过滤 df < 2 的词,因为只出现一次的函数名、产品型号或错误码,可能恰好是最关键的检索线索

中文词语之间没有天然空格;如果文档侧把一个术语切成两部分,查询侧却保留成一个词,倒排索引就可能无法按预期命中

分词器 特点与适用方向 安装命令
jieba 精确、全模式与搜索模式;支持关键词提取和词性标注,适合通用项目 pip install jieba
pkuseg 支持不同领域分词模型,可用于专业资料对照评估 pip install pkuseg
thulac 中文分词与词性标注,可用于相关研究与应用 pip install thulac
HanLP 分词之外还提供命名实体识别、依存分析等 NLP 能力 pip install hanlp
LAC 提供词法分析能力,可评估其领域适应性与运行成本 pip install lac

可以先用 jieba 建立基线,再观察专有名词、复合词和领域术语是否被正确切分;当分词误差已经影响召回时,再比较其他分词器;"准确率提高 5%---10%" 或 "某工具一定更慢" 都必须对应具体语料与运行环境

ColBERT:在 token 层面进行延迟交互

Dense 把文本汇聚为单一向量;Cross-encoder 则把问题和文档放在一起编码,直接计算两者的交互关系;ColBERT 采用另一种折中:分别编码问题与文档,保留 token 级向量,在评分时才进行交互

文档 token 向量可以提前计算;查询到来后,对查询中的每个 token,寻找文档中与它最相似的 token,再汇总这些最佳匹配,这就是 MaxSim:

复制代码
Score(q, d) = Σ_i max_j (q_i · d_j)

用 "如何/部署/系统" 作为查询词项,"安装/步骤/如下/配置/环境" 作为文档词项,可以得到下面这组示例相似度:

查询词项 安装 步骤 如下 配置 环境 最大值
如何 0.21 0.15 0.18 0.12 0.09 0.21
部署 0.85 0.42 0.31 0.78 0.65 0.85
系统 0.33 0.28 0.45 0.51 0.37 0.51

第一行选择 0.21,第二行选择 0.85,第三行选择 0.51,总分为 0.21 + 0.85 + 0.51 = 1.57;每个查询 token 都有机会找到自己的最佳匹配,不必依赖整段池化后的单一表示;这些数字用于解释计算过程,并非模型实测结果

不同实现可能对 MaxSim 求和或做长度归一化;例如,FlagEmbedding 的 colbert_score 对逐行最大值求和后,还会除以查询向量数;按上面的三个查询向量计算,对应为 1.57 / 3 ≈ 0.5233,因此不能默认接口返回值与求和示例一致;参见 FlagEmbedding 评分实现

多向量的成本也更高;假设每个向量为 1024 维 FP32,一个向量约 4 KiB,128 个向量便约 512 KiB,原始向量存储比单向量多 128 倍;实际索引还受投影维度、压缩与结构开销影响,因此不能把 "10---50 倍" 视为固定比例

方面 Dense ColBERT 式多向量
表示 每段一个向量 每段多个 token 向量
文档预计算 可以 可以
评分 比较整段表示 聚合 token 之间的最佳匹配
主要资源压力 向量总量和近邻搜索 更多向量的存储、读取与交互计算
使用方向 大规模语义召回的基础方案 细粒度检索或候选重评分

不能把 Cross-encoder、ColBERT、Sparse、Dense 排成固定的质量与速度排行榜;尤其不能把 "一对向量的点积时间" 与 "一次完整模型编码时间" 直接比较;是否值得引入多向量检索,要用相同硬件、语料、候选规模和评估口径判断

三路表示如何组合:

可以先建立 Dense + Sparse,或 Dense + BM25 的混合召回;Dense 负责 "如何部署" 与 "安装步骤" 之间的语义匹配,词项路补充 processPayment 等标识符的匹配信号,再通过 RRF 等方法融合结果

BM25 的查询端不需要神经模型编码;神经稀疏权重需要模型计算,但若与 Dense 共享一次编码器前向过程,不能把它简单算作再完整运行一次模型;额外成本要区分共享编码、输出头和索引查询

ColBERT 可以按需引入;语料较小、细粒度错误突出、资源较充足时,可以用它做对照实验;"少于 1 万个 chunk" 只是方便起步的规模示例,不是算法的适用上限;另一条常用路径是混合召回后再使用 Cross-encoder 精排,以候选筛选控制交互计算量

二、写入向量库:存储架构与数据库选型

向量数据库的作用与分类:

当向量从几百个增加到百万甚至更大规模,逐个比较的成本会不断增加;普通结构化索引擅长 WHERE age = 25 这类条件,却不能直接解决高维空间中的近邻查找

向量数据库除了保存向量,还需要管理文本标识、元数据与查询能力;HNSW、IVF 等索引让系统能够减少搜索范围,用近似结果换取效率;它们不意味着任何规模和过滤条件下都能保证毫秒级响应

常见索引思路包括:

  • 树结构:例如 Annoy,通过空间划分缩小候选范围
  • 哈希:例如 LSH,把相近对象尽量放入相同的桶
  • 邻近图:例如 HNSW,沿图中的连接寻找更接近查询的节点
  • 聚类与量化:IVF 先划分搜索区域,PQ 则压缩向量表示;两者可以组合,但并非同一个操作

主流向量存储方案:

方案 主要特点 适合考察的场景
Pinecone 托管向量服务 希望减少自建运维的应用
Milvus 开源分布式向量系统,提供多种索引选择 大规模向量管理与检索
Qdrant Rust 实现,提供过滤与量化相关能力 需要向量检索与元数据过滤的应用
Weaviate 向量数据库与检索集成能力 需要多种检索和模型集成的项目
Chroma 便于从本地开发起步 原型、实验与小型应用
FAISS 相似性搜索算法库,不是完整数据库 本地实验、自行构建检索服务
pgvector PostgreSQL 的向量扩展 希望结合 SQL、事务与现有业务数据

原型可以从 Chroma 或 FAISS 开始;需要分布式管理和更高并发时,再评估专用服务;已经使用 PostgreSQL 的项目,可以先评估 pgvector,让向量与业务记录共享事务和 SQL 过滤能力

10 万、百万或千万向量都可以作为压测规模,但不能作为切换产品的固定门槛;同样,SLA、低于 100 ms 的延迟或每秒 4000 次请求,需要对应具体服务条款或测试条件;选择时应同时比较查询负载、过滤需求、运维成本与事务一致性

ANN 索引:HNSW、IVF 与 Annoy

为什么需要近似最近邻

暴力搜索会计算查询与全部文档向量的距离,再取 Top-K;它可以作为精确检索基线,但耗时随数据量与维度增加,还受到硬件和批处理方式影响;"10 万条约 100 ms、百万条约 1 秒" 只能是特定环境的示例

ANN,即近似最近邻,用索引限制需要访问的候选,允许一定的近邻召回损失以换取速度;这里的召回率通常是相对精确近邻结果而言,不能直接等同于业务问题的答案召回率

HNSW:沿分层邻近图逐步搜索

HNSW 构建多层邻近图,上层节点少,底层包含全部节点;查询从上层入口开始,寻找更接近查询的邻居,再逐层下降;可以把它想象成先看全国地图定位区域,再看城市与街道地图缩小范围

插入新向量时,系统先确定它参与的层级,从高层搜索入口,在相关层寻找候选邻居,选择连接并修剪邻接列表;邻居选择并不只是机械保留最近的 m 个点,还可能使用启发式策略维持图的可导航性

三个关键参数分别控制连接密度、建图搜索和查询搜索:

参数 作用 调大后的主要代价
mM 控制图连接数量 更多边带来存储与构建开销
ef_construction 控制建图时的候选搜索宽度 构建时间增加
ef_search,部分库称 ef 控制查询时的候选搜索宽度 查询耗时增加

可以用 m=16 开始对照,也可以比较 8、32 等配置;具体层的最大邻居数由实现决定,不能保证所有层都恰好受 m 条边限制;调整 m 和建图策略通常需要重建索引,而查询搜索宽度一般可以运行时调整

ef_construction 可比较 48---200 等范围,但 "64 是默认值" 必须指明使用哪个数据库;查询侧可比较 40、100、200,观察召回和延迟是否值得交换;没有通用的 "增加不到 2 ms" 保证,也不能预设这些配置必然对应 88%、95%、97% 的召回率

尤其要注意,不存在 ef_search ≤ ef_construction 的通用约束 ;hnswlib 的查询 ef 至少应覆盖请求的邻居数 k,可以大于构建时的搜索宽度;参数说明见 hnswlib 文档

IVF:先分簇,再搜索附近的簇

IVF 通过聚类把向量分配到多个列表;查询时先选择最近的几个簇,再在这些簇内搜索,从而避免遍历全部向量

例如有四个簇,查询位于簇 1 与簇 2 附近;当 nprobe=2 时,只搜索这两个簇,暂不访问簇 3、簇 4;如果真正的近邻被分到未访问的簇,就可能漏掉,因此搜索更多簇通常能够提高近邻召回

  • nlist:簇或倒排列表的数量;修改它通常需要重新训练和构建索引
  • nprobe:查询时访问多少个簇;通常可以运行时调整,值越大,计算范围越广

√NN/100 可以作为某些实现讨论簇数的经验量级,但不构成通用上下界;IVF 完成训练后也可以添加向量,只有分布变化较大时才需要评估重新训练;在 FAISS 中还可以结合 PQ 压缩向量,具体结构见 FAISS 索引说明

Annoy:多棵随机投影树寻找候选

Annoy 使用随机投影树逐步划分空间;查询从树根根据划分进入相应区域,直到得到较小的候选集合;单棵树可能把近邻分到不同区域,因此通过多棵树扩大找到候选的机会

例如,一棵树把查询定位到包含 A、B 的区域,另一棵树可能再提供 C;系统合并并去重候选,最后按距离选择近邻;最终排序不是按候选在多棵树中出现的次数投票

它的两个主要参数是 n_treessearch_k;前者影响树的数量与索引构建成本,可以比较 50---100 等配置;后者控制查询时检查的节点数量,在速度与召回之间取舍;search_k=-1 表示采用默认预算,通常为 n_trees × 请求近邻数,并不表示遍历所有叶子

Annoy 的一个特点是只读索引文件可以通过 mmap 映射,多进程共享同一份索引;因此适合更新较少、读取较多的场景;构建完成后不能直接继续添加数据,新数据需要重建并发布新的索引版本;这些行为见 Annoy 文档

三种索引如何取舍:
方面 HNSW IVF Annoy
核心结构 多层邻近图 聚类与倒排列表 多棵空间划分树
查询预算 ef_search nprobe search_k
主要额外开销 图的连接信息 聚类训练与列表管理 多棵树的构建和存储
数据更新 通常支持增量插入 训练后可追加,分布变化需关注 构建后只读,更新需重建
典型考虑 增量更新与较高近邻召回 大规模分区检索,可结合压缩 静态索引、多进程文件共享

频繁更新的知识库可以优先评估 HNSW;大规模数据与压缩需求可以考察 IVF;按周或按月更新、需要共享静态索引时,可以考察 Annoy;实际内存和速度还取决于具体实现,mmap 也不代表索引无需物理内存

HNSW 与 WHERE 过滤:为什么结果可能不足

实际业务往往只搜索指定目录、租户或未归档资料;如果先在全量图中搜索,再过滤候选,原本找到的近邻可能大部分被排除,最终返回数少于 LIMIT

过滤后只剩几十个候选时,直接计算这些候选的距离可能比走 ANN 更合适;但是否会自动选择这种计划,取决于数据库优化器,而不是所有向量系统共有的行为

遇到结果不足时,可以检查:

  • 查询搜索宽度是否太小,过滤后可用候选是否不足
  • 是否支持迭代扫描或补搜,以继续寻找满足条件的结果
  • 统计信息是否过期,导致优化器错误估计过滤后的规模

在 PostgreSQL 中可以通过 EXPLAIN ANALYZE 查看实际执行计划;pgvector 提供迭代扫描等相关配置,使用前要确认版本和扫描预算;小结果集走顺序扫描并不一定有问题;参见 pgvector 过滤与迭代扫描说明

三、结构化索引:组织知识本身

ANN 解决的是 "怎样快速找到附近的向量";结构化索引则追问 "文本块之间的关系怎样保存";只把片段当成独立记录,可能难以回答统计、跨文档综合和关系链问题

为什么扁平片段有时不够:

统计问题需要完整范围;假设有 100 个案例,其中 90 个是黑猫、10 个是白猫;如果 Top-K 只取 20 个案例,模型可能只看到 15 个黑猫和 3 个白猫,无法据此推算全库比例;把 K 调大也不保证得到完整集合

如果已经基于全量资料核验并保存 "共有 100 只猫,其中黑猫 90%、白猫 10%",检索这条汇总即可回答;关键是统计覆盖了完整数据,而不是模型对少数片段做了猜测

相似案例不能替代适用规则;退伍军人 John 获得优惠,医生 Sarah 获得折扣,教师 Mike 不符合条件;护士提问时,检索可能因职业语义接近而优先召回 Sarah,进而错误泛化

如果有权威规则明确写着 "优惠仅适用于退伍军人和医生",就应把完整规则纳入索引;仅凭三个案例还不足以推出 "所有其他职业都不符合条件",知识提炼也不能凭空把案例扩展成规则

这些例子说明,需要跨文档统计或规则判断时,索引阶段可能需要额外整理汇总、规则及关系;模型可以执行一定的总结与推理,但无法凭空恢复没有检索到的证据

RAPTOR:从细节向上生成层次摘要

RAPTOR 先把文本块作为叶子节点,按语义关联聚类,再为每组内容生成摘要;摘要可以继续聚类和概括,形成从具体片段到较高层主题的结构

例如,多段关于 SSE 指令集的内容可以汇聚为 "x86 SIMD 指令集的各代演进";具体片段说明某一代的功能,父级摘要描述它们之间的演进关系;涉及指令细节时,仍要回到对应资料,不能用抽象摘要替代具体依据

这种组织方式允许在多个抽象层次检索;查询 "请解释 SSE 指令集" 时,可以从较高层概览获得方向,再找到底层细节;实现也可以把多个层级放在一起检索,并不一定每次都严格从根沿树向下走;参见 RAPTOR 论文

GraphRAG:通过实体关系连接证据

知识图谱用实体和关系组织信息;三元组可以写成 "北京---是首都---中国" 或 "张三---就职于---腾讯",多个三元组连接成网络

当问题是 "我的医生所在医院的地址",系统需要连接 "用户→医生→医院→地址";图结构能够保存这条关系链,帮助检索相关证据;但回答是否可靠,仍取决于关系是否正确、是否完整以及是否过期

实体消歧与词义消歧也不同;判断 bank 指银行还是河岸,是结合语境判断词义;区分同名的两个 "张医生",则需要建立不同实体标识,例如 "张医生-A---科室---牙科" 和 "张医生-B---科室---心脏科";图谱可以保存消歧后的结果,但前面的实体识别与对齐仍需可靠完成

Microsoft GraphRAG 会从文本提取实体与关系,构建图结构,并通过社区发现组织相关实体,生成社区摘要,支持局部与整体问题的检索;它不只是简单地把向量库替换成图数据库;参见 GraphRAG 官方说明

结构化提取也有局限;"如果下周还下雨,我就取消去海边,改去博物馆" 包含条件和时间;若只保存几条孤立的 "去海边" "去博物馆" 关系,就可能破坏原意;条件并非原则上无法建模,但过于简单的三元组提取容易漏掉这些限定,因此需要保留原始文本作为依据

什么时候值得引入结构化索引:

如果主要问题是 "退款政策是什么",准确召回相应片段通常就能解决;如果经常需要比较 "SSE 与 AVX 的架构差异",或从整体架构逐步深入具体指令,多层摘要与关系组织才更值得投入

结构化索引需要额外提取、聚类、摘要与更新维护,部分查询还会增加模型调用;一种互补方式是保留完整自然语言资料,使用元数据、摘要和关系辅助检索;在需要多跳关系或精确实体定位的场景中,再把图谱作为专项能力,而不是替代全部原文

四、上下文感知检索:先补背景,再建立索引

结构化索引处理知识组织关系,而上下文感知检索关注每个片段是否脱离语境;例如 "该公司第二季度的收入增长了 3%",单独出现时无法说明公司是谁、年份是什么,也可能缺少相关业务范围

Anthropic 的 Contextual Retrieval 在索引前使用模型为片段生成简短背景,再与原片段拼接;例如前缀可以说明 "本段来自 ACME 公司 2025 年第二季度财务报告",随后保留收入增长 3% 的原句;前缀必须来自文档中真实存在的上下文,不能补写没有依据的信息

拼接后的内容可以同时用于两条路径:

  • BM25:增加 ACME、年份、季度等可匹配词项,让原本缺少关键词的片段有机会命中
  • Dense:补足语义背景,让向量更准确地表示这段内容谈论的对象

这个过程发生在索引阶段,处理的是知识库片段;它与运行时压缩会话历史不同,前者为片段补背景,后者围绕当前任务整理上下文窗口

代价主要是额外的上下文生成调用;对于反复共享的完整文档前缀,可以利用提示缓存降低成本,但具体费用取决于模型、缓存计费和片段数量;Anthropic 发布该方法时给出的每百万文档 token 约 1.02 美元,是其指定假设下的历史估算,不是固定报价

在其报告的评估设置中,Contextual Embeddings 与 Contextual BM25 将 top-20 检索失败率从 5.7% 降到 2.9%,相对下降约 49%;再结合重排序器,报告的相对降幅为 67%;这是特定数据和配置下的结果,不是所有知识库都能获得的收益;实验与成本假设见 Anthropic Contextual Retrieval

多路表示决定系统依据什么信号匹配,ANN 决定怎样缩小搜索范围,结构化索引与上下文前缀则帮助资料保留关系和语境;把这些选择与实际问题对应起来,知识库才能兼顾查询效率与证据完整性

相关推荐
Joy T2 小时前
Spring AI 2.0 进阶入门:RAG、Structured Output 与 Agent 信息闭环
java·人工智能·spring·rag·springai·agent入门
AI-Frontiers18 小时前
智能体化检索增强生成:关于智能体化 RAG 的综述
rag
四点半-企业AI获客1 天前
AI搜索引用机制拆解:从抓取、解析到引用打分的完整链路
人工智能·geo·rag·ai搜索·搜索引擎优化
龙骑士baby3 天前
重建 AI 认知第 6 篇:RAG——答案不在"检索 + 生成"这四个字里
ai·llm·rag
Mr. zhihao3 天前
让裁判替你看答卷:RAGAS 实操因果链
rag·ragas·rag评估
SLD_Allen3 天前
RAG for Agent:Agent 什么时候需要查知识库?
agent·rag
一只小bit4 天前
LlamaIndex框架:简单RAG框架的全过程实现手册
llm·milvus·rag·llamaindex·deepseek
云烟成雨TD4 天前
LlamaIndex 系列【24】检索增强策略:交叉编码器(Cross‑Encoder)
ai·agent·rag·llamaindex
码农哈丁4 天前
用 Trait 给系统留出后路:RAG 存储层如何做到 5 种后端可插拔
人工智能·知识图谱·rag