
很多人刚接触 RAG 时,总觉得流程很简单:把 PDF 或 Word 扔进向量数据库,写一段 Prompt,让大模型参考召回的内容回答。但在实际业务中,你会发现模型经常在胡说八道,或者回答的内容总是偏离核心事实。
遇到问答答偏,别急着怪大模型参数不够大。在多数情况下,问题出在数据预处理和检索流程上。如果喂给模型的上下文碎片根本不相关,或者缺斤少两,模型再聪明也只能硬猜。想要彻底解决答偏问题,需要拆解完整的构建流程,重点抓好切块(Chunking)与召回(Retrieval)两个环节。
一、 先看全景:RAG 知识库构建的标准五步
搭建一个稳定的知识库,必须按顺序走完这五个步骤:
1.文档解析与清洗:把各类文件(PDF、DOCX、Markdown、Excel)转成干净的纯文本或 Markdown,过滤掉页眉、页脚、无意义的水印和广告符。
2.文本分块(Chunking):按照合理的规则把长篇大论拆成固定长度或语义完整的知识片段(Chunk)。
3.向量化与元数据标注(Embedding & Metadata):调用向量模型把文本块转为高维向量,同时打上文档 ID、章节层级、创建时间等元数据标签。
4.混合索引构建(Indexing):把向量存进向量数据库,同时构建用于全文关键词匹配的倒排索引(BM25)。
5.检索与生成(Retrieval & Generation):通过查询改写、混合检索、重排(Rerank)捞出最精准的内容,拼入 Prompt 让大模型总结输出。
绝大多数“答偏”的灾难,在第二步(切块)和第五步(检索)就已经注定了。
二、 为什么切块不当会导致回答答偏?
切块的本质是语义边界划分。切得太大,向量会“稀释”;切得太小,向量会“断片”。
先看一个真实案例:一段产品手册写着“Pro 版本配备 100W 快充,30 分钟充满;Standard 版本配备 33W 快充,70 分钟充满”。
•如果按固定 50 个字强行切断,切片刚好停在“Standard 版本配备 100W…”,后半句跑到下一个切片里。
•用户提问:“Standard 版本的充电功率是多少?”
•检索召回了这个残缺切片,大模型看到的是“Standard 版本配备 100W”,直接输出错误答案。这就是切块造成的上下文截断事故。
另一个极端是切块过大(比如一个 Chunk 设到 2000 Tokens)。文本里塞进了规格、售后政策、兼容列表,向量模型在给它做表征时,特征被严重平摊。当用户问具体的“螺丝规格”时,这个大块的语义相似度计算得分甚至不如一篇随口提到螺丝的博客文章,直接被系统过滤掉。
常见的切块策略对比与选型如下:
| 切块策略 | 核心逻辑 | 典型分块大小 (Tokens) | 优势 | 劣势与避坑提示 |
|---|---|---|---|---|
| 固定字符切分 (Fixed Size) | 设定硬性长度 + 字符重叠度 (Overlap) | Chunk: 300-500 Overlap: 50-100 |
处理速度极快,系统开销低,易于批量处理。 | 极易切断核心专有名词与逻辑句子,只适合结构单一的短文小说。 |
| 递归字符切分 (Recursive) | 按照段落(`nn`)、单行(`n`)、标点(句号、问号)逐层拆解 | Chunk: 400-600 Overlap: 10% |
尽量在自然语言标点处断句,保留了基本的段落逻辑。 | 无法感知表格结构,遇到跨层级的子标题仍会丢掉父级上下文。 |
| Markdown 结构切分 | 依据 `#`、`##` 等标题树层级进行切分 | 依据小节实际字数,通常 300-800 | 完美保留文档层级,切块的主题明确。 | 需要源文件解析为标准 Markdown。如果小节内容过长,仍需配合递归二次切分。 |
| 语义切分 (Semantic Split) | 计算相邻句子之间的 Embedding 余弦相似度,相似度骤降时切断 | 动态(通常 200-800) | 逻辑自洽度最高,每个块都围绕单一主题。 | 耗费更多 Embedding 调用成本,计算耗时明显增加。 |
| 父子分块 / 小块检索大块召回 (Parent-Child) | 建立两层结构:小块(如 128 Tokens)用于检索,大块(如 512 Tokens)作为上下文传给模型 | 检索层: 128-200 上下文层: 512-1024 |
既能精确匹配小粒度关键词,又能给大模型提供足够完整的背景信息。 | 索引构建较复杂,存储体积会有所增加。 |
实操避坑原则:宁可加重叠(Overlap),也不要让切片硬着陆。如果使用固定或递归切分,必须设置 10% 到 20% 的 Overlap,这样能把被切断的关键词在下一个分块中补齐。
三、 检索召回优化:别只靠单纯的向量搜索
很多人把向量检索当成万能药,但向量数据库找的是“意思相近”,而不是“事实相符”。
例如用户搜:“型号 A8-2023 的固件更新日志”,向量搜索很可能会把“型号 A8-2024 的配置更新”判定为极度相似并召回,而真正包含“A8-2023”的段落因为用词冷门,得分反而落后。
要避免这种偏差,召回环节必须进行组合优化。
1. 混合检索(Hybrid Search):向量与关键词打底
不要单独使用稠密向量检索(Dense Vector Retrieval)。一定要同时引入稀疏检索(Sparse Retrieval,如 BM25)。
•BM25 负责把关精准的专有名词、产品型号、错误码、工单编号。
•向量检索 负责理解同义词、意图推断和长句子语义。
最后通过 RRF(Reciprocal Rank Fusion) 算法将两者的排名加权合并。这一步能直接解决 40% 以上因为专有名词无法匹配而导致的答偏。
2. 加入重排机制(Rerank):从“广撒网”到“精挑细选”
向量数据库为了保障百毫秒级的搜索速度,底层使用的是双编码器(Bi-Encoder)架构,它只计算两个独立向量之间的夹角,对细节语义的辨别精度有限。
正确的做法是:
•粗排阶段:通过混合检索捞出 Top 30 或 Top 50 的候选切片。
•精排阶段:引入交叉编码器(Cross-Encoder)重排模型(例如 BAAI 的 BGE-Reranker、Cohere Rerank)。重排模型会把用户的 Query 和每一个切片拼在一起同时分析注意力交互,给出精准的相关性得分。
•过滤截断:只取重排得分最高的前 3 到 5 个切片喂给大模型。这样既避免了无关切片干扰模型,又防止因为上下文过长引发模型的注意力丢失(Lost in the Middle)。
3. 查询改写(Query Rewrite)与 HyDE
用户提问往往很短,或者包含模糊代词。
•多轮会话改写:用户追问“它的续航多久?”,系统先用小模型把问题补全为“小米 14 的电池续航多久?”,再去知识库检索。
•假设性文档嵌入(HyDE):如果问题非常抽象,先让大模型生成一段虚构但结构合理的“假设答案”,然后用这个假设答案的向量去数据库里检索真实切片。因为答案和答案在向量空间中的距离,远比问题和答案的距离更近。
主流检索召回优化方案对比如下:
| 优化技术 | 解决的典型问题 | 实现复杂度 | 延迟增加 | 推荐业务场景 |
|---|---|---|---|---|
| 纯向量检索 (Baseline) | 处理通用语义泛化查询 | 最低 | 无额外延迟(基准) | 基础 Demo,简单闲聊或无明确技术术语的内容。 |
| 混合检索 (BM25 + 向量) | 专有名词、代码编号、型号匹配失效 | 中等 | 约 5-15 ms | 所有生产级企业知识库的必备配置。 |
| 交叉编码重排 (Rerank) | 粗排切片相似度高但关键逻辑无关 | 中等 | 约 50-200 ms | 合同法务审查、金融研报、复杂的故障排查手册。 |
| 查询补全与改写 | 用户提问指代不清、跨多轮上下文遗失 | 中等 | 约 200-500 ms (取决于小模型速度) | 多轮对话客服、个人助理。 |
| 父子分块检索 (Parent-Child) | 单个小切片信息不全,模型无法完整归纳 | 较高 | 极低(主要是查表映射) | 包含复杂操作指南、长流程审批规范的知识库。 |
四、 从零调优知识库的落地排错指南
如果你的知识库现在问答表现不佳,可以按照这套排查路线自查:
1.先做“命中测试”,打印检索到的原始切片:
在看大模型回答前,把系统检索出来的 Top-K 切片直接打印出来。
•如果切片里根本没有答案:说明切块或检索召回失效了。重点去调 BM25 权重,检查文件是否被解析乱码,或者换用多语言表现更好的 Embedding 模型。
•如果切片里有答案但排在很后面(比如第 8 名):系统只传了前 3 名给模型。这时应该引入 Reranker,把第 8 名拽到第 1 名。
•如果切片里明确包含完整正确信息,但模型依然答错:问题出在大模型端。检查 Prompt 是否设置了严格的“仅基于参考资料回答”,或者把系统提示词里的无关限制删掉。
2.固定关键参数的安全基准线:
•文本切块:中文内容建议单块大小维持在 400 到 600 字符,重叠度设为 10% 到 15%。
•检索召回数:初筛候选集设定在 Top 30,经过 Rerank 重排后,送入大模型的最终切片控制在 Top 3 到 Top 5。
•阈值设定:不要盲目设置过高的向量相似度绝对阈值(比如直接卡 0.8),不同 Embedding 模型的余弦得分分布差异极大。应优先使用 Top-K 结合 Rerank 分数进行筛选,避免把原本正确的切片全部过滤掉。
3.元数据过滤前置:
如果知识库有不同部门或不同产品的文档,不要把所有内容扔进同一个大池子里硬搜。在入库时打上 `department: HR` 或 `product_line: A` 的元数据标签。在检索发生前,先用 SQL 方式做硬过滤,把搜索范围缩小到目标子集内,这样可以大幅度减少错误召回的几率。
做好 RAG 的关键从来不在于追求花哨的概念,而在于把文本清洗、分块边界、双路检索和重排这几个具体参数调优落到实处。数据喂得准,大模型的输出自然就不会偏。
原创文章,作者:七点互动,如若转载,请注明出处:https://ai.qidianhudong.com/aikonw/4266.html