当前位置: 首页 > news >正文

检索增强生成全链路解析:从文档加载到评估的大模型知识库工程实践

很多开发者第一次接触大模型时,第一反应是“调用 API 太简单了”:把 Prompt 封装好,用户问题丢给 GPT 或国内商用模型,一个聊天机器人就上线了。但真正进入企业项目就会发现,API 只是一个入口,真正难的部分在于:怎么让模型“看到”私有知识、怎么控制幻觉、怎么评估系统效果、怎么在有限显存环境下做推理部署。这些问题背后,正是 LLM 工程化的完整链路。

如果说 LLM 工程是一门需要体系化学习的课程,那么 GenAI 和 RAG 就是其中最核心的两个板块。RAG 不是“把一个 PDF 塞给大模型”这种一句话能讲清的操作,而是一套数据工程、检索系统、生成策略和评估体系的组合。这也是这门 Udemy 课程第三部分的重点:从纯 Prompt 调用走向生产级知识库应用。

这篇文章会以该课程第三部分为线索,梳理 RAG 完整链路(文档加载、切分、向量化、检索、生成)、Agentic RAG 和 OAG 等进阶方向、FP16/FP32/BF16 精度问题,以及 RAG 知识库评估指标。如果你正在做知识库问答、想系统学习 LLM 工程,或者正从传统后端转向 AI 应用开发,这篇内容应该能帮你建立一份更清晰的行动地图。

1. 为什么 RAG 是 LLM 落地绕不开的方向

先做一个判断:在 2025 年这个时间点,RAG 已经不只是“一个技术方案”,而是 LLM 应用落地事实上的标准形态。聊天、写作、翻译可能用不到 RAG,但凡是涉及私有数据、实时数据、专业文档的场景,RAG 几乎都是第一选择。

原因在于 LLM 本身有三大硬约束。

第一,知识截止。预训练模型的知识停留在训练数据截止时间,训练之后发生的事情它不知道。如果你问它某个产品上周发布的新功能,它大概率会一本正经地编一个答案。

第二,私有数据不可见。企业内部的规章制度、产品手册、客服工单、专利文档,模型在训练时根本没有见过。直接让模型回答这些内容,它只能靠“合理猜测”,而合理猜测在专业场景里往往就是事故。

第三,幻觉问题。即使模型不知道答案,它也会因为语言模型的本质而生成一个看起来通顺的回复。这不是模型“坏”,而是概率生成机制导致的必然结果。解决幻觉最有效的工程手段之一,就是用检索到的真实内容去约束生成范围。

没有 RAG 的时候,要让模型掌握新的领域知识,主流方案是微调(Fine-tuning)。但微调的成本高、周期长,每次知识更新都要重新训练一轮。更关键的是,微调擅长改变模型的行为方式和表达风格,却并不擅长记忆大量新事实。让一个 7B 模型通过微调背下一本 500 页的产品手册,既不经济,也容易过拟合。

RAG 的思路是把“记忆”从模型内部搬到外部:给模型一本可以随时翻阅的参考书,这个参考书就是你的知识库。模型回答之前,先从参考书里找出与问题最相关的几个片段,再把这些片段作为上下文交给模型生成答案。用“开卷考试”来类比 RAG 和普通 Prompt 生成的区别,非常直观。

但在真实项目中,这套“开卷考试”的工程复杂度远高于想象。很多人以为 RAG 就是“向量数据库 + Prompt”,实际做下去才发现,文档怎么拆、按什么粒度拆、检索用什么向量、top-k 怎么设、重排怎么做、效果用什么指标来衡量,每一步都可能让最终效果出现数倍的差距。

2. RAG 完整链路与核心概念

2.1 RAG 的标准流程

一个标准的 RAG 系统,由四个环节组成。

第一,数据准备阶段。原始文档需要经过加载、解析、清洗、切分,变成适合检索的文本块(chunk)。这个环节经常被低估,但它的质量直接决定了整个知识库的上限。如果原始文档是 PDF,页眉页脚、表格、扫描图片都会成为干扰项;如果切分粒度不对,再好的向量模型也检索不准。

第二,索引构建阶段。每个文本块通过 embedding 模型转换为向量,写入向量数据库。同时可以保留原始文本和元数据(来源、页码、标题等),方便后续溯源。

