语料有一百万个片段,上下文预算只够放五个。RAG 的全部工程问题,都是从这道算术题里长出来的。
一、RAG 要解决的不是”知道得更多”
大模型的知识编码在权重里,这种参数化记忆有三个绕不过去的限制。
第一是更新成本。改一条事实要么等下一次预训练,要么做微调,而这两种手段的周期都跟不上业务数据的变化速度——产品文档昨天刚改,今天就该答对。
第二是溯源困难。权重里没有出处信息,模型给出一个数字,没有任何办法指出它来自哪份文件的哪一页。审计场景里这一点是硬伤:合规、医疗、法务要的不是”大概对”,而是”依据在这里”。
第三是容量。企业内部真正有价值的知识大多是私有的,量级在百万到上亿个片段,这类内容不会出现在任何模型的预训练数据里。
一个常见的反应是把这些都归为”知识不够”,于是去微调。但对事实类知识,微调不是合适的工具:它擅长改变行为方式(输出格式、语气、领域术语习惯),不擅长精确地注入和更新事实。模型学会一条新事实需要反复暴露,而且新事实与旧事实会互相干扰。
RAG 换了方向:知识留在外部,模型只负责读。检索器从语料里取出一小批相关片段放进上下文,让模型基于这些片段作答。原始设定(Lewis 等,NeurIPS 2020)是给预训练模型外挂一个稠密检索器并端到端训练,在开放域问答上刷新了当时的成绩;被继承下来的是这个结构本身——参数化记忆加非参数化记忆。
需要说清的是一点:RAG 解决的不是知识总量问题,而是上下文选择问题。窗口不管多大都是有限的,语料是海量的,两者差了六到九个数量级:
- 语料规模:10^6 到 10^9 个片段
- 一次回答真正用得上的上下文:几千到几万个 token,通常对应 3 到 10 个片段
所以这套系统的本质是一个在硬预算下的排序问题:从成千上万个候选里,挑出那几个真正该进窗口的。
二、长上下文为什么没有替掉检索
上下文从 4k 涨到 128k,甚至出现百万级的窗口,一个自然的疑问是:把整份文档甚至整个知识库塞进去不就行了。三个原因让这条路走不通。
第一是成本。注意力的计算量和显存随上下文长度平方增长,解码时每个新 token 还要对全部历史再做一次注意力。上下文长十倍,单次请求的成本涨得远不止十倍。
第二是精度。把答案放进上下文,模型不一定用得上。对长上下文使用方式的系统评测发现,关键信息在开头和结尾时模型表现最好,落在中间时明显变差,这就是长上下文里的中间凹陷。另有专门评测长上下文有效长度的基准(RULER)测出模型的有效窗口远小于标称值:需要从长文本里聚合多条信息时,能力在远低于标称长度的位置就开始下降。
第三是干扰。检索噪声不只是浪费 token,它会主动拉低答案质量。有工作专门研究了往 RAG 里塞不相关文档的影响,结论是无关内容会显著降低准确率,在某些设置下甚至不如不给任何上下文;另一项研究用筛选的方式丢掉无用文档,结果提升了鲁棒性。两件事合起来说明:少而准优于多而杂。
长上下文改变的是检索的边界,没有取消检索。窗口越长,越需要一个机制来决定放什么进去——因为塞得越多,每一段的边际价值越低,噪声的代价越高。
三、系统的两条链路
RAG 系统由两条链路组成,一条离线跑,一条在线跑。
离线链路(索引):文档解析 → 清洗 → 分块 → 元数据抽取 → 向量化 → 建索引。
在线链路(查询):查询改写 → 检索召回 → 重排 → 上下文组装 → 生成 → 引用与校验。
| 环节 | 目标 | 常见做法 | 常见失效 |
|---|---|---|---|
| 解析 | 从 PDF、HTML、表格里拿到正文与结构 | 版面分析、OCR、保留结构 | 表格被拉平、页眉页脚混入、跨页断句 |
| 分块 | 切成语义自洽的小单元 | 按结构切、固定长度加重叠 | 答案被切断、块内指代失去上下文 |
| 向量化 | 把片段映射到可比的空间 | 嵌入模型加归一化 | 查询与片段用了不对称的前缀 |
| 索引 | 在可接受的延迟内找到近邻 | HNSW、IVF、倒排 | 参数用默认值、过滤与向量检索互相打架 |
| 召回 | 把相关片段捞进候选集 | 稠密加稀疏混合 | 专有名词、编号、数字召回不到 |
| 重排 | 把真正有用的排到前面 | 交叉编码器 | 直接跳过这一步 |
| 组装 | 在预算内组织上下文 | 去重、排序、加编号 | 关键证据被埋在中段 |
| 生成 | 基于证据作答,能说没有 | 引用约束、允许拒答 | 用参数记忆补答案、误读证据 |
这张表里最值得记住的一条是:误差会逐级累积。假设每个环节各自有九成的可靠度,五个环节串起来大约只剩六成:
$$P_{\text{端到端}} \approx \prod_{i=1}^{5} p_i = 0.9^5 \approx 0.59$$
只看最终答案对不对,就永远不知道该修哪一环。把每个环节单独量化,是这套系统能不能长期维护下去的分水岭。
四、技术架构与部署形态
链路清楚之后,接下来是这些环节在部署上怎么摆的问题。
一次在线请求会经过这些组件:
- 接入层:鉴权、限流,把用户身份、租户、权限标签解析出来。这些标签要一路传到检索层,成为过滤条件
- 编排层:查询改写、判断要不要检索、路由到哪个知识库或哪几个库
- 检索层:向量检索与全文检索并行执行,各自返回候选
- 融合与重排:先把候选融合,再用重排模型收到 3 到 10 条
- 组装与生成:拼上下文、调用生成模型、流式返回
- 后处理:把引用编号映射回原文位置、敏感词过滤、埋点
旁路有三块:缓存(嵌入、检索结果、答案)、可观测(每次请求落一条 trace)、反馈采集(点赞点踩、引用点击)。
部署形态有三条路,判断依据是数据合规等级、日请求量,以及团队有没有 GPU 运维能力。
| 形态 | 组成 | 优势 | 代价 |
|---|---|---|---|
| 全托管 | 云向量库加模型接口 | 上线快,无运维 | 数据出境与合规风险,单次成本高,容易被厂商锁定 |
| 全自建 | 本地模型加自建向量库 | 数据不出内网,单次成本可控 | 要养 GPU 与运维,效果调优全靠自己 |
| 混合 | 本地嵌入与检索,云端生成 | 兼顾合规与效果 | 链路更长,两套运维 |
验证阶段用全托管最快;规模化之后,通常是每天几十万次请求这个量级,自建的边际成本才开始低于按次调用。金融、政务、医疗这类有数据出境约束的场景,嵌入模型必须本地部署——检索用的片段会进嵌入模型的输入,这一步同样算数据出境,容易被漏掉。
同步与异步要分开。索引、重建、评测、批量回填都走异步任务队列,Web 进程只处理在线查询。把索引任务塞进 Web 进程是很常见的起步做法,代价是部署时会和查询抢资源,失败重试也没有地方挂。
多租户的隔离有三个级别,选择取决于租户数量和合规要求。
| 级别 | 做法 | 隔离强度 | 代价 |
|---|---|---|---|
| 库级 | 每个租户一套库或索引 | 最强,物理隔离 | 资源浪费,跨租户检索做不了 |
| 表级 | 同库不同表或分区 | 强,运维简单 | 租户多时元数据膨胀 |
| 行级 | 同一张表加租户字段强制过滤 | 最弱,依赖过滤条件不出错 | 最省资源 |
行级隔离的失效方式很典型:某条查询路径忘了拼过滤条件,或者拼接条件时被注入绕开,结果就是越权。这件事必须在检索层做,而不是生成层——等到生成层再过滤,片段已经进了上下文,答案里可能已经带上去了。同时要为”过滤条件写漏”专门写测试用例。
可观测的最低要求是每次请求落一条 trace:原问题、改写后的查询、两路召回的前若干候选及分数、重排后的顺序、最终进入上下文的片段 id、每部分 token 用量、首 token 延迟与总延迟、是否拒答、用户反馈。没有这条 trace,排查只能靠猜;有了它,后面那套按症状分类的排查方法才落得下去。
缓存分四层,失效策略各不相同。嵌入缓存按内容哈希做键,基本不会失效;检索结果缓存按查询、权限标签、索引版本三者做键,索引更新时整体失效;答案缓存必须带权限维度,否则会越权;模型侧的前缀缓存由推理框架管理,对固定的系统提示词收益最大。
五、分块:最被低估的一步
分块要把文档切成”语义自洽、又足够聚焦”的单元。这里有一对天然矛盾。
检索希望块小。块越大,一个向量要承载的语义越多,向量越糊——检索本身是拿查询和块做相似度比较,块里混的主题越多,匹配越不准。
生成希望块大。块太小,答案需要的上下文被切散,模型看到的证据不完整,容易答错或答不完整。
同时满足两边做不到,工程上的出路是把检索粒度和生成粒度解耦。
| 做法 | 检索单元 | 送给模型的单元 | 适用场景 |
|---|---|---|---|
| 固定长度加重叠 | 固定窗口 | 同一个窗口 | 起步方案,结构简单的文本 |
| 按结构切分 | 标题或段落 | 同一段落 | Markdown、技术文档、法规 |
| 小块检索大块生成 | 句子或小块 | 所在段落或整节 | 通用方案,最稳妥 |
| 命题级 | 拆成原子陈述 | 若干命题 | 事实密集的语料 |
| 上下文增强块 | 块加所属文档摘要 | 增强后的块 | 指代缺失严重时 |
几条具体经验。
重叠是廉价的保险。固定长度切分时留 10% 到 20% 的重叠,能明显减少答案正好被切在边界上的情况,代价是索引体积变大。
按结构切优于按长度切。Markdown 标题、代码函数边界、合同的条款项都是天然语义边界,顺着它们切比按字符数切准确得多。
小块检索加大块生成是通用解。用 256 token 左右的块做检索,命中后把它所在的段落或整节(800 到 2000 token)送给模型,检索的聚焦性和生成的完整性可以同时拿到。
上下文缺失是这里最隐蔽的失败。一个片段写着”该参数默认为 5”,这个”该”指的是上一节讲的东西——片段被检索到了,模型依然不知道它在说什么。常见的修法有两种:给每个片段拼一段由模型生成的简短上下文说明,或者给块加上标题路径作为前缀。这类做法对召回的提升很明显,代价是索引阶段要为每个片段额外跑一次模型,成本按语料规模线性上升。
元数据不是附属品。来源、章节路径、文档类型、生效时间、权限标签,这些字段决定了能不能做过滤,而过滤往往是企业场景里提升精度最快的手段。
参数起步值与按文档类型的切法
| 参数 | 起步值 | 调整方向 |
|---|---|---|
| 检索块大小 | 300 到 500 字(约 256 到 512 token) | 召回不足就再切小,证据不完整就切大 |
| 块间重叠 | 10% 到 20% | 边界切断答案的情况多就加大 |
| 生成块大小 | 800 到 2000 字 | 答案常缺上下文就加大 |
| 每块携带的元数据 | 来源、章节路径、版本、权限标签 | 按过滤需求加,这一层不要省 |
不同文档的切法差别很大:
- 结构化文档(Markdown、HTML):按标题层级切,把标题路径写进块的前缀
- 合同与法规:按条、款、项切,条款编号必须留在块内,跨条款的引用也要保留
- 代码:按函数、类、方法切,把文件路径和函数签名放进块里
- 表格:不要按行切散。整表一块往往太大,常见做法是把表头与每一行拼成一句自然语言再切
- FAQ 与工单:一问一答一块。这类文档自带问答对,也是最省事的高质量语料
六、嵌入模型:怎么选、容易踩什么坑
嵌入模型把文本映射到向量空间,语义相近的文本在这个空间里距离近。相似度通常用余弦相似度衡量:
$$\text{sim}(q, d) = \frac{q \cdot d}{\lVert q \rVert \, \lVert d \rVert}$$
训练方式是对比学习:一个问题与它对应的正确段落构成正样本对,同一批数据里其他段落作为负样本,训练目标是让正样本对的相似度高于负样本:
$$\mathcal{L} = -\log \frac{\exp(\text{sim}(q, d^{+}) / \tau)}{\exp(\text{sim}(q, d^{+}) / \tau) + \sum_{i=1}^{n} \exp(\text{sim}(q, d_{i}^{-}) / \tau)}$$
负样本的质量直接决定模型好坏,这也是后来大量工作在做难负样本挖掘的原因。
选型要看这几个维度。
| 维度 | 说明 |
|---|---|
| 语言与领域 | 中文场景直接选在中文语料上训练过的模型;通用模型在法律、医疗、代码上普遍偏弱 |
| 维度 | 常见 384 到 4096 维。维度决定索引显存,支持截断的模型可以按需降维 |
| 长度上限 | 决定单块能有多大。多数模型上限 512 token,长块方案需要 8k 以上的模型 |
| 是否指令化 | 带指令的模型可以用一句任务描述换整体表现,指令写错会掉点 |
| 输出类型 | 有的模型同时输出稠密、稀疏、多向量三种表示,便于做混合检索 |
有三个坑值得单独说。
查询与文档不对称。相当一部分嵌入模型是按非对称检索训练的:查询侧和文档侧要加不同的前缀,或者走不同的编码路径。漏加前缀不会报错,只会让召回率凭空掉一截,而排查时很难想到是这个原因。这类约定写在模型的说明文档里,不在代码里。
换了模型没重建索引。索引里的向量和查询向量换模型后就不在同一个空间里了,相似度计算失去意义,但系统仍然能返回结果——只是全都无关。向量必须和模型版本绑定,版本号记在索引的元数据里。
拿榜单当结论。嵌入模型有大规模的公开评测榜(MTEB 一线),但榜单覆盖的任务和具体业务差得远,榜单本身也会被针对性优化。更可靠的做法是拿几百条真实查询做小规模评测,看在自己数据上的召回率。同一份数据上,一个针对性微调过的小模型经常打赢通用的大模型。
把全量语料灌进索引是一次性批处理,工程上有几个必须处理好的点。
幂等。用内容哈希或”文档 id 加版本号”作为片段主键,重跑不会产生重复向量。批量任务中断是常态,正确性不能建立在”跑之前先清空”上。
限流与重试。嵌入接口有速率限制,批大小取 32 到 128 条、并发控制在个位数比较稳妥;失败的批次要能单独重试,而不是整批回滚。更常见的做法是按文档切批次、每篇文档独立提交,失败的文档进重试队列。
成本要提前算。嵌入按 token 计费,成本是语料总 token 数再乘一遍分块重叠带来的系数。一份一亿 token 的语料按 1.2 倍估算就是一点二亿 token 的输入量,这个数字决定了失败的代价和重建的频率。
归一化要统一。不少模型的输出没有归一化,而索引和距离度量默认按余弦相似度工作。入库前统一做 L2 归一化,距离度量选余弦或内积,能消掉这一层不确定性。
七、索引与最近邻检索
向量检索要解决的是最近邻问题,精确计算需要和每个向量比较一遍,复杂度是 O(N·d),语料上千万时无法接受,所以都用近似最近邻,在召回率、延迟、内存之间做交易。
| 索引 | 结构 | 特点 | 关键参数 |
|---|---|---|---|
| 扁平索引 | 暴力计算 | 召回百分之百,十万以内可用 | 无 |
| HNSW | 分层图 | 查询快、召回高、内存占用大 | M、ef_construction、ef_search |
| IVF | 聚类倒排 | 省内存、需要训练、召回依赖探测数 | nlist、nprobe |
| IVF-PQ | 聚类加乘积量化 | 内存能压到十分之一以下,有精度损失 | 子空间数、每子空间比特数 |
| DiskANN | 图加磁盘 | 单机可放十亿级,延迟略高 | 内存驻留比例 |
实用的判断有这么几条。
一百万向量以内,PostgreSQL 的 pgvector 就够用,没有必要上分布式向量库。单独运维一套系统的成本,通常超过它省下的那点延迟。
HNSW 是默认选择,其中 ef_search 是延迟与召回之间的旋钮,调大召回上升、延迟上升。这个参数要按业务实测,不要用默认值直接上线。
内存不够时先考虑量化,再考虑换系统。乘积量化把每个子空间用极少比特编码,代价是距离估计有误差,需要搭配重排来补回精度。
过滤是这里最容易被忽略的陷阱。业务查询几乎都带条件——只看某个租户的、只看最近一年的、只看已发布版本的。在图的遍历过程中做过滤会出问题:符合条件的结果之间可能没有连边,图的搜索会走死,召回率断崖式下降;先向量检索再过滤,则可能过滤完只剩两条。较新的索引结构(ACORN 一线)把谓词和图的连接联合考虑来专门解决它。工程上常见的折中是:把高频过滤字段做成独立的子索引或分区,或者把候选集开得足够大再做过滤。
以 PostgreSQL 加 pgvector 为例,最小可用的结构是这样:
CREATE TABLE chunks (
id bigserial PRIMARY KEY,
doc_id text NOT NULL,
content text NOT NULL,
meta jsonb NOT NULL, -- 来源、章节路径、权限标签、生效时间
embedding vector(1024) NOT NULL,
content_hash text NOT NULL UNIQUE -- 幂等去重
);
CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 200);
CREATE INDEX ON chunks USING gin (meta);
参数起步值:m 取 16,召回不够往上调到 32 或 64,代价是内存;ef_construction 取 200,建索引慢一些但图的质量更好。在线延迟与召回的平衡由查询时的 SET LOCAL hnsw.ef_search = 64 控制,这个值必须按业务实测,从 40 开始往上试。
容量算术要提前做。1024 维单精度向量是 4 KB,一百万条就是 4 GB,再加上图结构的连边开销,常驻内存通常在 6 GB 上下;换成半精度直接省一半。这就是”内存不够先量化”的具体含义。
过滤条件要分层处理。高频、基数小的字段,比如租户、文档类型、是否删除,做成物理分区或独立子索引;时间范围这类条件留在查询的条件里;权限标签这类会频繁变化的过滤放在检索之后做二次筛选,同时把候选集开大一些,比如召回从 50 提到 200,来抵消过滤造成的损失。
八、混合检索:稠密不是全部
稠密检索擅长语义相近,但有一类查询它系统性地做不好:精确匹配。产品型号、错误码、人名、函数名、合同编号、版本号这类 token 没有语义可循,靠向量相似度就是碰运气。反过来,纯词法检索对同义改写、跨语言、口语化提问无能为力。
BM25 是词法检索的事实标准,也是被长期低估的基线。它给每个词算一个权重,再按词频和文档长度做衰减:
$$\text{score}(q, d) = \sum_{t \in q} \text{idf}(t) \cdot \frac{f(t, d) \cdot (k_1 + 1)}{f(t, d) + k_1 \cdot \left(1 - b + b \cdot \frac{|d|}{\text{avgdl}}\right)}$$
其中词权重衡量这个词有多罕见:
$$\text{idf}(t) = \log \frac{N - n(t) + 0.5}{n(t) + 0.5}$$
$k_1$(词频饱和,常用 1.2 到 2.0)和 $b$(长度归一化,常用 0.75)是两个按语料调的旋钮。BM25 的关键优势是:不需要训练、不需要 GPU、对罕见词天然敏感,而且被打磨了几十年。
工程上的默认配置是两条路都跑,再融合结果。融合方式里最简单可靠的是倒数排名融合:
$$\text{RRF}(d) = \sum_{r \in R} \frac{1}{k + \text{rank}_{r}(d)}$$
它只用排名、不用分数,因此不需要在不同检索器的打分之间做归一化。这一点很重要:余弦相似度和 BM25 分数完全不在一个量纲上,硬做加权归一化既脆弱又难调。常数 $k$ 通常取 60。
还有一条中间路线值得知道:可学习的稀疏表示(SPLADE 一线)。它保留倒排索引的形态,部署成本和 BM25 一样低,但词的权重由模型学出来,还支持把查询词扩展到相关词,因此兼顾了词法的精确和语义的泛化。
参数起步值:BM25 的 k1 取 1.5、b 取 0.75,长文档居多的语料把 b 调到 0.5 到 0.7;两路各取 50 个候选;融合用 RRF 时 k 取 60;融合后进重排的候选控制在 50 到 100。
有一类场景可以只用 BM25:语料里到处都是型号、编号、错误码,用户查询也基本是这类精确词。此时加一路向量检索收益很小,却要多维护一份索引、多一份延迟。反过来,如果查询以自然语言问句为主、语料是叙述性文本,向量检索是主力,BM25 的价值在于兜住那些被向量模型忽略的罕见词。
九、重排:投入产出比最高的一步
召回和排序对模型的要求不同。召回要快、要覆盖,所以用双塔结构:查询和文档各自独立编码成向量,相似度是事后算的点积。文档向量可以离线算好,代价是查询和文档从来没有真正见过面,无法建模词与词的交互。
重排用交叉编码器:把查询和文档拼在一起送进模型,让注意力在两者之间自由交互,直接输出相关性分数。准确率明显更高,但每个候选都要单独跑一次前向,无法预计算,因此只能用在候选集上。
标准的做法是两段式:先用便宜的方法召回 50 到 200 个候选,追求召回率;再用交叉编码器逐个打分,取前 3 到 10 个,追求精度。
这一步的收益通常大于换嵌入模型。换嵌入模型的收益是渐进的,而且需要重建全量索引;加一个重排器是即时的,只影响在线链路。代价在延迟上:对 100 个候选做交叉编码通常在几十到几百毫秒,随候选数和文档长度增长。常见的折中是重排 50 个候选、每段截断到 512 token。
介于两者之间还有一类方案:延迟交互(ColBERT 一线)。它为每个 token 生成向量,打分时对查询的每个 token 在文档里取最大相似度再求和:
$$\text{score}(q, d) = \sum_{i \in q} \max_{j \in d} E_{q_{i}} \cdot E_{d_{j}}^{\top}$$
文档侧可以离线预计算,所以既有双塔的速度,又有接近交叉编码器的精度。代价是存储膨胀——每个 token 一个向量,索引体积比单向量方案大一到两个数量级;后续工作用向量压缩和残差量化把这个代价压了下去。
工程上的取值:候选 50 到 100 个,每个候选截断到 512 token(超出的部分对相关性判断贡献很小),批量打分而不是逐条调用,批大小 8 到 16。这样一组参数在中等规模的模型上,整段重排的延迟大致在 100 到 300 毫秒。
重排模型不必和嵌入模型同源,但要用同一套标注数据评测。上线时必须留降级路径:重排服务超时就退回融合后的顺序,宁可用略差的排序,也不能让整个请求失败。
十、查询侧:用户的问题不能直接拿去检索
用户输入是对话,检索需要的是自洽的查询,两者之间通常要过一道转换。
| 处理 | 解决的问题 | 代价 |
|---|---|---|
| 改写与指代消解 | 多轮对话里的”它””那个方案” | 一次模型调用 |
| 多查询扩展 | 单次改写覆盖不全 | 检索次数翻倍 |
| 假设答案检索 | 问句和文档措辞差距大 | 生成内容偏了会带偏检索 |
| 问题分解 | 多跳问题需要多个子查询 | 多轮检索与融合 |
| 查询路由 | 不知道该查哪个库、要不要查库 | 需要规则或训练 |
| 条件抽取 | 从问题里抽时间、实体等过滤条件 | 抽错会直接漏掉正确文档 |
几个值得展开的点。
假设答案检索(HyDE 一线)的机制是让模型先写一段假设的答案,再拿这段答案去检索,而不是拿问题去检索。理由是问答文本和文档文本的措辞分布不同:问题短、口语化,文档长、陈述式,生成的假设答案在文体上更接近真实文档。机制也说明了它的风险——假设答案如果编错了方向,检索会被带到完全无关的区域。它适合”模型有相关知识但表述不匹配”的场景,不适合模型完全不懂的领域。
多跳问题需要分解。”某公司的创始人在哪所大学读书”需要两步:先查出创始人,再用创始人姓名查学校。单次检索无论怎么调 k 都拿不到完整证据,因为第二步的查询词依赖第一步的答案。这类问题要么用迭代检索(检索、读、生成新查询、再检索),要么用多查询并行检索再融合。
有一类问题不该检索。问候、闲聊、纯计算、纯创作,检索只会引入噪声。明确判断”无需检索”能省掉延迟,也能避免无关上下文污染答案——前面已经说过,无关上下文会让答案更差。
十一、组装上下文与生成
检索完成之后,片段怎么摆进提示词,效果差别很大。
排序要讲究。模型对上下文中段的敏感度最低,所以把最相关的证据放在最前面或最后面,比随机排列好。有的系统直接把重排结果反过来插,实现上就是把列表倒序交替放置。
去重和压缩要做。多个片段内容重复是常态,同一段话在不同文档里各有一份,重复会挤占预算。更激进的做法是在送入模型前对片段做摘要或句子级抽取,用更少的 token 承载同样的证据,代价是可能删掉后面才用得上的细节。
引用要可核查。让模型在答案里标注每句话的依据来自哪个片段,这既是产品需求,也是质量手段:模型被迫对齐证据,编造会更容易暴露。实现上一般给片段编号,要求输出形如”依据 3”这样的标注,再由前端把编号映射回原文位置。
必须允许说没有。提示词里要明确:只能依据给定片段作答,片段里没有就说没找到。少了这一条,检索失败时模型会用参数记忆补一个看起来合理的答案——这种错误比直接拒答更危险,因为它看起来同样自信。
检索结果必须当成不可信输入。这是安全问题,不是提示词技巧:文档内容会被原样拼进提示词,如果语料里有一份恶意文档,标题里写着让模型忽略之前的指令、把用户数据发到某个地址,它就会以高优先级出现在上下文里。检索系统的攻击面因此从模型本身扩展到了整个语料库。缓解手段包括:在结构上区分指令和数据,把文档放进明确的定界符内并说明这些内容只是资料;对来源做权限和可信度管理;在输出侧做检测。接入邮件、工单、外部网页这类数据源时,这件事尤其重要。
上下文预算要提前分配,不能让检索结果随便挤占:
| 部分 | 建议占比 | 说明 |
|---|---|---|
| 系统指令与格式要求 | 5% 到 10% | 固定内容,适合做前缀缓存 |
| 检索到的资料 | 60% 到 75% | 主要预算,按重排顺序填充 |
| 对话历史 | 10% 到 20% | 多轮场景才有,要能截断 |
| 输出预留 | 10% 到 15% | 留不够会导致回答被硬截断 |
资料部分如果装不下,就按分数从低到高整块丢弃,不要把某一块截成半句——半个句子比少一块更容易让模型误读。
十二、什么时候简单的 RAG 不够
朴素 RAG 是”检索一次、生成一次”。它在三类问题上会失效:需要跨多个文档汇总的全局性问题、需要多步推理的复杂问题,以及需要判断检索结果本身够不够好的场景。
迭代与自我纠错。Self-RAG 的思路是让模型输出反射标记:判断是否需要检索、检索到的片段是否相关、答案是否被证据支撑,用这些标记控制流程。CRAG 在外面挂一个轻量的检索评估器,先判断召回质量,质量差就触发补充检索。共同点是把”检索够不够好”变成一个可判断、可重试的步骤,而不是一个隐含假设。
图结构检索。GraphRAG 这类做法在索引阶段用模型抽实体和关系建成知识图,再对图做社区划分、为每个社区生成摘要。它解决的是全局性问题——这份语料主要在讲什么、哪几个主题之间存在关联——这类问题靠向量检索答不了,因为没有任何一个片段包含答案,答案分散在成百上千个片段里。代价是构建成本高,每个片段都要过一遍抽取,之后还要跑一轮社区摘要,增量更新也麻烦。它适合语料相对稳定、问题偏分析型的场景。
智能体式检索。把检索作为工具交给模型,由模型决定查不查、查什么、查几轮,中间可以读结果、改写查询、再查。灵活性最高,代价是延迟和成本都不可控,每一轮都要一次模型调用,而且需要防住死循环。
结构化数据。表格数据的正确解法通常不是 RAG。能写 SQL 的数据用文本到 SQL,把问题翻译成查询语句再执行,准确性和可解释性都更好;半结构化的表格可以先检索到相关行再做计算。把整张表塞进向量库做相似度检索是很常见的误用。
十三、评估:先量召回,再谈生成
RAG 的评估难点在于”好”是多层的:检索对不对、答案有没有依据、有没有回答问题,是三个独立维度。
先分开量。检索侧用召回@k,即 top-k 里包含正确片段的查询占比:
$$\text{Recall@}k = \frac{|D_{\text{相关}} \cap D_{\text{top-}k}|}{|D_{\text{相关}}|}$$
这一步不能省。如果召回@10 只有六成,那么无论提示词怎么写、模型换多强,四成的问题注定答不对,因为证据根本没进上下文。把召回和生成分开量,才知道该修哪一端。
生成侧看两个维度:忠实度,即答案里的每个断言能否在检索到的上下文里找到依据;相关性,即答案是否回应了问题。公开的评测框架(RAGAS 一线)为这两个维度提供了自动化近似指标,做法是用模型充当裁判,把答案拆成原子断言再逐条核对上下文。
用模型当裁判要留出误差预算。裁判模型有自己的偏好,倾向于给长答案和格式漂亮的答案更高分,也会偏向与自己风格一致的输出,同一份答案换个提示词模板就可能差几分。所以它适合做趋势对比——这个改动让忠实度上升还是下降——不适合当绝对分数,关键结论要抽样人工核对。
测试集从哪来。真实查询日志最贴近生产,但项目早期没有;从文档反向生成问题能快速铺量,缺点是生成的问题和文档措辞高度相似,天然好检索,指标会虚高;人工标注最难,也最能发现真正的失败模式。常见的做法是从日志里取真实问题,让标注人员标出应该被检索到的片段,这个过程同时建立了检索侧的黄金集。
把评测做成能重复跑的脚本,每次改动输出同一张表:召回@1、召回@5、引用准确率、平均延迟,以及每类问题的失败条数。黄金集起步 50 到 200 条真实问题,覆盖查询的主要类型:精确词查询、口语化改写、多跳、无答案。最后这一类必须专门放,它检验的是系统会不会编。
线上要埋三种信号:用户有没有点开引用链接(说明证据被认可)、有没有重新提问(说明上一次没答好)、有没有转人工。这三个信号的绝对值意义不大,趋势才有意义。
十四、成本、延迟与运维
延迟预算要拆开看,否则优化没有方向。一次普通的问答请求大致是这样:
| 环节 | 典型量级 | 备注 |
|---|---|---|
| 查询改写与扩展 | 100 到 500 毫秒 | 一次小模型调用 |
| 查询嵌入 | 10 到 50 毫秒 | 与嵌入模型大小相关 |
| 向量检索 | 5 到 50 毫秒 | 与索引类型、ef_search 相关 |
| 重排 | 50 到 500 毫秒 | 与候选数、模型大小强相关 |
| 生成 | 通常占大头 | 与输出长度线性相关 |
几个能显著改变成本的点。
前缀缓存。RAG 的提示词通常是一段固定的系统指令,加上变化很小的格式说明,再拼上检索到的片段。把固定前缀做成缓存,后续请求可以直接复用,在长系统提示词的场景下能省下大量首 token 延迟和计算。
缓存要分层。查询嵌入可以缓存,同一句话重复出现的概率不低;检索结果也可以缓存,但要注意语料更新,需要设置过期或版本号;答案级缓存要谨慎,权限不同的用户拿到同一份缓存答案会直接造成越权。
重建索引的代价。更换嵌入模型意味着全量重算向量,语料越大越贵。工程上要保留原始片段和模型版本号,让重建成为可以分批、可以灰度的事情,而不是一次停服操作。
删除和权限必须传导到索引。文档被删掉、权限被收回之后,它在索引里必须同步消失,否则检索会把它当证据送给模型。这不是性能问题,是合规问题。多租户场景还要保证隔离在检索层就成立,而不是靠生成层过滤。
嵌入不是匿名的。已经有研究证明,从嵌入向量可以还原出相当比例的原文。把嵌入当成”脱敏后的向量”处理是有风险的,敏感字段应当在入库前就处理掉。
容量和时间的账要在动手之前算一遍:
| 项目 | 估算方式 | 十万个片段、1024 维的举例 |
|---|---|---|
| 向量内存 | 片段数 × 维度 × 4 字节 | 400 MB,加图结构约 600 MB |
| 嵌入成本 | 语料 token 数乘单价 | 一次性支出,重建频率由语料更新速度决定 |
| 全量重建耗时 | 语料 token 数 ÷ 吞吐 | 8 并发、每分钟 20 万 token,1.2 亿 token 约 10 小时 |
| 增量写入 | 单条或小批插入的延迟 | pgvector 单条毫秒级,小批更省 |
索引切换用双写加灰度,不要原地更新。做法是新建一份索引、按比例切流量过去、观察召回与延迟,确认后再下线旧索引。原地更新一旦出错,回滚要重建,代价远大于多留一份存储。
增量更新要处理三类事件。新增文档直接插入片段;修改文档按 doc_id 删旧插新;删除文档必须同步删除,包括缓存里和已经拼好的上下文。修改还有一个细节:先删后插会出现短暂的空窗,先插后删会出现短暂的重复,两种都可以接受,但要明确选哪一种并在评测里容忍它。
十五、上线顺序与排查
从零搭一套 RAG 不需要一开始把所有环节都做齐。按收益排,顺序大致是:
- 先让链路跑通:固定长度分块、只用 BM25、直接拼上下文。这一步的价值在于把评测跑起来,拿到第一版召回率
- 补上向量检索与融合。通常带来最明显的一次召回提升
- 加重排。候选从 50 缩到 5,精度提升明显,且只动在线链路
- 修分块。按结构切、小块检索大块生成,这一步的收益常常大于换模型
- 加查询改写。多轮对话场景必须做,单轮场景收益有限
- 前面都做完之后再考虑图检索、智能体式检索这类架构
每一档都要用同一份黄金集评测,否则无法判断改动是不是真的有效。
排查按症状分四类,定位方法各不相同。
症状一:正确答案没被检索到。先查分块——把正确的文档切开看,答案是不是被切在两个块之间,或者块内出现了失去上下文的指代。再查查询——用户原话和文档表述差多远,差得远就该上改写或 HyDE。最后查检索——把两路召回的候选分别打出来,看正确块分别排在第几位。这一步最有效的手段是把前 20 个候选连同分数打印出来人工看一遍,比盲调参数快得多。
症状二:正确块被检索到,但排在后面。这是重排的用武之地。对照看重排前后的位置:如果重排前在第 8 位、重排后进了前 3,说明候选集是够的;如果重排前后都在第 8 位,说明这个重排模型不适用于该领域,需要换模型或补领域数据微调。
症状三:证据齐全,答案还是错的。问题多半在组装和提示词上。检查关键证据是不是被埋在了上下文中间,做法是拿最相关的块做一次放在开头、放在中间、放在结尾的对比实验;检查提示词有没有明确要求只用资料作答;检查资料和指令有没有在格式上混在一起。还有一种情况是资料里确实有答案但模型没识别出来,验证方法是把资料里的关键句单独拿出来问一遍,如果这样能答对,那就是上下文组织的问题。
症状四:答案对了但引用错。通常是编号与片段的映射出了问题,或者模型复述时挪用了别的片段。修法是缩短单块长度、减少同时给的片段数(3 到 5 块通常比 10 块更容易对齐),并在评测里单独统计引用准确率。
还有一个跨症状的通用做法:每次失败案例都按上面四类归档,积累一段时间后,哪一类最多就先修哪一类。这条经验比任何单项调参都更省时间。
十六、技术选型
选型的原则是能少一个组件就少一个,而不是按功能列表逐项打勾。下面按层给出主流选择和各自的真实代价。
编排层
| 方案 | 定位 | 优势 | 代价 |
|---|---|---|---|
| LangChain | 通用编排框架 | 集成与连接器最多 | 抽象层多、迭代快,出问题定位链路长 |
| LlamaIndex | 面向检索的数据框架 | 索引与检索抽象成熟,RAG 组件齐 | 深度定制时要读源码 |
| Haystack | 流水线式框架 | 结构清晰,生产取向 | 生态规模小一些 |
| Dify、RAGFlow、FastGPT | 开箱产品 | 上手快,自带知识库管理与界面 | 定制受产品形态限制 |
| 只依赖向量库与模型 SDK | 手写编排 | 可控、好排查、依赖少 | 前期开发慢 |
一个常见的路径是:用产品或框架做原型,跑到生产之后逐步收敛成手写编排加成熟向量库加模型 SDK。原因是 RAG 的失败大多发生在数据层和参数层,而不是编排层,框架在这类问题上反而增加定位成本。
向量库与检索引擎
| 方案 | 许可证 | 适合规模 | 特点 |
|---|---|---|---|
| pgvector | PostgreSQL 许可 | 百万级 | 与业务数据同库,事务一致,运维零增量 |
| Qdrant | Apache 2.0 | 千万级 | 过滤与混合检索设计扎实,单机部署轻 |
| Milvus | Apache 2.0 | 亿级 | 分布式,组件多,运维复杂度高 |
| Weaviate | BSD-3 与自有许可混合 | 千万级 | 内置混合检索与向量化模块 |
| Chroma、LanceDB | Apache 2.0 | 十万级 | 嵌入式,适合单机应用与原型 |
| Elasticsearch | Elastic 许可 | 千万级 | 全文检索最强,向量是后加的能力 |
| OpenSearch | Apache 2.0 | 千万级 | 上一条的开源分支 |
| 云托管服务 | 商业 | 不限 | 免运维,要评估数据出境与长期成本 |
许可证这一列要看仔细。Elasticsearch 从 7.11 起改用 Elastic License 与 SSPL,对外提供托管服务有约束,OpenSearch 分支就是这么来的;Dify、FastGPT、MinerU 都是 Apache 2.0 加附加条款,明确限制了多租户 SaaS 场景和 LOGO 修改;Arize Phoenix 用的是 Elastic License 2.0,不属于开源许可证;Langfuse 主体是 MIT,ee 目录下是商业许可。选之前读一眼 LICENSE,比事后换组件便宜得多。
嵌入与重排
中文场景按尺寸分三档。选型时在同一份黄金集上跑召回对比,多数情况下”中等尺寸加一个重排器”优于”最大尺寸不加重排”。
| 档位 | 代表 | 特点 |
|---|---|---|
| 小 | bge-small-zh、m3e-small 一类 | 延迟低,可 CPU 推理,适合海量语料的第一轮召回 |
| 中 | bge-large-zh-v1.5、bge-m3、GTE 系列、Qwen3-Embedding 0.6B | 通用主力;bge-m3 同时输出稠密、稀疏、多向量 |
| 大 | Qwen3-Embedding 4B 与 8B、各家接口的旗舰嵌入模型 | 效果优先,需要 GPU,索引重建代价高 |
重排这一档:bge-reranker 系列(base 与 large)、mxbai-rerank,以及 Cohere、Jina 这类托管接口。本地部署的重排模型通常在 0.3B 到 2B 之间,延迟与效果同步上升。
文档解析
| 文档类型 | 可选工具 |
|---|---|
| 纯文本、Markdown、HTML | 标准库或 unstructured 足够 |
| 版式规整的 PDF | PyMuPDF 一类直接抽取 |
| 双栏、表格、公式的 PDF | MinerU、marker、Docling,或云端版面分析接口 |
| 扫描件 | 先 OCR,再做版面分析 |
解析质量对最终效果的影响经常被低估。同一份 PDF,抽出来的正文顺序错了,后面再好的模型也救不回来。语料里有表格和扫描件时,解析环节值得单独评测。
十七、模型选择
嵌入模型
按顺序问五个问题就能把候选收到两三个:数据能不能出内网;语料主要是什么语言;领域词汇和通用语料差多远;单块最长多少 token;能接受的索引内存是多少。剩下的交给黄金集量化。
需要微调嵌入模型的信号只有一类:在自己的数据上召回@10 明显低于同规模模型在公开基准上的水平,而且换分块方式、加查询改写都救不回来。做法是用查询与正例片段构成样本对做对比学习,负例取同批其他片段再加难负样本。代价是索引要全量重建,要先算清值不值。
重排模型
选型看三个数:候选数、延迟预算、提升幅度。0.3B 级别的模型对 50 个候选打分通常在几十毫秒,2B 级别要到几百毫秒。有时值得做两级重排:小模型把 200 个候选收到 20 个,大模型再从 20 个收到 5 个,总延迟比让大模型直接处理 200 个低得多。
生成模型
RAG 对生成模型的要求和通用对话不同,要专门看四点:
- 指令遵循:能不能守住”只用资料作答”。这不是所有模型都做得到
- 拒答倾向:资料里没有时会不会说没有,还是顺着问题编
- 长上下文下的信息保持:资料变长之后,中间位置的证据还能不能用上
- 引用与格式的稳定性:能否稳定输出规定的标注格式
一个实用的顺序是先用能力最强的闭源模型跑通全链路,把上限和基线立起来;再用可自建的开源模型(Qwen、DeepSeek、Llama 这几条线)去逼近,差距用提示词和微调补。判断标准分三层:换模型后只有引用格式变差,微调格式就够;答案是散的、抓不住重点,先检查上下文组装;连”只用资料作答”都守不住,这个模型不适合这个位置。
微调生成模型的时机要晚。语料质量、分块、检索参数都没调好之前做微调,等于把一个坏系统的行为固化下来。
十八、应用落地
不同场景的重点差别很大。
| 场景 | 核心难点 | 架构要点 | 验收看什么 |
|---|---|---|---|
| 企业内部知识库 | 权限复杂、语料来源杂、没人维护 | 检索层做权限过滤,增量同步,解析流水线 | 首答解决率、转人工率 |
| 客服与售后 | 要跟订单、工单这类结构化数据联动 | 意图路由,结构化查询与 RAG 分工 | 自助解决率、一次解决率 |
| 法律与合规 | 引用要精确到条款,版本时效性强 | 条款级分块,按生效时间过滤,强制引用 | 引用准确率、漏检率 |
| 医疗与金融 | 拒答优先,全程留痕 | 提高拒答阈值,人工复核队列,审计日志 | 有害回答率,这一项必须零容忍 |
| 代码助手 | 检索单元是符号而不是段落 | 按函数与类切分,带上调用关系,与 IDE 集成 | 采纳率、编译通过率 |
| 数据分析 | 表格与文本混在一起 | 文本转查询与 RAG 分工,指标口径统一 | 查询正确率 |
落地的顺序建议是这样:
- 选一个窄场景,有明确的用户和可量化的目标。一上来做”全公司知识助手”的失败模式太多,没法定位
- 用 50 到 200 条真实问题建黄金集,先量出基线
- 内部灰度,收集失败案例并按前面四类归档
- 按上线顺序逐项改进,每一项都用同一份黄金集验证是否真的有效
- 接入业务指标——解决率、转人工率、平均处理时长,而不是只看回答质量
- 明确语料维护责任:谁负责更新文档、谁批准权限、谁处理过期知识
两个组织层面的坑值得提前说。一是语料没人维护比选错技术更致命,知识过期之后系统表现会持续下滑,而且没有技术手段能补。二是把 RAG 当搜索用:用户其实只想找到那份文档,系统却非要给一段总结,反而增加核对成本。有些场景里,把检索结果以列表加高亮的形式直接返回,比生成答案更有用。
十九、开源参考项目
下面这些项目的定位、许可证与活跃度数据取自各仓库(2026 年 10 月)。读这些项目时,先看它的分块实现和检索实现,那是 RAG 的核心;界面和部署脚本次要。
全栈问答产品:
| 项目 | star | 许可证 | 定位 |
|---|---|---|---|
| RAGFlow | 92k | Apache 2.0 | 从深度文档理解切入的 RAG 引擎,解析环节做得最细 |
| Dify | 159k | Apache 2.0 加附加条款 | LLMOps 平台,含 RAG 流水线与工作流编排 |
| Open WebUI | 156k | 自定义许可,BSD 风格加品牌条款 | 面向自建模型的对话界面,带知识库能力 |
| AnythingLLM | 67k | MIT | 桌面与自托管一体的个人或团队知识库 |
| Khoj | 38k | AGPL-3.0 | 面向个人知识(笔记、邮件、文档)的检索问答 |
| FastGPT | 30k | Apache 2.0 加附加条款 | 中文知识库问答,流程编排与知识库管理完整 |
| QAnything | 14k | AGPL-3.0 | 中文问答系统,中文语料处理有积累 |
框架与库:
| 项目 | star | 许可证 | 定位 |
|---|---|---|---|
| LangChain | 148k | MIT | 通用编排框架,集成最多 |
| LlamaIndex | 53k | MIT | 面向 RAG 的数据框架,索引与检索抽象最全 |
| Haystack | 27k | Apache 2.0 | 流水线式框架,生产取向 |
| txtai | 13k | Apache 2.0 | 语义搜索与检索一体,依赖轻 |
| R2R | 8k | MIT | 生产取向的检索系统封装,更新节奏已放缓 |
向量检索:
| 项目 | star | 许可证 | 定位 |
|---|---|---|---|
| Milvus | 46k | Apache 2.0 | 分布式向量库,面向亿级规模 |
| Qdrant | 35k | Apache 2.0 | 过滤与混合检索做得扎实 |
| Chroma | 30k | Apache 2.0 | 轻量,适合原型与单机应用 |
| pgvector | 23k | PostgreSQL 许可 | Postgres 的向量扩展,中小规模首选 |
| Weaviate | 17k | BSD-3 与自有许可混合 | 内置向量化模块与混合检索 |
| LanceDB | 12k | Apache 2.0 | 嵌入式,直接跑在文件之上 |
文档解析:
| 项目 | star | 许可证 | 定位 |
|---|---|---|---|
| MinerU | 82k | Apache 2.0 加附加条款 | 复杂 PDF 与 Office 文档转结构化,中文处理好 |
| Docling | 69k | MIT | 通用文档转换与结构化 |
| marker | 41k | Apache 2.0 | PDF 转 Markdown 与 JSON,速度与精度平衡 |
| unstructured | 16k | Apache 2.0 | 多格式抽取的通用库,集成面广 |
评测与可观测:
| 项目 | star | 许可证 | 定位 |
|---|---|---|---|
| Langfuse | 36k | MIT,ee 目录为商业许可 | 链路追踪与评测平台 |
| DeepEval | 19k | Apache 2.0 | 通用 LLM 评测框架,指标齐全 |
| RAGAS | 16k | Apache 2.0 | RAG 专项评测指标,忠实度与相关性 |
| Phoenix | 12k | Elastic License 2.0 | 可观测与评测,注意许可证不属于开源范畴 |
| TruLens | 3.6k | MIT | 评测与实验跟踪 |
中文场景可用的公开数据与基准:MTEB 与 C-MTEB 是嵌入模型的通用与中文评测集;BEIR 是跨领域检索基准;MS MARCO 是段落检索的经典训练与评测数据;CRUD-RAG 与 MultiHop-RAG 更贴近 RAG 的端到端评测,前者有中文覆盖。这些基准用来做初筛,最终判断仍要靠自己的数据。
二十、常见误解
“RAG 是让模型知道更多。” 它做的是上下文选择,模型的知识量没有变化。所以语料质量、分块方式、检索排序才是主线。
“换个更强的嵌入模型就能解决召回。” 召回链路上有四个环节:分块、查询表述、检索算法、过滤条件。实际项目里问题出在后两者的概率,远高于出在嵌入模型上。
“长上下文可以让 RAG 退休。” 上下文越长,噪声的边际代价越高,中间位置的证据越容易丢。检索的价值随窗口变长不降反升。
“RAG 能消除幻觉。” 它把无依据的编造换成了误读检索到的证据,还引入一类新错误:引用了一个看起来相关、实际不支持的片段。前者容易发现,后者更隐蔽。
“重排可以以后再加。” 它是单点收益最高的一步,改动小、见效快,通常应该优先于任何模型替换。
“检索到的内容可以直接信。” 语料库是外部输入,它是攻击面,不是可信来源。
“向量库得选一个专用的。” 一百万向量以内,PostgreSQL 加 pgvector 通常是最省事的选择。等真的遇到规模或功能瓶颈再迁移,成本远低于提前引入一套分布式系统的运维成本。
参考
- 2005.11401 — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks — NeurIPS 2020(CCF-A)
- 2002.08909 — REALM: Retrieval-Augmented Language Model Pre-Training — ICML 2020(CCF-A)
- 2004.04906 — Dense Passage Retrieval for Open-Domain Question Answering — EMNLP 2020
- 2007.01282 — Leveraging Passage Retrieval with Generative Models for Open Domain Question Answering(FiD)— EACL 2021
- 2307.03172 — Lost in the Middle: How Language Models Use Long Contexts — TACL
- 2404.06654 — RULER: What’s the Real Context Size of Your Long-Context Language Models? — 预印本 2024
- 2401.14887 — The Power of Noise: Redefining Retrieval for RAG Systems — SIGIR 2024(CCF-A)
- 2310.01558 — Making Retrieval-Augmented Language Models Robust to Irrelevant Context — ICLR 2024
- 2312.06648 — Dense X Retrieval: What Retrieval Granularity Should We Use?(命题级检索)— EMNLP 2024
- 2409.04701 — Late Chunking: Contextual Chunk Embeddings Using Long-Context Embedding Models — 预印本 2024
- 2210.07316 — MTEB: Massive Text Embedding Benchmark — EACL 2023
- 2212.03533 — Text Embeddings by Weakly-Supervised Contrastive Pre-training(E5)— 预印本 2022
- 2205.13147 — Matryoshka Representation Learning — NeurIPS(arXiv 2022)
- 2402.03216 — M3-Embedding: Multi-Linguality, Multi-Functionality, Multi-Granularity Text Embeddings through Self-Knowledge Distillation(BGE-M3)— ACL 2024
- 1603.09320 — Efficient and Robust Approximate Nearest Neighbor Search Using Hierarchical Navigable Small World Graphs(HNSW)— IEEE TPAMI 2018
- 1702.08734 — Billion-Scale Similarity Search with GPUs(FAISS)— IEEE Transactions on Big Data 2017
- 2403.04871 — ACORN: Performant and Predicate-Agnostic Search Over Vector Embeddings and Structured Data — PACMMOD 2024
- 10.1145/1571941.1572114 — Reciprocal Rank Fusion Outperforms Condorcet and Individual Rank Learning Methods(RRF)— SIGIR 2009(CCF-A)
- 10.1561/1500000019 — The Probabilistic Relevance Framework: BM25 and Beyond — Foundations and Trends in Information Retrieval 2009
- 2107.05720 — SPLADE: Sparse Lexical and Expansion Model for First Stage Ranking — SIGIR 2021(CCF-A)
- 2004.12832 — ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT — SIGIR 2020(CCF-A)
- 2112.01488 — ColBERTv2: Effective and Efficient Retrieval via Lightweight Late Interaction — NAACL 2022
- 2212.10496 — Precise Zero-Shot Dense Retrieval without Relevance Labels(HyDE)— ACL 2023(CCF-A)
- 2310.11511 — Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection — ICLR 2024
- 2401.15884 — Corrective Retrieval Augmented Generation — 预印本 2024
- 2404.16130 — From Local to Global: A Graph RAG Approach to Query-Focused Summarization — 预印本 2024
- 2309.15217 — RAGAS: Automated Evaluation of Retrieval Augmented Generation — EACL 2024
- 2310.06816 — Text Embeddings Reveal (Almost) As Much As Text — EMNLP 2023
- 2401.05856 — Seven Failure Points When Engineering a Retrieval Augmented Generation System — CAIN 2024
- 2312.10997 — Retrieval-Augmented Generation for Large Language Models: A Survey — 预印本 2023
- 上下文检索 — 工程博客 2024(给片段拼接上下文说明的做法与实测收益)