最近在做一个金融研报的问答Agent,用RAG做知识库。单轮问答效果还行,但一旦问题涉及多步推理(比如“某公司2023年营收增速和2022年相比变化了多少,主要受哪个业务影响”),检索召回就经常缺一块,导致LLM只能瞎编或者答非所问。我现在用的是向量检索+BM25混合,也试过把问题拆成子查询再分别检索,但子查询之间怎么合并、去重、排序,总感觉没弄明白。想问问各位,遇到这种多跳场景,是应该换GraphRAG,还是在检索后加一层重排(rerank)?或者有没有更实用的做法,比如先让LLM生成查询计划再执行?求真实工程经验,别推太多论文,谢谢!
Agent+RAG做复杂查询时,多跳检索总是漏召回,大家怎么优化的?
全部回复
共 44 条我也踩过这个坑,子查询拆完合并那步确实最容易掉链子。后来我是让LLM先出个查询计划,每个子查询带个依赖标记,检索完按依赖链拼上下文而不是简单去重,效果稳不少。GraphRAG对多跳确实友好,但建图成本高,金融研报实体关系又密,维护起来挺累的。可以先在rerank那层加个cross-encoder试试,成本低,能救回不少漏召的片段。
多跳漏召回这个问题我们踩过差不多的坑,说点实在的。你现在的痛点其实不在检索层,而在“查询规划”和“证据聚合”这两块没打通。把问题拆子查询方向是对的,但别让每个子查询独立去召回然后硬合并,那样去重和排序必然乱。我的做法是让LLM先出一个带依赖关系的查询计划,比如先查营收增速、再查业务构成,第二步的检索query里带上第一步的结果作为上下文,这样召回是链式的而不是并行的。GraphRAG在实体关系密集的场景确实有用,但金融研报里表格和数字多,图构建成本高、更新也麻烦,不一定划算。rerank一定要加,但它是补救不是主菜,放在链式检索每一跳之后做精排,能明显减少噪声。另外建议把召回评估从“命中率”换成“证据覆盖率”,看每跳需要的证据是不是都齐了,不然你永远不知道是哪一步断的。真正实用的组合是:查询计划+链式检索+每跳rerank,GraphRAG当补充手段而不是主力。
多跳漏召回这事我踩过坑,说点实在的。你现在的混合检索加子查询拆分方向没错,但问题往往出在子查询之间的“桥接实体”没接上,比如第一跳查出公司A的营收数据,第二跳要查业务构成时,检索query里如果没带上公司A或者具体年份,向量和BM25都容易飘。我的做法是在每跳检索后加一个小步骤:让LLM从已召回片段里抽一个“中间答案锚点”,再拼进下一跳的query里,比单纯拆子查询管用。至于GraphRAG,金融研报这种实体关系密集的场景确实有优势,但构建和维护成本不低,如果只是问答不是推理链路特别长,先别急着上。rerank我建议加,但别指望它救漏召回,它只能把已经召回的排好,漏了的它找不回来。生成查询计划再执行这个思路可以,但重点是计划里要包含“每跳的验证条件”,否则LLM生成完就一路跑偏。我目前比较稳的组合是:混合检索+中间锚点回填+轻量rerank,GraphRAG当补充索引,不是替代。
多跳漏召回不一定是检索器的问题,很多时候是子查询拆得不对。我们之前也踩过坑,后来改成让LLM先出查询计划,明确每一步要查什么实体、什么指标,再按依赖顺序执行,合并时用实体+时间做key去重,效果比单纯换GraphRAG稳。rerank可以加,但别指望它救回根本没召回的片段。GraphRAG成本高,金融研报这种实体关系密集的场景可以试,但先把查询规划做扎实更划算。