第三,检索阶段。用户输入问题后,先把问题也转换为向量,然后在向量数据库中做相似度检索,取回最相关的 top-k 个文本块。更复杂的系统会在这个阶段加入关键词检索和重排模型。

第四,生成阶段。把检索到的文本块和用户问题组装成 Prompt,交给 LLM 生成最终答案。为了减少幻觉,Prompt 中通常会明确要求模型只基于检索内容作答,无法回答时要明确说明。

2.2 RAG 和微调不是二选一

很多入门者会在 RAG 和微调之间纠结。我的建议是,先分清楚你要解决的是哪一类问题。

RAG 适合解决“知识更新”和“私有数据接入”的问题。比如 FAQ 问答、产品文档问答、行业报告摘要。它的优势是知识可以随时更新、答案可以溯源,一次数据更新不需要重新训练模型。

微调更适合解决“行为方式”和“输出格式”的问题。比如让模型学习某个业务场景下的固定话术、指令遵循习惯,或者把输出格式严格限定成系统需要的 JSON 结构。微调改变的是模型的“性情”,RAG 给的是模型的“素材”,两者服务的层次完全不同。

生产系统里常见的做法是两者结合:先微调出一个懂业务话术的底座模型,再用 RAG 为它提供实时事实。对大部分团队来说,RAG 的性价比上限更高,因为它不涉及训练资源。不要一上来就微调,先把 RAG 链路跑通。

2.3 从 RAG 到 Agentic RAG 和 OAG

课程第三部分的内容里,进阶方向会从“单次 RAG”延伸到“Agentic RAG”和“OAG”这类新概念。理解这两个概念,有助于看清楚 RAG 演进的脉络。

Agentic RAG 的核心变化是:把 RAG 从“一次检索 + 一次生成”升级为“多轮决策循环”。简单说,就是让 LLM Agent 承担检索规划的角色。它先理解用户问题,决定是否要检索、检索什么;拿到检索结果后判断信息是否足够,如果不够,就改写查询词再检索,或者调用外部工具获取信息;最后综合多轮结果生成答案。

这种设计解决的是复杂问题拆解场景。比如用户问“帮我对比一下 A 产品和 B 产品在三个维度的差异”,单次向量检索很难把三个维度一次找全。Agent 可以把这个问题拆成多个子问题,分别检索,再汇总。这就是 LLM Agent 与 RAG 结合的典型价值。

OAG 指的是 Ontology-Augmented Generation,即本体增强生成。它和 RAG 的区别在于,RAG 检索的是非结构化的自然语言文本,OAG 使用的是结构化的本体或知识图谱。本体会预先定义实体、关系和规则,比如在通信协议文档中,“ACK/NACK”“RRC 状态”这样的概念和它们之间的关联会被显式建模。生成时,系统先从本体中查询符合逻辑约束的事实,再交给 LLM 生成。

在专业领域,比如 3GPP 协议规范、医疗指南、金融监管文件这类文档中,OAG 比普通 RAG 更容易保证语义一致性。普通 RAG 容易把不同版本的协议内容混在一起,而基于本体的检索可以根据版本关系和实体约束做更精确的过滤。RAG 和 OAG 并不互斥,一个成熟的专业知识库系统往往两种手段同时使用。

3. 文档加载解析全流程:容易被低估的一环

如果说 RAG 链路中有一个最容易被低估、但又最决定效果上限的环节,那一定是文档加载和切分。很多团队把大量时间花在调 Prompt 和换模型上,却忽略了知识库的“地基”。实际上,如果输入到向量库的文本本身就是脏的、碎的、无上下文的,再好的检索模型也救不回来。

3.1 不同文档类型的加载难点

先从加载开始。现实项目里遇到的文档远比教科书例子复杂。

PDF 是最常见的格式,但 PDF 内部差异很大。文本型 PDF 可以直接抽取文字,但页眉页脚会污染正文;表格型 PDF 抽取后可能变成一段无结构的字符串;扫描型 PDF 需要先 OCR,而 OCR 又可能引入错字。Word 文档的问题在于样式标记和批注,PPT 的难点在于每页内容太碎片化。HTML 页面则需要抽取正文、剥离导航和脚本。这些工作属于典型的数据工程,听起来不“AI”,但直接决定下游质量。

在这个阶段,可以借助 LangChain 的 document loader 体系。它提供了针对 PDF、Word、HTML、Markdown、PowerPoint 等多种格式的加载器。也可以引入 Unstructured 等解析库来做表格识别和 OCR。不过,不能只依赖现成工具,业务文档的布局规则往往需要自己写解析逻辑。

