RAG系统:知识检索增强 - 核心内容总结

1. 核心概念

什么是RAG?

检索增强生成(Retrieval-Augmented Generation, RAG) 是一种将信息检索与文本生成相结合的技术。其核心原理是:

  1. 检索:从外部知识库查询相关内容
  2. 增强:将检索结果整合到提示词中辅助模型生成
  3. 生成:输出准确且透明的答案

核心价值

RAG解决了大语言模型的两个基本限制:

  • 静态、有限的知识:模型有训练数据截止日期,无法访问实时信息
  • 缺乏领域专长:通用模型在专业领域可能缺乏深入知识
  • 幻觉问题:检索验证有助于减少模型幻觉
  • 可解释性:提供信息来源以增强答案可信度

2. 发展历程

第一阶段:Naive RAG (2020-2021)

  • 检索方法:传统关键词匹配算法(TF-IDF、BM25)
  • 生成模式:直接将检索到的文档拼接进提示词上下文
  • 特点:简单的”检索-阅读”模式,适合字面匹配但语义理解有限

第二阶段:Advanced RAG (2022-2023)

  • 检索方法:转向基于密度的语义检索
  • 生成模式:引入查询重写、文档分块、重排序等优化技术
  • 进展:模型能理解超越关键词的语义相似性

第三阶段:Modular RAG (2023至今)

  • 检索方法:混合检索、多查询扩展、假设文档嵌入
  • 生成模式:链式思维推理、自我反思和修正
  • 特点:模块化、可插拔、可组合的独立组件,适应多样化场景

3. 基本工作流程

数据准备阶段

  1. 数据提取:从知识源提取内容
  2. 文本分割:将文档切分为可管理的块
  3. 向量化:将文本块转换为高维向量
  4. 数据库构建:构建可检索的知识数据库

应用阶段

  1. 用户查询:接收用户问题
  2. 检索:从数据库中搜索相关信息
  3. 提示词注入:将检索结果整合到上下文中
  4. 答案生成:使用大语言模型生成准确响应

4. 系统架构

Hello-Agents的RAG系统采用**“五层七步”**设计模式:

用户层:RAGTool统一接口
    ↓
应用层:智能问答、搜索、管理
    ↓
处理层:文档解析、分块、向量化
    ↓
存储层:向量数据库、文档存储
    ↓
基础设施层:嵌入模型、大语言模型、数据库

完整处理流水线

任意格式文档 → MarkItDown转换 → Markdown文本
→ 智能分块 → 向量化 → 存储与检索

各层详细解析

1. 用户层:RAGTool统一接口

作用:对外暴露的API,用户直接交互的界面

具体职责

  • 提供简单易用的方法调用
  • 隐藏底层复杂性
  • 参数验证和错误提示

示例

# 用户代码示例
rag = RAGTool(knowledge_base="./knowledge")
 
# 添加文档
rag.add_document("report.pdf")
 
# 提问
answer = rag.ask("报告讲了什么?")
 
# 搜索
results = rag.search("Python教程", top_k=5)

类比:像餐厅的前台服务员,接收你的订单并转给后厨处理


2. 应用层:智能问答、搜索、管理

作用:业务逻辑层,决定如何响应用户请求

具体职责

  • 判断请求类型(问答、搜索、管理)
  • 整合多个模块(RAG + Memory)
  • 执行复杂的业务流程
  • 生成报告和统计数据

示例

class PDFLearningAssistant:
    def handle_user_request(self, user_input):
        # 判断请求类型
        if is_question(user_input):
            # 执行问答流程
            return self.handle_question(user_input)
        elif is_document_upload(user_input):
            # 执行文档处理流程
            return self.handle_upload(user_input)
        elif is_summary_request(user_input):
            # 整合RAG和Memory生成学习报告
            return self.generate_summary()

类比:餐厅的厨师团队,根据订单决定做什么菜、用什么食材


3. 处理层:文档解析、分块、向量化 ⭐核心转换层

作用:将原始文档转换为机器可理解的形式

为什么需要这一层

  • 原始文档(PDF)大语言模型看不懂
  • 文档太大,需要分割成小块
  • 文字需要转换成向量才能”理解”语义

