RAG 入门实战:给大模型外挂一个知识库
RAG 入门实战:给大模型外挂一个知识库
大模型很能说,但它有两个先天缺陷:知识有截止日期(训练之后发生的事一无所知),以及会一本正经地编造(行话叫"幻觉")。问它"咱们公司年假几天",它只会礼貌地胡说八道。
微调能注入知识吗?能,但代价高、更新慢——知识库每周都在变,总不能每周重训一次模型。RAG(Retrieval-Augmented Generation,检索增强生成)给出了更聪明的解法:回答之前,先去你的知识库里把相关资料查出来,塞进提示词,让模型"看着资料答题"。知识更新只需要改库,不用动模型。
这篇把 RAG 从原理到落地讲一遍:流程、切片、向量检索、生成细节、评估方法和最常见的坑。
一、什么场景值得上 RAG
· 企业知识库问答:员工手册、制度、产品文档
· 客服机器人:基于工单和 FAQ 回答
· 文档助手:"帮我在这 200 页规格书里找 XX 参数"
· 代码库问答:基于仓库文档回答实现问题
共同特征:答案存在于你私有的资料里,且资料的更新频率高于重训模型的频率。反过来,如果只是想让模型学会某种输出风格或领域话术,微调更合适;如果只是一次性的长文档问答,直接塞长上下文也行。
|
维度 |
RAG |
微调 |
长上下文直塞 |
|
知识更新 |
改库即生效 |
要重新训练 |
每次对话都要带全量 |
|
成本 |
低到中 |
高 |
token 费用高 |
|
可溯源 |
好,答案能标注出处 |
差 |
一般 |
|
适合 |
知识频繁变化、要求出处 |
学风格、格式、领域语言 |
一次性长文档 |
二、RAG 的完整流程:先建索引,再查再答
RAG 分两个阶段。离线索引把资料变成可检索的形态;在线检索生成在每次提问时发生。
离线索引(做一次,随文档更新增量做)
· 文档加载与清洗:PDF、Word、网页、数据库记录转成纯文本。这一步的解析质量决定整个系统的上限——扫描件要 OCR,PDF 里的表格要专门处理
· 切片(Chunking):长文档切成几百字的小段,每段是检索的最小单位
· 向量化(Embedding):用 embedding 模型把每个切片变成一个高维向量——语义相近的文本,向量距离就近
· 入库:向量、原文、元数据(来源、时间、部门)一起存进向量库
在线检索生成(每次提问都走一遍)
· 问题向量化:用户的提问同样被转成向量
· 检索:在向量库里找距离最近的 top-k 个切片,混合检索再加关键词一路
· 重排:用交叉编码器把最相关的切片精排到最前面
· 生成:把命中的切片拼进提示词,让模型"看着资料回答",并要求标注引用
一句话记住本质:RAG = 搜索引擎 + 带资料开卷考试。检索质量决定下限,生成环节决定上限。
三、切片:被低估的第一决定因素
大多数 RAG 效果差,问题不在模型,而在切片切得不好。四种常见策略:
|
策略 |
做法 |
适合 |
|
固定长度 |
每 N 个 token 切一刀 |
快速基线 |
|
递归切分 |
优先按段落切,超长再按句子回退 |
通用默认,主流框架的缺省做法 |
|
按结构切 |
按标题层级、Markdown 节、表格行切 |
手册、wiki 等结构规整的文档 |
|
语义切分 |
相邻句子向量突变处下刀 |
质量优先、不怕成本 |
常见经验值:切片大小 500–1000 token,相邻切片保留 10%–15% 的重叠(overlap),避免答案正好被切在边界上。两个原则比数字更重要:
· 一片一个话题:一段讲年假、一段讲考勤,别混在一起
· 切片自含上下文:检索命中后它是独立给模型看的,"如上文所述"这种切片就是废片——可以在每个切片前拼上它所属的标题路径
四、Embedding 与向量库:怎么存、怎么查
Embedding 模型把文本映射成语义空间里的一个点:"年假天数"和"休假多少天"两个切片字面不同,向量却很近。检索就是"在所有点里找离问题最近的 k 个"。
选型速查:
|
向量库 |
形态 |
适合 |
|
FAISS |
本地库 |
原型、研究 |
|
Chroma |
嵌入式 |
小项目、快速验证 |
|
pgvector |
PostgreSQL 扩展 |
已有 PG,向量数据和业务数据同居 |
|
Qdrant |
独立服务/托管 |
生产环境,运维省心 |
|
Milvus |
分布式服务 |
亿级向量、大规模生产 |
选 embedding 模型看三件事:主要语言(中文效果差异很大,主流选择如 BGE 系列)、效果与维度(MTEB 之类的榜单可以参考,但务必用自己的数据实测)、成本与私有化要求。注意:换 embedding 模型等于换了一套坐标系,全库必须重新向量化——所以一开始就别拍脑袋。
五、检索环节:别只做"向量最近邻"
纯向量检索有个盲区:产品型号、报错码、人名这类精确词,向量相似度反而不敏感。生产级 RAG 通常做混合检索:向量检索(管语义)+ 关键词检索(BM25,管字面),两路结果合并。再加一道重排(rerank):先用便宜的手段召回 top 20–50,再用交叉编码器精排出 top 3–5。"先广撒网再精排"是当前的主流架构,BGE-reranker、Cohere Rerank 都是这个位置上的常用件。
检索端还有两个实用开关:
· 元数据过滤:按部门、时间、文档类型先过滤再检索——"2024 年之后的通知"这类问题全靠它
· 查询改写:用户问法千奇百怪,先让模型把问题改写、展开成适合检索的形式;多轮对话里还要把"那第二种呢"这种指代补全
六、生成环节:模板里必须有的三句话
拼提示词不是把检索结果一股脑塞进去。模板里这三句话能挡掉一大半事故:
· 只依据资料回答:资料里没有的,明确说"资料中没有提到",不许编
· 标注引用:每个结论注明来自哪条切片,方便人工核对
· 冲突要摆出来:新旧制度在资料里打架时,把冲突说清楚,而不是随机选一个
另外,别把 top-20 全塞进去:上下文越长,模型对每段的注意力越稀薄,中间部分还容易被忽略。精选 3–5 段、按相关性排序,效果通常好于大水漫灌。
七、评估:别凭感觉调参
RAG 系统最容易死于"开发者自己试了十个问题,感觉还行"。至少建一个几十条的小评测集:问题 + 标准答案 + 出处。两层指标分开看:
· 检索层:该命中的切片有没有进 top-k(召回率)、最好的切片排多前(MRR)。检索不对,生成必错——大部分调优应该先做在检索端
· 生成层:答案是否忠实于检索到的资料(忠实度)、是否切题(答案相关性)。RAGAS 这类框架能自动化打分,但人工抽查永远不可替代
调优顺序固定:先修解析和切片 → 再修检索(混合检索、重排、过滤)→ 最后调提示词和生成参数。跳过前两步直接改提示词,是新手最常见的无效努力。
八、五个常见坑
1. PDF 解析想当然。 扫描件没有文本层、双栏排版被按顺序读串、表格变成乱码——解析质量不行,后面全白搭。复杂 PDF 用版面分析工具,表格单独处理。
2. 表格被切碎。 表格拦腰切断后,每半张表都检索不准。整张表作为一个切片,或转成 Markdown/键值对再切。
3. 只用向量检索。 报错码、产品型号这类精确词,纯向量几乎必挂。上混合检索。
4. 没有元数据。 "最新的""我们部门的"这类过滤全靠元数据。索引时就把时间、部门、版本存进去。
5. 上线即不管。 文档下线了索引还在,回答引用一年前的旧制度。给索引加更新和失效机制,评测集留着做回归。
九、最小可用代码骨架(示意)
用 Chroma 加任意 embedding 与大模型 API,几十行搭出骨架:
# 索引阶段(示意代码)
import chromadb
client = chromadb.PersistentClient(path="./kb")
col = client.get_or_create_collection("docs")
for doc in load_documents("./handbook"): # 文档加载与清洗
for i, chunk in split_chunks(doc.text): # 切片
col.add(
ids=[f"{doc.name}:{i}"],
documents=[chunk],
metadatas=[{"source": doc.name}], # 元数据
)
# 检索生成阶段(示意代码)
question = "入职满一年有几天年假?"
hits = col.query(query_texts=[question], n_results=5)
context = "\n---\n".join(hits["documents"][0])
prompt = f"""仅依据以下资料回答问题;资料不足以回答时,明确说"资料中没有提到"。
资料:
{context}
问题:{question}
回答(注明引用的资料编号):"""
# 把 prompt 交给任意大模型 API 即可
load_documents、split_chunks 是留给你的两个函数,也是整篇最值得花时间的两个函数。生产环境要换掉的部分:embedding 调用、持久化向量库、混合检索与重排、自动化评测——骨架不变。
速查卡
|
环节 |
关键决策 |
|
解析 |
扫描件 OCR、表格专门处理 |
|
切片 |
500–1000 token、10% 重叠、一片一话题 |
|
向量化 |
按主要语言选模型,用自己的数据实测 |
|
检索 |
混合检索 + 重排 + 元数据过滤 |
|
生成 |
精选 3–5 段、要求引用、答不出就说不知道 |
|
评估 |
小评测集 + 检索/生成两层指标,先修检索端 |
写在最后
RAG 的迷人之处在于它把"让模型变聪明"变成了一个普通工程问题:解析、切片、检索、生成,每一层都能单独测量、单独改进。第一版不用追求完美——一个"解析干净 + 递归切片 + 向量检索 + 引用出处"的朴素系统,跑通评测集之后再逐层升级。
从把你们团队 wiki 里的前十篇文档索引进 Chroma 开始吧。
- 点赞
- 收藏
- 关注作者
评论(0)