RAG开发的零散笔记
啥时候适合用RAG
当你的知识库少于20w个Token(大概500页材料),你可以将整个知识库包含在你给模型的提示中,而无需使用RAG或类似方法
数据预处理
RAG的源数据需要进行严格的数据预处理,保留与业务核心相关的内容。包括:
- 内容清洗:去除文档中所有和核心知识无关的内容,如网页导航栏,页眉页脚,广告,版权声明等
- 格式转换和规范化: 将复杂的格式(如PDF的多栏布局,word的表格)转换成更简洁利于llm理解的格式(如markdown),统一处理文档中的空格,换行和特殊字符
- 修复或增强: 修正明显的拼写错误或OCR识别错误。
文本分块
将原始资料分割成片段chunks的过程,这些chunks是RAG系统信息处理的基本单元,他们将被送入Embedding模型进行向量化, 然后存入向量库进行索引
文本分块的核心是一个Trade-Off,检索精度和上下文完整性的平衡。
小块(Smaller Chunks):
- 优点 :信息更聚焦,语义更集中。这使得查询向量更容易匹配到包含特定关键词或高度相关语义的小块,从而提高检索的精度。更容易命中“靶心”。
- 缺点 :可能丢失重要的上下文信息。单个小块可能只包含一个事实片段,缺乏必要的背景、前提或后续解释,导致 LLM 无法理解完整的语境或回答需要综合信息的复杂问题。
大块 (Larger Chunks):
- 优点 :能保留更丰富的上下文信息,包含更长的逻辑链条或更完整的背景描述。这有助于 LLM 理解更复杂的概念、事件的前因后果或不同信息点之间的关系。
- 缺点 :可能包含较多与当前查询不直接相关的信息(噪音),从而稀释了核心相关性信号,可能降低检索精度(匹配到包含相关词但整体主题跑偏的块)。同时,更大的块也增加了 LLM 处理的负担和潜在的幻觉风险。
分块的方式有如下几种:
固定大小分块,这是最懒人的方法。很容易破坏语义完整性,造成上下文严重割裂
基于句子分块。首先使用句子分割算法(如.。?!等)将文本分割成独立的句子,然后将一个或多个连续的句子组合成一个chunk,使其大小接近目标范围。 句子长度差异可能比较大,有的长,有的短,导致chunk不均匀。影响后续处理和检索稳定性
递归字符分块,这是langchain等框架中常用的一种更智能的策略, 它会先预设一个“分隔符”优先级列表来递归分割文本,例如,优先尝试按 \n\n (段落) 分割,如果分割后的块仍然太大,再尝试按 \n (换行符) 分割,然后按空格分割,最后如果还太大,就按字符 "" 分割。目标是在保持较大语义块(如段落)的同时,确保最终块大小不超过限制。
基于文档分块: 这种策略利用文档本身的结构信息进行分割,例如 HTML 的
<div>, <p>, <li>标签,Markdown 的标题 #, ##, 列表 -, *,或者 JSON/YAML 的层级结构。
向量化
检索系统召回率的上限,从数据被向量化的一刻,就已经被基本确定了, 后续的所有优化,都只是在逼近这个上限。
常见的嵌入模型
嵌入模型的核心特点有:
- 上下文窗口:决定了模型一次能处理多长的文本,处理长文档应该选用大窗口模型
- 向量维度: 向量的长度(如384,1024,4096),维度越高,能区分的语义细节越丰富,但是计算,存储成本和查询延迟也越高
- 语义理解模式:
- 密集向量
- 稀疏向量
- 混合模型
- 多语言能力:如果需要处理多语言,需要选择多语言模型,确保不同语言的相同语义在向量空间对齐
HNSW 算法
HNSW(分层可导航小世界 Hierarchical Navigable Small World)是目前向量检索领域最流行的算法之一