RAG入门到实践:Embedding、向量检索与混合召回全解析

发布时间:2026/8/26 13:14:03
RAG入门到实践:Embedding、向量检索与混合召回全解析 RAG检索增强生成是目前大模型落地最常用的技术方案之一。它的核心实现可以概括成一句话在让大模型回答之前先从外部知识库里检索相关资料把资料片段连同问题一起交给模型再由模型生成答案。这样既能让模型使用私有知识也能明显减少幻觉。这篇文章会把 RAG 的完整业务流程拆开讲重点放在 Embedding 嵌入模型的工作原理、向量检索机制以及一个入门项目从零开始怎么落地。如果你是刚接触 RAG 的开发者想知道 Embedding 和向量检索到底是什么或者你已经跑过简单 Demo但切块质量差、检索不准、输出不稳定想弄明白怎么排查这篇都适合你。下面我按实际落地顺序拆解不绕弯尽量把关键参数和判断标准说清楚。1. 先用一条链路看懂 RAG 完整业务流程很多教程一上来就讲 LangChain、LlamaIndex、向量数据库结果新手看完头更晕。我建议先不看代码先理解 RAG 到底在解决什么问题完整流程里到底有哪些环节每个环节又是干什么的。1.1 为什么需要 RAG大模型不知道、记不住、考不到大模型本身不具备“实时查资料”的能力。模型训练完成后知识就固定在参数里理解能力很强但记忆内容会落后。它不知道你内部文档里写了什么也不知道最近几天新增的数据更不知道某个项目的私有约定。强行问它只能靠推理和训练时见过的东西“编”这就是幻觉的来源。有人会说把文档全塞进上下文窗口不就行了理论上可以做但现实很受限制。长上下文模型虽然能接收几十万字但 token 成本高、响应延迟大而且当文档量超过窗口上限时一样失效。更重要的是大模型对塞进来的长文并不是“精确查找”它会在海量文本里迷失重点最后生成的结果未必引用到你最想要的那段内容。RAG 的思路是反过来不把全部资料交给模型而是先根据问题把最相关的几段资料找出来再让模型只基于这几段资料回答。模型不需要“记住”所有文档它只需要“理解”检索出来的内容。所以 RAG 的本质不是增强模型记忆而是把“记忆”外置成一套可检索的知识库。1.2 RAG 的核心流程与每个环节的职责一套完整的 RAG 业务流程可以拆成七个环节文档接入读取 PDF、Markdown、Word、TXT、数据库记录等原始内容。文本切块把长文档切成适合 Embedding 和检索的文本块。Embedding 向量化把每块文本转换成向量。向量存储把向量和原文写入向量数据库建立索引。召回用户查询时把问题转成向量去向量库里找相似片段。重排对召回的候选片段做二次排序去掉不相关信息。生成把排序后的片段拼进 Prompt交给大模型生成答案。这七个环节里最影响效果的是切块、Embedding 和重排。很多人以为 RAG 效果差是模型不够聪明实际上大多数问题出在“检索不到”或“检索太杂”。下面我会逐个拆。1.3 判断一个 RAG 系统好坏的标准评估 RAG 系统不能只看回答是否通顺。我更建议用这几个维度做基线维度判断方式常见现象检索准确率查看召回片段是否真的和问题相关返回一堆无关内容回答像在硬凑答案忠实度回答中的关键结论是否能在召回片段里找到依据模型开始自由发挥没有引用来源响应延迟从提问到完整返回的耗时检索慢、生成长、并发一高就超时资源占用CPU、内存、显存、磁盘 IO 是否稳定批量任务跑到一半卡死显存溢出可重复性同一问题多次查询结果是否稳定结果时好时坏大概率是切块或检索不稳定做项目时先把这五项跑熟再谈优化。2. Embedding 嵌入模型到底是什么怎么选怎么用Embedding 是整个 RAG 系统里最容易被低估的部分。很多人直接把框架默认配置拿过来跑结果效果不好也不知道该换什么。这一节把嵌入模型的工作机制和选型思路讲清楚。2.1 Embedding 的直观理解把句子变成有方向的高维向量Embedding 做的事情很简单输入一段文本输出一串浮点数。这串浮点数就是向量比如 768 维、1024 维、1536 维。关键不在于数字多而在于数字之间的空间关系能够表达语义关系。举个例子“今天天气怎么样”“明天会下雨吗”“番茄炒蛋怎么做”前两句话的向量距离会非常近因为它们都涉及天气查询第三句话和它们的距离则明显更远。向量间的距离可以通过余弦相似度、内积、欧氏距离来度量其中余弦相似度在文本场景里最常用。计算过程对使用者是黑盒文本会先被切分成 token再经过多层 Transformer 编码最后通过池化操作变成一个固定维度的向量。这个向量的质量取决于模型的训练数据、训练方式和向量维度不是框架能自动优化的。2.2 主流 Embedding 模型与适用场景目前常见的 Embedding 模型分两类云端 API 和本地开源模型。云端 API 的好处是部署省事、并发稳定适合快速验证和中大型业务。国内云厂商、海外模型服务商都有对应接口。缺点是数据需要出网且每次调用按 token 计费知识库量大时会持续产生成本。本地开源模型的好处是数据不出内网、不花钱、可以自定义部署。常见的选择包括 BGE 系列、M3、E5 系列等。BGE-M3 是前几年开源的中英双语多语言模型支持长文本输入还能同时输出稠密向量和稀疏向量做混合检索很方便。如果你只是学习入门本地模型完全够用。选模型时不要只看名字要关注三个点输入长度最大支持多少 token长文档是否会被截断。多语言能力你的知识库是中文为主还是中英混合。向量维度维度越高通常表征越细但存储和检索成本也越高。2.3 Embedding 的输入长度、向量维度与成本判断Embedding 模型不是“喂多长都能进”。每个模型都有最大输入长度比如 512 token 或 8192 token。如果你把一整篇几千字的文档直接丢进去超过长度就会截断后半段信息直接丢失。这也是为什么 RAG 要做文本切块。切块的第一目的不是节省成本而是让每块文本都落在 Embedding 模型的有效长度内。向量维度影响存储和检索成本。假设每条向量是 1024 维100 万条文本块就是 10 亿个浮点数按 float32 算大约 4GB。如果全放内存还能接受如果放在磁盘型索引里检索性能就会明显下降。所以选择 Embedding 模型时不要盲目追求“越大越好”要考虑知识库规模和服务器资源。实用建议先拿 100 条经典问题跑一遍对比不同 Embedding 模型的召回效果。不要一上来就全库向量化成本高调试周期也长。3. 向量检索的工作原理从索引到 TopK 召回Embedding 只是把文本变成向量真正决定“能不能找到”的是向量检索。很多人误以为向量检索就是把所有向量挨个算一遍距离这在数据量小的时候确实可以但知识库一旦变大暴力搜索完全扛不住。3.1 向量索引不是暴力全表扫向量数据库会为向量建立索引常用的索引类型包括平面索引、IVF、HNSW 等。平面索引就是暴力全表扫准确率最高但数据量大时延迟无法接受。IVF 会把向量分成多个聚类先定位到最有可能的聚类再在聚类内部搜索速度明显提升但召回率可能略降。HNSW 是基于图的近似最近邻搜索搜索速度快、召回率高是生产环境最常见的索引之一。这些索引都属于近似最近邻搜索也就是 ANN。所谓“近似”是说它不保证每次都能返回全局最相似的结果但通过参数调节可以在召回率和速度之间取得平衡。你看到很多向量数据库宣传“百万级数据毫秒返回”背后基本都是在用 ANN。3.2 相似度计算方法向量检索的相似度计算方式主要有三种度量方式含义适用场景余弦相似度衡量向量方向一致性与长度无关文本语义相似度最常用内积方向和长度都影响结果某些模型训练时使用内积欧氏距离衡量空间距离距离越小越相似图片向量、部分文本场景在向量数据库里需要确认你所用的 Embedding 模型推荐哪种度量方式。比如有些模型归一化后余弦相似度和内积是等价的数据库配置错误会导致检索结果偏离预期。3.3 为什么需要 BM25 多路召回和 Rerank纯向量检索有一个典型问题语义相似但不包含关键信息。比如你搜“身份证丢了怎么补办”向量可能召回一堆“身份证办理流程”的句子却漏掉了包含“丢失补办材料”的精确段落。原因在于向量模型更关注语义不一定对专有名词、编号、短关键词敏感。解决思路是混合检索。常见做法是“向量检索 BM25 关键词检索”多路召回。BM25 是传统文本检索算法基于词频和文档频率打分对精确词汇、编号、产品名很敏感。两路召回后合并候选集再用 Rerank 模型对这些候选做精排序把真正与问题相关的片段排在前面。这套流程就是热词里常提到的“向量混合检索加 BM25 多路召回”。实际项目中除了 BM25还会有基于规则的过滤、时间过滤、权限过滤等都是用来减少噪声、提升召回到精排的准确性。我在实际项目里经常看到一种情况只开向量检索Top5 里只有 1 条相关加入 BM25 之后相关片段能跑到 3 条再加 Rerank前两名基本都是有效内容。所以如果你的检索质量上不去不要只盯着向量模型先想想是不是没做混合检索和重排。4. 快速入门从零搭一个本地 RAG 项目理解了原理之后就可以动手了。这一节给出最小可运行的落地路径环境以本地开发机为参考适合跑通流程不适合直接代表生产环境。4.1 环境准备和依赖选择我建议先准备 Python 3.10 以上环境建议用虚拟环境或 conda 隔离避免依赖冲突。常用组件大概这些文档解析pypdf、docx、markdown 解析库文本切块框架自带的 splitter或者自己写规则Embedding本地模型或者云端 API向量数据库学习阶段可以用 FAISS知识库大一点再上 Milvus、Qdrant、pgvector 等大模型OpenAI 接口、本地 Ollama、vLLM 部署或者云厂商模型编排框架LangChain、LlamaIndex也可以用 Dify 这类平台快速搭如果你不想一开始就引太多框架也可以自己写检索代码反而更容易理解原理。只是到了生产阶段框架能帮你减少重复工作但也会引入一层抽象报错时定位起来更麻烦。不同框架版本之间 API 差异比较大。下面给的代码是通用示例重点在理解流程落地时要以你安装的版本文档为准。4.2 文档加载与切块策略第一步是准备知识库。我建议先用 5 到 10 个 Markdown 文档做测试别一上来就导入整个 PDF 文件夹。PDF 解析会涉及扫描件、表格、页眉页脚各种问题都会干扰你判断 RAG 本身的效果。文档加载完成后要做切块。切块有两个核心参数chunk_size每块文本的最大长度一般按 token 计算。chunk_overlap相邻两个块之间重叠的长度目的是避免上下文被切断。切得过短检索很精准但上下文不完整模型回答时缺少背景切得过长上下文完整但噪声多检索命中率下降Embedding 长文本时还可能被截断。经验做法是从 200 到 500 token 开始调观察检索命中情况再增减。4.3 建索引与检索生成的代码示例以 LlamaIndex 风格为例跑通完整链路只需要几行核心代码from llama_index.core import SimpleDirectoryReader, VectorStoreIndex # 1. 加载文档 documents SimpleDirectoryReader(./docs).load_data() # 2. 切块、向量化、建索引 index VectorStoreIndex.from_documents(documents) # 3. 创建问答引擎 query_engine index.as_query_engine() # 4. 查询 resp query_engine.query(什么是 RAG) print(resp)这段代码背后做了很多事自动切块、调用 Embedding 模型、写入向量索引、查询时完成向量检索、拼装 Prompt、调用大模型生成答案。如果你希望更可控可以拆开写# 查询向量化 query_vec embed_model.get_text_embedding(question) # 在索引中检索 hits vector_index.search(query_vec, top_k10) # 拼接上下文 context \n\n.join([hit.text for hit in hits]) prompt f请基于下面的资料回答问题。 资料 {context} 问题{question} 这样写的好处是每一步都能打印中间结果方便调试。实际项目里我建议至少打印一次“检索到了哪些片段”不要只看最后答案。如果检索结果里没有关键内容生成阶段无论怎么调 Prompt 都救不回来。4.4 从单条查询到批量验证单个问题跑通之后再做批量验证。批量测试不是简单循环加并发要注意三件事先跑单条确认日志、输出、检索结果都正常。批处理时不要一上来就开大并发先用 1 到 2 个并发观察资源占用。批量输出要单独写入文件方便后续对比。如果批量任务跑到一半卡住不用急着怀疑模型。先看 CPU、内存、显存和输出目录很多时候是磁盘写入失败或者并发数太高导致 OOM。5. 切块、检索质量和 Rerank决定 RAG 效果的关键跑通 Demo 不难难的是把效果调到可用。这一节会把影响效果的关键点逐条拆开并给出调整思路。5.1 切块大小和重叠怎么设置切块策略没有“一套参数走天下”。不同类型的文档适合的切块方式完全不同。文档类型推荐做法原因散文类文档按固定 token 切overlap 50-100内容连贯固定长度可批量处理代码文档按代码块结构切不要强行切断函数定义表格类文档转成 Markdown 表格后按行/块切避免表格内容被截断Markdown按标题和段落层级切保留文档结构和语义边界PDF先清洗页眉页脚再切避免重复信息污染 Embedding切块后可以做一个自检随机抽 10 个问题去知识库里定位看答案所在片段是否完整。如果答案内容被切到两个块里模型就可能生成得很别扭。5.2 检索不到和检索太杂怎么调检索不到常见原因有三个查询问题和知识库表述差异太大纯向量检索没匹配上。切块太小关键信息被切没。TopK 设置太短比如只取 1 条漏掉了正确答案。检索太杂则可能是切块太大一块里混合了多个主题。没有做重排候选集里噪声太多。相似度阈值太低什么内容都被召回。调整顺序建议先看 TopK 召回结果再调切块再调相似度阈值最后加 Rerank。不要一上来就换 Embedding 模型成本高而且定位不准。5.3 Rerank 模型的作用Rerank 模型在 RAG 链路里越来越常见。它的任务是把向量检索和 BM25 召回的多路候选集重新按相关性排序。粗召回阶段我们为了召回率会放宽条件多拿一些可能相关的内容。比如候选集 50 条真正相关的可能只有 5 条。Rerank 模型会逐条计算查询与文本之间的相关性重新打分最后取 Top5 进入 Prompt。常见的 Rerank 模型有 bge-reranker 系列等。它们通常比 Embedding 模型更贵、更慢但只在候选集上做二次排序整体性能可以接受。实际项目中加不加 Rerank效果差距往往很明显。我一般建议只要知识库内容超过几百条就值得加。6. 常见问题与排查链路效果差、卡住、资源不够怎么办最后一部分聊排查。RAG 项目的问题点分散在多个环节如果不按链路排查很容易浪费大量时间。6.1 输出答非所问先看检索再看生成当模型回答得文不对题不要立刻怀疑 Prompt 写得不好。更可能是检索根本没有找到正确资料。排查顺序打印检索到的片段列表看相关内容是否在 TopK 里。如果检索片段相关但回答不用这些内容再调整 Prompt 或温度参数。如果检索片段里没有相关答案就去检查切块、Embedding 模型和是否做了混合检索。如果检索片段本身正确但表述混乱则检查文档复制粘贴时是否带入了大量页眉页脚或格式噪声。如果同一问题时好时坏检查向量索引是否更新或知识库中是否存在重复冲突内容。这一套查下来基本能确定问题出在哪个节点。6.2 任务卡住或内存暴涨先看日志和资源占用有时候任务不是“效果差”而是“根本跑不动”。这通常不是大模型的问题而是开发环境问题。第一看日志。有没有超时、连接失败、磁盘写入失败。很多向量库写入时日志只报 warning不注意就忽略。第二看资源。内存、显存、CPU 占用曲线如果持续上涨可能是任务队列积压也可能是切块后文本块数量过多导致索引内存爆炸。第三看输入文件。PDF 扫描件、超大图片、损坏文件都可能导致解析卡死。第四看配置。并发数、批量大小、超时时间、向量维度是否一致这些参数都可能出现明显错误。建议在项目启动时就统一做三件事数据源目录、日志目录、输出目录分开任务加唯一 ID每条失败记录可追踪。这样排查起来会轻松很多。6.3 生产化要额外考虑什么如果你要把 RAG 从 Demo 变成真实服务至少要额外考虑这些点增量更新知识库不是一次性写入要支持新增、修改、删除文档索引要能同步更新。异步任务文档上传、切块、Embedding、写入索引都比较耗时不能放在请求同步链路里。权限隔离不同用户只能检索到有权限的知识库内容否则会存在越权风险。失败重试Embedding 接口或大模型接口会有超时要有超时重试机制。监控记录检索命中率、平均响应时间、错误率、token 消耗方便评估成本和效果。这些看起来都是运维问题但在实际项目中它们最终都会变成功能问题。比如没有增量更新用户上传新文档后检索不到没做重试服务偶发故障时整个任务失败没有权限隔离数据安全直接亮红灯。从我自己的经验看RAG 开发最难的部分不是把流程跑通而是把“检索质量”做到稳定可靠。很多人折腾到最后发现瓶颈不在大模型而在数据清洗、切块策略和检索链路。如果你想快速入门最好的办法不是看一堆框架文档而是找一个小知识库把切块、Embedding、检索、Rerank 的中间结果全部打印出来看一遍调一遍再上批量。踩过几轮坑之后你对 RAG 的理解会比背概念扎实得多。

相关新闻