具体操作

  1. 文档解析:PDF → Markdown(用MarkItDown工具)

    # 输入:PDF文件
    "report.pdf" (二进制格式)
     
    # MarkItDown转换
    markdown_text = markitdown.convert("report.pdf")
     
    # 输出:结构化Markdown
    """
    # 技术报告
    本章介绍RAG系统...
    ## 核心概念
    RAG是一种...
    """
  2. 智能分块:Markdown → 文本块(按标题、段落分割)

    # 输入:Markdown文本
    markdown_text = "# 标题\n段落1\n段落2\n..."
     
    # 按语义分割
    chunks = smart_chunk(markdown_text)
     
    # 输出:文本块
    [
        "# 标题\n段落1",
        "段落2\n段落3",
        ...
    ]
  3. 向量化:文本块 → 高维数字向量(用嵌入模型)

    # 输入:文本块
    chunk = "RAG是一种检索增强生成的技术"
     
    # 嵌入模型转换
    embedding = embed_model.encode(chunk)
     
    # 输出:高维向量
    [0.1, 0.5, -0.2, 0.8, ...]  # 通常有1024或1536维

类比:食材加工环节,把生肉洗净、切片、调味,让后厨能烹饪


4. 存储层:向量数据库、文档存储

作用:持久化存储,管理数据

为什么需要分离存储

  • 向量需要快速检索(找相似的)
  • 文档需要展示给用户
  • 元数据需要用于过滤和统计

具体存储内容

  1. 向量数据库(Qdrant):存储向量(处理层的输出)

    # 存储结构
    {
        "id": "doc1_chunk_0",
        "vector": [0.1, 0.5, -0.2, ...],  # 向量
        "payload": {
            "text": "RAG是一种检索增强生成的技术",  # 原始文本
            "source": "report.pdf",  # 来源
            "timestamp": "2025-01-30"  # 时间
        }
    }
  2. 文档存储:存储原始Markdown文本

    # 用于展示给用户或重新处理
    /knowledge_base/documents/
    ├── report.pdf
    ├── report.md
    └── metadata.json
  3. 元数据:存储来源、时间、标签等信息

    {
        "document_id": "report_001",
        "chunks": 15,
        "total_tokens": 12500,
        "created_at": "2025-01-30T10:00:00",
        "tags": ["技术", "RAG", "AI"]
    }

类比:仓库,分类存放加工好的食材和原材料,方便快速取用


5. 基础层:嵌入模型、LLM、数据库

作用:提供底层技术能力

为什么独立成层

  • 这些是通用的AI能力,可以复用
  • 可以随时替换(换不同的模型)
  • 可以统一管理和监控

具体组件

  1. 嵌入模型(text-embedding-v3)

    # 负责把文字变成向量
    embedding_model = TextEmbeddingV3()
     
    # 可以替换成其他模型
    # embedding_model = SentenceTransformer("all-MiniLM-L6-v2")
  2. 大语言模型(GPT-4等)

    # 负责生成回答
    llm = GPT4Model()
     
    # 可以替换成其他模型
    # llm = Claude3Model()
  3. 数据库引擎

    # 提供查询能力
    vector_db = QdrantClient()

类比:厨房的基础设施(炉灶、刀具、水电),可以灵活更换升级


为什么需要分层?

问题1:为什么处理层、存储层、基础层要分开?

层级职责数据状态可替换性示例
基础层提供AI能力模型本身高(可换不同模型)换嵌入模型
处理层数据转换变换过程中中(可改算法)改分块策略
存储层数据管理存储状态高(可换数据库)换向量数据库

实际例子

  • 想用更好的嵌入模型?只需修改基础层,不用动其他层
  • 想改进分块算法?只需修改处理层,存储和基础层不变
  • 想换成其他向量数据库?只需修改存储层,其他层不受影响

完整数据流转示例

场景1:添加文档

用户代码:
    rag.add_document("report.pdf")

用户层:
    ↓ 调用 RAGTool.add_document()

应用层:
    ↓ 判断这是文档上传请求
    ↓ 调用处理层

