检索增强提示:接外接知识
检索增强生成(RAG)在提示阶段先检索与问题相关的外部资料,再把资料连同问题一起交给模型,使回答基于可追溯的原文而非仅凭记忆。Lewis 等人在 2020 年的论文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》中系统提出该范式(arXiv:2005.11401),其核心洞察是把”知识”从模型权重里搬出来,交给一个可随时更新的外部索引。
是什么
RAG 可以拆成两个彼此独立的阶段。检索阶段负责在文档库里找出与问题最相关的若干片段,生成阶段负责在给定这些片段的条件下作答。用概率的语言描述,模型建模的不再是 P(答案 | 问题),而是 P(答案 | 问题, 检索到的文档)。
这个拆分带来一个重要区分:参数化知识存在模型权重里,训练完成即冻结,更新它意味着重新训练或微调;非参数化知识存在外部索引里,改一份文档、重建一次索引就生效。RAG 的价值几乎全部来自后者的可更新性和可审计性。
一条完整的链路通常包含五步:
文档 → 切分(chunking) → 嵌入(embedding) → 写入向量库
↓
用户问题 → 改写/嵌入 → 检索 top-k → 重排 → 填入提示 → 模型作答(带出处)
为什么有用
知识时效性。 模型的训练数据有截止时间,问它截止之后发生的事,它要么说不知道,要么编。私有数据(内部制度、客户合同、代码库)更是从来不在训练集里。RAG 让这两类知识都能即时接入。
幻觉抑制而非消除。 当提示中给出明确资料并要求”只依据资料回答”,模型的编造空间被显著压缩,因为它有更可靠的路径可走。但要注意这只是抑制:如果检索到的片段本身有误,或者片段之间互相矛盾,模型仍可能给出错误答案,只是错误来源从”模型记忆”变成了”文档质量”。
可溯源。 这一点在企业场景往往比准确率更重要。带出处的回答允许人工抽查,出错时能定位到具体段落,而纯参数化模型的输出无法审计。
成本结构。 相比微调,RAG 的边际成本主要是嵌入和检索,改一份文档不需要动模型。代价是每次请求都要消耗额外的上下文 token,且引入了检索这一新的故障点。
怎么做
切分:容易被低估的一步
切分粒度直接决定检索上限。切太碎,单个片段缺少上下文,模型看不懂;切太大,片段里混入无关内容,稀释了信号也浪费了 token。工程上常用的做法是按文档结构(标题、段落)优先切,再对超长块做递归切分并留少量重叠:
# LangChain 的递归切分器,优先在语义边界处断开
from langchain_text_splitters import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 按字符数,中文可适当调小
chunk_overlap=50, # 重叠避免关键句被切断
separators=["\n\n", "\n", "。", ";", " ", ""],
)
chunks = splitter.split_text(doc_text)
LlamaIndex 提供了 SentenceSplitter 等类似组件,思路一致。重叠比例通常取块长的 10% 左右,过大会让索引膨胀且召回重复内容。
检索:稠密、稀疏与混合
稠密检索(把文本编成向量做近邻搜索)擅长语义匹配,能处理”年假”和”带薪休假”这类同义表述;稀疏检索(如经典的 BM25)擅长精确关键词,对产品型号、错误码、人名这类低频词更稳。两者的失效模式恰好互补,所以生产系统常用混合检索,再用 Reciprocal Rank Fusion(RRF)之类的方法合并排序。
# 混合检索的骨架:两路召回后融合,再交给重排模型
dense_hits = vector_store.search(query_vec, top_k=20)
sparse_hits = bm25_index.search(query_text, top_k=20)
fused = reciprocal_rank_fusion([dense_hits, sparse_hits], k=60)
top_docs = reranker.rank(query_text, fused[:20])[:5] # 交叉编码器精排
这里的 reranker 通常是交叉编码器:它把问题和候选片段拼在一起联合编码打分,精度高于向量点积,但无法预计算,所以只用于对少量候选精排。开源方向可以看 Hugging Face 上的 BAAI bge-reranker 系列,商业 API 有 Cohere Rerank,选型时以自己数据上的实测为准。
向量存储方面,FAISS 适合单机与实验,Qdrant、Milvus、Chroma 提供服务化能力,如果数据本来就在 Postgres 里,pgvector 能省掉一整套运维。
提示:把资料和指令分清楚
提示要做三件事:划出资料边界、限定作答依据、规定无据可依时的行为。
你是企业制度问答助手。只能依据下面【参考资料】回答。
若资料不足以回答,直接说"资料中未提及",不要推测。
每个结论后用 [编号] 标注来源。
【参考资料】
[1](员工手册 v3,第 4.2 节)年假需提前 3 个工作日在 OA 系统提交申请。
[2](员工手册 v3,第 4.5 节)病假须在返岗后 2 日内补交三级医院证明。
【问题】我想休年假,要提前多久申请?
【回答】
其中”资料不足就说不知道”这条兜底指令是实践中收益最高的一句,它给了模型一条比编造更省力的退路。
工程取舍
top-k 不是越大越好。 增加 k 提高召回率,但也引入更多噪声片段,并挤占上下文预算。Liu 等人的研究(arXiv:2307.03172,通称 “Lost in the Middle”)发现模型对长上下文中间部分的信息利用率明显低于首尾,因此把最相关的片段排在开头或结尾,往往比单纯堆更多片段更有效。
长上下文不能完全替代检索。 上下文窗口变大后,“把整本手册塞进去”看似可行,但成本随 token 线性增长、延迟上升,且信息利用率并不均匀。检索的作用是先做信息筛选,这个价值不会因为窗口变大而消失。
查询改写的性价比。 用户问题往往口语化、指代不清。在检索前让模型把问题改写成更适合检索的形式(补全指代、拆成多个子查询),通常能明显提升召回。HyDE(Hypothetical Document Embeddings,arXiv:2212.10496)走得更远:先让模型生成一段”假想答案”,再用它去检索,利用的是答案与文档在向量空间中更接近这一性质。
元数据与索引维护
纯向量检索有个常被忽视的短板:它只看语义相似度,不理解”哪一版""哪个部门""什么时候生效”。而现实中的错误答案,很大一部分来自检索到了过期版本或不该被这个用户看到的文档。解决办法是给每个片段挂上元数据,检索时先做结构化过滤再算相似度:
{
"text": "年假需提前 3 个工作日在 OA 系统提交申请。",
"metadata": {
"source": "员工手册",
"version": "v3",
"section": "4.2",
"effective_from": "2024-01-01",
"visibility": ["all-staff"],
"deprecated": false
}
}
有了这层结构,就能表达”只检索当前生效版本""只检索该用户有权限的文档”这类约束。权限过滤必须在检索层做,不能靠提示词约束模型不要说——后者不是安全边界。
索引维护同样需要设计。文档更新时,如果只追加不删除,旧版本片段会长期留在索引里与新版本竞争召回,表现为”有时答对有时答错”这种最难排查的现象。工程上通常按文档 ID 做全量替换(先删除该文档所有片段,再重新切分写入),并保留一份切分产物快照,便于回溯某个错误答案当时到底命中了什么内容。
怎么评测
不评测的 RAG 系统等于盲调。评测要分层做,否则出问题时分不清是检索的锅还是生成的锅。
- 检索层:用标注好的问题—文档对,算 Recall@k、MRR、nDCG。BEIR 与 MTEB 是社区常用的公开检索/嵌入评测基准,可用于嵌入模型初筛,但最终选型必须在自己的数据上验证,公开榜单排名不保证在垂直领域同样领先。
- 生成层:关注忠实度(回答是否只用了给定资料)和答案相关性。Ragas 这类开源框架把 faithfulness、answer relevancy、context precision/recall 做成了可计算指标,适合做回归测试。
- 端到端:维护一份几十到几百条的黄金问答集,每次改动跑一遍对比,比看单个 case 的感觉可靠得多。
常见误区
- 以为加了向量库就等于解决幻觉。 检索不准时,模型基于错误资料的错误回答反而更有说服力、更难被发现。
- 忽略”资料里没有”的情况。 不加兜底指令,模型倾向于用参数化知识补齐空缺,而这部分内容既无出处也不可控。
- 只调生成提示,不查检索结果。 排查问题的第一步应该是把召回的片段打印出来看,而不是继续改提示词。
- 切分与嵌入模型不匹配。 嵌入模型有输入长度上限,块长超过上限会被截断,导致后半部分内容实际未被索引。
能力边界
RAG 擅长的是”答案明确写在某几段文字里”的问题。它不擅长需要全局聚合的任务,比如”这一千份合同里平均条款期限是多久”——这类问题本质是结构化查询,应该走数据库而不是向量检索。多跳推理(答案要串联多份文档才能推出)也需要额外的迭代检索设计,单轮召回通常不够。此外,检索引入的延迟和额外故障点,在对响应时间敏感的场景需要单独做降级策略。
小结
检索增强提示通过把外部资料显式接入提示,让模型基于真实、可追溯的内容作答。它的效果上限由检索质量决定,因此工程重心应放在切分策略、混合检索与重排、以及分层评测上,而不是反复打磨生成提示。同时要清楚它的边界:RAG 缓解而非消除幻觉,且不适合需要全局聚合的任务。
参考与延伸阅读
- RAG 原始论文(Lewis 等, 2020)。已核验。https://arxiv.org/abs/2005.11401
- “Lost in the Middle: How Language Models Use Long Contexts”(Liu 等, 2023)。已核验。https://arxiv.org/abs/2307.03172
- LlamaIndex 官方文档,含切分、检索与评测模块。已核验。https://docs.llamaindex.ai/
- Ragas:RAG 评测框架文档。已核验。https://docs.ragas.io/