-
Notifications
You must be signed in to change notification settings - Fork 2
Home
RAG = Retrieval-Augmented Generation(检索增强生成)
想象一下:
- 你在考试时可以查阅资料书📖
- AI回答问题时也可以"查阅"知识库
- 这就是RAG的核心思想
传统AI vs RAG AI:
传统AI: 问题 → AI大脑 → 回答
RAG AI: 问题 → 搜索知识库 → 找到相关资料 → AI大脑+资料 → 更准确的回答
传统图书馆:
- 你问管理员:"有关于苹果的书吗?"
- 管理员只能找标题里有"苹果"字的书📖
- 如果你问"水果营养",他找不到"苹果维生素"的书
智能图书馆(你的RAG系统):
- 你问:"苹果有什么营养?"
- 智能管理员不仅找"苹果",还能理解你想了解"营养价值"
- 他会找到所有相关内容:苹果的维生素、矿物质、纤维等
graph TD
A[文档输入] --> B[文档处理]
B --> C[文本分割]
C --> D[向量化]
D --> E[存储索引]
F[用户查询] --> G[查询处理]
G --> H[向量检索]
G --> I[关键词检索]
H --> J[结果融合]
I --> J
J --> K[返回结果]
subgraph 文档处理流程
B --> |Document Loader| B1[文档解析]
B1 --> |Text Splitter| C
C --> |M3E-Base| D
D --> |Elasticsearch| E
end
subgraph 查询处理流程
G --> |Query Parser| G1[查询解析]
G1 --> |M3E-Base| H
G1 --> |IK Analyzer| I
H --> |Cosine Similarity| J
I --> |BM25| J
end
核心组件说明:
- Document Loader: 支持PDF、Word、HTML等多格式文档加载
- Text Splitter: 采用500字分片,50字重叠的分割策略
- M3E-Base: 768维向量编码模型
- Elasticsearch: 分布式搜索引擎,支持向量和关键词混合检索
- IK Analyzer: 中文分词器
- Query Parser: 查询意图解析器
- BM25 & Cosine Similarity: 混合相似度计算
RAG = Retrieval-Augmented Generation(检索增强生成)
想象一下:
- 你在考试时可以查阅资料书📖
- AI回答问题时也可以"查阅"知识库
- 这就是RAG的核心思想
传统AI vs RAG AI:
传统AI: 问题 → AI大脑 → 回答
RAG AI: 问题 → 搜索知识库 → 找到相关资料 → AI大脑+资料 → 更准确的回答
传统图书馆:
- 你问管理员:"有关于苹果的书吗?"
- 管理员只能找标题里有"苹果"字的书📖
- 如果你问"水果营养",他找不到"苹果维生素"的书
智能图书馆(你的RAG系统):
- 你问:"苹果有什么营养?"
- 智能管理员不仅找"苹果",还能理解你想了解"营养价值"
- 他会找到所有相关内容:苹果的维生素、矿物质、纤维等
想象每个词都有自己的"颜色":
- "苹果" = 红色🔴
- "香蕉" = 黄色🟡
- "汽车" = 蓝色🔵
但实际上,计算机用的不是颜色,而是768个数字来表示每个词:
- "苹果" = [0.1, 0.8, 0.3, 0.9, ...](768个数字)
- "香蕉" = [0.2, 0.7, 0.4, 0.8, ...](768个数字)
相似的词有相似的数字组合:
- "苹果"和"香蕉"的数字很接近(都是水果)
- "苹果"和"汽车"的数字差很远(完全不同类别)
想象你要描述一个人:
- 1个数字:只能说身高
- 10个数字:身高、体重、年龄...
- 768个数字:能描述这个人的方方面面
768个数字能描述文字的方方面面:
- 第1个数字:这个词是不是关于食物?
- 第2个数字:这个词是不是表示颜色?
- 第3个数字:这个词是不是表示情感?
- ...
- 第768个数字:这个词的语法特征?
如果整本书一起背:
- 太长了,大脑记不住
- 找信息时要翻遍整本书
如果分成小章节背:
- 每章都能记住
- 找信息时直接找相关章节
当前系统也是这样:
- 把长文档切成500字的小段
- 每小段都转换成768个数字
- 搜索时只找最相关的几个小段
想象两个相邻的段落:
- 第1段:"...苹果含有维生素C,对健康"
- 第2段:"很有好处,还能预防感冒..."
如果不重叠:
- 信息被切断了,"对健康很有好处"这个完整意思丢失了
如果重叠50字:
- 第1段:"...苹果含有维生素C,对健康很有好处..."
- 第2段:"...对健康很有好处,还能预防感冒..."
- 完整信息保留了!
关键词搜索(像查字典):
- 你查"苹果",只能找到写着"苹果"的内容
- 查不到"红富士"、"水果之王"这些相关内容
语义搜索(像聪明的朋友):
- 你说"苹果",朋友知道你可能也想了解"水果"、"营养"、"维生素"
- 能找到所有相关内容,即使没有直接写"苹果"
当前系统两种都用:
- 主要用语义搜索(权重很高)
- 关键词搜索做补充(权重很低)
想象两个箭头:
- 箭头A指向"苹果营养"的方向
- 箭头B指向"水果健康"的方向
如果两个箭头指向相同方向:
- 角度很小,相似度很高(接近1.0)
如果两个箭头指向相反方向:
- 角度很大,相似度很低(接近0)
余弦相似度就是测量这个角度!
传统管理员:
- 有一本厚厚的目录册
- 你要什么书,他从头到尾翻目录
- 很慢!😫
超级管理员(ElasticSearch):
- 有一个神奇的索引系统
- 每个词都知道在哪些书里出现过
- 瞬间就能找到!⚡
普通电话本(正向索引):
张三 → 138-1234-5678
李四 → 139-8765-4321
王五 → 137-1111-2222
要找谁的电话是138开头的?得一个个翻!
黄页(倒排索引):
138开头 → 张三
139开头 → 李四
137开头 → 王五
直接就能找到!
ElasticSearch也是这样:
"苹果"这个词 → 出现在文档1、文档5、文档10
"营养"这个词 → 出现在文档1、文档3、文档7
英文天然有空格:
"I love apples" → "I" + "love" + "apples"
中文没有空格:
"我爱吃苹果" → 怎么分?
新手切菜:
"我爱吃苹果" → "我" + "爱" + "吃" + "苹" + "果"
切得太碎,意思都没了!
老师傅切菜(IK分词器):
"我爱吃苹果" → "我" + "爱吃" + "苹果"
既保持了意思,又方便搜索!
ik_max_word模式(超级老师傅):
"中华人民共和国" →
- "中华人民共和国"(完整的)
- "中华人民"(部分的)
- "人民共和国"(另一部分)
- "中华"(更小的)
- "人民"(更小的)
- "共和国"(更小的)
这样无论你搜索什么词,都能找到相关内容!
关键词侦探:
- 只认识具体的词汇
- 你说"找苹果",他只找写着"苹果"的地方
- 很死板,但很准确
语义侦探:
- 很聪明,能理解意思
- 你说"找苹果",他知道你可能也想要"水果"、"营养"相关的
- 很灵活,但有时会想太多
当前系统让两个侦探合作:
- 语义侦探当队长(权重1.0)
- 关键词侦探当助手(权重0.00001)
- 结合两人的发现,给出最好的答案
传统方法(暴力搜索):
- 像在人群中一个个问"你是张三吗?"
- 10万人要问10万次
智能方法(向量索引):
- 像有一个神奇的地图
- 直接指向张三在哪里
- 只需要问几十次就找到了
想象一个有768条街道的神奇城市:
第1条街:专门住"食物相关"的词
- "苹果"住在这条街的88号
- "香蕉"住在这条街的92号
- "汽车"不住这条街(住在0号)
第2条街:专门住"颜色相关"的词
- "红色"住在这条街的95号
- "苹果"也在这条街有个小房子(45号)
- "快乐"不住这条街
每个词在这个城市里都有一个完整的地址:
- "苹果" = [88号食物街, 45号颜色街, 12号味道街, ...]
- "香蕉" = [92号食物街, 78号颜色街, 15号味道街, ...]
当你搜索"苹果营养"时:
- 系统找到"苹果"住在哪里
- 看看"苹果"的邻居都有谁
- 发现"维生素"、"纤维"、"矿物质"都住在附近
- 把这些邻居的信息都告诉你
距离越近,关系越密切:
- "苹果"和"香蕉"住得很近(都是水果)
- "苹果"和"汽车"住得很远(完全不相关)
想象你有一幅巨大的拼图:
- 整幅图太大,桌子放不下
- 想找某个细节,要看遍整幅图
- 存储起来也很困难
聪明的做法:
- 把大拼图分成小块
- 每小块都有完整的意思
- 需要时只拿出相关的小块
没有重叠的问题:
拼图块1: [🍎苹果很甜,含有]
拼图块2: [维生素C和纤维]
信息断裂了!不知道什么"含有维生素C"
有重叠的好处:
拼图块1: [🍎苹果很甜,含有维生素C]
拼图块2: [含有维生素C和纤维素]
↑ 重叠部分保持连接
信息完整,知道是苹果含有维生素C!
想象你在看一场话剧:
- 舞台上有很多演员
- 但聚光灯只照亮主要演员
- 你的注意力跟着聚光灯走
AI读句子也有"聚光灯":
句子:"苹果很甜很好吃"
AI的聚光灯:
🔦苹果 (亮) - 这是主角
很 (暗) - 这是配角
🔦甜 (亮) - 这是重要特征
很 (暗) - 又是配角
🔦好吃 (亮) - 这是重要结论
AI学会了人类的阅读习惯:
- 名词通常比较重要(苹果、好吃)
- 形容词描述特征(甜)
- 副词通常是修饰(很)
- 动词表示动作
通过大量训练,AI知道:
- 在"苹果很甜"中,"苹果"和"甜"最重要
- 在"我爱吃苹果"中,"我"、"爱吃"、"苹果"都重要
工厂的不同车间:
- 分词车间:把文档切成词语
- 索引车间:建立词语到文档的映射
- 向量车间:处理768维向量数据
- 搜索车间:响应用户查询
文档进入工厂时:
1. 原料检验:检查文档格式
2. 分词处理:IK分词器切词
3. 向量加工:转换成768维向量
4. 质量检测:验证数据完整性
5. 入库存储:保存到对应索引
6. 建立索引:更新倒排索引
用户查询时:
1. 接收订单:用户提交查询
2. 订单分析:理解查询意图
3. 生产调度:决定搜索策略
4. 并行生产:同时进行关键词和向量搜索
5. 质量控制:按相似度排序
6. 包装发货:返回搜索结果
小孩学说话的过程:
- 听大人说话(大量输入)
- 模仿发音(尝试输出)
- 大人纠正(反馈学习)
- 反复练习(强化记忆)
- 最终学会(掌握语言)
AI学习语言也是类似过程:
- 喂给AI海量文本(就像给小孩读很多书)
- 让AI预测下一个词(就像让小孩接话)
- 告诉AI对错(就像大人纠正小孩)
- 反复训练(就像反复练习)
- 最终AI学会了语言规律
想象AI是个学生:
第一阶段:通识教育
- 读遍了互联网上的文章
- 学会了基本的语言规律
- 知道"苹果"通常和"水果"、"甜"、"红色"相关
第二阶段:专业训练
- 专门学习如何把文字转换成向量
- 学会了把相似意思的词放在相近位置
- 这就是你系统中的M3E模型
想象每个词都是一支箭:
- "苹果" = 一支指向"水果营养区"的箭🏹
- "香蕉" = 另一支也指向"水果营养区"的箭🏹
- "汽车" = 一支指向"交通工具区"的箭🏹
两支箭指向同一方向:
苹果 🏹→
香蕉 🏹→
角度很小,相似度接近1.0
两支箭指向不同方向:
苹果 🏹→
汽车 🏹↗
角度较大,相似度较低
两支箭指向相反方向:
快乐 🏹→
悲伤 ←🏹
角度180度,相似度接近-1.0
直线距离的问题:
"苹果" = [1, 1]
"大苹果" = [2, 2](内容一样,只是重复了)
直线距离 = √[(2-1)² + (2-1)²] = √2 ≈ 1.41(距离很远)
余弦相似度 = 1.0(完全相同)
余弦相似度只关心方向,不关心长度:
- 方向相同 = 意思相同
- 长度不同 = 只是表达强度不同
古代没有标点符号:
原文:"学而时习之不亦说乎"
不同的断句,意思完全不同:
断句1:"学而时习之,不亦说乎?"(学了要经常复习,不是很快乐吗?)
断句2:"学而时,习之不,亦说乎?"(意思就乱了)
中文分词也是这样的艺术:
原句:"我要买苹果手机"
分词1:"我 要买 苹果手机"(要买iPhone)
分词2:"我 要买 苹果 手机"(要买水果和手机)
IK分词器就像经验丰富的语文老师:
遇到歧义时的处理:
"苹果手机很好用"
老师分析:
- "苹果手机"是一个整体概念(iPhone)
- 不应该分成"苹果"+"手机"
- 结果:"苹果手机 很 好用"
ik_max_word的贪心策略:
"中华人民共和国"
普通分词:"中华人民共和国"(只有一种分法)
ik_max_word:"中华人民共和国 + 中华人民 + 人民共和国 + 中华 + 人民 + 共和国 + 共和 + 国"
好处:无论用户搜索什么词,都能匹配到!
小镇知识库(1万个文档片段):
- 一个管理员就够了
- 大家都认识,找人很快
- 响应时间:眨眼间(<100毫秒)
中等城市(10万个文档片段):
- 需要分区管理
- 有完善的索引系统
- 响应时间:思考一下(100-500毫秒)
超级大都市(100万个文档片段):
- 需要多个分区同时工作
- 复杂的交通网络(分布式系统)
- 响应时间:稍等片刻(500毫秒-2秒)
没有高速公路的时代:
- 从A城到B城,要经过每个村庄
- 路程很长,时间很久
有了高速公路网:
- 先上高速,快速到达目标区域
- 再下高速,精确找到目的地
- 大大节省时间
HNSW向量索引也是这样:
第3层高速路: A城 ========== B城 (粗略定位)
第2层国道: A城 == C镇 == B城 (中等精度)
第1层小路: A城-村1-村2-B城 (精确定位)
搜索过程:
1. 先在高速路上快速接近目标
2. 下到国道进一步精确
3. 最后在小路上找到确切位置
我们收集了一些影响检索效率的典型问题。让我们用具体案例来分析如何优化:
❌ 低效的文档结构:
文档A:"如何申请年假?请登录人事系统,点击假期申请..."
文档B:"年假申请流程:登录人事系统,选择假期申请选项..."
文档C:"申请年假怎么办?进入人事系统,找到假期申请..."
🧠 向量化结果:
文档A向量:[0.8, 0.3, 0.9, 0.2, ...]
文档B向量:[0.7, 0.4, 0.8, 0.3, ...] ← 高度相似
文档C向量:[0.9, 0.2, 0.7, 0.4, ...] ← 高度相似
🔍 用户搜索"年假申请"时:
- 返回3个几乎相同的答案
- 用户困惑:到底哪个是正确的?
- 系统资源浪费:存储和计算冗余
✅ 优化后的文档结构:
统一文档:"年假申请完整指南"
├── 1. 常规申请流程
├── 2. 特殊假期处理
├── 3. 紧急申请处理
└── 4. 常见问题解答
好处:
🎯 单一权威来源
📊 向量更加集中和准确
⚡ 检索效率提升
❌ 误导性标题:
标题:"办公设备问题"
内容:主要讲打印机配置,只有一小段提到办公设备
标题:"员工入职"
内容:包含入职、培训安排、权限申请、设备领取等多个主题
🔤 IK分词器处理:
标题"办公设备问题" → ["办公", "设备", "问题"]
内容主要是"打印机配置" → ["打印机", "配置", "设置", "连接"]
📐 相似度计算混乱:
用户搜索"设备故障" → 匹配到标题
但实际内容是打印机配置 → 答案不相关
用户体验差 → 信任度下降
✅ 标题内容一致性优化:
原标题:"办公设备问题"
优化后:"打印机配置指南"
原标题:"员工入职"
优化后:拆分为多个文档
├── "员工入职流程"
├── "新员工培训指南"
├── "权限申请流程"
└── "设备领取手册"
好处:
🎯 标题即内容预览
📊 向量匹配更精准
⚡ 用户满意度提升
❌ 扁平化内容:
"员工福利相关问题大全"
- 健身补贴流程是什么?答:请通过福利平台...
- 补贴发放日期?答:每月20日和月底...
- 如何选择补贴类型?答:分为健身补贴和学习补贴...
- 申请截止时间?答:发放日前三天...
- 申请附件要求?答:请提供消费凭证...
(50个问题混在一起)
✂️ 文档分片问题:
500字分片可能把相关问题分开:
片段1:[补贴流程 + 发放日期 + 类型选择]
片段2:[类型选择 + 截止时间 + 附件要求]
片段3:[附件要求 + 其他问题...]
🔍 检索时的问题:
用户问"补贴流程"可能匹配到片段2
但片段2主要讲类型,流程信息不完整
✅ 结构化文档组织:
"员工福利指南"
├── 1. 基础流程
│ ├── 1.1 申请步骤
│ ├── 1.2 审批流程
│ └── 1.3 发放时间
├── 2. 操作细节
│ ├── 2.1 类型选择
│ ├── 2.2 凭证要求
│ └── 2.3 截止时间
└── 3. 常见问题
├── 3.1 发放延迟
├── 3.2 审批失败
└── 3.3 系统故障
好处:
🎯 逻辑清晰,便于分片
📊 相关内容聚集,向量更准确
⚡ 检索精度提升
❌ 语言混乱:
"如何申请系统权限?How to apply system permission?
请通过工单系统提交申请。Please submit via ticket system.
填写申请表单时注意以下事项:
1. 请填写具体系统名称
2. 需要说明申请原因
3. 确保信息准确无误"
🔤 IK分词器困惑:
"申请表单" → 中英混合影响分词
"具体系统名称" → 分词不准确
中英混合 → 向量化效果差
🧠 M3E模型处理:
中英混合文本的向量表示不稳定
相似度计算不准确
检索结果不一致
✅ 语言分离策略:
方案1:完全分离
├── "系统权限申请指南(中文版)"
└── "System Permission Application Guide (English)"
方案2:结构化双语
"系统权限申请 / System Permission Application"
├── 中文说明:详细的中文操作步骤
├── English Guide: Detailed English instructions
└── 关键术语对照表:
- 申请表单 = Application Form
- 系统名称 = System Name
好处:
🎯 分词准确率提升
📊 向量化质量显著改善
⚡ 多语言用户体验优化
❌ 孤立的问答:
Q: "支付日期是什么时候?"
A: "每月15日和最后第二个工作日"
Q: "如何提交?"
A: "通过飞书工作台的审批系统"
Q: "需要什么附件?"
A: "收据或发票"
🔍 用户搜索"补贴发放时间":
系统返回:"每月20日和月底"
用户困惑:这是什么的发放时间?工资?补贴?奖金?
📊 向量相似度计算:
"发放时间"可能匹配到:
- 工资发放时间
- 补贴发放时间
- 奖金发放时间
无法区分具体场景
✅ 上下文丰富化:
优化前:"发放日期是每月20日和月底"
优化后:"员工福利补贴发放时间安排
公司员工福利补贴的发放日期为每月20日和每月最后一个工作日。
如果发放日恰逢非工作日,将提前至最近的工作日进行发放。
注意:福利补贴与工资发放是分开处理的。"
好处:
🎯 上下文完整,消除歧义
📊 向量包含更多语义信息
⚡ 用户理解度提升
❌ 专业术语堆砌:
"请通过工单系统提交业务申请,在管理平台配置系统权限,
确保身份认证通过后访问数据平台进行信息查询操作。"
🔤 分词结果:
["工单", "系统", "提交", "业务", "申请", "管理", "平台"...]
🧠 向量化问题:
- 专业术语向量表示不稳定
- 用户用自然语言搜索时匹配度低
- 新员工完全看不懂
🔍 搜索匹配失败:
用户搜索:"如何申请系统权限?"
系统无法匹配到"业务申请"
✅ 术语解释和多表达方式:
"系统权限申请指南
1. 什么是工单系统?
工单系统是公司的服务管理系统,
用于处理各种业务相关的申请和工单。
2. 申请流程:
- 登录工单系统(服务管理平台)
- 选择业务申请(系统权限申请)
- 在管理平台(统一管理平台)配置权限
- 等待身份认证(登录认证)通过
3. 常用术语对照:
- 系统权限申请 = 业务申请
- 服务平台 = 工单系统
- 统一平台 = 管理平台"
好处:
🎯 新手友好,降低理解门槛
📊 多种表达方式提高匹配率
⚡ 搜索成功率提升
✅ 内容质量检查:
□ 消除重复和冗余内容
□ 确保标题与内容匹配
□ 建立清晰的层次结构
□ 分离多语言内容
□ 丰富上下文信息
□ 解释专业术语
✅ 技术优化检查:
□ 控制文档长度(建议2000-5000字)
□ 使用统一的术语和表达
□ 添加关键词标签
□ 定期更新过时信息
□ 建立文档间的关联关系
✅ 用户体验检查:
□ 从用户角度组织内容
□ 提供多种表达方式
□ 包含常见问题场景
□ 添加实际操作示例
□ 建立反馈收集机制
📊 数据驱动优化:
1. 监控搜索日志,识别高频无结果查询
2. 分析用户反馈,发现内容盲点
3. 定期评估检索准确率
4. 根据使用数据调整文档优先级
#### 🌟 **总结**
通过这些优化措施,知识库的检索效率和用户体验将得到显著提升:
**核心优化原则**:
1. **内容去重**:一个问题一个权威答案
2. **结构清晰**:层次分明,逻辑清楚
3. **语言统一**:避免中英混杂
4. **上下文完整**:提供充分的背景信息
5. **术语友好**:解释专业词汇,提供多种表达
**技术实现要点**:
- 利用RAG系统的向量化特性,优化文档结构
- 结合IK分词器特点,改善中文表达
- 考虑ElasticSearch索引机制,提升检索效率
- 基于用户搜索行为,持续优化内容
**提示**:好的知识库不仅需要先进的技术,更需要高质量的内容。技术是工具,内容是灵魂,两者结合才能发挥RAG系统的最大价值!
---
## 📚 **总结**
至此,您已经全面了解了RAG知识库系统的工作原理和优化方法。
**回到目录** ⬆️ [📖 目录导航](#📖-目录导航)
**下一步建议**:
1. 🔄 **实践应用**:将学到的优化方法应用到实际项目中
2. 📊 **效果监控**:定期评估知识库的检索效果
3. 🔧 **持续改进**:根据用户反馈不断优化文档质量
4. 📚 **深入学习**:关注RAG技术的最新发展动态