RAG,你需要了解的都在这篇文章里

#AI
13 分钟阅读

首先,RAG 的全称是检索增强生成(Retrieval-Augmented Generation),它的核心是通过构建并利用知识库来增强大语言模型的回答能力。但在其标准的流程中,会衍生出很多概念和技术细节,这些细节在许多地方都至关重要。

我们先看一个最经典的 RAG 流程是怎么样的:

Image
Image

数据处理阶段:

  1. 整理知识,汇总文档
  2. 对文档进行切分,这一步称为分块(Chunking),产物是Chunks
  3. 对切分后的段落(Chunks)选择合适的Embedding 模型进行向量化(Embedding)
  4. 将向量化的数据存放到向量数据库(Vector Database)

用户查询阶段:

  1. 用户提问
  2. 将问题同样通过 Embedding 模型进行向量化
  3. 到向量数据库中进行语义检索(Retrieve)
  4. 把检索到的相关内容(Context)汇总成一个提示词(Prompt),提交给大语言模型(LLM)
  5. LLM 根据 Prompt 生成答案并返回

这是一个非常经典的 RAG 流程。不过,其中有很多细节值得探讨。这篇文章一方面是科普,另一方面也想探索一些最佳实践以及可以在项目中应用的技术。

一、文档处理(Parsing)🔗

这一步其实是一个非常棘手的问题。在真实的业务场景下,会存在各种格式的文档,例如:

  1. Markdown (.md) 文档
  2. 纯文本 (.txt) 文档
  3. PDF (.pdf) 文档
  4. Word (.docx) 文档
  5. Excel (.xlsx) 数据
  6. PPT (.pptx) 文档
  7. ...

对于这些文档,很多常规的知识库构建方法可能只是简单地进行 OCR 或纯文本提取,但这样肯定是不可取的,因为会丢失非常多的结构化语义信息(如标题层级、表格、列表等)。

现在比较好的做法是利用专门的文档解析工具(如Unstructured.io, LlamaParse),它们能理解文档的内部结构,然后将所有异构文档统一转换为一种富文本格式(如 Markdown),以便进行标准化的后续处理。

除了上面提到的工具,这里还强烈推荐下微软开源的多模态处理工具 markitdown

二、文本分块(Chunking)🔗

这一步同样至关重要。因为 Embedding 模型一次能处理的上下文长度是有限的,此外,如果文本长度过长,也可能导致 LLM 产生幻觉或引入过多噪音。因此,合理的切分至关重要。

传统的做法,这里以 Dify 平台的功能来举例说明,有:

Image
Image
  1. 基于长度:例如按 1000 个字符来进行切分。弊端很明显,太容易切断完整的语义,导致上下文信息丢失。
  2. 基于正则或段落:按换行符或特定符号切分。好处是能保留段落的常见语义信息,但对于上下文联系紧密的跨段落内容,依然会丢失关联。
  3. 基于整篇文章:如果文章长度超出 Embedding 模型限制再进行切分。好处是信息更加密集,但缺点依然存在:对于超长文章,切分后上下文关联仍可能丢失;同时,召回的单个 Chunk 内容过长,需要后续进行更精细的处理。

为了改进上述方式,一些框架也引入了**段落重叠(Overlap)**的机制,即把上一段结尾的部分内容加入到下一段的开头,再进行向量化。但在我的项目经验来看,这种机械重叠带来的实际效果提升有限。

我想表达的是,没有“万能的银弹”,还是要结合你的项目情况来选择合理的 Chunking 方法。下面我们讨论一种目前比较有前景的技术——智能分块(Agentic Chunking)

如果你使用过 Coze 这样的平台,上传一篇文章后会很疑惑,为什么没有设置相关的切分选项,它就自动帮你处理好了?我推测其背后很可能就是使用了 Agent 来做处理。

它的原理是给定一个 Prompt,让 LLM 来执行切分任务,例如:请对用户给定的文档进行合理的语义切分,确保每个分块都是一个独立的、完整的意义单元,同时长度不能超过2000个token。 当然,这只是一个简单的示例,实际的 Prompt 会比这个复杂得多。

