【第 4 篇:RAG 知识库问答——检索只是第一步】

【第 4 篇:RAG 知识库问答——检索只是第一步】 第 4 篇RAG 知识库问答——检索只是第一步系列记录《从零搭建企业级 LLM 应用》这是第 4 篇上一篇Dify——低代码开发平台快速搭建一个智能体下一篇记忆系统——长短期记忆与混合记忆知识库调通了但答不对第 3 篇里我把 Dify 知识库接好了搜文档这个动作已经能跑通。接下来就是 RAG 最核心的部分——拿到检索结果让 LLM 生成回答。一开始的想法很简单用户提问 → Dify 检索文档 → 把检索结果拼到 prompt 里 → 让 LLM 回答。大概就是用户公司的年假政策是什么 → Dify 检索返回文档片段 → 拼 prompt根据以下资料回答{文档内容} 问题年假政策 → LLM 生成答案跑了几轮就发现不对劲了。有几个问题反复出现检索结果质量差LLM 基于不相关内容硬编了一个答案同一个问题换种问法检索结果完全不一样LLM 偶尔编造文档里根本没有的数据第一步查询改写——不同问法搜出来的应该一样 ——《扩写问题》同一个意图用户可能有三种表达年假怎么休 我想请年假HR 流程是什么 关于带薪年假的规定直接用原话去搜语义匹配效果参差不齐。尤其短的问法向量包含的信息很少。所以我加了查询改写这一环在送入检索之前先让 LLM 把用户的口语化问题转换成更适合语义搜索的表达同时输出关键词和子问题输入年假怎么休 输出{ rewritten_query: 企业员工带薪年假的申请流程和使用规定, keywords: [年假, 带薪休假, 申请流程], sub_questions: [年假天数如何计算, 年假申请流程是什么] }两个保护措施短问题跳过改写。10 字以内的问题改写后容易偏离原意直接搜原文更靠谱。改写失败回退。改写后的 query 搜不到结果时自动用原始问题再搜一次。有时候 LLM 改写的措辞跟文档原文差距太大反而匹配不上。第二步答案验证——给回答装一个质检员 ——《自检回答》检索质量提升后还是会碰到 LLM 基于不够相关的文档片段硬编答案的情况。我的解法在生成答案之后再加一步验证。用另一个 LLM 调用判断答案是否靠谱GOOD有明确的文档依据内容具体 → 通过HALLUCINATION出现了文档没提到的内容或编造了数据 → 需要重来NO_CONTEXT文档里确实没有相关信息答案已说明 → 直接告知用户INSUFFICIENT文档与问题关联度不够 → 换表达重试验证 prompt 的设计原则不要太严格。只要文档与问题有相关性就判 GOOD不因不够全面打回——那是生成质量的问题不是幻觉。异常默认通过。验证 LLM 调用失败网络超时等不阻断正常流程。HALLUCINATION 和 INSUFFICIENT 处理不同。幻觉需要换表达重搜上下文不足则尝试更宽泛检索。第三步重试循环——一次不行换种方式再试 ——《自检未通过时重试换种表达问题的方式重新检索回答》验证不通过时给一次重试机会。策略是换一种表达方式重新检索。重试上限设为 1 次原因幻觉重试有意义第一次是看到了似是而非的内容然后编造答案换表达可能命中更精准的文档。不相关重试意义不大第一次检索结果就跟问题无关换表达大概率还是不行。重试后仍不行就返回部分答案加可能不够完整的提示不无限循环。之前踩过坑Data Agent 开发时没限制重试次数Agent 反复执行耗时暴涨。同一类问题不能犯两次。第四步规则引擎兜底答案生成和验证之后最后过一道规则引擎——防止技术错误信息暴露比如答案里不小心包含了 API 异常信息、代码报错。检测到就用兜底回复替换。这个检查与业务逻辑解耦规则写在 YAML 配置文件里不改代码就能调整。整条链路的全貌用户提问 │ ├─ 查询改写长问题结构化短问题跳过 │ ├─ 首次检索用改写 query 搜 Dify │ └─ 无结果 → 回退检索用原始 query │ ├─ LLM 生成答案基于检索上下文 │ ├─ 答案验证 │ ├─ GOOD → 继续 │ ├─ HALLUCINATION / INSUFFICIENT → 换表达重搜最多 1 次 │ └─ NO_CONTEXT → 直接返回 │ └─ 规则引擎后校验 → 返回最终答案做完 RAG 的几点感受① RAG 不是检索生成两件事是六件事。开始以为 RAG 就是搜一下然后让 LLM 回答。实际做下来发现真正让 RAG 可靠的是查不到怎么办回退、答对了没有验证、答错了怎么补救重试、有没有暴露不该暴露的信息规则引擎。② 查询改写是性价比最高的优化。只加了一个 LLM 调用把用户问题标准化检索准确率就提升了一大截。改写的本质是补全信息——用户问得短帮他把隐含意图补上。③ 重试次数要严格控制。一开始没限制Agent 反复重试导致 token 消耗和等待时间都失控。硬性限制为 1 次大部分情况够用特殊情况直接告知没找到比一直转圈强。④ 验证不能太严格。如果要求完全准确、覆盖全面才给 GOOD大部分回答都会被判定不合格重试反而引入更多问题。验证的目标是拦截明显的幻觉不是追求完美答案。下一篇记录多轮对话是怎么记住上下文的SqliteSaver 和 SQLite messages 表两套持久化各有分工我梳理清楚了它们的关系。