做了一段时间大模型应用之后我越来越觉得 RAG 是这个阶段最值得投入精力的技术方向。原因很简单大模型再强也没法凭空知道你内部文档里的内容而 RAG 恰恰用一套“检索 生成”的组合把外部知识“接”进了模型回答里。这篇文章想一次性把 RAG 相关的概念讲清楚再附上我自己的完整实践过程。适合刚接触 RAG 的开发者也适合那些已经跑通 Demo 但检索效果不理想、想系统优化的朋友。这两年有个词特别火叫“外挂知识库”。其实背后就是 RAGRetrieval-Augmented Generation检索增强生成。它解决的是一类非常现实的问题模型训练完之后知识就停在那个时间点了无法自动知道你的新文档、内部制度、产品手册、聊天记录。你当然可以重新训练一个模型但成本高、周期长而且不是所有团队都有这个条件。RAG 等于给模型加了一个“可随时翻阅的资料架”回答问题时先查资料再写答案。这套思路能落地、能迭代、能评估比很多花哨的架构实在得多。1. RAG 到底是什么核心概念与整体思路拆解1.1 大模型知识边界带来的三个痛点先说清楚为什么需要 RAG。大模型本身是一个“参数化的知识存储体”它把训练时见过的文本压缩进了网络权重里。这个机制有两个天然限制一是知识有截止时间二是知识范围取决于训练数据三是它不知道自己不知道什么。第一个痛点最好理解。一个大模型如果训练数据截止在某个时间点之后发生的产品变更、政策调整、项目进度它都“看不见”。很多业务场景恰恰要求回答的是最新信息比如「当前版本是否支持某某功能」「这个月的排期是什么」。这不是模型能力问题是知识时效问题。第二个痛点更隐蔽。即使模型训练数据很新也不包含你公司的私有文档。它知道通用知识但不知道你们内部的工作流、特殊字段、行业黑话。硬问就会出现一本正经地胡说八道因为模型在回答没见过的问题时只能靠泛化能力“编”一个听起来合理的答案。第三个痛点是被大家讨论最多的“幻觉”。由于模型在生成时没有外部依据它无法区分“我记得”和“我推测”。有时候它给出的答案结构完整、语气自信但关键细节完全对不上。在客服、医疗、法律、金融这些高合规场景里这种不可控性是致命的。RAG 的思路就是绕过“把知识塞进参数”这条路。它只在生成前临时去知识库里检索相关内容把检索到的文本片段作为参考材料让模型基于材料作答。模型不需要“背住”你的文档只需要在回答时“读懂”你给的参考资料。这样知识更新、权限控制、答案溯源都变得可控。1.2 RAG 与微调为什么优先考虑 RAG很多人在了解到大模型无法回答私有知识后第一反应是微调第二反应是 RAG。我见过不少团队在这两个方案之间纠结其实它们解决的问题有重叠但不完全一样。微调是让模型“学会某种行为或表达模式”比如把回答风格改成更口语化、更简洁或者让模型学会在特定领域输出特定结构的结果。微调改变的是模型的参数成本高且每次知识更新都要重训。更关键的是微调很难精确记住事实型细节。你可以在训练数据里反复强调“年假规则是 15 天”但模型可能还是会混淆相近的数字。RAG 则更像“开卷考试”。它不改变模型参数只是给模型临时提供参考资料。你的文档还是原来的文档向量索引还是那份索引内容更新时重建索引就行模型不用动。对于大多数“知识查询型”需求RAG 是更轻、更快、更容易调试的方案。那什么时候才需要微调在我看来需要稳定输出格式、固定工具调用逻辑、或者大幅度降低回复口吻漂移时微调更有价值。RAG 和微调也不是二选一的关系比较成熟的工程往往先用 RAG 解决知识注入再用微调解决输出风格和指令遵循问题。但起步阶段建议不要一上来就微调先用 RAG 跑通最小闭环成本最低见效最快。1.3 RAG 流水线三阶段索引、检索、生成RAG 的标准流程可以拆成三块索引Indexing、检索Retrieval、生成Generation。很多文章喜欢画复杂的架构图但核心就这三件事。索引阶段负责把原始文档变成“机器可检索”的结构。文档进来后先解析成纯文本然后按一定规则切分成小块每一块用嵌入模型转成向量最后写入向量数据库。这里有很多细节会影响效果比如文档太多要不要清理格式、表格怎么处理、分块多大合适我会在后面详细展开。检索阶段负责从向量库里找到与用户问题最相关的内容。用户输入查询后查询文本也用同样的嵌入模型转成向量然后在向量库里做相似度搜索取回 Top-K 个最相关的文本片段。看似简单但这里藏着 RAG 效果好坏的关键召回准不准、排序对不对。生成阶段负责把检索到的内容组织成答案。系统把用户问题和检索到的参考片段一起放进 Prompt让大模型基于参考内容作答。这段逻辑同样不能小看Prompt 怎么设计决定了模型是否会被无关内容带偏、是否会在找不到答案时老实说不知道而不是硬编。三阶段环环相扣。索引出问题检索就召回不准检索出问题生成阶段拿到的材料就是垃圾Prompt 出问题就算材料对了也答不对。所以后面我会按这个链路一层一层讲实操。2. 索引环节的细节与实操要点2.1 文档加载与预处理解析、清洗、结构保留文档加载是 RAG 流水线里最不起眼但最容易出问题的地方。很多人图省事把 PDF 直接扔给解析器提取出一堆带乱码、页码、页眉页脚的文本然后直接切块入库最后检索结果一言难尽。其实绝大多数检索质量事故根源都在预处理没做好。文档预处理有个基本原则能先清洗就清洗不要把格式垃圾带到切块阶段。常见做法包括去除页眉页脚、去掉页码、合并断行、把表格转成带上下文的结构化描述。段落合并经常被忽略PDF 解析出来的一行文本往往因为排版被拦腰断开直接切块会切出大量半句话。我的习惯是先按段落重新组合文本识别出“看上去不完整的换行”并合并。表格处理要单独说。表格在纯文本里非常容易“读”乱转成 Markdown 表格或键值对描述都行。最好的方式是保留表格结构的语义比如把“字段名 值”抽取成一句自然描述「报销标准交通费每天不超过 80 元」。模型检索到这种描述后理解难度比拿到原始表格低得多。还有一类容易被忽略的是文档的多级标题。切块时如果完全没有结构意识很可能把一个小节的标题切到上一个块里导致该块内容缺乏上下文。实际项目中我通常会把“标题 正文”一起保留在 chunk 里或把标题作为 metadata 附加到该节所有子块上。这样既方便检索也可以在生成阶段告诉模型“这段话来自哪个章节”。2.2 分块策略块大小、重叠、边界选择分块是 RAG 里最像“调参数”的环节没有标准答案但有一些靠谱的参考区间。我一般把 chunk_size 控制在 300 到 800 token 之间具体取多少取决于文档类型和嵌入模型的最大输入长度。为什么要限制 chunk 大小因为向量检索比的是语义相似度一个 chunk 如果太长里面包含多个主题检索时整体向量会被“平均化”导致与查询语句的相关度被稀释。反过来说chunk 如果太小比如只有一两句话语义信息太少同样容易召回不准。块大小的本质是平衡“语义完整性”和“信息聚焦度”。还有一个概念叫重叠overlap。切块时让相邻块共享一部分文本能避免把重要句子正好截断在边界上。比如 chunk_size512overlap50意思是每两个相邻块之间有 50 个 token 是重复的。这样即使关键信息落在上一块末尾下一块也能覆盖到。切块的边界选择比大小更容易被忽略。很多人直接按固定 token 数硬切结果把一句话切成两段检索出来全是“半句话”。更合理的做法是优先按 Markdown 标题、段落、句子边界切。用一个简单的判断逻辑先尝试在段落边界切如果段落太长再退回到句号、问号、换行符这些自然边界切。中文环境下句号和分号都是不错的候选边界。我在实操中还会区分“问答型文档”和“描述型文档”。问答型文档每个 QA 对天然就是一块不需要重叠。描述型文档则需要按章节语义切块。切完一定人工抽查十几块看看有没有出现上下文断裂。这个步骤非常推荐肉眼扫一遍能发现很多指标暴露不了的问题。2.3 嵌入模型选型中文场景怎么选嵌入模型负责把文本变成向量。这个模型的选型直接影响检索质量而且不同模型的维度、语言能力、效果差别很大。国外的一些通用嵌入模型在中文场景下表现并不稳定。倒不是说英文模型不能用而是中文分词、语序、多义词处理对模型要求更高。很多团队一开始随便选一个通用模型结果中文检索效果平平以为是自己数据问题其实是嵌入模型没选好。中文场景我的建议是优先试专门针对中文优化过的开源嵌入模型。选型时可以看三个指标检索任务上的召回准确率、向量维度大小、对长文本的支持程度。维度不是越高越好高维度意味着更大存储和计算开销但维度太低也可能丢失信息。常见 embedding 维度范围从几百到上千都有关键是看模型在目标数据集上的表现而不是盲目追求某个数值。选嵌入模型还有一个容易踩坑的地方索引和查询必须用同一个模型。如果索引时用模型 A查询时换了模型 B两个模型的向量空间根本不匹配检索结果会完全错乱。所以升级嵌入模型时必须全量重新索引不能只换查询端的模型。另外如果文档包含大量术语、产品名、生僻词可以考虑在预处理阶段对这些词做词汇增强。比如把「RAG」和「检索增强生成」建立映射让查询和文档能在同一语义层面上匹配。这是一种很实用的工程技巧比换模型成本低很多。2.4 向量存储与元数据设计向量数据库负责海量向量的存储和相似度检索。选择哪个向量库不重要重要的是想清楚索引结构、元数据过滤和数据更新方式。先说元数据metadata。这是我在项目里最看重的一点。每个 chunk 向量除了本身的内容向量还应该带上文档名、章节路径、更新时间、来源链接、权限级别等字段。为什么重要因为真实场景里很少是“全局检索”大多是“某个产品范围”“某段时间内”“某类文档类型”的检索。有了元数据就可以在检索前先过滤既能提高精度也能减少无关结果干扰。比如用户问「2025 年市场部培训计划」如果文档有部门和时间元数据检索时可以先限定部门市场部、时间2025再在剩下的向量里找相似内容。这个过滤能大幅减少向量检索的压力也能避免明明检索到类似内容但不是目标范围的问题。向量库的索引类型也需要关注。小规模项目用暴力检索Flat完全够几万条向量毫秒级返回。上百万条向量后需要切换到倒排索引、HNSW 这类近似最近邻索引否则检索延迟会明显上升。我的经验是项目初期不要过早优化存储架构先用最简单的方式跑通业务逻辑等数据量上来再换索引。增量更新也很重要。RAG 系统不是一次性建好索引就不动了。文档新增、修改、删除后向量库里对应的向量也要同步。最朴素的做法是定时全量重建数据量小时完全可行数据量大时则要按文档 ID 做增量更新删除旧向量、写入新向量。至少要做到“来源文档有版本号”否则你很难判断检索到的是不是最新内容。3. 检索与生成让模型真正“看”到正确答案3.1 检索策略Top-K、相似度阈值、重排序索引建完之后进入检索环节。这里的第一个参数是 Top-K也就是最终取多少个候选片段交给模型。Top-K 太小可能漏掉唯一的正确答案Top-K 太大会把大量无关内容塞进 Prompt不仅浪费 token还容易干扰模型判断。我在实践里一般初始值设为 4 到 6然后根据业务场景调整。如果是精确查找类问题比如查一个具体编号、金额Top-K 可以设置得小一点并且提高相似度阈值只保留最相关内容。如果是开放性问题比如“总结一下某文档的观点”Top-K 可以适当加大让模型看到更全面的材料。相似度阈值是另一个常用工具。向量检索返回的结果即使排在最前面也可能和查询完全不相关。这时候需要设置一个最低相似度分数低于阈值的候选一律不采用。阈值怎么定没有固定值我习惯在验证集上跑一批问题观察相关结果和不相关结果的分数分布然后选择一个能把两者分开的临界值。这个分布通常会有一个大断层断层处就是比较合理的阈值。重排序Rerank是效果提升最明显的一步。向量检索负责粗召回拿到 Top-50 或 Top-100 的候选然后用一个更强的排序模型在这些候选中重新精排挑出最相关的 Top-5 或 Top-6。粗召回的目的是“宁可多召回也不错漏”精排的目的是“最终拿给模型的必须是最精准的”。这套方案在文档数量大、内容相似度高的场景里特别管用。还有一个很容易被忽视的检索技巧查询改写。用户提问通常很口语化比如「年假能休多少天」。直接拿原句去检索可能不如先改写成标准化表达比如「年假天数规定」。部分实现里会先用大模型把用户问题转换成几个检索子查询再分别检索合并结果。这个操作在问题是复合型、条件比较多时尤其有效。3.2 Prompt 构造与安全限制检索到的内容最终要通过 Prompt 交给模型。Prompt 构造的成败往往比模型能力还重要。我在实践中总结了一份“底线模板”核心是四个部分角色、任务、参考材料、约束。角色用来告诉模型以什么身份回答问题比如“你是一个企业知识库助手”。任务里说明你要做什么比如“根据下面的参考资料回答用户问题”。参考材料部分按顺序列出检索到的文本片段。约束部分则写清楚不能做什么比如“只能基于参考资料回答不要输出参考材料之外的信息”“如果资料中没有答案直接说不知道不要编造”。为什么一定要写“不知道就直说”这是对抗幻觉最有效的手段之一。模型在指令明确的情况下会更倾向于在资料找不到答案时表达无法回答而不是强行补全。实测下来这条约束比“你要准确”有效得多。参考材料的顺序也有讲究。我的做法是把经过重排序后得分最高的片段放在最前面并在每个片段前面标注来源编号。当模型最后输出答案时如果让它引用某个片段编号用户就能回溯到原始文档。这既提升可信度也有利于后续排查。另外要注意 token 长度。Prompt 不能无限长参考材料过多会挤占模型输出空间还可能出现模型把不相关内容强行纳入推理链的情况。我习惯在构造 Prompt 前先统计参考材料总 token如果超限就截断得分较低的片段而不是一股脑全塞进去。3.3 引用溯源与答案质量兜底很多人觉得 RAG 输出答案就结束了但真实项目里还有一个重要环节溯源和兜底。溯源指的是答案要能对应到具体的参考文档位置。最简单的实现是让模型在输出答案时附带引用编号例如“[1]”“[2]”然后在答案下方列出每个编号对应的文档标题和链接。这个功能看起来简单但对用户信任度的提升非常明显。尤其是在企业客服、内部知识库场景里用户看到能点击查阅的出处比只看一段干净答案更放心。兜底要处理的是“检索失败”和“答案无法生成”两种情况。检索失败很好理解向量库里没有相关内容这时候就不要强行回答。答案无法生成的情况稍微隐蔽一些检索到了内容但内容和问题可能并不直接匹配模型自己也能判断出来这时应该允许模型返回“没有找到相关答案”。这两个兜底逻辑都需要在 Prompt 里明确并且在后端接口返回结构里预留一个状态字段比如answer_status值为success或no_answer。还有一类情况是检索结果“看起来相关但实际错误”。比如用户问 A 产品价格检索到 B 产品相似描述。这个靠单轮检索很难完全避免所以需要结合元数据过滤和重排序来降低风险。同时建议在答案后面加一句“以上信息基于知识库文档具体以最新发布文件为准”给用户一个心理预期也给系统留出误差空间。4. 完整 RAG 实践过程从零搭一条最小闭环4.1 环境准备与技术选型下面分享一下我搭 RAG 最小闭环的完整路径。假设你没有现成的 RAG 平台想从零开始做一个能回答内部文档问题的系统下面这套流程可以直接参考。环境上需要准备三样东西一个大模型问答接口一个嵌入模型一个向量数据库。大模型接口负责最后的生成嵌入模型负责把文档和查询变成向量向量数据库负责存储和检索向量。具体用哪个服务商、哪个开源库可以根据你的团队情况定没有绝对最优。我建议第一版不要上过于复杂的架构。先选一个最熟悉的编程语言我常用 Python用轻量方式把链路跑通再考虑工程化。向量库选择上如果数据量在百万级以内、部署环境简单完全可以用本地文件型向量库如果数据量很大、需要分布式和权限控制再考虑服务型向量库。数据准备阶段要明确知识库范围。第一版不要一上来塞几百个文档先挑 20 到 50 个经常被问到的高频文档人工清洗好格式再建索引。这样你能在可控范围内观察检索效果快速定位问题而不是被海量数据淹没了排查方向。4.2 核心代码骨架伪代码也能跑通逻辑下面我用伪代码展示核心链路重点在于逻辑清晰换成你手头的组件也一样能跑。先看索引侧。# 1. 读取文档 raw_docs load_documents(knowledge_base/, file_typepdf) # 2. 清洗去页眉页脚、合并换行、按标题提取结构 clean_docs [clean_text(doc) for doc in raw_docs] # 3. 分块优先按标题/段落边界切控制块大小 chunks [] for doc in clean_docs: chunks.extend(split_doc( doc, chunk_size512, chunk_overlap50, split_byheading_and_paragraph )) # 4. 向量化用同一个嵌入模型 embeddings [] for chunk in chunks: embeddings.append(embed_model.encode(chunk.text)) # 5. 写入向量库同时保存元数据 vector_store.add( ids[c.id for c in chunks], embeddingsembeddings, texts[c.text for c in chunks], metadatas[c.metadata for c in chunks] )这段流程里最需要注意的是分块和向量化的顺序。必须“清洗 - 分块 - 向量化”如果先向量化再切块向量会切得零碎语义丢失严重。还有一点嵌入模型对单次输入长度有限制超长 chunk 会被截断所以分块时得注意模型支持的最大序列长度。再看查询侧。# 1. 查询向量化 query 员工的年假规则是什么 query_vec embed_model.encode(query) # 2. 可以先用元数据过滤再向量检索 candidates vector_store.search( query_vec, top_k50, filter{category: HR, dept: 全部} ) # 3. 重排序取最终Top-5 reranked rerank_model.rerank(queryquery, candidatescandidates) final_context reranked[:5] # 4. 构造Prompt prompt build_prompt( system你是一个企业知识库助手只能基于参考材料回答。, contextfinal_context, questionquery, instruction如果材料中没有答案请直接说不知道。 ) # 5. 调大模型生成答案 answer chat_model.chat(prompt)这段代码最关键的变量是final_context。很多第一版错误都出在这里要么 Top-K 设太大塞了太多无关内容要么没有重排序高质量片段被埋在低质量结果后面。我强烈建议第一次跑查询时把检索返回的 Top-20 结果全部打印出来人工看一遍你能很直观地感受到“向量相似度高”和“真正回答了问题”之间有多少差距。4.3 关键参数调优经验跑通之后下一步就是调优。我分享一组我常用的初始参数和调节方向大家可以根据自己的结果微调。分块大小中文文档我一般从 400 token 起测。如果检索出来的片段经常“话没说完”说明块太小如果片段里混了多个主题说明块太大。调整幅度每次 100 token 左右不要一次改 300。重叠大小初始设 50 到 80 token。如果发现切块边界把关键句切断了适当加大重叠如果文档很短重叠甚至可以设为 0。Top-K粗召回阶段设 50重排序后最终取 5。如果答案经常信息不全加到 6 或 7如果答案开始出现无关内容降回 4。这个数取决于文档质量也取决于问题类型。重排序必要性数据量上千条以后我基本必加重排序。重排模型会额外增加响应延迟和成本但换来的是答案命中率明显提升。如果项目对响应速度极度敏感可以考虑只对 Top-20 候选做重排而不是全量候选。我始终坚持一个原则参数调优不是猜而是要看实际样本。准备 50 个有标准答案的问题跑一遍系统统计命中率再针对错误案例微调。没有评估集的调参基本就是瞎试。5. 常见问题与排查技巧实录5.1 检索结果完全不相关这是最常遇到的情况用户问了一个问题返回的参考片段牛头不对马嘴。排查时先别怀疑模型从几个层面逐层看。第一步看查询本身。查询文本是否包含太多口语化表达比如「怎么请年假呀」这种句子嵌入模型可能匹配到一堆和“请假流程”有关但并非“年假”的内容。可以先把查询改写为更规范的说法再检索。第二步看嵌入模型是否匹配。如果索引时用的模型和查询时用的模型不一致结果必然乱套。这种问题常发生在调试阶段因为换了模型但没有重建索引。检查方式很简单随机打印几个查询向量和文档向量算一下整体相似度分布如果普遍非常低大概率就是模型不一致。第三步看分块是否合理。如果文档切得太粗糙比如一块包含几百个 token 的多主题内容嵌入向量会变成“大杂烩”和查询的相关度被稀释。这种情况的典型表现是“检索结果看起来沾边但都对不上重点”。解决办法是缩小区块按更细的标题或段落切分。5.2 文档被切碎之后语义不连贯另一个高频问题是检索到的片段单独看没问题但整段读起来上下文缺失模型据此生成的答案也残缺。这种现象往往不是切块“切错了”而是切块时没有照顾到相邻内容的关系。我常用的对策是在每个 chunk 里保留足够上下文。具体做法有两种一种是在 chunk 的文本开头补一小段“上文摘要”另一种是把所属标题和父章节标题写进 metadata生成阶段让模型先看标题再看正文。后一种对长文档特别有用比如一本操作手册里的某个参数说明脱离了所属章节读者根本不知道在说什么。如果问题还很严重可以考虑“段落级召回 句子级裁剪”的组合。也就是先把段落作为基本检索单元检索到相关段落后再用规则或模型抽取出其中最相关的几句话作为最终 context。这样既保留了段落级语义又不至于把无关句子全塞给模型。5.3 模型跳过检索结果直接作答明明向量库里有正确答案检索也返回了正确片段但模型最后还是按照自己的知识回答了而且回答内容跟参考材料矛盾。这类问题非常让人头疼因为它既不是检索问题也不是简单的模型能力问题而是 Prompt 约束不够强。我遇到过好几次这种情况最后都是靠加强指令约束解决的。可以在 Prompt 里加上一句“你的回答内容必须完全来自上面的参考资料。如果你发现参考资料不足以回答问题请回答‘知识库中没有找到相关信息’。”同时把参考资料和用户问题用明确的标记区分开比如用[参考资料开始]...[参考资料结束]包裹让模型更容易理解边界。还有一个技巧是把“检索到的内容数量”和“格式要求”写进指令。比如“这里提供了 5 段参考资料请结合这 5 段内容回答”。模型在明确数量和范围受限的情况下会更倾向于从给定材料里找答案而不是自由发挥。5.4 增量更新与重复向量问题知识库上线后文档更新是常态。这时候最容易出现的问题是旧文档的向量没删干净新文档的向量又写进去了导致检索时旧内容重复出现甚至新旧版本相互矛盾。解决增量更新问题的关键是每个文档都要有唯一 ID并且 metadata 里记录文档版本、发布时间、更新时间。更新文档时先用文档 ID 把旧向量全部删除再插入新向量。如果向量库不支持按 metadata 删除就需要额外维护一份“文档 ID - 向量 ID”的映射表。批量导入时还容易出现重复向量。同一份文档如果因为脚本 bug 被跑了两次向量库里就有两份重复内容检索时返回的结果可能一模一样。我的做法是入库前先检查目标文档 ID 是否已存在存在就跳过同时在索引流程里加一个幂等标识确保同一批数据不会被重复写入。5.5 评估 RAG 效果没有指标就是盲调很多人调 RAG 只靠“感觉”觉得回答好像变好了就开始上线。但一旦效果不稳定就说不清是哪一环出了问题。我这两年最大的体会是RAG 项目必须从第一天就建立评估集。评估集不需要很庞大先准备 50 到 100 个真实高频问题每个问题配好标准答案或至少判断标准。跑完系统后人工判断回答是否可接受统计命中率。有了这个基线每次改参数、换模型、调 Prompt都能对比前后效果而不是凭感觉。更细致的评估可以分成三个维度检索命中率正确片段是否在最终 context 里、生成准确率答案内容和标准答案是否一致、幻觉率答案里是否出现了资料之外的内容。这三个维度对应三阶段优化定位问题会非常快。我也建议把错误案例分类积累起来。比如有的是“检索到了但模型没用”有的是“没检索到正确片段”有的是“检索到但被重排序排掉了”。积累一段时间后你会发现自己系统的短板集中在哪一块再针对性优化。6. 进阶优化方向与个人的一点体会6.1 混合检索、重排序、对话记忆当基础 RAG 跑通后有几个进阶方向非常值得投入。第一个是混合检索。向量检索擅长语义相似但有时不够精确。比如用户搜「TD 256」这种产品型号向量检索可能匹配到一堆和 TD 相关的泛化描述反而不如关键词匹配精准。混合检索的做法是把向量检索和关键词检索结果合并再通过重排序统一排序兼顾语义和精确匹配。这个组合在技术文档、产品型号、制度编号场景里提升非常明显。第二个是重排序模型的单独优化。重排序模型本身也有训练和参数空间可以选取一批“真实查询 相关/不相关文档”数据做微调。这一步投入产出比很高但前提是已经积累了足够多的人工标注样本。早期阶段先用通用重排模型就够。第三个是多轮对话记忆。用户在知识库问答中很少只问一句话往往会追问“那报销标准呢”“最长可以多久”。如果没有记忆系统每次都只能看到当前这一句很容易丢上下文。实现方式也不复杂把前几轮的用户问题和系统答案摘要后作为检索辅助信息构造查询时带上它们就能显著提升多轮问答体验。6.2 从 Demo 到生产要补的功课Demo 能跑通和上线能稳定运行中间隔着一大堆功课。我踩过不少坑挑几个重要的提醒大家。权限控制是大头。知识库里的文档不一定所有用户都能看向量库里的向量如果权限没隔离检索时很容易把不该看的文档内容带出来。解决方案是在 metadata 里存权限标记检索时强制过滤用户不可见的文档。这个逻辑必须在检索源头做不能指望 Prompt 让模型规避。然后是成本控制。每条查询都要走嵌入模型、重排序模型、大模型生成三层叠加起来 token 消耗不小。生产环境可以做结果缓存相同或相似问题直接返回上次答案大幅降低调用量。缓存 key 建议基于规范化后的查询文本而不是原始文本否则「年假几天」和「年假有多少天」会被当成两个问题。还有是响应延迟。RAG 系统比普通问答多了检索和重排序步骤延迟天然更高。如果要压缩耗时优先看三个地方向量库索引类型是否适合数据量、重排序是否真的对每个候选都必要、大模型的流式输出是否开启。没有特殊要求时流式输出会明显改善用户体验。6.3 最后分享一个我的经验法则做了这么多 RAG 项目我最大的体会是不要一开始就追求复杂架构。先把“清洗文档 - 分块 - 向量化 - 检索 - Prompt 生成”这条闭环跑起来然后准备好评估集再逐点优化。很多时候你以为要换模型、上重排序结果最后发现只是分块没切好或者向量模型没配对。我也越来越觉得RAG 的价值不是让模型“记住所有事”而是让系统知道自己有哪些知识、哪些没有。它带来的不仅是更准确的回答还有一种思路上的改变把“模型要什么都知道”降级成“模型能知道从哪里找答案”。后者在工程上要靠谱得多。如果你也在搭自己的知识库问答系统建议先从一份干净的文档、几十个问题开始跑通后再慢慢加数据。你会发现大部分问题不需要更强大的模型只需要把检索这条“后勤链路”捋顺。这也是我在这篇文章里最想传达的东西。