处理层:
    ↓ 1. 文档解析
       "report.pdf" → MarkItDown → "报告内容.md"

    ↓ 2. 智能分块
       "报告内容.md" → ["段落1", "段落2", "段落3"]

    ↓ 3. 向量化(调用基础层的嵌入模型)
       "段落1" → 嵌入模型 → [0.1, 0.5, -0.2, ...]
       "段落2" → 嵌入模型 → [0.3, -0.1, 0.7, ...]
       "段落3" → 嵌入模型 → [-0.2, 0.6, 0.4, ...]

存储层:
    ↓ 存储向量到Qdrant
    存储原始文本和元数据

返回:"文档添加成功,共3个文本块"

场景2:问答

用户代码:
    answer = rag.ask("报告讲了什么?")

用户层:
    ↓ 调用 RAGTool.ask()

应用层:
    ↓ 判断这是问答请求
    ↓ 应用层整合RAG检索 + LLM生成

处理层(MQE扩展):
    ↓ 原始查询:"报告讲了什么?"
    ↓ 扩展查询(MQE):
       - "报告的主要内容"
       - "报告的核心观点"

基础层(嵌入模型):
    ↓ 将扩展查询转向量
       "报告的主要内容" → [0.2, 0.4, ...]
       "报告的核心观点" → [0.1, 0.3, ...]

存储层(Qdrant检索):
    ↓ 向量相似度搜索
    ↓ 找到最相似的3个向量
    ↓ 返回对应的文本块:
       [
           "RAG系统是一种检索增强生成的技术...",
           "本章介绍了RAG的核心概念...",
           "RAG的主要优势包括..."
       ]

应用层:
    ↓ 将检索结果整合到提示词
    prompt = """
    上下文:[RAG系统是一种检索增强生成的技术...]
    问题:报告讲了什么?
    """

基础层(LLM):
    ↓ 生成最终答案
    "报告主要介绍了RAG系统的概念、发展历程和核心技术..."

返回给用户层

代码示例:完整的RAGTool使用

# ==================== 用户层使用 ====================
from hello_agents.tools import RAGTool
 
# 初始化
rag = RAGTool(
    knowledge_base="./my_knowledge",
    chunk_size=1000,
    chunk_overlap=200
)
 
# ==================== 场景1:添加文档 ====================
# 用户只需简单调用,内部自动走完整流程
rag.add_document("technical_report.pdf")
# 内部执行:
#   1. 处理层:PDF → Markdown → 分块 → 向量
#   2. 存储层:存储到Qdrant
#   3. 基础层:调用嵌入模型
 
# ==================== 场景2:智能问答 ====================
# 用户提问
answer = rag.ask(
    "什么是RAG?",
    enable_mqe=True,     # 启用多查询扩展
    enable_hyde=True,    # 启用假设文档嵌入
    top_k=3              # 返回最相关的3个片段
)
 
# 内部执行:
#   1. 处理层:MQE扩展查询,HyDE生成假设答案
#   2. 基础层:将查询转向量
#   3. 存储层:从Qdrant检索相似文档
#   4. 应用层:整合上下文和问题
#   5. 基础层:LLM生成最终答案
 
print(answer)
# 输出:"RAG(检索增强生成)是一种将信息检索与文本生成相结合的技术..."
 
# ==================== 场景3:搜索文档 ====================
# 只搜索,不生成答案
results = rag.search(
    "Python教程",
    top_k=5,
    score_threshold=0.7  # 只返回相似度>0.7的
)
 
# 内部执行:
#   1. 基础层:查询转向量
#   2. 存储层:Qdrant检索
#   3. 返回原始文本块
 
for result in results:
    print(f"相似度: {result.score:.2f}")
    print(f"内容: {result.text}")
    print(f"来源: {result.source}")
    print("---")
 
# ==================== 场景4:统计信息 ====================
stats = rag.stats()
print(f"文档数: {stats.total_documents}")
print(f"文本块数: {stats.total_chunks}")
print(f"总token数: {stats.total_tokens}")

架构对比:不分层 vs 分层

❌ 不分层的缺点

# 所有逻辑混在一起
def add_document(file):
    # 混合了:文件处理、分块、向量化、存储
    pdf_text = read_pdf(file)  # 处理逻辑
    chunks = split_text(pdf_text)  # 处理逻辑
    vectors = embed(chunks)  # 基础层调用
    save_to_qdrant(vectors)  # 存储逻辑

