RAGFlow 实战(三):检索调参实录——从「检索不到」到「检索得准」
RAGFlow 实战(三):检索调参实录——从「检索不到」到「检索得准」
一、检索是 RAG 的主战场
文档切好了,接下来全是检索的问题。RAGFlow 的检索测试接口(POST /api/v1/retrieval)就是调参的主战场——绕过聊天历史,纯检索质量验证。这篇把所有检索侧的实战结论一次讲完。
二、结论 1:精确查询,就要短问句
拿产品参数表做精确查询,我一开始很自然地写长问句:
1 | Product ID M20978 的 Torque 是多少? |
Top-1 返回的是邻居行——不对。换成只发 ID:
1 | M20978 |
命中 1 条,正是要的那行。
原因:语义化问句里的通用词(Product / ID / Torque)会让 ES 的 minimum_should_match 放行大量邻居行,ID 的信号被稀释了。精确查询(按编号/ID 找行)就发短词,或者走结构化字段过滤。这条经验对表格类知识库是决定性的。
三、结论 2:中文长文本,把向量权重调到 0.7
实测中文长文本的关键词得分普遍只有 0.14~0.33——中文分词语义下的关键词匹配天然吃亏,长文本的命中主要靠向量。
1 | retrieve --question "xxx" --vector-weight 0.7 |
反过来,找专有名词时短词查询效果最好:实测 魇渊 这个词,长句查询得分 0.27,单词查询 0.57。权重没有银弹,按语料调:
| 场景 | vector-weight |
|---|---|
| 中文长文本、叙述性内容 | 0.7(向量为主) |
| 专有名词、编号精确查询 | 0.3 以下(关键词为主) |
| 不确定 | 默认 0.3 起步,A/B 对比 |
四、结论 3:检索为空,先查阈值——头号原因是人为的
「检索不到东西」的排查顺序:
- 相似度阈值是不是调太高——这是头号人为原因。阈值调太严,把正确答案挡在门外;
- 文档解析是否真的 done(见系列第一篇的上传≠解析);
- 索引里有没有 chunk;
- embedding 模型是否加载成功。
宁可多召回几条让 LLM 自己筛,也不要严到把答案挡在门外。相似度阈值默认 0.2,先别动它。
五、结论 4:前端高亮不是命中清单
判断检索质量,看 Top-N 的完整内容,不要看前端高亮。
前端高亮是 ES 的摘录(fragment_size=50,最多 5 片),它只是「关键词出现的片段」,不是「命中的 chunk 清单」。盯着高亮调参,会被摘录的片段骗——正确做法是拉 chunks 数组,看 similarity / term_similarity / vector_similarity 三个分项。
六、结论 5:HTTP 200 +「未找到」≠ 模型问题
这条是「不报错但不对」的经典:
1 | HTTP 200 + answer = "知识库中未找到相关内容" |
这不是模型连通性问题,是检索没送对料——软失败,日志里一片绿。请求 pending 或报错才是连接问题。排查时先分清:是「没检到」还是「没连上」,两者的排查方向完全相反。
七、结论 6:聊天链路比检索链路多两件事
调参时要注意,聊天和检索走的是同一套混合检索引擎,差别只在聊天多两步:
refine_multiturn(默认开启):多轮对话时,把整段聊天历史压缩改写成一个独立问题再检索;- LLM 读块出答案。
所以聊天时「问对了但答错了」,问题可能在 query 改写而不在检索。调试经验:先用检索测试接口验证纯检索质量,再进聊天链路——两步分开,定位才快。
八、把调参变成工程:回归测试
调参最怕「感觉变好了」。我的做法是准备 20~30 个有标准答案的问题,改任何配置(切块方法、权重、阈值、embedding)前后各跑一遍,对比命中率和答案完整度:
1 | QUESTIONS = [ |
一个百分比,把「感觉」变成数字。RAG 调优的所有结论,都该以这种形式落盘。
九、小结
检索调参六条:精确查询发短词、中文长文本权重 0.7、检索为空先查阈值、高亮不是命中清单、软失败和连不上要分清、聊天链路多一步 query 改写。加上回归测试的方法论,检索侧就算入门了。下一篇讲怎么把这套全脚本化——API 自动化。