3.2 文本切分策略

切分是另一个关键决策点。切分的核心矛盾是:块太大,向量化后语义会被稀释,检索不够精准;块太小,上下文不完整,LLM 生成时看到的背景信息太少。经验上的常见范围是 200 到 500 个 token。但这只是起点,具体值要根据文档类型和测试效果调整。

切分方式也分几个层次。

固定大小切分最简单,按 token 数硬切,但会切断句子和段落。递归字符切分是 LangChain 中最常用的方式,它按分隔符优先级递归尝试,尽量保住段落和句子结构,适合通用文档。按 Markdown 标题切分适合结构化文档,能保证每个块对应一个语义完整的章节。语义切分则利用 embedding 的相似度来决定边界,效果最好但计算成本高。

切分时还要设置 overlap,也就是相邻块之间的重叠区域。Overlap 的意义在于,如果一条知识恰好落在切分边界上,没有重叠就会导致它被切断,检索时自然找不到。一般建议 overlap 设置为 chunk size 的 10% 到 20%。

下面给出一段基于 LangChain 的 PDF 加载与切分示例代码。这段示例使用 LangChain 0.x 早期的 API 写法,新版中的导入路径可能有调整,请以你安装的包版本为准。

# document_prepare.py from langchain_community.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter # 1. 加载 PDF 文档 loader = PyPDFLoader("./data/product_manual.pdf") documents = loader.load() print(f"加载得到 {len(documents)} 页内容") # 2. 递归字符切分 splitter = RecursiveCharacterTextSplitter( chunk_size=400, # 每个文本块的目标大小(token 级别) chunk_overlap=50, # 相邻块重叠大小 separators=["\n\n", "\n", "。", "!", "?", ";", " ", ""], ) chunks = splitter.split_documents(documents) print(f"切分后得到 {len(chunks)} 个文本块") # 3. 查看第一个块的元信息和前 200 字 print(chunks[0].page_content[:200]) print(chunks[0].metadata)

在真实项目中,不建议把所有文档类型都统一走同一条切分逻辑。正确做法是先对文档做分类:规章制度类按章节切,产品手册类按功能模块切,FAQ 类按问答对整体保留。切分策略应该被当成一个可配置的参数,允许在评估后反复调整,而不是写死一次就不动了。

4. 环境准备与依赖安装

要动手跑通 RAG 示例,需要先准备一套 Python 环境。下面的环境清单不针对特定版本,建议以“安装时最新稳定版”为准,本文重点演示通用思路。

操作系统推荐 macOS 或 Linux,Windows 也可以运行,但依赖安装时更容易遇到编译问题。Python 版本建议 3.9 以上,最好使用 3.10 或 3.11。

核心依赖拆成三部分:

  • 向量化与检索框架:langchain、langchain-community、langchain-openai。
  • 向量存储:chromadb 或者 faiss-cpu。
  • 文档解析:pypdf、unstructured、pandas。
  • 模型调用:openai,如果使用国内大模型则改成对应 SDK。

创建虚拟环境并安装依赖:

python -m venv .venv source .venv/bin/activate pip install --upgrade pip pip install langchain langchain-community langchain-openai pip install chromadb faiss-cpu pip install pypdf unstructured

如果你要调用 OpenAI 接口,需要提前配置环境变量。如果使用其他模型服务或本地部署的模型,替换对应的 embedding 和 LLM 类即可。

export OPENAI_API_KEY="你的密钥"

如果你所在环境无法直接使用境外模型服务,可以选择国内厂商提供的兼容接口,或者使用本地部署的模型。这个选择不影响 RAG 的架构思路,只影响具体调用方式。

5. 向量化与检索:RAG 的核心决策点

5.1 Embedding 模型选择

文本块准备好之后,下一步是向量化。这一步的核心是选择一个合适的 embedding 模型。

Embedding 模型会把一段文本映射成高维向量,语义相近的文本在向量空间中的距离也更近。目前选择很多:OpenAI 提供了 text-embedding-3-small 和 text-embedding-3-large,国内也有 BGE、M3E 等开源中文 embedding 模型,还有各种本地可部署的模型。

选择 embedding 模型时,有三个考量因素。

