☰
RAG智能体技术栈全链路归档:从分块策略到智能体编排的工程实践
2026/11/2 9:06:49 网站建设 项目流程

1. 为什么我要把整套 RAG 智能体技术栈“归档”下来

做 RAG 智能体开发这两年多,我最大的感受不是技术难,而是信息碎。今天在某个仓库里看到一段好用的检索重排逻辑,明天在另一篇分享里发现一个分块策略的巧思,后天又踩到一个向量库元数据过滤的坑——这些东西散落在浏览器书签、临时笔记、聊天记录里,等到真正要搭一个新项目时,反而什么都找不齐。所以从去年下半年开始,我给自己定了一个规矩:每跑通一个环节,就把它整理成一份可复用的归档文档,按“技术体系”而不是“项目”来组织。这份文档就是这套归档思路的完整呈现,它不讲某一个具体业务,而是把 RAG 智能体从数据接入到最终回答的整条链路拆开,逐层记录选型理由、参数依据和实测结论。

如果你正在做知识库问答、企业文档助手、或者任何需要“让模型基于私有资料说话”的东西,这份归档应该能帮你省掉大量重复试错的时间。它适合三类人:刚接触 RAG 想建立全局认知的新手、已经能跑通 Demo 但效果不稳想系统优化的中级开发者、以及需要给团队沉淀一套标准流程的技术负责人。我不会假设你精通向量检索或智能体编排,但我会假设你愿意动手跑一遍——因为下面很多结论,光看是看不出门道的。

整份归档的核心逻辑只有一句话:RAG 智能体的质量,不取决于你用了多强的模型,而取决于你对“检索—增强—生成”这条链路上每个环节的掌控程度。模型是通用的,但你的数据、你的分块、你的召回策略、你的提示词结构,才是决定回答准不准的关键。接下来我会按技术体系的层次,从最底层的文档处理一直讲到最上层的智能体编排,每一层都给出可复现的操作和踩坑记录。

2. 文档接入层:分块策略决定了检索质量的上限

2.1 为什么“按字数切”是最容易埋雷的做法

几乎所有 RAG 教程的第一步都是“把文档切成小块”,然后随手写一个chunk_size=500, overlap=50。我一开始也这么干,直到发现一个诡异现象:用户问“第三章提到的那个审批流程需要几个节点”,系统检索出来的全是第三章开头和结尾的碎片,中间那段真正描述节点的内容反而没被召回。原因很简单——固定字数切分会把语义完整的段落拦腰截断,而向量模型对残缺文本的编码质量会明显下降。

后来我改成按文档结构切分:Markdown 按标题层级切,PDF 按段落和表格边界切,代码文件按函数和类切。具体做法是先解析出文档的层级树,再以“最小语义单元”为块,如果某个单元超过阈值(我一般设 800 字符),才在句子边界处二次切分。这样切出来的块,每一块都是一个完整的意思,检索时命中率会高很多。

提示:不要迷信“块越小召回越准”。块太小会丢失上下文,块太大又会稀释关键信息。我的经验值是中文文档 300 到 800 字符之间,英文 200 到 500 词之间,具体要看文档的信息密度。

2.2 元数据不是可选项,是过滤器的命根子

很多人建向量库时只存text和embedding两个字段,觉得元数据是“以后再说”的事。我踩过的坑是:当知识库里有多个来源、多个版本、多个部门的文档时,用户问“最新的报销标准是什么”,系统会把三年前的旧版本也召回回来,因为向量相似度根本分不清时间。元数据是 RAG 从“能用”到“好用”的分水岭。

我现在建库时至少会存这几类元数据:来源文件路径、文档版本号、生效日期、所属部门或分类、块在原文中的位置索引。检索时先用元数据做一次硬过滤(比如只查生效日期在今天的版本),再做向量相似度排序。这一步加进去之后,回答的准确率提升非常明显,尤其是那种“同一主题多个版本”的场景。

元数据字段作用常见坑
source_path追溯原文位置路径含中文时部分库编码异常
version多版本过滤版本号格式不统一导致排序错乱
effective_date时效性过滤时区问题导致“今天”判断偏差
category分类召回分类体系变更后旧数据未回填
chunk_index上下文拼接索引从 0 还是 1 开始要统一

2.3 表格和图片的处理:别让结构化信息变成乱码

知识库里最容易被糟蹋的就是表格。直接按文本切分,一个三列五行的表格会被切成十几段毫无意义的碎片。我的做法是:解析阶段识别出表格后,把整个表格转成 Markdown 格式作为一个完整块存储,同时在元数据里标记content_type=table。检索时如果命中表格块,生成阶段会提示模型“以下内容为表格,请按行列关系理解”。

