主要步骤#
对于 rag 体系,主要分为以下的步骤:
| 阶段 | 核心动作 | 进阶动作 |
|---|---|---|
| 数据准备 | 数据etl、分块、元数据提取、Embedding、索引建立 | 语义切分、元数据提取 |
| 用户输入 | 接收 Query | 查询改写、子问题拆解 |
| 召回 | 向量数据库检索 | 混合检索 (Hybrid Search) |
| 排序 | Rerank (精排) | 阈值过滤、上下文去噪 |
| 生成 | LLM 生成答案 | 引用溯源 (Citations) |
| 阶段 | 核心任务 | 为什么“不简单”? |
|---|---|---|
| 查询增强 | Query 改写/拆解 | 难点在于维持对话上下文,不让 LLM 跑题。 |
| 混合检索 | 语义 + 关键词 | 难点在于权重分配(Alpha 值),调优很吃经验。 |
| 精排重测 | Rerank 模型计算 | 难点在于性能平衡,要在精度和响应速度间取舍。 |
| 生成回复 | Prompt 组装 | 难点在于防止幻觉,并实现高精度的引用溯源。 |
数据准备(indexing pipeline)#
数据清洗(etl,extract,transform,load)#
在分块之前,原始文档往往是“脏”的。
- 核心动作:解析 PDF、Word、HTML 等格式,提取纯文本。
- 挑战点:PDF 里的多栏排版、页眉页脚、广告弹窗、特殊字符。这些“噪音”如果进入向量库,会严重干扰 Embedding 的计算。
- 进阶动作:使用布局分析(Layout Analysis)技术(如
LayoutParser或Unstructured),识别出哪里是正文,哪里是表格。
分块(chunking)#
块太小,丢失上下文;块太大,向量特征会被稀释,检索不准。
- 基础:固定长度切分 (Fixed-size)
- 设定一个字数(如 500 字),每隔 500 字切一刀。
- 缺点:经常会把一句话切成两半。
- 核心:递归字符切分 (Recursive Character)
- 先按段落切,段落太长按句子切,句子太长按空格切。
- 优点:尽量保持了语义单元的完整性。
- 进阶:语义切分 (Semantic Chunking)
- 原理:计算相邻两句话的 Embedding 相似度,如果相似度突然断崖式下降,说明话题变了,就在这里切断。
- 价值:保证了每一个 Chunk 内部只讲一件事情。
元数据提取 (Metadata Extraction)#
在同一个数据库的同一条记录(Row/Document)里,同时存放“特征向量”和“结构化属性”。
不要只存向量,要给每个 Chunk 打上“身份证”。
- 核心动作:记录来源(文件名、页码、URL)。
- 进阶动作:
- 摘要生成:用 LLM 给这个 Chunk 写一句摘要。
- 实体提取:提取出里面提到的人名、项目名、日期。
- 层级信息:记录它属于哪个章节标题。
- 目的:在检索时,你可以先通过元数据过滤(比如:只搜“2024年”的文档),这比模糊的向量检索要可靠得多。
| 字段名 | 内容类型 | 示例 |
|---|---|---|
| ID | 唯一标识符 | doc_chunk_123 |
| Vector | 向量数据 | [0.12, -0.05, 0.88, ...] (1536维) |
| Payload/Metadata | 元数据 (身份证) | { "title": "2024年报", "page": 15, "date": "2024-05-01", "category": "finance" } |
| Original Text | 原始文本 | "公司2024年第一季度营收增长15%..." |
向量化 (Embedding)#
【*】入库(索引)时的 Embedding 模型和查询(检索)时的 Embedding 模型必须是同一个,甚至参数配置都必须完全一致。
将文本转为高维数学向量。
- 核心动作:调用 Embedding 模型(如 OpenAI 的
text-embedding-3-small或国产的BGE系列)。 - 进阶知识:
- 模型选型:不同的模型“侧重点”不同。有的擅长短句,有的擅长长文档。
- 多向量策略 (Multi-Vector):为一个大块生成多个小向量(比如:摘要向量、Q&A 向量),这样用户问法再刁钻也能匹配上。
索引构建 (Indexing)#
向量存进数据库时,需要一种“地图”来快速查找。
- 核心算法:HNSW (Hierarchical Navigable Small World)。
- 这是目前最流行的算法。你可以把它想象成一个“朋友圈”,它通过建立多层级的小团体,让搜索时不需要遍历几百万条数据,而是通过几跳就能找到最接近的邻居。
在向量空间里,数据是高维的点(比如 1536 维)。
- 如果不建索引:用户提一个问题,数据库必须拿这个问题的向量,去跟库里 100 万个向量逐一计算“余弦相似度”。这叫 暴力搜索 (Brute-force),数据一多,服务器就崩了。
- 如果建了索引:数据库预先给这些点建立了一种**“导航结构”**。查询时,它能像地图导航一样,通过几个关键路口,直接跳到目标点附近。
入库慢:因为要一边存数据,一边实时计算和调整这个复杂的层级地图(建索引)。查询快:因为有了地图,搜索复杂度从 O(N) 降到了 O(log N)。
A. 小世界 (Small World) —— “朋友圈”理论#
想象你在一个巨大的派对上要找“周杰伦”,但你不认识他。
- 你先问身边的人:“你认识周杰伦吗?”
- 身边的人说:“我不认识,但我认识一个搞音乐的,我带你去问他。”
- 这个搞音乐的人说:“我不认识,但我认识周杰伦的经纪人。”
- 经纪人带你找到了周杰伦。 这就是“六度分隔理论”:虽然每个人只连接了几个邻居,但通过这些“朋友圈”的跳转,你可以飞快地找到目标。在 HNSW 中,每个向量点都会选择几个距离它最近的向量作为“邻居”连线。
B. 分层 (Hierarchical) —— “高速公路”理论#
HNSW 把这个朋友圈分成了很多层。
- 最顶层(高速公路):只有极少数的点。你在这里一跨步,可能就跨过了几万个数据点。
- 中间层(省道):点稍微多一点,动作变细。
- 最底层(街道):包含所有的数据点。
查询流程:
- 你从最顶层进入,在极少数的点里找到离你最近的那一个。
- 顺着这个点“降落”到下一层。
- 在这一层局部寻找更近的点,再降落。
- 最后降落到最底层,完成精准锁定。
用户输入处理#
用户往往不知道自己想要什么,或者问得很模糊。
- 查询改写 (Query Rewriting):
- 核心动作:利用 LLM 将用户的口语转化为更适合搜索的“关键词”或“标准问”。
- 示例:用户问“那个去年那个卖得最好的蓝色的东西是啥?”,改写后变成“2024年度销量冠军 蓝色产品 名称”。
- 子问题拆解 (Sub-query Decomposition):
- 进阶动作:如果问题很复杂(如“对比 A 和 B 的财报”),LLM 会将其拆分为“A 的财报数据”和“B 的财报数据”两次检索。
检索阶段(多路召回与融合)#
较为复杂,这里就简单地进行罗列。
- 混合检索 (Hybrid Search):
- 核心动作:同时启动向量检索(搜意思)和关键词检索(搜字面)。
- 为什么要混合?:向量检索擅长找“意思近的”,但容易漏掉“型号、人名、缩写”等精确信息。
- 多路召回融合 (RRF):
- 进阶动作:向量搜回来 50 条,关键词搜回来 50 条,如何给它们排总榜?通常使用 RRF 算法(倒数排名融合),给两边的排名加权求和,选出综合实力最强的 Top N。
排序与去噪#
- Rerank (精排):
- 核心动作:调用专门的 Reranker 模型(如 BGE-Reranker)。
- 底层逻辑:向量检索是“看一眼长相”,Rerank 是“坐下来深度谈话”。它会让 Query 和每一个候选 Chunk 深度对齐计算得分,虽然慢,但极准。
- 阈值过滤 (Thresholding):
- 进阶动作:如果最相关的 Chunk 分数都很低(比如低于 0.3),系统应直接判定为“库里没答案”,直接告诉用户“不知道”,防止 LLM 强行编造。
- 上下文去噪 (Context Compression):
- 细节:把选中的 Chunk 里无关的句子删掉,只保留关键段落,节省 LLM 的 Token 消耗并减少干扰。
生成阶段:逻辑整合与溯源#
- Prompt 注入:
- 核心动作:将检索到的背景知识拼接到 Prompt 中。
- 黄金指令:要求 LLM “仅根据提供的 Context 回答,严禁自我发挥”。
- 引用溯源 (Citations):
- 进阶动作:要求 LLM 在回答的每一句话后面标注来源。
- 示例:根据[文档1]显示,营收增长了 10%;而[文档2]提到研发投入在下降。这样用户点击引用标号就能看到原始出处,增加信任感。
评论
还没有评论,来发第一个吧