第一是语言适配。如果你的知识库主要是中文,建议优先在中文语料上表现更好的模型,或者做多语言模型,而不是直接使用以英文为重心的小模型。

第二是维度与成本。维度越高,通常表达能力越强,但存储和计算成本也越高。text-embedding-3-small 默认只有几百维,对于大多数知识库场景已经够用。

第三是推理环境。如果知识库部署在内部网络,无法访问外部 API,那就必须选择可在本地 GPU 或 CPU 上运行的 embedding 模型。开源模型在本地部署完全没有问题。

5.2 向量数据库选型

向量数据库的作用是存储向量并支持快速相似度检索。选型可以从项目规模出发。

FAISS 是 Meta 开源的向量检索库,不是一个完整数据库,不提供数据持久化和权限管理,但它轻量、高效,适合原型验证和小规模项目。Chroma 是一个更完整的本地向量数据库,提供了简单的 API 和持久化能力,适合中小团队快速起步。Milvus 和 Qdrant 是面向生产环境的分布式向量数据库,支持水平扩展、多租户、权限控制和丰富的过滤能力,适合数据量达到几十万甚至上百万条级别的系统。

选型建议:个人学习和搭建原型直接用 FAISS 或 Chroma;企业项目评估 Milvus、Qdrant;如果团队已经引入了 Elasticsearch 8.x 且同时在用 ES 做全文检索,也可以考虑用它内置的向量检索能力,以减少运维组件的数量。

5.3 检索策略:向量检索、混合检索与重排

很多人把 RAG 的检索等同于“向量相似度检索”,但这只是起点。

向量检索适合语义相关性判断,比如“最大负载多少”能找到包含“负载能力”的文档,即使没有“最大负载”这四个字。缺点是对精确关键词不敏感。关键词检索(比如 BM25)恰恰相反,它擅长精确匹配,比如产品型号、错误码、人名,但无法理解同义改写。

真实知识库中,这两类问题同时存在。于是就有了混合检索:同时执行向量检索和关键词检索,再把两部分结果合并,用重排序模型(Rerank)重新打分,选出最终进入 Prompt 的内容。重排阶段通常把候选从 20 条压缩到 3 到 5 条,能显著提升生成质量,但也会带来额外的计算延迟。

对于刚起步的团队,建议先用纯向量检索跑通流程,再加入关键词检索和重排,逐步验证每一步带来的收益,不要一上来就堆复杂组件。

下面是一个基于 Chroma 和 LangChain 的完整检索问答示例。这里使用 LangChain 中常见的RetrievalQA封装。

# rag_qa.py from langchain_community.vectorstores import Chroma from langchain_openai import OpenAIEmbeddings from langchain_openai import ChatOpenAI from langchain.chains import RetrievalQA # 1. 初始化 embedding 模型 embeddings = OpenAIEmbeddings(model="text-embedding-3-small") # 2. 把上一步切分好的 chunks 写入 Chroma 向量库 vectorstore = Chroma.from_documents( documents=chunks, embedding=embeddings, persist_directory="./chroma_db", ) # 3. 构建检索器 retriever = vectorstore.as_retriever( search_type="similarity", search_kwargs={"k": 4}, ) # 4. 初始化生成模型 llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) # 5. 构建 RAG 问答链 qa_chain = RetrievalQA.from_chain_type( llm=llm, retriever=retriever, return_source_documents=True, ) # 6. 执行查询 query = "产品手册中,该设备的最大负载是多少?" result = qa_chain.invoke({"query": query}) print("答案:", result["result"]) print("\n--- 参考来源 ---") for doc in result["source_documents"]: print("来源:", doc.metadata.get("source", "未知")) print("内容:", doc.page_content[:100])

这个代码里有几个细节值得注意。

search_kwargs={"k": 4}表示只取回 4 个最相关的文本块。k 值太小容易漏答案,k 值太大则会把无关内容塞给 LLM,让答案跑偏。一般从 4 到 6 起步,再根据评估效果调整。

temperature=0是问答场景的常见配置。知识库问答要求稳定、忠实,不需要创造性输出。而写文案、头脑风暴类场景才需要提高温度。

return_source_documents=True一定要保留,否则你很难知道答案是来自知识库还是模型自己编的。生产系统中,来源溯源是知识库功能的基本要求。

5.4 从示例到生产系统

上面的示例跑通之后,要往生产系统走,还有几件事需要补充。