问题

  • 难以测试(想测试分块逻辑,必须连带嵌入和存储)
  • 难以复用(其他项目想用分块功能,无法单独提取)
  • 难以维护(修改嵌入模型,影响整个函数)

✅ 分层的优势

# 用户层
class RAGTool:
    def add_document(self, file):
        chunks = self.processor.process(file)      # 处理层
        self.storage.save(chunks)                  # 存储层
 
# 处理层
class DocumentProcessor:
    def process(self, file):
        text = self.parser.parse(file)    # 解析
        chunks = self.chunker.split(text) # 分块
        vectors = self.embedder.encode(chunks) # 基础层
        return chunks, vectors
 
# 存储层
class VectorStorage:
    def save(self, chunks, vectors):
        self.qdrant.upsert(chunks, vectors)

优势

  • 每层独立测试
  • 每层独立优化
  • 每层可独立替换

5. 实现细节

5.1 多模态文档加载

MarkItDown作为通用文档转换引擎,支持:

  • 文档:PDF、Word、Excel、PowerPoint
  • 图像:JPG、PNG、GIF(通过OCR)
  • 音频:MP3、WAV、M4A(通过转录)
  • 文本:TXT、CSV、JSON、XML、HTML
  • 代码:Python、JavaScript、Java等

关键特性

  • 统一转换为结构化Markdown格式
  • 增强的PDF处理,带有后备机制
  • 错误处理和优雅降级

5.2 智能分块策略

Markdown感知分割

系统利用Markdown结构进行精确的语义分割:

标准Markdown文本 → 标题层级解析 → 段落语义分割
→ 基于Token的分块 → 重叠策略优化 → 准备向量化