图片的处理更麻烦。纯文本 RAG 是没法直接检索图片的,但很多文档的关键信息就在图里。我目前的方案是:对图片做 OCR 提取文字,把 OCR 结果作为该图片块的文本内容,同时保留图片路径。如果 OCR 质量差,就人工补一段描述。这样至少保证图片里的信息不会完全丢失。至于多模态向量检索,那是另一个话题,后面讲进阶方案时再展开。

3. 向量化与索引:选对模型比调参更重要

3.1 嵌入模型的选择逻辑:别只看排行榜

选嵌入模型时,很多人直接看某个榜单的第一名就用。但榜单测的是通用语义相似度,而你的场景可能是法律条文、医疗记录或者内部工单,领域差异非常大。我的做法是:先用自己的数据做一个小规模评测集,大概 50 到 100 个“问题—正确块”对,然后拿几个候选模型分别跑召回率,谁高用谁。

中文场景下,我实测下来 BGE 系列和 M3E 系列在通用文档上表现稳定,但如果你的文档有大量专业术语,可能需要考虑领域微调过的模型。另外要注意模型的最大输入长度——有些模型标称支持 512 token,但实际超过 256 之后语义编码质量就明显下降,这种细节榜单不会告诉你。

3.2 向量库选型:从“能跑”到“能扛”的差距

向量库的选择取决于你的数据规模和部署条件。我按实际用过的几个做个对比:

向量库适用规模部署难度我的使用感受
FAISS单机百万级低适合原型,但不支持元数据过滤,生产要自己包一层
Chroma单机十万级低开发体验好,元数据过滤够用,大规模性能一般
Milvus集群亿级中高功能全,但运维成本高,小项目杀鸡用牛刀
Qdrant单机千万级中过滤性能强,Rust 写的,资源占用低,我目前主力
pgvector跟随 Postgres低已有 Postgres 的话最省事,但索引类型选择要谨慎

我现在的默认选择是 Qdrant,原因是它的元数据过滤和向量检索可以混合执行,不像 FAISS 那样要自己先过滤再检索。pgvector 也很香,尤其是团队已经在用 Postgres 的时候,少维护一个组件就是少一个故障点。

3.3 索引参数:HNSW 的 ef 和 M 到底怎么设

如果你用 HNSW 索引,有两个参数会直接影响检索速度和召回率:M(每个节点的连接数)和ef_search(搜索时的候选队列大小)。M 越大,索引越占内存,但召回率越高;ef_search 越大,搜索越慢,但越不容易漏掉正确结果。

我的经验配置是:M 设 16 到 32 之间,ef_search 设 64 到 128 之间。如果发现召回不稳,先把 ef_search 往上调,因为这个参数可以在查询时动态改,不用重建索引。M 则需要在建索引时定好,改起来成本高。另外记得监控索引的召回率——定期拿评测集跑一遍,如果发现下降,可能是数据分布变了,需要重新评估分块策略。

4. 检索层:从“能查到”到“查得准”的关键动作

4.1 混合检索:为什么纯向量检索不够用

纯向量检索有个天然缺陷:它对精确匹配不敏感。用户问“错误码 E5021 是什么意思”,向量模型可能把“E5021”和“E5022”编码得非常接近,因为数字在语义空间里差异很小。这时候就需要关键词检索来兜底。我现在的标准配置是向量检索 + BM25 关键词检索,两路各取前 20 个结果,然后用 RRF(倒数排名融合)合并。

RRF 的好处是不需要调权重,它只看排名不看分数,对两路检索的分数尺度差异不敏感。具体公式是每个文档的得分等于1/(k+rank)的累加,k 一般取 60。实测下来,混合检索比纯向量检索在“含专有名词、编号、代码”的问题上召回率提升非常明显。

4.2 重排:把最相关的块推到最前面

检索回来 20 个块,但生成阶段不可能全塞给模型,通常只取前 3 到 5 个。这时候重排模型就派上用场了。重排模型(Reranker)和嵌入模型不同,它是对“问题—文档对”做精细打分,计算量大但精度高。我的流程是:混合检索取前 20,重排后取前 5,再送给生成模型。

重排模型我常用的是 BGE-Reranker 系列,中文效果稳定。注意重排模型也有最大长度限制,如果块太长会被截断,所以分块时控制长度不仅是为了嵌入质量,也是为了重排质量。另外重排会引入额外延迟,如果对响应时间敏感,可以只对前 10 个做重排,或者用更轻量的模型。

4.3 查询改写:用户的问题往往不是最好的检索词

用户问“这个怎么弄”,你拿这句话去检索,大概率什么都查不到。查询改写就是让模型先把用户问题改写成更适合检索的形式。我常用的策略有三种:一是扩展,把口语化问题改写成包含关键术语的查询;二是分解,把复合问题拆成多个子问题分别检索;三是假设文档生成,让模型先“编”一个可能的答案,再用这个答案去检索。