一是索引的增量更新。文档会更新、删除、追加,不能每次全量重建。实践中会引入调度任务和消息队列,按文档哈希或版本号判断是否需要重新向量化。

二是向量数据库的安全性。私有知识库通常涉及敏感数据。向量库本身往往没有严格的权限模型,需要在应用层做好访问控制,对用户查询和检索结果做权限过滤。

三是检索质量监控。线上系统一般会记录每次查询的召回文档、相关性分数和最终答案,并定期抽样做人工评估。这样当某个知识点的检索质量下降时,可以及时定位是数据更新问题还是模型变更问题。

6. LLM 精度问题:FP16、FP32、BF16 在工程中的取舍

在 RAG 示例中,你可能用的是托管模型 API,不需要关心权重存储的精度问题。但如果你要做本地推理、私有化部署,或者用开源模型搭建知识库,那么 LLM 的精度问题就是绕不开的工程决策。

6.1 为什么精度问题值得关注

大模型的权重是一组浮点数。浮点数的表示精度和范围,由格式决定。同一个模型参数,用不同精度存储和计算,会直接影响三件事:显存占用、推理速度、输出质量。

先给一个粗略的显存估算。一个 7B(70 亿参数)参数的模型,以 FP32 存储,参数大小约为 7 × 4 字节等于 28GB。FP16 或 BF16 是半精度,每个参数 2 字节,所以约 14GB。如果再算上推理过程的中间激活值,实际占用会更高。这也是为什么 8GB 显卡几乎跑不动 7B 模型的全量推理,通常需要配合 4bit 量化。

6.2 三种精度格式背后的设计差异

FP32 是单精度浮点数,宽度 32 位,其中指数位 8 位,尾数位 23 位。它是 CPU 和 GPU 上最通用的标准格式,精度最高。模型预训练和科学计算常用 FP32 作为基准。缺点是显存占用大、计算速度相对慢。

FP16 是 IEEE 半精度浮点数,宽度 16 位,其中指数位 5 位,尾数位 10 位。相比 FP32,它节省一半显存,计算速度也更快。但指数位只有 5 位,导致它能表示的数值范围变小。当某个权重数值很大时,会被表示成无穷大;当数值极端小时,又容易变成 0。这就是“溢出”和“下溢”问题。在训练大模型时,如果直接用 FP16,梯度很容易在反向传播中丢失。

BF16 是 Brain Floating Point,也是 16 位,但指数位有 8 位,和 FP32 相同,尾数位只有 7 位。它的巧妙之处在于“牺牲精度,保留范围”。因为和 FP32 拥有相同的指数范围,BF16 在高数值范围下更不容易溢出,训练时稳定性明显优于 FP16。代价是尾数少,同一个数值,BF16 能表示的小数精度比 FP16 低。

6.3 三种精度的对比

精度格式位宽指数位尾数位主要优点主要缺点常见用途
FP3232 位8 位23 位精度最高显存占用大、计算慢预训练基准、科学计算、调试
FP1616 位5 位10 位显存减半、速度快数值范围小,训练易溢出混合精度训练、GPU 推理
BF1616 位8 位7 位数值范围与 FP32 相同,训练稳定尾数少,精度略低大模型预训练、推理部署

6.4 实际工程中的选择建议

在本地部署开源 LLM 做知识库推理时,更稳妥的选择通常是 BF16,而不是 FP16。因为大模型推理阶段对数值范围更敏感,FP16 在极端权重分布下偶尔会出现输出质量劣化。而在需要极致推理速度时,GPU 对 FP16 的计算吞吐往往更高,这时可以使用 FP16 并做针对性评测,确认任务指标没有明显回退再做选择。

如果显存实在不够,就需要考虑量化方案,把权重降低到 INT8 甚至 INT4。量化后模型文件更小,推理速度提升,但会有更明显的精度损失。是否可接受,不能拍脑袋决定,必须在业务测试集上做对比评估。

这里真正容易踩坑的地方是:很多人看到模型量化后“看起来回答还挺正常”,就直接上生产,结果在专业术语密集、格式要求严格的场景中,量化模型频繁答非所问。任何精度选择都应该和评估体系绑定,用数据决策,而不是凭感觉。

7. RAG 知识库指标:如何评估一套 RAG 系统

很多开发者在把 RAG 系统搭起来之后,会遇到一个尴尬问题:系统已经能运行了,但到底好还是不好,说不清楚。如果连好坏都无法量化,后续优化就无从下手。RAG 系统的评估,是这部分课程非常强调的内容。

