在金融风控等垂直行业的系统开发中,RAG(Retrieval-Augmented Generation)系统的召回准确性至关重要。一次因召回文档不准而导致的合规报告生成错误,足以让我们深刻体会到:跑通 RAG 流程或许只需三天,但将召回效果调优到生产可用,却可能需要三个月。

本文将聚焦于我们在实践中遇到的核心挑战,并分享在文档处理、召回策略和生成优化三大环节的解决方案,旨在帮助开发者构建更高效、更精准的 RAG 系统。

一、文档处理:格式兼容性决定召回上限

当知识库包含 PDF 合同、Excel 数据表、Word 需求文档等多种格式时,单一的文档加载与切分策略往往会失效。

核心问题

  • 混合内容解析失效:PDF 中的表格与正文被分离开来,导致上下文关联丢失;图表(如架构图)在解析后可能变成无意义的乱码。
  • 结构化数据丢失:Excel 中的关联字段或表格在向量化过程中被拆解成独立的文本片段,破坏了原有的数据结构。

解决方案:构建文档预处理流水线

针对不同格式的文档,我们建立了一套定制化的预处理流水线。

  1. 智能解析 PDF:利用 PyMuPDF 等工具,不仅提取文本,更重要的是保留表格、图片与上下文文本的空间坐标关联。这使得模型能够理解“位于第三段下方的表格”或“与该图表相关的说明文字”。

    # PDF 处理示例:使用 PyMuPDF 提取图文关系
    def parse_pdf_with_layout(doc):
        for page in doc:
            # 以字典形式获取文本块及其位置信息
            text_blocks = page.get_text("dict")["blocks"]
    
            # 查找页面中的表格
            tables = page.find_tables()
    
            # TODO: 编写逻辑,将表格与其坐标邻近的文本块关联起来
            # ...
    
  2. 非结构化内容重组:对于图片、图表等难以直接向量化的内容,我们采用分块-重组策略。例如,将图片区域映射到其在文档中相邻的文本区块,或者直接提取图片标题和注释作为其文本描述。

  3. 元数据描述索引:对于关键的架构图、流程图等,我们放弃传统的向量化方法,转而为其建立元数据描述索引。通过人工或多模态模型生成对图像内容的详细文字描述(例如,“该图展示了一个三层应用架构,包括表示层、业务逻辑层和数据层…”),然后对这段描述文字进行索引和检索。

二、召回优化:多策略融合提升精准度

单纯依赖向量相似度搜索在复杂业务场景下存在明显缺陷。

核心问题

  • 业务术语召回缺失:用户查询“KYC 流程”,但知识库中的官方文档使用的是“客户尽职调查”,导致因用词不同而召回失败。
  • 相似度陷阱:查询返回的 Top-K 结果在向量空间上虽然相近,但可能内容高度重复或与查询意图无关,导致信息淹没。

解决方案:混合检索与查询扩展

我们采用多种策略组合的“组合拳”来提升召回效果。

  1. 查询重写(Query Rewriting):利用 LLM 对用户的原始查询进行扩展,生成 2-3 个同义或相关的查询。例如,将“KYC 流程”扩展为“客户尽职调查步骤”、“用户身份验证方法”等,再将这些查询的召回结果进行合并。

  2. 假设性文档嵌入(HyDE):这是一种反向检索思路。我们先让 LLM 根据用户问题生成一个假想的、最完美的答案(假设性文档),然后用这个假想答案的向量去知识库中搜索最相似的真实文档块。这种方法能更好地捕捉查询的深层语义。

  3. 混合检索(Hybrid Search):将基于向量的语义检索与传统的关键词检索(如 BM25)相结合。语义检索擅长理解意图,而关键词检索能确保包含特定术语的文档被精准命中。通过为两种检索结果设置不同的权重并进行重排序(Re-ranking),可以显著提升召回的准确性和相关性。

此外,向量库的精细化管理也至关重要。我们采用分层存储方案,将高频访问、高质量的核心文档与普通文档分开索引,优化检索效率。

三、生成优化:不可忽视的上下文清洗

将从知识库中召回的原始数据直接抛给 LLM,往往会带来意想不到的负面影响。

核心问题

  • 格式噪声干扰:从网页或复杂文档中解析出的内容可能残留 HTML/XML 标签,干扰 LLM 的理解。
  • 无效信息稀释:文档中的页眉、页脚、页码等噪声会降低上下文的有效信息密度。
  • 内容冗余:多个召回文档块可能包含重复或高度相似的信息,分散模型的注意力。

解决方案:构建召回后清洗流水线

在将召回内容传递给生成模型之前,我们增加了一道严格的清洗和精炼流程。

  1. 格式转换器:将 HTML 表格等复杂格式统一转换为对 LLM 更友好的 Markdown 格式,保留其结构化信息。
  2. 噪声过滤器:基于文档布局和正则表达式,自动识别并剔除页眉、页脚、导航栏等通用噪声文本。
  3. 冗余检测器:计算召回文档块之间的余弦相似度,移除相似度高于特定阈值(我们测试发现 0.87 是一个较优值)的重复内容。

升级:引入智能体(Agent)框架

为了让 RAG 系统具备动态获取信息的能力,我们引入了智能体框架。当知识库无法满足用户查询时,智能体可以主动调用外部工具。

# 智能体调用外部工具示例
agent.execute(
    tool_name="web_search",
    params={"query": "2024年最新的金融监管政策"},
    callback=rag.retrieve # 将外部搜索结果注入召回管道
)

通过这种方式,RAG 系统能够结合内部知识库和实时外部信息,提供更全面、更及时的回答。

总结

经过近半年的持续迭代,我们的 RAG 系统召回准确率从最初的 63% 提升到了 91%。核心经验可以归结为以下三点:

  • 文档处理没有银弹:必须为不同数据格式定制精细化的解析和预处理流程。
  • 召回策略需打组合拳:单一的检索算法无法应对所有场景,混合检索、查询重写等多策略融合是必经之路。
  • 生成质量依赖于清洗:召回后的上下文清洗和精炼流程,其重要性不亚于选择一个更强大的生成模型。

👉 如果你需要 ChatGPT 代充 / Claude / Claude Code / 镜像 / 中转 API