-
Notifications
You must be signed in to change notification settings - Fork 2
Home
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: 中文分词器 什么是RAG? RAG就是检索增强生成,简单说就是让AI在回答问题前先查资料。
就像考试时可以翻书一样:
传统AI:问题 → AI大脑 → 回答 RAG AI:问题 → 搜索知识库 → 找到资料 → AI大脑+资料 → 更准确的回答 智能搜索的原理 把文字变成数字 计算机不认识文字,需要把每个词转换成768个数字来表示。相似的词会有相似的数字组合:
"苹果"和"香蕉"的数字很接近(都是水果) "苹果"和"汽车"的数字差很远(完全不同) 这768个数字就像一个人的详细档案,能描述这个词的各种特征。
文档分片的必要性 长文档需要切成小段处理,就像把厚书分成章节:
每段500字,便于处理和检索 段与段之间重叠50字,保证信息完整性 避免重要信息被切断 两种搜索方式 关键词搜索:
只能找到包含确切词汇的内容 搜"苹果"找不到"红富士" 语义搜索:
理解词汇含义,找到相关内容 搜"苹果"能找到"水果营养"相关信息 我们的系统主要用语义搜索,关键词搜索做补充。
ElasticSearch的作用 ElasticSearch就像一个超级图书管理员,用倒排索引快速定位信息:
传统方式:逐个翻找 → 很慢 倒排索引:直接定位 → 很快
"苹果"这个词 → 出现在文档1、5、10 "营养"这个词 → 出现在文档1、3、7 中文分词 中文没有天然的词汇分隔符,需要IK分词器来处理:
"我爱吃苹果" → "我" + "爱吃" + "苹果" IK分词器的ik_max_word模式会生成多种分词组合,提高搜索匹配率。
相似度计算原理 向量相似度的几何意义 每个文档片段被转换成768维向量后,可以想象成768维空间中的一个点。相似度计算就是测量两个点之间的关系。
余弦相似度计算:
向量A = [a1, a2, a3, ..., a768] 向量B = [b1, b2, b3, ..., b768]
余弦相似度 = (A·B) / (|A| × |B|) 其中:
- A·B = a1×b1 + a2×b2 + ... + a768×b768 (点积)
- |A| = √(a1² + a2² + ... + a768²) (向量长度)
- |B| = √(b1² + b2² + ... + b768²) (向量长度) 相似度值的含义:
1.0:完全相同的语义 0.8-0.9:高度相关 0.6-0.8:中等相关 0.3-0.6:弱相关 0.0:完全无关 负值:语义相反 为什么用余弦相似度而不是欧氏距离 欧氏距离的问题:
文档A:"苹果很好吃" → 向量[1, 1, 0] 文档B:"苹果很好吃很好吃" → 向量[2, 2, 0] (重复表达)
欧氏距离 = √[(2-1)² + (2-1)² + (0-0)²] = √2 ≈ 1.41 看起来差异很大,但实际语义相同 余弦相似度的优势:
余弦相似度 = (1×2 + 1×2 + 0×0) / (√2 × √8) = 6 / 4 = 1.0 正确识别为完全相同的语义 余弦相似度只关注方向(语义),不关注长度(表达强度),更适合文本语义比较。
混合检索的权重计算 系统同时使用向量检索和关键词检索,最终得分计算:
最终得分 = 向量相似度 × 1.0 + BM25得分 × 0.00001
例如: 文档1:向量相似度0.85,BM25得分100 最终得分 = 0.85 × 1.0 + 100 × 0.00001 = 0.851
文档2:向量相似度0.82,BM25得分200 最终得分 = 0.82 × 1.0 + 200 × 0.00001 = 0.822 可以看出,向量相似度占主导地位,关键词匹配只是微调。
文档存储机制 文档解析和存储流程
- 文档上传和解析
原始文档 → Document Loader → 提取纯文本 支持格式:PDF、Word、HTML、TXT等 2. 文本分片处理
长文档 → Text Splitter → 多个500字片段 每个片段包含:
- chunk_id: 唯一标识符
- content: 文本内容
- metadata: 元数据(来源文档、页码等)
- overlap: 与前后片段的重叠部分
- 向量化处理
文本片段 → M3E-Base模型 → 768维向量 例如: chunk_1: "苹果营养丰富..." → [0.1, 0.8, 0.3, ..., 0.9] chunk_2: "苹果含有维生素..." → [0.2, 0.7, 0.4, ..., 0.8] 4. ElasticSearch存储结构
{ "_index": "knowledge_base", "_id": "doc_123_chunk_1", "_source": { "document_id": "doc_123", "chunk_id": "chunk_1", "content": "苹果营养丰富,含有多种维生素...", "vector": [0.1, 0.8, 0.3, ..., 0.9], "metadata": { "filename": "水果营养指南.pdf", "page": 1, "upload_time": "2024-01-15T10:30:00Z" }, "chunk_index": 1, "total_chunks": 5 } } 5. 索引建立
倒排索引:每个词对应包含它的文档片段 向量索引:HNSW算法建立向量间的邻近关系 元数据索引:按文档ID、时间等字段建立索引 检索过程详解 用户查询的完整流程
- 查询预处理
用户输入:"苹果有什么营养价值?" ↓ Query Parser处理:
- 去除停用词
- 标准化表达
- 提取关键信息
- 双路检索
向量检索路径:
查询文本 → M3E-Base → 查询向量[0.15, 0.75, 0.35, ...] ↓ 在向量空间中搜索相似片段 ↓ 计算余弦相似度,返回Top-K结果 关键词检索路径:
查询文本 → IK分词器 → ["苹果", "营养", "价值"] ↓ 在倒排索引中查找包含这些词的片段 ↓ 使用BM25算法计算相关性得分 3. 结果融合和排序
向量检索结果:
- chunk_1: 相似度0.89
- chunk_3: 相似度0.85
- chunk_7: 相似度0.82
关键词检索结果:
- chunk_1: BM25得分120
- chunk_2: BM25得分95
- chunk_3: BM25得分88
融合计算: chunk_1: 0.89 × 1.0 + 120 × 0.00001 = 0.8912 chunk_3: 0.85 × 1.0 + 88 × 0.00001 = 0.85088 chunk_2: 0.0 × 1.0 + 95 × 0.00001 = 0.00095
最终排序:chunk_1 > chunk_3 > chunk_7 > chunk_2 4. 结果返回
{ "results": [ { "chunk_id": "doc_123_chunk_1", "content": "苹果营养丰富,含有维生素C、纤维素...", "score": 0.8912, "metadata": { "filename": "水果营养指南.pdf", "page": 1 } } ], "total": 15, "took": 45 } 文档删除机制 删除操作的影响范围
- 标记删除
DELETE /knowledge_base/_doc/doc_123_chunk_1 DELETE /knowledge_base/_doc/doc_123_chunk_2 ... DELETE /knowledge_base/_doc/doc_123_chunk_N 2. 索引更新
倒排索引:移除已删除片段的词汇映射 向量索引:从HNSW图中移除对应节点 元数据索引:清理相关元数据记录 3. 存储回收
ElasticSearch的段合并过程: 旧段:[chunk_1, chunk_2, chunk_3, chunk_4] 删除chunk_2后: 新段:[chunk_1, chunk_3, chunk_4] 物理空间得到释放 4. 缓存清理
清理查询结果缓存 更新统计信息 重建相关的聚合数据 文档更新机制 更新策略:删除+重建 为什么不能直接更新?
文档内容变化可能导致分片数量改变 向量表示完全不同,需要重新计算 保持数据一致性,避免部分更新的复杂性
- 更新流程
步骤1:标记旧版本文档为删除状态 步骤2:解析新版本文档 步骤3:重新分片和向量化 步骤4:写入新的文档片段 步骤5:更新索引 步骤6:物理删除旧版本数据 2. 版本控制
{ "document_id": "doc_123", "version": 2, "previous_version": 1, "update_time": "2024-01-16T14:20:00Z", "status": "active" } 3. 更新过程中的查询处理
更新期间的状态:
- 旧版本:标记为"deleting"
- 新版本:标记为"indexing"
- 查询时:优先返回"active"状态的片段
- 避免返回不一致的结果
- 批量更新优化
单文档更新:逐个处理,实时生效 批量更新:
- 收集所有待更新文档
- 批量删除旧版本
- 批量处理新版本
- 一次性提交索引更新
- 减少索引重建次数 性能影响分析 删除操作:
轻量级:只是标记删除 索引更新:异步进行 存储回收:段合并时进行 更新操作:
重量级:需要重新处理整个文档 临时存储增加:新旧版本同时存在 索引压力:需要重建相关索引 优化建议:
批量操作减少频次 非高峰期进行大量更新 监控存储空间使用情况 知识库文档优化指南 问题一:重复内容和冗余信息 问题表现
文档A:"如何申请年假?请登录人事系统,点击假期申请..." 文档B:"年假申请流程:登录人事系统,选择假期申请选项..." 文档C:"申请年假怎么办?进入人事系统,找到假期申请..." 对RAG系统的影响
向量化后这些文档高度相似 用户搜索时返回多个重复答案 造成困惑:到底哪个是正确的? 浪费存储和计算资源 优化方案
统一文档:"年假申请完整指南" ├── 1. 常规申请流程 ├── 2. 特殊假期处理 ├── 3. 紧急申请处理 └── 4. 常见问题解答 好处:单一权威来源,向量更准确,检索效率提升
问题二:标题和内容不匹配 问题表现
标题:"办公设备问题" 内容:主要讲打印机配置,只有一小段提到办公设备
标题:"员工入职" 内容:包含入职、培训安排、权限申请、设备领取等多个主题 对RAG系统的影响
IK分词器处理标题和内容得到不同的关键词 用户搜索"设备故障"匹配到标题,但内容是打印机配置 答案不相关,用户体验差 优化方案
原标题:"办公设备问题" 优化后:"打印机配置指南"
原标题:"员工入职" 优化后:拆分为多个文档 ├── "员工入职流程" ├── "新员工培训指南" ├── "权限申请流程" └── "设备领取手册" 好处:标题即内容预览,向量匹配更精准
问题三:缺乏层次结构 问题表现
"员工福利相关问题大全"
- 健身补贴流程是什么?答:请通过福利平台...
- 补贴发放日期?答:每月20日和月底...
- 如何选择补贴类型?答:分为健身补贴和学习补贴...
- 申请截止时间?答:发放日前三天...
- 申请附件要求?答:请提供消费凭证... (50个问题混在一起) 对RAG系统的影响
500字分片可能把相关问题分开 用户问"补贴流程"可能匹配到主要讲类型的片段 流程信息不完整 优化方案
"员工福利指南" ├── 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. 填写申请表单时注意以下事项:
- 请填写具体系统名称
- 需要说明申请原因
- 确保信息准确无误" 对RAG系统的影响
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: "收据或发票" 对RAG系统的影响
用户搜索"补贴发放时间",系统返回"每月20日和月底" 用户困惑:这是什么的发放时间?工资?补贴?奖金? "发放时间"可能匹配到多种不同场景,无法区分 优化方案
优化前:"发放日期是每月20日和月底"
优化后:"员工福利补贴发放时间安排 公司员工福利补贴的发放日期为每月20日和每月最后一个工作日。 如果发放日恰逢非工作日,将提前至最近的工作日进行发放。 注意:福利补贴与工资发放是分开处理的。" 好处:上下文完整,消除歧义,向量包含更多语义信息
问题六:技术术语缺乏解释 问题表现
"请通过工单系统提交业务申请,在管理平台配置系统权限, 确保身份认证通过后访问数据平台进行信息查询操作。" 对RAG系统的影响
专业术语向量表示不稳定 用户用自然语言搜索时匹配度低 新员工完全看不懂 用户搜索"如何申请系统权限"无法匹配到"业务申请" 优化方案
"系统权限申请指南
-
什么是工单系统? 工单系统是公司的服务管理系统, 用于处理各种业务相关的申请和工单。
-
申请流程:
- 登录工单系统(服务管理平台)
- 选择业务申请(系统权限申请)
- 在管理平台(统一管理平台)配置权限
- 等待身份认证(登录认证)通过
-
常用术语对照:
- 系统权限申请 = 业务申请
- 服务平台 = 工单系统
- 统一平台 = 管理平台" 好处:新手友好,多种表达方式提高匹配率
优化检查清单 内容质量:
消除重复内容 标题与内容匹配 建立清晰层次 统一语言表达 丰富上下文信息 解释专业术语 技术要求:
文档长度控制在2000-5000字 使用统一术语 定期更新内容 建立文档关联 用户体验:
从用户角度组织内容 提供多种表达方式 包含实际操作示例 收集用户反馈 持续优化 监控搜索日志,找出无结果查询 分析用户反馈,发现内容盲点 定期评估检索准确率 根据使用数据调整优先级 总结 好的知识库需要技术和内容的结合:
技术提供检索能力 内容决定用户体验 持续优化保证效果 核心原则:内容去重、结构清晰、语言统一、上下文完整、术语友好。