7.1 先从离线评估集开始

在讨论指标之前,先建立一个基本前提:评估需要一套固定的测试集。没有测试集谈指标,都是纸上谈兵。

测试集的构建方式是:从知识库中挑选一批有代表性的文档,针对它们设计 50 到 100 条问题,并为每个问题标注期望答案或至少标注“应该从哪些文档片段中检索”。这个集合称为黄金集。以后每次调整切分参数、更换 embedding 模型、修改检索策略,都在同一套黄金集上跑,看指标变化。

7.2 检索质量指标

RAG 系统的检索环节直接决定了“模型看到了什么”。如果检索结果里根本没有正确答案,生成环节再强也白搭。所以检索质量必须独立评估。

Hit Rate 是最直观的指标,表示在检索返回的 top-k 结果中,是否至少有一条是相关的。如果检索了 100 个问题,其中 85 个问题在 top-5 结果里有正确答案,Hit Rate@5 就是 85%。它反映的是“有没有召回”。

MRR 全称是 Mean Reciprocal Rank,用于衡量第一个相关结果出现在什么位置。如果第一个相关问题排在第 1 位,得 1 分;排在第 3 位,得 1/3 分。MRR 越高,说明相关结果越靠前。它反映的是“召回到什么位置”。

Precision@k 和 Recall@k 则进一步细化了准确率评估。Precision@k 表示返回的 k 个结果中有多少比例是相关的;Recall@k 表示所有相关文档中被召回的比例。

这些指标之间的关系可以这样理解:Hit Rate 是底线,MRR 是排序质量,Recall 和 Precision 是更严格的双向评估。在实际项目中,通常先看 Hit Rate,再关注 MRR,最后结合业务需求看是否要调整 k 值。

7.3 生成质量指标

检索质量好,不代表最终答案好。LLM 可能没有遵循 Prompt 指令、可能遗漏关键信息、也可能在检索内容之外自行发挥。生成质量需要单独评估。

Faithfulness(忠实度)衡量生成内容是否忠实于检索到的上下文。如果模型明明看到资料里写“最大负载 50kg”,却在答案里说“最大负载 80kg”,就是不忠实。这个问题本质上就是幻觉。

Answer Relevancy(答案相关性)衡量生成内容是否切题,是否回答了用户的问题。有时候模型复述了一堆原文,但用户问的是“怎么解决”,模型回答的是“是什么”,就是不相关。

这两个指标在生产系统中都可以自动计算,也可以抽样人工评分。自动计算的典型工具是 RAGAS,它利用 LLM 作为评测器,输入问题和答案以及检索文档,返回上述指标的分数。但要注意,用 LLM 评 LLM 会有偏好偏差,关键业务场景建议保留人工抽检环节。

7.4 一个最小化的 MRR 计算示例

理解 MRR 最快的方式是亲自动手实现一次。下面的伪代码演示了 MRR 的计算逻辑。

# eval_mrr_example.py def reciprocal_rank(relevant_rows, k): """ relevant_rows: 检索结果列表,按相关性分数降序排列 k: 只看前 k 条结果 返回该查询的 reciprocal rank 值 """ for rank, row in enumerate(relevant_rows[:k], start=1): if row["is_relevant"]: return 1.0 / rank return 0.0 # 示例:一次查询的检索结果,按相关性从高到低 query_result = [ {"doc_id": "doc_1", "is_relevant": False}, {"doc_id": "doc_2", "is_relevant": True}, {"doc_id": "doc_3", "is_relevant": False}, ] k = 3 rr = reciprocal_rank(query_result, k) print(f"本次查询的 reciprocal rank: {rr}") # MRR 就是多次查询 reciprocal rank 的均值 all_queries = [ {"doc_id": "doc_1", "is_relevant": False}, {"doc_id": "doc_2", "is_relevant": True}, {"doc_id": "doc_3", "is_relevant": False}, ] def mean_reciprocal_rank(queries, k): total = 0.0 for query in queries: total += reciprocal_rank(query, k) return total / len(queries) mrr_value = mean_reciprocal_rank([query_result, query_result], k=3) print(f"MRR@3: {mrr_value}")

