跳到主要内容

RAG 召回摘要问题排查

RAG「召回老是只拿到摘要/标题」,通常不是模型问题,而是检索阶段把 chunk 做得太“轻”或索引里只有摘要字段导致的。按下面顺序排查,基本都能定位并解决:

1) 先确认:你到底把什么写进了向量库?

最常见情况:embedding 的输入用的是 summary / title,或者只把摘要字段入库了,所以召回结果当然也只像“摘要”。

  • 检查 embedding 代码:embedding 的 text_to_embed 是否来自摘要字段?
  • 检查入库字段:向量库里每条记录是否有 content_chunk(原文片段)以及 doc_id / source / offset 等元信息?
  • 快速验证:随便抽一条向量库记录,看 text/payload 是否就是摘要。

修复原则

  • embedding 必须来自原文 chunk(摘要可以作为 metadata,或辅助 BM25/重排特征,但不要替代 chunk 原文)。
  • 召回返回的 text 应该是可直接拼进 prompt 的原文片段,不是 summary。

2) Chunk 策略:别把 chunk 做成“自动摘要”

如果你在切分时做了“每段先总结成一句话再入库”,那召回自然像摘要。

推荐做法(经验值):

  • chunk size:中文 300–800 字(或 500–1500 tokens)
  • overlap:10%–20%(例如 80–150 字)
  • chunk 里保留:原文 + 小量结构(标题层级/小节名)

另外,务必把这些写进 metadata:

  • document_title / section_title / heading_path
  • chunk_index
  • source_url
  • start_char/end_char 或页码

这样召回后你能“回填上下文”,不至于只靠一段话。

3) 召回时返回字段:不要只取 summary 字段

很多人 query 时只取了 summary(比如为了省 token),导致看起来“召回都是摘要”。

  • 检查 query 返回:是否有 chunk_text?还是只取了 summary
  • 如果你做了两段式:先召回 doc,再取 doc.summary ——那你需要在第二段再召回 doc 下的 chunks,或者直接召回 chunks。

正确链路(常见可行):

  1. query → topK chunks(向量/BM25/混合)
  2. 可选:cross-encoder rerank top 50 → top 5–10
  3. 把 top chunks 原文拼 prompt(带来源)

4) 你看到“像摘要”,也可能是重排/压缩器在作祟

如果你用了:

  • LLM-based rerank
  • contextual compression(压缩检索结果)
  • “回答前先总结证据”的链

这些会把 chunk 压成摘要再喂给下游。

排查方法:

  • 在进入 LLM 前,打印/日志输出最终 prompt 里的“证据块”到底是什么。
  • 关掉压缩器,直接把原文 chunk 喂给生成,看是否恢复。

5) 混合检索 + 重排,能显著减少“泛泛摘要”

如果你的语料结构化强、标题多,纯向量容易召回“概述性段落”。

建议:

  • Hybrid:BM25(关键词) + 向量(语义)一起召回,再合并去重
  • Rerank:cross-encoder(例如 bge-reranker、cohere rerank 等)对 top 50 做重排
  • MMR:让 topK 更“多样”,减少都落在概述段落

6) 如果你确实需要摘要:让摘要作为“补充视图”,不是召回主体

可以在每个 chunk 或 doc 旁边存:

  • doc_summary(文档级)
  • chunk_summary(可选,用于浏览/展示) 但回答时:
  • 证据引用:用 chunk_text
  • 用户展示:可以额外显示 summary 作为“预览”

如果你把你当前的链路贴一下(哪怕是伪代码也行):

  1. 入库时 embedding 用的字段;2) chunk 大小/overlap;3) query 返回哪些字段;4) 是否用了压缩/重排。 我可以直接指出是哪个环节把内容变成“摘要”的。