深入理解 RAG 系统
核心原理与技术架构
📋 目录
第一部分:RAG 基础概念
第二部分:三大核心技术深度解析
-
- 为什么需要切块?
- 三种主流切块策略
- 切块的关键参数
- 重叠策略的重要性
- 元数据增强
-
- 为什么需要向量?
- 从 One-Hot 到词嵌入的演进
- 向量空间的几何直观
- 余弦相似度 vs 欧氏距离
- 向量维度的语义意义
-
- 为什么需要查询增强?
- HyDE (假设文档嵌入)
- 查询扩展
- 查询分解
- 混合检索
- 重排序 (Reranking)
第三部分:实战与最佳实践
第一部分:RAG 基础概念
什么是 RAG?
RAG(Retrieval-Augmented Generation) = 检索增强生成
一种将信息检索与大语言模型生成相结合的 AI 架构模式
RAG 的核心价值
解决 LLM 的四大痛点
| 痛点 | RAG 的解决方案 |
|---|---|
| 知识时效性 | 实时检索最新信息,无需重新训练 |
| 领域专业性 | 注入私有知识库,支持垂直领域 |
| 可验证性 | 提供来源引用,答案可追溯 |
| 成本效益 | 无需微调,动态更新知识 |
RAG 系统架构全景
┌─────────────────────────────────────────────┐
│ RAG 完整工作流程 │
└─────────────────────────────────────────────┘
用户提问
↓
┌──────────────┐
│ 查询增强 │ ← 理解用户意图
│ Query │
│ Enhancement │
└──────────────┘
↓
┌──────────────┐
│ 混合检索 │ ← 召回相关文档
│ Hybrid │
│ Retrieval │
└──────────────┘
↓
┌──────────────┐
│ 重排序 │ ← 精排最相关内容
│ Reranking │
└──────────────┘
↓
┌──────────────┐
│ LLM 生成 │ ← 基于检索内容生成答案
│ Generation │
└──────────────┘
↓
返回答案
数据准备流程
在用户查询之前,需要先将知识库进行向量化处理:
原始文档 (PDF/Markdown/HTML...)
↓
┌──────────────────┐
│ 文档解析 │ 解析各种格式
└──────────────────┘
↓
┌──────────────────┐
│ 文本切块 │ 切分成小段落 ⭐️ 核心技术1
│ Text Chunking │
└──────────────────┘
↓
┌──────────────────┐
│ 向量嵌入 │ 转换为数字向量 ⭐️ 核心技术2
│ Embedding │
└──────────────────┘
↓
┌──────────────────┐
│ 向量存储 │ 存储到向量数据库
│ Vector Store │ (Pinecone/Qdrant/PgVector)
└──────────────────┘
系统核心组件
📦 数据处理层
- 文档解析器:处理 PDF、Word、HTML、Markdown 等格式
- 文本切块器:将长文档分割成语义完整的片段
- 元数据提取器:提取标题、日期、作者等结构化信息
🧮 向量化层
- 嵌入模型:将文本转换为高维向量(OpenAI/BERT/多语言模型)
- 向量数据库:高效存储和索引向量(支持毫秒级检索)
- 相似度计算:余弦相似度、欧氏距离等
🔍 检索层
- 查询理解:分析和增强用户问题 ⭐️ 核心技术3
- 检索策略:向量检索、关键词检索、混合检索
- 重排序模块:优化检索结果的相关性排序
🤖 生成层
- 提示工程:构建高质量的提示模板
- 大语言模型:生成最终回答(GPT-4/Claude/Qwen等)
第二部分:三大核心技术深度解析
接下来重点讲解 RAG 系统的三大核心技术
一、文本切块 (Text Chunking)
为什么需要切块?
技术限制
- 嵌入模型有输入长度限制(通常 512 tokens)
- LLM 上下文窗口有限(即使是 GPT-4 也只有 128K tokens)
- 单次处理整个文档不现实
检索精度
- 小块更容易匹配具体问题
- 粗粒度文档会包含大量无关内容
- 降低噪声,提高信噪比
成本控制
- API 调用按 token 计费
- 精准切块减少不必要的 token 消耗
语义聚焦
- 每个块聚焦单一主题
- 提高匹配相关性
- 便于后续引用和追溯
三种主流切块策略
策略 1:固定大小切块 (Fixed-Size)
原理
- 按固定字符数或 token 数切分
- 可设置重叠区域避免语义断裂
示例
原文:[5000 tokens 的长文档]
↓
块1: tokens 0-512 (重叠 50)
块2: tokens 462-974 (重叠 50)
块3: tokens 924-1436 (重叠 50)
...
✅ 优点
- 实现简单,处理速度快
- 块大小可控,便于管理
- 适合批量处理
❌ 缺点
- 可能在句子中间切断
- 忽略文档语义结构
- 可能破坏段落完整性
适用场景:日志文件、聊天记录、均匀分布的文本
策略 2:语义切块 (Semantic Chunking) (<- QukaAI)
原理
- 基于语义边界,通过Embedding模型进行智能切分
- 识别段落、章节、主题转换点
- 保持语义完整性
语义边界识别
文档结构分析:
├─ 标题识别 (#、##、加粗文本)
├─ 段落边界 (双换行)
├─ 列表结构 (1. 2. 3. / - - -)
└─ 语义相似度跳变点
✅ 优点
- 保持语义完整性
- 尊重文档结构
- 提高检索质量
- 用户体验更好
❌ 缺点
- 实现复杂度较高
- 处理速度较慢
- 块大小不够均匀
- 需要额外的语义分析
适用场景:技术文档、教程、结构化文章
策略 3:递归字符切块 (Recursive Character Splitting)
原理
- 按优先级尝试多个分隔符
- 递归切分直到满足大小要求
分隔符优先级
1. 段落边界: "\n\n"
2. 换行符: "\n"
3. 句子边界: "。!?"
4. 子句边界: ",、;"
5. 词边界: " "
6. 字符级别: ""
工作流程
文档
↓ 尝试按 "\n\n" 切分
段落列表
↓ 段落仍过大?按 "\n" 切分
句子列表
↓ 句子仍过大?按 "。" 切分
子句列表
↓ 直到满足大小要求
最终块
✅ 优点
- 兼顾结构和大小
- 灵活适应不同文档
- LangChain 官方推荐
- 平衡性最佳
❌ 缺点
- 配置较复杂
- 需要针对语言调整分隔符
适用场景:通用文档处理,生产环境首选
切块的关键参数
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 块大小 | 256-1024 tokens | 根据模型限制和文档特点调整 |
| 重叠率 | 10-20% | 避免语义断裂,保持上下文连续性 |
| 最小块大小 | 100 tokens | 过小的块语义不完整 |
| 最大块大小 | 模型限制的 80% | 留出空间给元数据和提示 |
重叠策略的重要性
问题场景
❌ 无重叠切块:
Chunk 1: "...机器学习模型需要大量数据"
Chunk 2: "进行训练。深度学习是..."
关键信息被切断了!
解决方案
✅ 有重叠切块(20% 重叠):
Chunk 1: "...机器学习模型需要大量数据"
Chunk 2: "模型需要大量数据进行训练。深度学习是..."
两个块都包含完整信息!
重叠率建议
- 一般文档:10-20%
- 技术文档:15-25%(概念连续性强)
- 对话记录:20-30%(上下文依赖性高)
元数据增强
为每个块添加元数据,大幅提升检索效果:
核心元数据字段
{
"chunk_id": "doc123_chunk_5",
"content": "实际文本内容...",
"document_id": "doc123",
"document_title": "RAG 系统设计指南",
"section": "第三章:向量检索",
"page_number": 42,
"author": "张三",
"created_at": "2024-11-15",
"chunk_index": 5,
"total_chunks": 23,
"keywords": ["RAG", "向量检索", "嵌入"],
"prev_chunk_id": "doc123_chunk_4",
"next_chunk_id": "doc123_chunk_6"
}
元数据的价值
- 过滤检索:按文档、章节、日期筛选
- 上下文扩展:获取相邻块补充信息
- 答案引用:提供精确的来源定位
- 权重调整:重要章节加权
二、向量嵌入 (Embedding)
为什么需要向量?
计算机本质上只能处理数字,而人类语言是符号系统。
向量嵌入 = 从符号到数值的桥梁
从 One-Hot 到词嵌入的演进
One-Hot 编码的局限
原理
- 为每个词分配一个唯一索引
- 用一个超长向量表示,只有一位是 1,其余都是 0
示例
词汇表 = ["猫", "小猫", "狗", "鱼", "爱"]
"猫" → [1, 0, 0, 0, 0]
"小猫" → [0, 1, 0, 0, 0]
"狗" → [0, 0, 1, 0, 0]
致命缺陷
1️⃣ 维度爆炸
- 50,000 词汇 = 50,000 维向量
- 99.998% 的位置都是 0(极度稀疏)
- 存储和计算成本巨大
2️⃣ 无法表达语义
- 任意两个不同词的相似度都是 0
- “猫” 和 “小猫” 的相似度 = 0
- “猫” 和 “汽车” 的相似度 = 0
- 无法反映词与词之间的语义关系
数学证明
"猫" = [1, 0, 0, 0, 0]
"小猫" = [0, 1, 0, 0, 0]
点积 = 1×0 + 0×1 + 0×0 + 0×0 + 0×0 = 0
结论:所有不同词都相互"正交"
词嵌入 (Word Embedding) 的突破
核心思想
- 用密集的低维向量表示词汇
- 语义相似的词,向量距离更近
示例对比
One-Hot(50,000 维,稀疏):
"猫" → [0, 0, 1, 0, 0, ..., 0] (只有 1 个非零值)
"小猫" → [0, 0, 0, 0, 1, ..., 0] (相似度 = 0)
Word Embedding(300 维,密集):
"猫" → [0.8, -0.3, 0.5, ..., 0.2]
"小猫" → [0.75, -0.4, 0.52, ..., 0.18]
相似度 = 0.96 ✅ 高度相似!
关键特性
✅ 语义相似性可计算
相似度("猫", "小猫") = 0.96 ← 非常接近
相似度("猫", "狗") = 0.75 ← 都是宠物
相似度("猫", "汽车") = 0.08 ← 不相关
✅ 支持语义运算
vector(国王) - vector(男人) + vector(女人) ≈ vector(女王)
vector(北京) - vector(中国) + vector(日本) ≈ vector(东京)
✅ 维度大幅降低
One-Hot: 50,000 维
Embedding: 300-1536 维(降低 98%)
向量空间的几何直观
想象一个三维空间(实际是 768 维或更高):
动物性
↑
| 猫 •
| • 小猫
狗 •|
|
|_______________→ 体型
/
/ • 鱼
↓
水生性
空间特性
1️⃣ 相似词聚集成簇
- 动物类:猫、狗、兔子、老虎
- 水果类:苹果、香蕉、橙子
- 交通工具:汽车、飞机、火车
2️⃣ 方向代表语义
- 余弦相似度测量向量夹角
- 方向相同 = 语义相似
- 长度不重要,方向才重要
3️⃣ 可进行向量运算
- 加法:组合语义
- 减法:去除某种属性
- 结果仍是有效的语义向量
余弦相似度 vs 欧氏距离
为什么用余弦相似度?
余弦相似度:关注方向,忽略长度
公式:cos(θ) = (A · B) / (||A|| × ||B||)
特点:
- 范围:-1 到 +1
- +1 表示方向完全相同(最相似)
- 0 表示垂直(不相关)
- -1 表示方向相反(对立)
欧氏距离:关注两点间的直线距离
公式:d = √[(x₁-x₂)² + (y₁-y₂)² + ...]
问题:
- 受向量长度影响大
- 长度相同方向相同的两个向量,距离可能很大
直观对比
向量 A = [1, 0] (长度 = 1, 方向 = →)
向量 B = [2, 0] (长度 = 2, 方向 = →)
向量 C = [0, 1] (长度 = 1, 方向 = ↑)
欧氏距离:
d(A, B) = 1.0 ← 方向相同,但距离不为 0
d(A, C) = 1.41 ← 垂直
余弦相似度:
cos(A, B) = 1.0 ← 完全相同 ✅
cos(A, C) = 0.0 ← 不相关 ✅
结论:余弦相似度更准确反映语义关系
向量维度的语义意义
每一维可以理解为一种”隐含特征”或”概念”
简化示例(5 维嵌入空间)
维度含义:
- 维度 0: 动物性 (-1 非动物 ~ +1 动物)
- 维度 1: 情感倾向 (-1 负面 ~ +1 正面)
- 维度 2: 抽象程度 (-1 具体 ~ +1 抽象)
- 维度 3: 动态性 (-1 静态 ~ +1 动态)
- 维度 4: 时间性 (-1 过去 ~ +1 未来)
不同词的向量:
"猫" → [ 0.9, 0.3, -0.8, 0.4, 0.0]
"爱" → [ 0.0, 0.9, -0.2, 0.7, 0.0]
"悲伤" → [ 0.0, -0.8, 0.5, -0.6, 0.0]
"未来" → [ 0.0, 0.2, 0.9, -0.3, 0.9]
实际模型的维度
- BERT: 768 维
- OpenAI text-embedding-3-small: 1536 维
- OpenAI text-embedding-3-large: 3072 维
每个维度的含义是隐式学习的,人类无法直接解释
向量是如何学到语义的?
核心理论:分布式假设
“一个词的意思由其上下文决定” —— J.R. Firth
学习过程示意
训练语料:
- "猫 喜欢吃 鱼"
- "小猫 喜欢追逐 老鼠"
- "猫 在树上 爬"
- "猫 是可爱的 宠物"
模型学习到:
- "猫" 经常出现在 "宠物"、"可爱"、"爬树" 等上下文
- "小猫" 出现在相似的上下文
→ 结论:相似上下文 → 相似向量
结果:
vector(猫) ≈ vector(小猫) ✅
vector(猫) ≠ vector(鱼) ✅
三、查询增强 (Query Enhancement)
为什么需要查询增强?
用户查询的典型问题
❌ 过于简短
用户:RAG 优化
系统:需要更多上下文才能理解具体问题
❌ 表达模糊
用户:这个怎么搞?
系统:"这个"是什么?"怎么搞"具体指什么操作?
❌ 专业术语缺失
用户:怎么让 AI 不胡说八道?
系统:用户实际想问 "如何减少 LLM 幻觉"
❌ 多义词歧义
用户:苹果怎么样?
系统:是水果还是科技公司?
查询增强的价值
- 将模糊查询转化为精确查询
- 扩展语义覆盖范围
- 提高召回率和准确率
技术 1:HyDE (假设文档嵌入)
核心思想
- 不直接搜索查询
- 让 LLM 先生成”假设的答案”
- 用假设答案的向量去检索
为什么有效?
问题:
"RAG 系统如何优化?"
→ 短查询向量,语义信息少
HyDE 生成的假设答案:
"RAG 系统优化可以通过以下方式:
1. 改进文档切块策略,使用语义切块...
2. 使用混合检索结合向量和关键词...
3. 引入重排序模块提升精度..."
→ 长文本向量,语义信息丰富
检索结果:
假设答案 ↔ 真实文档
语义更接近,匹配更准确 ✅
流程对比
传统检索:
查询 → 向量化 → 检索
"RAG优化" → vec → 结果
HyDE:
查询 → LLM生成假设答案 → 向量化 → 检索
"RAG优化" → "详细优化方案..." → vec → 结果
优点
- 显著提升长尾查询的召回率
- 自动补全用户未说明的上下文
- 对专业领域查询效果显著
缺点
- 额外的 LLM 调用成本
- 增加延迟(约 1-2 秒)
- 依赖 LLM 生成质量
适用场景
- 复杂、专业性强的查询
- 用户表达不完整的场景
- 对召回率要求高的场景
技术 2:查询扩展 (Query Expansion)
核心思想
- 生成多个查询变体
- 对每个变体分别检索
- 合并结果
扩展策略
策略 1:同义词替换
原查询:"如何优化 RAG 检索?"
生成变体:
- "如何提升 RAG 检索效果?"
- "如何改进 RAG 检索性能?"
- "怎样增强 RAG 搜索能力?"
策略 2:多角度改写
原查询:"RAG 系统很慢"
多角度变体:
- "如何提升 RAG 系统速度?"(解决方案角度)
- "RAG 系统性能瓶颈在哪?"(诊断角度)
- "RAG 响应时间优化方法"(技术角度)
策略 上下文扩展
原查询:"优化向量检索"
扩展:
---
历史记录:
"""
user: 对话背景。
assistant: 当前对话是关于 Nginx 的介绍和使用等。
user: 报错 "no connection"
assistant: 报错"no connection"可能是因为……
"""
原问题: 怎么解决
检索词: ["Nginx报错"no connection"如何解决?","造成'no connection'报错的原因。","Nginx提示'no connection',要怎么办?"]
---
结果合并策略
多个查询变体 → 多组检索结果
↓
按文档 ID 分组
↓
计算加权平均分数
↓
重新排序
↓
返回 Top-K
优点
- 提高召回率
- 覆盖不同表达方式
- 减少对单一查询的依赖
缺点
- 多次检索增加计算成本
- 可能引入噪声
- 需要合理控制变体数量(建议 3-5 个)
技术 3:查询分解 (Query Decomposition)
核心思想
- 将复杂查询拆分为多个子查询
- 分别检索每个子查询
- 综合多个答案
示例
复杂查询:
"对比 RAG 和微调的优缺点,并说明在什么场景下使用 RAG 更合适"
拆分为子查询:
1. "RAG 的优点和缺点是什么?"
2. "微调的优点和缺点是什么?"
3. "RAG 和微调的对比"
4. "RAG 的适用场景"
检索流程:
子查询 1 → 检索 → 答案片段 1
子查询 2 → 检索 → 答案片段 2
子查询 3 → 检索 → 答案片段 3
子查询 4 → 检索 → 答案片段 4
↓
综合生成最终答案
优点
- 处理多跳推理问题
- 每个子问题更精准
- 答案更全面
缺点
- LLM 调用成本增加
- 子查询拆分质量影响结果
- 答案综合需要额外处理
适用场景
- 多方面对比问题
- 需要多步推理的问题
- 跨文档信息整合
技术 4:混合检索 (Hybrid Search)
核心思想
- 结合向量检索和关键词检索
- 发挥各自优势
两种检索方式对比
| 维度 | 向量检索 | 关键词检索 (BM25) |
|---|---|---|
| 原理 | 语义相似度 | 词频统计 |
| 优势 | 理解语义、处理同义词 | 精确匹配、处理专有名词 |
| 劣势 | 可能漏掉关键词 | 无法理解语义 |
| 示例 | ”猫” ≈ “小猫” ✅ | “iPhone 15” 精确匹配 ✅ |
混合检索流程
用户查询: "iPhone 15 的性能提升"
↓
┌────┴────┐
↓ ↓
向量检索 关键词检索
(语义匹配) (精确匹配)
↓ ↓
结果A 结果B
└────┬────┘
↓
分数归一化
↓
加权融合 (α × 向量分数 + (1-α) × BM25分数)
↓
最终排序
权重参数 α 的选择
α = 0.7 → 偏重语义理解(推荐)
α = 0.5 → 平衡模式
α = 0.3 → 偏重精确匹配
适用场景
- 包含专有名词的查询(产品名、人名、地名)
- 需要精确匹配和语义理解的场景
- 生产环境的标准配置
技术 5:重排序 (Reranking)
为什么需要重排序?
初步检索的局限性
问题场景:
查询:"如何优化 RAG 系统的检索性能?"
初步检索结果(基于余弦相似度):
1. "RAG 系统是一种..." (分数 0.82) ← 相关但太泛
2. "性能优化的一般方法" (分数 0.79) ← 不够具体
3. "优化 RAG 检索的三种策略" (分数 0.75) ← 最相关!
问题:最相关的文档排名反而靠后!
根本原因
- 向量相似度只看”方向”,不够精细
- 没有考虑查询和文档的深层交互
- 关键词匹配可能受词频影响
重排序的价值
- 使用更强大的模型精细排序
- 考虑查询-文档的交互关系
- 显著提升前 K 个结果的质量
两阶段检索架构
第一阶段:召回 (Bi-Encoder)
10,000 个文档 → 向量检索 → Top 100 候选
速度:50ms
第二阶段:精排 (Cross-Encoder)
100 个候选 → 重排序 → Top 5 最佳结果
速度:200ms
总耗时:250ms ✅ 可接受
准确率:提升 50-100% ✅ 显著提升
完整的查询增强流程
生产环境推荐架构
用户查询
↓
┌──────────────────┐
│ 1. 查询理解 │
│ - 意图识别 │
│ - 实体提取 │
└──────────────────┘
↓
┌──────────────────┐
│ 2. 查询增强 │
│ - HyDE (可选) │
│ - 查询扩展 (3变体)│
└──────────────────┘
↓
┌──────────────────┐
│ 3. 混合检索 │
│ - 向量检索 (70%) │
│ - BM25 (30%) │
│ - 召回 Top 100 │
└──────────────────┘
↓
┌──────────────────┐
│ 4. 重排序 │
│ - Cross-Encoder │
│ - 精选 Top 5 │
└──────────────────┘
↓
┌──────────────────┐
│ 5. 上下文构建 │
│ - 相邻块扩展 │
│ - 元数据注入 │
└──────────────────┘
↓
送入 LLM 生成答案
第三部分:实战与最佳实践
五、实战案例:Quka.AI (Quokka)
项目简介
Quka.AI 是一个基于 RAG 的智能知识管理系统
核心定位
- C 端用户为主
- 重点:个人记忆存储,而非文档管理
- 场景:日记、笔记、工作记录、生活灵感
- 全场景AI助理,会根据语境进行Agent调用,避免一味地RAG,浪费Token引入噪音
系统架构
┌─────────────────────────────────────┐
│ 前端 (React + WebSocket) │
└─────────────────┬───────────────────┘
↓
┌────────────────┐
│ API Gateway │
└────────────────┘
↓
┌────────────┼────────────┐
↓ ↓ ↓
┌─────────┐ ┌─────────┐ ┌─────────┐
│文档摄入 │ │查询服务 │ │管理服务 │
└─────────┘ └─────────┘ └─────────┘
↓ ↓ ↓
┌──────────────────────────────────┐
│ PostgreSQL + pgvector │
│ (向量数据库) │
└──────────────────────────────────┘
↓
┌────────────────┐
│ LLM Service │
│ (多模型支持) │
└────────────────┘
核心功能
1. 记忆存储
- 自定义录入:Block 富文本 / Markdown 自由输入
- 文档上传:支持 PDF、Word、Markdown
- 网页抓取:一键保存网页内容
2. 智能日记
- 类似”每天一张草稿纸”
- 内置 @工作助理,协助整理日记
- 自动提取每日 TODO
- 以WebSocket为通信基础,方便扩展 多人 + 实时协同
3. 管家 Agent
- 类似 Excel 的数据管理
- 与 PostgreSQL 交互
- 自动理解并归类内容
- 支持自然语言查询表格
技术亮点
1. C 端交互设计
- 独立用户的 UI/UX 设计
- 突出个人记忆而非长篇文档
- 更贴近真实生活需求
- WebSocket 基底,支持协同和共享
2. 自适应切块
- 根据文档类型自动选择策略
- 代码文档保持函数完整性
- 表格数据保持结构完整
- Markdown 按标题层级切分
3. 实时更新
- 增量索引更新
- 无需重建整个知识库
- 支持文档修订和版本控制
实现概述
QukaAI 的 Chunk 策略
用户自定义录入内容(手动编辑,非文件导入)
使用LLM对用户文本进行理解与分析
- Summary
首先让 LLM 对完整的输入内容进行理解,从内容中提取 标题,标签,与内容相关的时间节点(若无则使用内容的创建时间代替)
- Chunk
将一块内容分成若干(如果有)个语义相关的分类,随后分别对原文及拆解后的分类内容做Embedding 最终形成 1 doc 对应 n chunks(embedding chunks),若有一个chunk被相似度命中,则引用原文全部内容(注意,这里的原文是指用户在界面中录入的一份自定义内容,而非一整份PDF) 。
文件导入
首先对文件进行转MarkDown处理,其次使用 语义切块 + 递归 + 重叠 的方式对文件进行 chunk,使用LLM阅读第一个分块来大概理解全文的内容,生成本篇内容的元信息,该元信息会关联至本篇内容的所有 chunk,同时每个 chunk 会记录下它的 前一个chunk 与 后一个chunk。
QukaAI 的 Retrieval 策略
-
语义增强
对用户的输入进行增强,结合上下文+当前用户的输入进行同义词替换 + 多角度改写 + 上下文替换,随后获得一组增强后的query
-
基础检索
将增强后的 query 进行 embedding 与系统中已经 embedding 后的 chunk 进行语义相似度对比,通过简单的 limit 算法取出大部分近似内容,若匹配到的 chunk 是通过文件切分出来的,则会拼接上该 chunk 的前后内容以及文件的元信息。
-
重排
将较多的近似内容再通过专业的重排模型与 query 进行进一步相似度评分,再通过 limit 算法取较少的最相似的部分内容
QukaAI 的 Generation 策略
组织用于 Generation 阶段的 Prompt,在 Prompt 中加入现实世界中的 时间节点(前后一个月),国际上大部分的节日日期,等等一系列与日常生活相关的元信息,再结合重排后的文档内容,最终由 LLM 融合理解并给出最终的回答。
比如:我把车停在了 B2 116号车位
问:我昨天把车停哪了?
思考:用户肯定不止一次记录了车位信息,所以昨天是什么时候就显得尤为重要,故需要在Prompt中加入近期时间节点的介绍(有了近期,LLM可以推理出跟久或更早的日期)
比如:(情人节当天):我今天给女朋友买了一辆车。 这段内容通过QukaAI处理后,会从内容中提取时间,LLM识别到是“今天”, 再对照Prompt中的时间节点知道了今天是 xxxx年2月14日
问:我去年的情人节给女朋友送了什么礼物? 通过Prompt中对国际上大部分主流节日日期的注入后,LLM可能会知道,中国的情人节是几月几号,美国的情人节是几月几号,也通过 “去年” 这个输入结合当前的时间节点信息推出去年是 xxxx年,随后在 Retrieval 的内容中除了匹配 “给女朋友送了什么礼物” 的语义,还会匹配事件发生的时间,最终得出 “xxxx年的情人节送了一辆车” 的结论。
在线体验
访问 quka.ai 免费试用
快速开始
- 注册账号
- 创建第一个笔记或上传文档
- 与 AI 对话,体验智能问答
- 使用 @工作助理 整理日记
开源地址
- GitHub: github.com/holdno/quka
六、总结:RAG 系统构建要点
技术架构很基础,细节还是在于 Prompt 优化上。
文档切块 ✂️
✅ 选择合适的切块策略
- 一般文档:递归字符切块(LangChain 推荐)
- 结构化文档:语义切块
- 简单场景:固定大小切块
✅ 关键参数
- 块大小:256-1024 tokens
- 重叠率:10-20%
- 添加丰富的元数据
向量嵌入 🧮
✅ 模型选择
- 预算有限:开源模型(all-MiniLM)
- 中文为主:bge-large-zh
- 追求精度:OpenAI text-embedding-3-large
✅ 优化策略
- 批处理提高效率
- 缓存降低成本
- 维度与性能平衡(1024-1536 维为佳)
查询增强 🔍
✅ 多策略组合
- 简单查询:直接检索
- 复杂查询:HyDE + 查询扩展
- 专有名词:混合检索(向量 + BM25)
✅ 重排序是关键
- 两阶段架构:Bi-Encoder 召回 + Cross-Encoder 精排
- 显著提升准确率(50-100%)
- 生产环境必备
系统优化 ⚡
✅ 性能优化
- ANN 索引(HNSW)
- 批处理 + GPU 加速
- 缓存热点查询
✅ 质量优化
- 建立评估数据集
- A/B 测试验证
- 持续迭代改进
七、常见陷阱避免 ⚠️
切块陷阱
❌ 切块过大:超过模型限制,检索粗糙 ❌ 切块过小:语义不完整,上下文缺失 ❌ 无重叠:关键信息被截断
检索陷阱
❌ 忽略查询增强:用户查询简短模糊,直接检索效果差 ❌ 单一检索策略:不同场景需要不同策略 ❌ 缺少重排序:初步检索的排序不够精准
优化陷阱
❌ 过度优化:盲目追求速度,牺牲准确率 ❌ 缺少评估体系:无法量化改进效果 ❌ 忽视成本:LLM 调用成本失控
八、进阶学习资源 📚
论文
- RAG 原论文:Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks
- HyDE:Precise Zero-Shot Dense Retrieval
- BERT:Pre-training of Deep Bidirectional Transformers
框架和工具
- LangChain:RAG 应用开发框架
- LlamaIndex:数据索引和查询引擎
- Sentence Transformers:句子嵌入库
- Haystack:端到端 NLP 框架
向量数据库
- Pinecone:托管向量数据库
- Qdrant:开源向量搜索引擎
- Milvus:云原生向量数据库
- Weaviate:开源向量搜索引擎
- pgvector:PostgreSQL 向量扩展