处理过程

  1. 解析标题层次(#, , )以保持语义边界
  2. 在段落级别分割以保持内容完整性
  3. 基于token计数计算分块大小以优化检索
  4. 实现重叠策略(默认200个token)以保持上下文连续性

双语Token估算

支持中英文混合文本:

  • CJK字符:每个计为1个token
  • 非CJK字符:基于空格分割计数

5.3 统一嵌入和向量存储

嵌入模型选项

  1. DashScope API(主要):基于云的嵌入服务(text-embedding-v3)
  2. 本地Transformer(后备):sentence-transformers/all-MiniLM-L6-v2
  3. TF-IDF(最后手段):轻量级关键词方法

关键实现

  • 批处理,可配置的批大小(默认:64)
  • 向量维度验证和归一化
  • 不匹配向量的自动维度调整
  • 带重试机制的错误处理
  • 针对更好嵌入质量的Markdown预处理

向量存储

  • 使用Qdrant向量数据库,带有命名空间隔离
  • 支持元数据过滤(memory_type、data_source、rag_namespace)
  • 启用带分数阈值的相似性搜索

6. 高级检索策略

6.1 多查询扩展(MQE)

概念:生成语义等价的多样化查询以提高召回率

优势

  • 解决查询与文档之间的词汇不匹配
  • 自动理解多种可能的解释
  • 对模糊查询或专业术语特别有效

实现示例

# 使用大语言模型生成多样化的查询扩展
原始查询:"如何学习Python?"
扩展查询:
- "Python入门教程"
- "Python学习方法"
- "Python编程指南"

影响:将召回率提高30-50%

6.2 假设文档嵌入(HyDE)

概念:“用答案找答案” - 先生成假设的答案段落,然后用它们检索真实文档

核心洞察:问题和答案存在于不同的语义分布中

  • 问题:疑问句
  • 文档:陈述句
  • 假设答案:桥接语义差距

优势

  • 假设答案在语义上更接近真实答案
  • 即使内容不准确,关键术语和概念也能指导准确检索
  • 显著提高领域特定查询的精确度

实现示例

# 生成假设答案段落
查询:"什么是大语言模型?"
假设答案:"大语言模型是在海量文本数据上训练的AI系统。它们能够理解和生成类似人类的文本..."

6.3 统一扩展检索框架

三步流程

  1. 扩展:生成多个扩展查询(MQE + HyDE)
  2. 检索:对每个扩展查询并行向量搜索
  3. 合并:去重并对所有结果排序以返回top-k文档

关键参数

  • enable_mqe:启用/禁用多查询扩展
  • mqe_expansions:扩展查询数量(默认:2)
  • enable_hyde:启用/禁用假设文档嵌入
  • candidate_pool_multiplier:扩展候选池(默认:4)
  • score_threshold:最小相似度分数

使用建议

  • 一般查询:仅启用MQE
  • 领域特定查询:同时启用MQE和HyDE
  • 性能敏感场景:使用基本检索或仅MQE

7. RAGTool API

支持的操作

  1. add_text:添加文本知识到知识库
  2. add_document:添加多格式文档(PDF、Office、图像、音频)
  3. search:使用可配置参数搜索知识库
  4. ask:大语言模型增强的智能问答
  5. stats:知识库统计信息

关键参数

  • knowledge_base_path:知识库目录路径
  • collection_name:Qdrant集合名称(默认:“rag_knowledge_base”)
  • rag_namespace:数据隔离的命名空间(默认:“default”)
  • chunk_size:每块最大token数(默认:1000)
  • chunk_overlap:块之间重叠token数(默认:200)

8. 实际应用:智能文档问答助手

本章演示了结合RAGTool和MemoryTool的完整实现:

系统组件

  1. PDFLearningAssistant:封装RAG和Memory逻辑的核心助手类
  2. Gradio Web界面:用户友好的Web应用程序
  3. 核心功能
    • 文档加载和处理
    • 高级检索的智能问答
    • 笔记记录和学习回顾
    • 统计和报告生成

工作流程

  1. 加载文档:MarkItDown转换 → 智能分块 → 向量化 → 存储
  2. 提问:MQE + HyDE高级检索 → 上下文感知的答案生成
  3. 记录学习:将问答历史和笔记存储到记忆系统
  4. 生成报告:汇总统计、学习指标和摘要

记忆集成

  • 工作记忆:当前学习任务和上下文
  • 情景记忆:学习事件和查询历史
  • 语义记忆:概念知识和理解
  • 感知记忆:文档特征和多模态信息

9. 关键技术亮点

9.1 优势

  1. 通用文档支持:MarkItDown将任何格式转换为统一Markdown
  2. 语义感知分块:利用Markdown结构进行精确分割
  3. 多策略检索:结合MQE、HyDE和混合方法
  4. 统一嵌入:支持多种嵌入模型,自动后备
  5. 命名空间隔离:为不同用户/应用分离知识库
  6. 记忆集成:与记忆系统无缝集成以增强能力

9.2 设计原则

  1. 模块化:每层可以独立优化和替换
  2. 可重用性:处理流水线代码完全可重用
  3. 可扩展性:易于添加新的检索策略或文档处理器
  4. 性能:批处理、缓存和高效向量操作
  5. 鲁棒性:全面的错误处理和后备机制

10. 未来方向

本章建议了几个探索领域:

  1. 多模态RAG:扩展到文本+图像或跨模态场景
  2. 高级检索:探索融合检索、学习排序等其他技术
  3. 知识图谱集成:结合向量检索与知识图谱推理
  4. 优化:针对特定任务评估不同的嵌入模型和检索策略
  5. 生产部署:可扩展性、多用户支持和性能优化

11. 学习建议

对于实践者:

  1. 动手实现:从零构建基本记忆模块并迭代
  2. 模型评估:比较不同嵌入模型和检索策略
  3. 真实项目:将记忆和RAG系统应用于实际个人项目
  4. 开源贡献:参与Hello-Agents开源项目
  5. 跨学科思维:将认知科学理论应用于工程解决方案

总结

RAG系统代表了增强大语言模型外部知识的先进方法,结合了文档处理、语义检索和智能生成的先进技术,以创建强大的知识赋能AI应用。通过多模态文档处理、智能分块、高级检索策略和记忆系统的集成,RAG为构建智能问答系统提供了完整的解决方案框架。

核心要点

  • RAG解决了大语言模型的知识限制和幻觉问题
  • 从Naive RAG发展到Modular RAG,技术不断演进
  • 高级检索策略(MQE、HyDE)显著提升检索效果
  • 模块化设计确保了系统的可扩展性和可维护性
  • 与记忆系统的集成为Agent提供了强大的知识基础