目前来看,通过 LLM 来做切分是效果较好的做法,但也存在一些挑战:

  1. 需要更长的处理时间和额外的计算资源(API 调用成本)。
  2. 对于超长文档,需要引入更复杂的机制来处理,因为 LLM 本身的上下文窗口也是有限的。在切分超长文档时,如何保证分块间的连贯性?是继续遵守段落重叠,还是引入某种记忆机制来引导下一轮的切分呢?

综合来看,Agentic Chunking 前景广阔,特别适合对精度和准确性要求极高的文档切分场景。

三、向量化(Embedding)🔗

选择合适的 Embedding 模型至关重要,这直接决定了语义向量化的效果。但这里也存在一个矛盾:

  • 高精度模型:通常性能更好,但其生成的向量维度更高,对运行和存储的要求也更高,意味着服务器和存储成本会增加,推理时间也会变长。
  • 低精度或性能较差的模型:成本低,但可能导致向量化的意义丢失,其语义搜索效果甚至可能不如传统的关键词搜索算法。
Image
Image

这里的 Embedding 模型可以去 Hugging Face 的**MTEB (Massive Text Embedding Benchmark)**排行榜上查看和选择,这是业界的黄金标准。

四、查询处理(Query Transformation)🔗

这一步也经常被忽略,但在真实场景下,用户的提问可能是天马行空的,或者与知识库的主题无关,这时直接检索效果会很差。我的建议是在检索前增加一个 LLM 预处理步骤。

  1. 意图识别与路由:对提问进行分类。如果是在知识库范畴内,则执行检索;对于其他任务(如闲聊、查询天气),则可以礼貌地拒绝或路由到其他工具。
  2. 查询改写/扩展:对原始提问进行精简或优化,甚至可以从不同角度生成几个新的问题,然后用这几个问题同时去检索,以提高召回的全面性和准确性。

五、重排(Reranking)🔗

这一步也叫重排序,是一个非常重要的优化点。向量数据库返回的结果是一个基于向量相似度粗略检索出的候选集。

通常我们会让向量数据库召回一个比最终需要的多一些的结果,也就是控制Top K的数量,比如召回 20 条。Reranking的作用就是利用一个更强大的、专门用于判断相关性的重排模型(Reranker),对这 20 条结果进行更精细的打分和重新排序。在 Dify 等平台中,还可以设置一个分数阈值,低于该分数的直接忽略。

Image
Image

所以总结一下,Reranking 这一步是为了对粗召回的结果进行二次精选,确保后续组合 Prompt 时,提供给 LLM 的是最高质量的上下文。

六、检索内容整合(Prompt Engineering)🔗

这一步就是把我们 Reranking 后的结果进行整合,设计成一个合理的 Prompt,方便 LLM 理解并生成答案。

这一步没有太多固定的讲解,需要根据具体任务和模型特性,进行合理的设计即可。

七、答案生成与审查(Generation & Guardrails)🔗

这是流程的最后一步,但通常会面临两个问题:

  1. 选择什么 LLM? 在大多数场景下,使用强大的通用大模型(如 GPT-4o, Claude 3 等)就足够了。但在特定领域下,比如为了结合公司的业务风格和专业术语,我们可能会选择一个经过微调(Fine-tuned)的专用模型。
  2. 内容审查与合规:这一步其实是对 LLM 最终生成的内容进行一次审查,可以通过规则或另一个 LLM 来判断答案是否有据可依(Groundedness Check)、是否包含不当内容,确保返回给用户的结果是安全、可靠且负责任的。

衍生点🔗

向量数据库🔗

可以看到我们 RAG 中非常重要的一环就是向量数据库,除了在 RAG 中使用,对于一些常见的文章搜索也可以广泛使用,例如你有一个博客,通常你的搜索可能是基于关键词或者模糊搜索,但是这些都没有脱离文字搜索,但是结合向量数据库你可以做到语义化的返回查询内容。

还有比如电商平台,你搜索关键词可能返回的商品会更加符合你的喜好,因为图片或者简介包含了我们需要搜索的内容。

最后🔗

Image
Image

完成上述的所有步骤和优化,我们的 RAG 流程才算得上健壮和完整。这里面包含了一些我自己的理解和经验,如果有不对的地方,欢迎一起交流和探讨。

文章目录