第三种方法听起来反直觉,但实测有效——因为答案和正确文档的语义相似度,往往比问题和文档的相似度更高。不过它也有风险,如果模型编得太离谱,会引入噪声。我的做法是把它作为多路召回中的一路,不单独依赖。

5. 生成层:提示词结构比模型参数更值得打磨

5.1 上下文注入的格式:让模型知道“哪段是资料”

很多人把检索到的块直接拼接后塞进提示词,结果模型分不清哪些是用户问题、哪些是参考资料、哪些是自己的知识。我的标准模板是这样的:

你是一个基于给定资料回答问题的助手。请严格根据以下资料回答问题,如果资料中没有相关信息,请明确说“资料中未提及”,不要编造。 资料: [1] {chunk_1} [2] {chunk_2} [3] {chunk_3} 用户问题:{question} 回答要求: - 引用资料时标注来源编号,如 [1] - 如果多个资料冲突,指出冲突并说明各自来源 - 回答要简洁,不要重复资料原文

这个模板的关键在于:明确边界(只根据资料回答)、编号引用(方便追溯)、冲突处理(避免模型强行融合矛盾信息)。加上这几条之后,幻觉率会明显下降。

5.2 温度与最大长度:生成阶段的参数取舍

生成模型的temperature我一般设 0.1 到 0.3 之间。RAG 场景不需要创造力,需要的是忠实于资料,温度越低越稳定。max_tokens则要根据回答长度预期来设,太短会导致回答被截断,太长会浪费资源并增加幻觉风险。我的经验是设 1024 到 2048 之间,具体看业务场景。

还有一个容易被忽略的参数是top_p。如果 temperature 已经很低,top_p 可以设 0.9 左右;如果 temperature 稍高,top_p 要相应降低,避免采样到低概率的离谱 token。这两个参数要配合调,不要单独动一个。

5.3 引用与溯源:让用户能验证答案

RAG 系统如果只给答案不给来源,用户没法验证,信任度会大打折扣。我在生成阶段强制要求模型标注引用编号,然后在返回结果时把编号映射回原文块和文件路径。这样用户看到答案后,可以点开来源看原文。这一步不仅提升体验,还能帮你发现检索问题——如果用户反馈“引用的资料不对”,你就能定位到是检索环节还是生成环节出了问题。

6. 智能体编排:让 RAG 从“单轮问答”变成“多步推理”

6.1 什么时候需要智能体,什么时候不需要

不是所有 RAG 都需要智能体。如果你的场景是“用户问一个问题,系统查资料回答”,那单轮 RAG 就够了,加智能体反而增加复杂度和延迟。需要智能体的信号是:问题需要多步推理、需要调用外部工具、或者需要根据中间结果决定下一步动作。

比如用户问“对比一下 A 方案和 B 方案在成本上的差异”,这就需要先分别检索 A 和 B 的资料,再让模型做对比。这种场景用智能体编排会更自然。我一般用 LangChain 或 LangGraph 来做编排,把检索、重排、生成、工具调用封装成节点,用状态图控制流转。

6.2 工具调用的边界:别让智能体“自由发挥”

智能体最大的风险是不可控。如果给它太多工具和太大自由度,它可能调用无关工具、陷入循环、或者做出意料之外的操作。我的做法是:每个工具都有明确的输入输出 schema,调用前做参数校验,调用后做结果检查。同时设置最大步数限制,超过就强制返回当前最优结果。

另外,工具的描述要写得非常具体。不要写“查询数据库”,要写“根据用户提供的订单号查询订单状态,输入为订单号字符串,输出为状态码和描述”。描述越具体,模型调用越准确。

6.3 多轮对话中的记忆管理

多轮对话里,用户的问题往往依赖上文。比如用户先问“A 方案的优点”,再问“那它的缺点呢”,第二个问题里的“它”指代 A 方案。如果直接把第二个问题拿去检索,肯定查不准。我的做法是在检索前先做指代消解,用对话历史把问题补全成“A 方案的缺点是什么”,再走检索流程。

记忆管理还要注意长度控制。对话历史不能无限增长,我一般保留最近 5 到 10 轮,更早的做摘要压缩。摘要也要存进向量库,这样用户提到很久之前的内容时还能检索到。

7. 评测与迭代:没有度量就没有优化

7.1 召回率与命中率:怎么建自己的评测集

RAG 评测不能只看“感觉准不准”,要有量化指标。我常用的两个指标是召回率(正确块是否在检索结果中)和命中率(正确块是否排在前 K 位)。建评测集的方法是:从真实用户问题中抽样 50 到 100 个,人工标注每个问题的正确来源块,然后跑检索看指标。

