RAG是什么
RAG的全称是什么,RAG的全称为 Retrieval-Augmented Generation , 中文名通常叫做 检索增强生成 。
拆开理解:
Retrieval(检索) 从外部知识库中找到相关资料
Augmented(增强) 把找到的资料作为上下文补充给大模型
Generation(生成) 大模型根据这些资料生成答案
传统LLM:
用户问题
|
↓
大模型
|
↓
答案
RAG:
用户问题
↓
知识库检索
↓
找到相关文档片段
↓
把片段放入 Prompt
↓
LLM生成答案
↓
回答用户
一个合格的RAG 需要经历哪几个步骤。
他其实是分2个步骤的 ,一个离线阶段(构建知识库),一个是在线阶段(用户查询)
离线阶段(构建知识库)
原始知识 (PDF,Word,网页,数据库,Markdown)→ Document Loader (文件读取,提取文本内容) → Parser / 清洗(整理文本) → Chunking (分段) → Embedding (文本变向量) → Vector Database(保存) → 知识库完成
在线阶段(Online)
用户提问 → 问题理解 → Query Embedding → 向量搜索 → 找到相关知识 → (Rerank)→ 组成上下文 → LLM → 回答
什么是 Parser
Parser 是什么, 是解析器,作用理解文档结构
举例
#PDF
================
第三章 用户管理
3.1 创建账号
管理员进入后台
点击新增用户
填写信息
================
普通识别大概是这样的
第三章 用户管理
3.1 创建账号
管理员进入后台
点击新增用户
填写信息
但是 Parser 会尽量识别:
{
"title":"第三章 用户管理",
"section":"3.1 创建账号",
"content":[
"管理员进入后台",
"点击新增用户",
"填写信息"
]
}
也就是说Parser会保留 : 标题层级,表格结构,列表,页码,元数据。
为什么 Parser 很重要?
因为 RAG 不只是搜索文字。 他需要去理解 这句话属于什么上下文?
例如:
```bash
用户管理
创建用户
普通用户需要审核
删除用户
需要管理员权限
```
如果没有 Parser ,他就会变成 用户管理 创建用户 普通用户需要审核 删除用户 需要管理员权限 数据结构就没了。
而模型理解就会变成 删除用户需要审核 但是事实上 创建用户需要审核 删除用户需要管理员权限 意思概念完全不同
清洗(Cleaning)
本质上最主要的就是 删除无意义内容,修正错误内容。
举例1 PDF页眉页脚 :
PortMax系统手册
第一页
账号管理流程
PortMax 版权所有 www.xxx.com
每一页都有 PortMax 版权所有,大量的重复垃圾,清洗就会删除 PortMax 版权所有 www.xxx.com
举例2: 断行
原文
用户需
要管理员
权限
变:
用户需要管理员权限
举例3: 乱码
原文
账号管理���流程
清洗后
账号管理流程
例4:HTML网页
原文
首页
登录
菜单
帮助
-----------------
正文:
如何创建账号?
-----------------
联系我们
备案信息
如果知识库检索到:
联系我们
清洗后: 保留
如何创建账号?
不同文件 Parser(解析) 不一样
| 文件 | Parser重点 |
|---|---|
| 提取文字、识别标题、表格 | |
| Word | 保留标题层级 |
| Excel | 理解行列关系 |
| HTML | 去除网页垃圾 |
| Markdown | 保留标题结构 |
| PPT | 保留页面结构 |
Chunking (数据切割)
简单的说就是把一篇很大的文档,切成很多“小知识块(Chunk)”,方便 Embedding 和检索
假设你有一个企业操作手册:
PortMax系统操作手册.pdf
100页
10万字
如果直接 Embedding:
整个PDF
|
↓
一个向量
就会产生一些问题
问题1:检索不精准
用户问:怎么修改订单?
但是整个文档包含:
账号管理
订单创建
订单修改
财务流程
权限管理
售后流程
...
Embedding 后只有一个“大概意思”。系统不知道订单修改在哪里。
问题2:超过模型上下文
你不可能10万字的文档给LLM,成本高,模型也处理不了
10万字文档
↓
全部塞给LLM
Chunk 长什么样?
原文:
订单管理
创建订单:
1. 点击新增订单
2. 填写客户信息
3. 保存订单
修改订单:
1. 找到订单
2. 点击编辑
切分:
Chunk 1:
订单管理
创建订单:
1. 点击新增订单
2. 填写客户信息
-----------------
Chunk 2:
修改订单:
1. 找到订单
2. 点击编辑
Chunking 的核心目的
核心就2个: 提高搜索准确率 ,给LLM合适上下文
比如提高搜索准确率
提问:怎么修改订单?
系统直接找到
Chunk 2:
修改订单流程
比如给LLM合适上下文
不能给出整个知识库的数量, 也不是给单纯的一句话 或者一小段话, 而是给出相关的500~1000字
Chunking 常见方式
1.固定长度切割
这个是最简单的,
举例:每500个token切一次
结果:
Chunk1 0-500
Chunk2 400-900
Chunk3 800-1300
中间会有100 token重复,这个概念叫 Overlap(重叠) ,避免语义被切断。
2.按结构切
# 根据文章的标识或者这些常规标记
标题
章节
段落
列表
以markdown举例:
# 用户管理
## 创建用户
内容...
## 删除用户
内容...
切割成:
Chunk1:
用户管理-创建用户
Chunk2:
用户管理-删除用户
3.父子分块(Parent-Child)
这个更加高级的切分方案
举例:
Parent:
员工入职流程
(3000字)
|
|
↓
Child:
提交资料
账号创建
权限申请
如果搜索 找 Child 回答: 拿 Parent
Embedding 是什么
Embedding 就是把“人类能理解的文字”,转换成“机器可以计算相似度的数字表示”。
也可以叫做向量化(Vectorization)
为什么需要 Embedding?
计算机看到 怎么修改账号? 和 账号如何更改? ,它其实不知道这两个意思很接近。
对于计算机来说 怎么修改账号? 只是一个 字符串A ,而 账号如何更改? 是 字符串B
但是人类知道 怎么修改账号?≈ 账号如何更改?
所以需要一种方式,让机器理解知道语义(大概就是这段话什么意思),这就是 Embedding。
Embedding 做了什么?
假设文本 账号修改流程 经过 Embedding 模型。
变成了下面这个格式 , 这叫做向量(Vector)
[
0.231,
0.543,
-0.123,
0.892,
...
]
再比如 如何修改账号?
[
0.231,
0.543,
-0.123,
0.892,
...
]
会发现他们的内容非常的相似,因为意思接近。
Rerank (重排序)
简单理解就是 Embedding 负责“粗找”,Rerank 负责“精挑”。 ,他解决的问题就是 向量找到的不一定是最相关的。
假设没有Rerank的情况下结构是这样的:
用户问题
↓
Embedding
↓
Vector DB搜索
↓
返回Top K文档
↓
LLM回答
例如用户搜索:怎么修改账号?
向量数据库找到:
Top 5:
1. 账号创建流程 85分
2. 账号修改流程 82分
3. 账号权限管理 80分
4. 密码修改流程 78分
5. 用户删除流程 75分
然后全部给 LLM:
账号创建...
账号修改...
权限管理...
密码修改...
用户删除...
这样就会产生一个很严重的问题: 里面有很多相关但不准确的信息。
Rerank 在这里应该做什么?
在原有的
用户:
怎么修改账号?
↓
向量搜索:
找到100个相关Chunk
↓
Rerank:
重新评分
↓
留下:
账号修改流程
↓
LLM
为什么 Embedding 不够?
因为 Embedding 主要判断 语义距离接近 ,但是语义接近不等于答案,
接近 ≠ 答案
举例用户提问:如何删除账号?
知识库:
A:
账号创建流程
B:
账号修改流程
C:
账号删除流程
Embedding会以为:
A 创建账号
B 修改账号
C 删除账号
三个都很接近,因为都存在 账号 ,所以可能评分是
A 0.82
B 0.80
C 0.79
A的评分会变高,但是实际上 C 才是正确答案。
Rerank 会进一步理解:
问题: 如何删除账号?
文档:账号删除流程 匹配程度最高,然后进行重新排序
C 删除账号流程 98分
B 修改账号流程 65分
A 创建账号流程 50分