在实际项目中,你可能不会手写这些指标,而是借助 Ragas 或其他评测框架。但理解计算逻辑非常重要。只有理解每个指标在奖励什么、惩罚什么,你才能在调优时判断“指标上升是否真的意味着系统变好”。

8. 常见问题与排查思路

RAG 系统在开发阶段的问题非常多,很多现象看起来相近,但原因完全不同。下面整理了一份常见问题排查表,可以收藏备用。

问题现象可能原因排查方式解决方案
启动时依赖安装失败Python 版本不兼容或缺少编译环境查看 pip 错误日志,确认 Python 版本升级到 Python 3.10+,或使用 conda 创建隔离环境
知识库检索不到相关内容文档切分过大或过小,语义被稀释或截断打开向量库,查看文本块语句是否完整调整 chunk_size 和 chunk_overlap,重新向量化
答案和用户问题不相关检索返回了无关内容,且进入了 Prompt打印 source_documents 查看召回文档调整 top-k、加入混合检索或重排
模型回答出现幻觉检索结果为空,模型被迫自行补全检查检索结果的相似度分数是否过低设置相似度阈值,明确要求模型不知道就说不知道
检索到正确内容但答案反而混乱塞进 Prompt 的上下文太多或相互矛盾检查 source_documents 的数量和内容降低 k 值,或对文档做去重和版本过滤
专业术语大量出现时效果变差embedding 模型对专业领域理解不足在黄金集上对比不同 embedding 模型的指标替换为领域微调过的 embedding 模型,或引入关键词检索
向量库持久化后重启数据丢失未配置持久化目录或使用了纯内存模式检查向量库初始化参数配置 persist_directory 或使用服务端向量数据库
本地部署模型显存不足精度选了 FP32/FP16,模型参数过大查看显存占用日志切换到 BF16 或量化到 INT8/INT4,验证效果
答案经常引用过时文档知识库没有增量更新机制检查文档更新时间戳引入数据版本管理和索引重建任务

排查 RAG 问题有一个通用顺序:先确认检索阶段有没有正确召回,再确认 Prompt 组装有没有问题,最后再怀疑生成模型。很多人第一反应是“模型不行”,结果花了很多时间换模型,问题依旧。实际上,RAG 系统的大部分效果问题都出在数据和检索环节。

9. 最佳实践与工程建议

RAG 项目做到最后,拼的往往不是某个环节的极致优化,而是工程体系是否完整。下面这几条最佳实践,来自常见生产项目的经验总结。

9.1 从最小可行 RAG 开始

不要在一开始就引入 Agentic RAG、混合检索、知识图谱等复杂组件。第一步应该用最快的速度跑通“文档加载 + 向量化 + 检索 + 生成”的最小链路,让业务方看到效果,也让自己对数据情况有感知。然后再用评估数据驱动优化。否则复杂系统一旦出问题,定位成本会非常高。

9.2 把文档预处理当成第一优先级

知识库项目的天花板往往在文档预处理阶段。建议对文档格式做一次全面盘点,把“哪些文档适合直接切分”“哪些文档需要 OCR”“哪些文档需要专门解析表格”列成明细表。对经常出现的固定版式,可以写专门的解析函数,而不是寄希望于一个通用解析器搞定所有文档。

9.3 检索环节先保证召回,再做精排

在检索链路设计上,可以用两级思路:第一级尽量放宽条件,保证相关文档能被召回;第二级用重排模型或更精细的过滤逻辑,把真正有用的内容排到前面。先优化 Hit Rate,再优化 MRR,最后才看生成质量。这个顺序不能反。

9.4 Prompt 要明确约束生成行为

生成阶段的 Prompt 至少应该包含三部分:系统指令、检索上下文、用户问题。系统指令要明确告诉模型“只能依据检索内容回答,不要使用训练时学到的知识补充;如果检索内容不足,回答不知道”。同时要求模型在回答时引用来源编号。这个设计能显著降低幻觉率,也让溯源成为可能。

9.5 记录完整的运行日志

线上 RAG 系统建议记录每次请求的完整链路:原始问题、改写后的问题(如果有)、召回的文档列表、相似度分数、送入 Prompt 的最终上下文、模型输出、耗时。这些日志既是调试故障的依据,也是后续搭建自动化评测集的数据来源。很多团队忽略了这一步,等到上线后效果变差,才发现没有任何线索可以回溯。

9.6 安全与权限是最后的底线