这个过程很枯燥,但非常值得。因为只有有了评测集,你才能判断一次改动(比如换分块策略、换嵌入模型、加重排)到底是提升了还是退步了。我见过太多人凭感觉调参,结果越调越差。

7.2 生成质量评估:忠实度与相关性

生成阶段的评估主要看两个维度:忠实度(回答是否基于资料,有没有编造)和相关性(回答是否切题)。忠实度可以用模型来打分,让一个强模型判断“回答中的每个陈述是否能在资料中找到依据”。相关性则可以用人工抽样评估,或者用模型做 pairwise 比较。

我一般会维护一个“回归测试集”,每次改动后跑一遍,看忠实度和相关性有没有下降。如果下降,就要回滚或调整。这个习惯帮我避免了好几次“改了一个地方,坏了另一个地方”的事故。

7.3 线上反馈闭环:用户点踩是最好的优化信号

线上系统的用户反馈是最宝贵的优化信号。我在返回结果时加了“有用/没用”按钮,用户点“没用”时记录下问题、检索结果和生成回答。每周分析这些 bad case,归类是检索问题、生成问题还是数据问题。检索问题就优化分块和召回,生成问题就改提示词,数据问题就补文档。

这个闭环跑起来之后,系统的准确率会持续提升,而不是上线即巅峰然后慢慢退化。

8. 部署与运维:让 RAG 智能体稳定跑起来

8.1 本地开发与生产环境的差异

本地开发时用 Ollama 跑本地模型很方便,但生产环境要考虑并发、延迟和成本。我的建议是:开发阶段用本地模型快速迭代,验证流程跑通后,生产环境根据预算选择 API 模型或自部署模型。如果数据敏感必须本地部署,那要提前评估 GPU 资源和推理框架(比如 vLLM 或 TGI)的吞吐量。

另外要注意模型版本锁定。API 模型会静默更新,今天跑通的结果明天可能就变了。生产环境要记录模型版本,并在更新时跑回归测试。

8.2 缓存策略:哪些环节可以缓存

RAG 链路里有很多可以缓存的地方:嵌入结果可以缓存(同样的文本不用重复编码)、检索结果可以缓存(同样的问题短时间内不用重复检索)、生成结果可以缓存(高频问题直接返回)。但缓存要注意失效策略——文档更新后,相关的嵌入和检索缓存要清除。

我一般用 Redis 做缓存层,嵌入和检索结果设较长的 TTL,生成结果设较短的 TTL 或不缓存(因为生成结果对上下文敏感)。缓存命中率上去之后,响应延迟和成本都会明显下降。

8.3 监控指标:延迟、成本和质量的平衡

生产环境要监控三个维度:延迟(检索和生成各占多少)、成本(token 消耗和 API 调用次数)、质量(用户反馈和自动评测指标)。这三个维度往往互相制约——想要质量高就得多检索多生成,延迟和成本就上去了。我的做法是设一个质量底线,在底线之上尽量优化延迟和成本。

比如检索阶段,如果前 3 个块的重排分数已经很高,就不需要再取更多块;生成阶段,如果问题简单,可以用更小的模型或更短的输出。这些动态策略能帮你在质量和成本之间找到平衡点。

9. 我在多个 RAG 项目里反复验证的几条经验

第一,分块策略的优先级高于模型选择。我见过太多人花大量时间对比嵌入模型,却用着最粗糙的固定字数切分。实际上,把分块做好带来的提升,往往比换一个更强的嵌入模型更明显。先把文档结构吃透,再谈模型。

第二,元数据过滤是性价比最高的优化手段。加几个元数据字段,做一次硬过滤,就能解决大部分“召回旧版本、召回无关部门”的问题。这个改动的成本极低,但效果立竿见影。

第三,评测集要尽早建,哪怕只有 20 个问题。没有评测集,所有的调优都是盲人摸象。20 个标注好的问题,就能帮你判断一次改动是正向还是负向。等系统大了再建评测集,成本会高很多。

第四,提示词里的“不知道”比“知道”更重要。明确告诉模型“资料中没有就说没有”,能大幅降低幻觉。很多 RAG 系统的问题不是查不到,而是查不到的时候模型硬编。

第五,智能体不是越复杂越好。单轮 RAG 能解决的问题,不要上智能体。每增加一个节点,就多一个故障点和一份延迟。先把单轮做到极致,再考虑多步编排。

这套归档我还在持续更新,每次遇到新的坑或者新的优化思路,都会补进去。RAG 这个领域变化很快,但底层逻辑——数据质量决定检索质量,检索质量决定生成质量——是不会变的。把这条链路吃透,换什么模型、换什么框架,你都能快速上手。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询