如果知识库包含了内部资料或用户隐私数据,在架构设计之初就要考虑权限隔离。不要让一个用户可以检索到另一个用户私有范围的内容。向量数据库层的过滤能力很重要,应用层也要做身份认证和操作审计。涉及敏感数据的项目,务必在测试环境验证权限过滤逻辑后再上线,并准备好回滚方案。

10. 总结:LLM 工程师的核心能力模型

回到这门 Udemy 课程第三部分的整体定位,它真正想训练的能力不是“会调用 API”,而是“会设计一套完整的 GenAI 系统”。从 RAG 链路到 Agent 概念,从精度问题到评估指标,这些知识点串联起来,指向的是 LLM 工程师的四种核心能力。

第一是数据工程能力。知道如何从真实业务文档中提取可用知识,如何处理 PDF、Word、HTML 等复杂格式,如何设计切分策略。

第二是检索系统设计能力。知道如何选 embedding、如何选向量数据库、如何设计混合检索和重排,而不是只会调用一个现成接口。

第三是模型部署与成本控制能力。理解 FP16、BF16、量化的取舍,知道在有限的 GPU 资源下如何平衡速度和质量。

第四是评估能力。能建立测试集,能看懂指标变化,能通过数据定位瓶颈。这是区分“能跑 Demo”和“能上生产”的分水岭。

如果这篇文章让你有收获,建议马上选一份实际文档,按照第二章到第五章的流程搭一个最小知识库,再做一套 50 条问题的评估集,记录当前指标。然后试着调整 chunk_size、切换 embedding 模型、加入重排,观察指标和答案质量的变化。

做 LLM 应用开发,最大的误区是以为“视频课刷完就是会了”。真正值回票价的方式,是把课程里的评估方法用到自己的知识库里,把系统从“能跑”改到“好用”。RAG 工程中还有很多细节值得深入,比如更复杂的文档解析、Agent 多轮检索、基于本体的约束生成、以及更细粒度的评测体系。每一条都值得再单独写一篇实践笔记。

http://www.cnnetsun.cn/news/4332516.html

相关文章:

  • PyTorch手写数字识别项目实战:从数据加载到模型部署的完整指南
  • 搜狐畅游校招Java笔试题解析:游戏开发工程师考点与实战
  • Java面试短期突击:从八股文到场景题的最小复习闭环
  • 基于Scrapy的Python爬虫架构设计与反爬应对策略
  • 呼叫中心IVR智能语音导航架构:自动分流、业务分层与通话提效技术解析
  • 计算机网络安全知识点
  • 外文翻译不用愁[特殊字符]零机翻感!论文英文翻译神器太绝了
  • JavaWeb仿小米商城项目实战:从Servlet到订单事务全流程解析
  • Claude + Obsidian 2.0:打造会读会写的 AI 第二大脑知识库
  • Qt平滑手写笔迹绘制:从事件采集到贝塞尔曲线拟合
  • 2026答辩季AI工具实测:大模型、通用AI PPT工具、毕业垂直工具,差距到底在哪?
  • 基于深度学习的阿尔茨海默病早期诊断辅助系统设计与实现
  • 用Accept标头让AI代理直接获取Markdown:内容协商实用指南
  • Simulink仿真结果曲线:从可视化到汽车动力性能结论的完整解析
  • RAG三层检索策略全解析:从查询理解到融合重排
  • 车载单圈视频数据工程:从GPS遥测到Python与ffmpeg分析
  • 基于MATLAB的SAR成像仿真与舰船检测工程实践
  • 怎么理解专业化分工与协作的原则
  • 最适合人工智能开发的编程语言优缺点对比
  • Codex API成本深度解析:重度使用一个月花多少钱?
  • 数学证明验证工具链:公式OCR、SymPy与大模型推理实战
  • 兰城装饰和艺家空间设计对比,兰溪装修怎么选?
  • 基于多目标粒子群算法的微电网优化调度Matlab实现详解
  • SpringBoot维修工单系统实战:从ZIP到上线全流程解析
  • Milvus学习总结
  • 基于深度学习的人流量检测系统设计与实现
  • 基于深度学习的仪表读数识别实战:从YOLO检测到OCR部署
  • 拆解一个YOLO图像识别系统:从数据标注到推理部署全流程
  • 基于Vue 3与TipTap的电子病历编辑器架构设计实践
  • 【计算机毕业设计】基于fastapi+vue的宠物领养管理系统