Skip to content

Releases: leonyangdev/UltimateRAG

v0.4.0

23 Dec 11:25

Choose a tag to compare

Stage 4: GraphRAG & Fine-tuning

🎯 概述

Stage 4 是 UltimateRAG 的最高阶段,实现了知识图谱增强的 RAG (GraphRAG) 和领域微调能力。

核心能力

能力 描述
知识图谱 自动从文档中抽取实体和关系,构建知识图谱
图检索 基于图遍历的智能检索,发现隐性关联
全局摘要 基于社区检测生成全局性摘要
Embedding 微调 使用私有数据微调 Embedding 模型
LLM 微调数据 自动生成高质量的微调训练数据
本地 LLM 微调 🆕 使用 LoRA 在本地设备上微调开源大模型

🚀 快速开始

1. 安装依赖

pip install -r requirements.txt

对于 Neo4j 支持(可选):

pip install neo4j

2. 配置环境

.env 文件中添加:

# 基础配置(继承自 Stage 1-3)
OPENAI_API_KEY=your_api_key
MODEL_NAME=gpt-4o

# GraphRAG 配置
GRAPH_STORE_TYPE=memory  # 或 neo4j
NEO4J_URI=bolt://localhost:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=your_password

# 微调配置
EMBEDDING_FINETUNE_MODEL=BAAI/bge-base-zh-v1.5

3. 使用 GraphRAG

from src.stage_4.main import run_graph_rag_demo

# 运行演示
run_graph_rag_demo()

或者手动使用:

from src.stage_4.graph_rag import GraphRAGChain
from src.stage_1.document_loader import DocumentLoader

# 加载文档
loader = DocumentLoader()
documents = loader.load_directory("./data/documents")

# 初始化 GraphRAG
graph_rag = GraphRAGChain(documents)

# 构建知识图谱(首次使用)
graph_rag.build_knowledge_graph()

# 提问
result = graph_rag.ask("分析文档中提到的公司之间的关系")
print(result.answer)

📖 模块详解

1. GraphRAG 模块

实体抽取 (EntityExtractor)

从文本中识别和提取命名实体:

from src.stage_4.graph_rag import EntityExtractor

extractor = EntityExtractor()
entities = extractor.extract("华为公司在深圳成立,任正非是创始人。")

# 输出:
# [
#   Entity(name="华为公司", type="Organization", ...),
#   Entity(name="深圳", type="Location", ...),
#   Entity(name="任正非", type="Person", ...)
# ]

支持的实体类型:

  • Person - 人物
  • Organization - 组织/公司
  • Location - 地点
  • Event - 事件
  • Concept - 概念/术语
  • Product - 产品
  • Time - 时间

关系抽取 (RelationExtractor)

提取实体之间的关系:

from src.stage_4.graph_rag import RelationExtractor

extractor = RelationExtractor()
relations = extractor.extract(
    text="华为公司在深圳成立,任正非是创始人。",
    entities=entities
)

# 输出:
# [
#   Relation(source="任正非", target="华为公司", type="founded", ...),
#   Relation(source="华为公司", target="深圳", type="located_in", ...)
# ]

知识图谱 (KnowledgeGraph)

管理实体和关系的图结构:

from src.stage_4.graph_rag import KnowledgeGraph

kg = KnowledgeGraph()

# 添加实体
kg.add_entity(entity)

# 添加关系
kg.add_relation(relation)

# 查询实体的邻居
neighbors = kg.get_neighbors("华为公司", hops=2)

# 查找路径
path = kg.find_path("任正非", "深圳")

# 获取子图
subgraph = kg.get_subgraph(["华为公司", "任正非"])

图检索器 (GraphRetriever)

基于图结构进行智能检索:

from src.stage_4.graph_rag import GraphRetriever

retriever = GraphRetriever(knowledge_graph)

# 检索相关实体和上下文
results = retriever.retrieve(
    query="华为的创始人是谁?",
    top_k=5
)

2. 微调模块

Embedding 微调

使用私有数据微调 Embedding 模型:

from src.stage_4.fine_tuning import EmbeddingFineTuner

fine_tuner = EmbeddingFineTuner(
    base_model="BAAI/bge-base-zh-v1.5",
    output_dir="./models/my_embedding"
)

# 生成训练数据
training_data = fine_tuner.generate_training_data(documents)

# 训练
fine_tuner.train(training_data, epochs=3)

LLM 微调数据准备

自动生成微调训练数据:

from src.stage_4.fine_tuning import LLMFineTuner

finetuner = LLMFineTuner()

# 生成 QA 对
qa_pairs = finetuner.generate_qa_pairs(documents)

# 导出为不同格式
finetuner.export_jsonl(qa_pairs, "train.jsonl")  # OpenAI 格式
finetuner.export_alpaca(qa_pairs, "train_alpaca.json")  # Alpaca 格式

本地 LLM 微调 (LoRA) 🆕

使用 LoRA 技术在本地设备上微调开源大模型:

from src.stage_4.fine_tuning import quick_finetune

# 一键微调(使用默认配置)
result = quick_finetune(
    data_path="./data/finetune/train_alpaca.json",
    model="Qwen/Qwen2.5-0.5B-Instruct",  # 推荐小模型
    epochs=3
)

自定义配置:

from src.stage_4.fine_tuning import LocalLLMFineTuner, LocalFineTuneConfig

config = LocalFineTuneConfig(
    base_model="Qwen/Qwen2.5-1.5B-Instruct",
    output_dir="./models/my_finetuned_model",
    lora_rank=8,
    epochs=3,
    device="cpu",  # 支持 cpu / cuda / mps
)

finetuner = LocalLLMFineTuner(config)
finetuner.run_full_pipeline("./data/finetune/train_alpaca.json")

# 使用微调后的模型
response = finetuner.chat("小米公司是什么时候成立的?")

📖 详细文档请参考 LocalFineTune.md


🔧 配置说明

Stage4Config 参数

@dataclass
class Stage4Config(Stage3Config):
    # GraphRAG 配置
    graph_store_type: str = "memory"  # memory / neo4j
    entity_types: List[str] = ...      # 支持的实体类型
    relation_types: List[str] = ...    # 支持的关系类型
    max_entities_per_chunk: int = 20   # 每个文档块最大实体数
    max_relations_per_chunk: int = 30  # 每个文档块最大关系数
    graph_traversal_depth: int = 2     # 图遍历深度
    
    # Neo4j 配置
    neo4j_uri: str = "bolt://localhost:7687"
    neo4j_username: str = "neo4j"
    neo4j_password: str = ""
    
    # Embedding 微调配置
    embedding_finetune_model: str = "BAAI/bge-base-zh-v1.5"
    embedding_finetune_epochs: int = 3
    embedding_finetune_batch_size: int = 32
    
    # LLM 微调数据配置
    qa_pairs_per_doc: int = 5
    qa_difficulty_levels: List[str] = ["easy", "medium", "hard"]

📊 架构图

┌─────────────────────────────────────────────────────────────────┐
│                        UltimateRAG Stage 4                      │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌──────────────────────┐    ┌──────────────────────┐          │
│  │    GraphRAG 模块      │    │    微调模块           │          │
│  ├──────────────────────┤    ├──────────────────────┤          │
│  │ • EntityExtractor    │    │ • EmbeddingFineTuner │          │
│  │ • RelationExtractor  │    │ • LLMFineTuner       │          │
│  │ • KnowledgeGraph     │    │ • TrainingDataGen    │          │
│  │ • GraphStore         │    │ • LocalLLMFineTuner  │ 🆕       │
│  │ • GraphRetriever     │    │   (LoRA 微调)        │          │
│  │ • GraphRAGChain      │    │                      │          │
│  └──────────┬───────────┘    └───────────┬──────────┘          │
│             │                            │                      │
│             └────────────┬───────────────┘                      │
│                          │                                      │
│             ┌────────────▼───────────────┐                      │
│             │     UltimateRAGChain       │                      │
│             │   (整合 Stage 1-4)         │                      │
│             └────────────────────────────┘                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
                              │
                              │ 继承
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Stage 1-3 组件                              │
│  VectorStore | HybridRetriever | Reranker | AgenticRAG | ...   │
└─────────────────────────────────────────────────────────────────┘

🎓 典型使用场景

场景 1: 企业关系分析

# 分析合同文档中的公司关系
result = graph_rag.ask("找出 A 公司和 B 公司之间所有的合作关系")

# 返回:
# - 详细的关系描述
# - 关系路径可视化
# - 相关证据文档

场景 2: 人物关系网络

# 分析新闻中的人物关系
result = graph_rag.ask("张三和李四是什么关系?他们之间有什么交集?")

场景 3: 全局概括

# 对大量文档进行全局性总结
result = graph_rag.ask("总结过去三年公司在 AI 领域的战略布局")

场景 4: 领域适配

# 微调 Embedding 模型适配医疗领域
fine_tuner.train(medical_documents)

# 使用微调后的模型
graph_rag.set_embedding_model("./models/medical_embedding")

⚠️ 注意事项

  1. 性能考虑

    • 实体/关系抽取会增加 LLM 调用,建议批量处理
    • 大规模图谱建议使用 Neo4j
    • Embedding 微调需要 GPU 效果更好
  2. 成本控制

    • 设置合理的 max_entities_per_chunk
    • 使用缓存避免重复抽取
    • 考虑使用本地 LLM 进行抽取
  3. 数据质量

    • 抽取质量依赖于 LLM 能力
    • 建议人工审核关键实体/关系
    • 定期清理冗余实体
  4. 本地 LLM 微调 🆕

    • CPU 训练速度较慢,建议使用小模型(0.5B-1.5B)
    • 16GB 内存推荐使用 Qwen2.5-0.5B 或 1.5B
    • LoRA rank 越小内存需求越低(推荐 4-8)
    • 详见 LocalFineTune.md

📈 与前序阶段对比

维度 Stage 3 Stage 4
检索方式 向量 + BM25 向量 + BM25 + 图遍历
上下文理解 局部文档 全局关联
问题类型 单文档问答 跨文档关系推理
定制能力 通用模型 领域微调
复杂度 中等

🔗 相关资源

v0.3.0

19 Dec 01:57

Choose a tag to compare

Phase 3: 架构进化 (Modular & Agentic RAG)

📚 本阶段学习收获

Tip

Phase 3 实现了让 RAG 系统具备"思考"能力的核心组件,系统不再是简单的"检索-生成"直线流程,而是一个能够动态决策的智能网络。


🎯 完成的功能

1. 智能路由器 (router.py)

  • 使用 LLM 结构化输出进行问题分类
  • 支持 5 种路由类型:知识库、Web 搜索、计算器、代码执行、直接回答
  • 包含置信度评估和回退策略
  • 提供基于关键词的快速路由备选方案

2. 自反思 RAG (self_rag.py)

  • 检索相关性评估(Relevance Evaluation)
  • 答案质量评估(Quality Evaluation)
  • 自动迭代优化(最多 N 轮)
  • 查询优化与重检索

3. 工具集成 (tools/)

  • Web 搜索工具:使用 DuckDuckGo 免费搜索
  • 计算器工具:安全的数学表达式求值
  • 代码执行器:受限沙箱中的 Python 执行
  • 统计计算器:数据统计分析

4. 父子索引检索器 (parent_child_retriever.py)

  • 大块(Parent)存储完整上下文
  • 小块(Child)用于精准匹配
  • 支持上下文窗口扩展
  • 内存映射存储

5. 上下文压缩 (context_compressor.py)

  • LLM 驱动的相关句子提取
  • 基于关键词的快速压缩
  • 压缩比统计与优化

💡 技术要点

1. LangChain 结构化输出

使用 Pydantic 模型定义输出格式,LLM 返回结构化数据:

from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI

class RouteDecision(BaseModel):
    route_type: RouteType = Field(description="路由类型")
    confidence: float = Field(description="置信度", ge=0.0, le=1.0)
    reasoning: str = Field(description="决策原因")

llm = ChatOpenAI(model="gpt-4o")
structured_llm = llm.with_structured_output(RouteDecision)
result = structured_llm.invoke(prompt)  # 返回 RouteDecision 实例

2. Self-RAG 工作流程

用户问题 → 检索文档 → 相关性评估 → 生成答案 → 质量评估
                ↑                                    ↓
                └─────── 质量不足时重新检索 ←────────┘

3. 父子索引原理

原始文档
    ↓
切分为大的父块(2000 字符)
    ↓
每个父块再切分为小的子块(400 字符)
    ↓
子块存入向量库,父块存入内存映射

检索时:用子块精准匹配 → 返回对应父块的完整上下文

4. 安全的代码执行

# 受限的内置函数白名单
SAFE_BUILTINS = {
    "int": int, "float": float, "str": str,
    "len": len, "range": range, "sum": sum,
    "min": min, "max": max, "abs": abs,
    # ... 更多安全函数
}

# 允许的模块白名单
ALLOWED_MODULES = {"math", "random", "datetime", "statistics"}

# 执行代码
exec(code, {"__builtins__": SAFE_BUILTINS}, local_vars)

📊 测试结果

✅ 8 个测试类全部通过
- TestCalculatorTool: 计算器测试
- TestStatisticsCalculator: 统计计算测试
- TestCodeExecutor: 代码执行测试
- TestKeywordRouter: 路由器测试
- TestToolResult: 工具结果测试
- TestParentChildRetriever: 父子索引测试
- TestContextCompressor: 上下文压缩测试

🔑 关键技术点

技术 解决的问题 实现难度 ROI
智能路由 问题分类错误 ⭐⭐⭐ ⭐⭐⭐⭐
Self-RAG 答案质量不稳定 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
工具调用 无法处理特定任务 ⭐⭐⭐ ⭐⭐⭐⭐
父子索引 检索精度与上下文的平衡 ⭐⭐⭐⭐ ⭐⭐⭐⭐
上下文压缩 Token 浪费 ⭐⭐ ⭐⭐⭐

🔗 文件结构

src/stage_3/
├── __init__.py                  # 包初始化
├── config.py                    # Stage 3 配置
├── router.py                    # 智能路由器
├── self_rag.py                  # 自反思 RAG
├── tools/
│   ├── __init__.py              # 工具包
│   ├── base.py                  # 工具基类
│   ├── search_tool.py           # Web 搜索
│   ├── calculator_tool.py       # 计算器
│   └── code_executor.py         # 代码执行
├── parent_child_retriever.py    # 父子索引
├── context_compressor.py        # 上下文压缩
├── agentic_rag_chain.py         # Agentic RAG 链
├── main.py                      # 主入口
└── tests/
    └── test_agentic_rag.py      # 单元测试

🚀 使用方法

# 运行 Agentic RAG 系统
cd /path/to/UltimateRAG
source .venv/bin/activate
python -m src.stage_3.main --data ./data/documents

# 可选参数
--no-routing       # 禁用智能路由
--no-self-rag      # 禁用自反思
--no-tools         # 禁用工具调用
--no-parent-child  # 禁用父子索引
--no-compression   # 禁用上下文压缩
--reindex          # 强制重新索引

📈 Phase 3 vs Phase 2 对比

特性 Phase 2 Phase 3
检索方式 混合检索 智能路由 + 多策略
答案质量 一次性生成 自反思迭代优化
处理能力 仅文档问答 文档 + 搜索 + 计算 + 代码
上下文 检索即返回 父子索引 + 压缩优化
智能程度 被动响应 主动决策

⚠️ 注意事项

1. 性能考量

  • 智能路由会增加一次 LLM 调用
  • Self-RAG 迭代会显著增加响应时间
  • 建议根据场景选择性启用功能

2. 安全考量

  • 代码执行器使用沙箱环境
  • 已禁用危险函数和模块
  • 设置执行超时防止死循环

3. 成本考量

  • 每个功能都会消耗额外 Token
  • 建议监控 Token 使用量
  • 可通过禁用不需要的功能控制成本

📖 参考资料


🎓 核心概念总结

Agentic RAG 的本质

传统 RAG 是 Pipeline(流水线):

Query → Retrieve → Generate → Answer

Agentic RAG 是 Agent(智能体):

                    ┌─→ 知识库检索 ─┐
                    │              │
Query → 路由决策 ──→├─→ Web 搜索 ──┼─→ 质量评估 ─→ 迭代优化 ─→ Answer
                    │              │
                    ├─→ 工具调用 ──┤
                    │              │
                    └─→ 直接回答 ──┘

关键洞察

  1. 智能路由是入口:好的分类决定了后续处理的效率和质量
  2. 自反思是保障:让系统能够自我纠错,提高答案可靠性
  3. 工具是扩展:突破纯文本问答的局限
  4. 父子索引是平衡:在检索精度和上下文完整性之间找到平衡点
  5. 压缩是优化:节省 Token,聚焦关键信息

🔮 Phase 4 展望

下一阶段将进入更高级的领域:

  • GraphRAG:知识图谱增强检索
  • 领域微调:Embedding 和 LLM 的定制化
  • 多模态:图片、表格等非文本数据处理

Note

Phase 3 的组件化设计为后续扩展奠定了良好基础。

v0.2.0

17 Dec 02:12

Choose a tag to compare

Phase 2: 质量飞跃 (Advanced RAG)

📚 本阶段学习收获

Tip

Phase 2 实现了多项高级 RAG 技术,显著提升了检索质量。


🎯 完成的功能

1. 语义分块 (semantic_chunker.py)

  • 基于句子嵌入判断语义边界
  • 动态调整分块大小
  • 保持段落完整性

2. 元数据提取 (metadata_extractor.py)

  • 自动提取标题、日期、文件信息
  • 支持元数据过滤检索
  • 增强文档可追溯性

3. 混合检索 (hybrid_retriever.py)

  • BM25 关键词检索 + 向量语义检索
  • 倒排融合算法 (RRF) 合并结果
  • 中英文混合分词支持

4. 查询重写 (query_rewriter.py)

  • 多路查询生成
  • HyDE 假设文档嵌入
  • 查询扩展(同义词)

5. 重排序 (reranker.py)

  • BGE-Reranker Cross-Encoder
  • 精细化排序 Top-K
  • 简单规则重排备选方案

💡 技术要点

混合检索融合算法 (RRF)

# 倒排融合公式: score = Σ 1/(k + rank)
for rank, (doc, _) in enumerate(results):
    doc_scores[doc_key] += 1 / (k + rank + 1)

语义分块判断

# 当相似度低于阈值且块足够大时断开
if similarity < threshold and len(chunk) >= min_size:
    chunks.append(current_chunk)
    current_chunk = new_sentence

HyDE 工作原理

用户问题 -> LLM生成假设答案 -> 用假设答案检索 -> 找到真实文档

📊 测试结果

✅ 6 个单元测试全部通过
- TestMetadataExtractor: 元数据提取测试
- TestHybridRetriever: 混合检索测试
- TestQueryRewriter: 查询重写测试
- TestReranker: 重排序测试

⚠️ 关键技术点

技术 解决的问题 ROI
混合检索 专有名词搜索不到 ⭐⭐⭐⭐⭐
Re-ranking 粗检索结果排序不准 ⭐⭐⭐⭐⭐
查询重写 用户表达不清晰 ⭐⭐⭐⭐
语义分块 固定分块切断语义 ⭐⭐⭐

🔗 文件结构

src/stage_2/
├── __init__.py               # 包初始化
├── semantic_chunker.py       # 语义分块器
├── metadata_extractor.py     # 元数据提取
├── hybrid_retriever.py       # 混合检索器
├── query_rewriter.py         # 查询重写
├── reranker.py               # 重排序器
├── advanced_rag_chain.py     # 高级 RAG 链
├── main.py                   # 主入口
└── tests/
    └── test_advanced_rag.py  # 单元测试

🚀 使用方法

# 运行 Advanced RAG 系统
cd /path/to/UltimateRAG
source .venv/bin/activate
python -m src.stage_2.main --data ./data/documents

# 可选参数
--no-semantic    # 禁用语义分块
--no-rerank      # 禁用重排序
--reindex        # 强制重新索引

📖 参考资料

v0.1.0

17 Dec 02:10

Choose a tag to compare

Phase 1: 原型验证 (MVP)

📚 本阶段学习收获

Tip

Phase 1 完成了 RAG 系统的基础架构搭建,实现了从文档加载到问答的完整流程。


🎯 完成的功能

1. 配置管理 (config.py)

  • 使用 dataclass 定义配置结构
  • 支持从环境变量加载配置
  • 实现单例模式的配置管理

2. 文档加载 (document_loader.py)

  • 支持 PDF、Markdown、TXT、DOCX 四种格式
  • 自动识别文件类型并选择加载器
  • 支持递归加载整个目录

3. 文本分块 (chunker.py)

  • 使用 RecursiveCharacterTextSplitter 智能分割
  • 支持中英文混合切分
  • 可配置块大小和重叠

4. 嵌入模型 (embedder.py)

  • 封装 OpenAI Embeddings
  • 支持自定义 base_url(兼容 DeepSeek 等)
  • 懒加载机制

5. 向量存储 (vectorstore.py)

  • 使用 ChromaDB 持久化存储
  • 支持相似度检索和带分数检索
  • 可转换为 LangChain Retriever

6. RAG 问答链 (rag_chain.py)

  • 组装检索器、Prompt 和 LLM
  • 支持普通问答和带来源问答
  • 支持流式输出

💡 技术要点

LangChain 1.1.3 新特性

# 使用 langchain_core 的基础类
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# 使用 LCEL (LangChain Expression Language) 构建链
chain = prompt | llm | StrOutputParser()

ChromaDB 集成

from langchain_community.vectorstores import Chroma

vectorstore = Chroma(
    collection_name="rag_documents",
    embedding_function=embeddings,
    persist_directory="./data/chroma_db"
)

分块最佳实践

  • chunk_size: 512 字符(约 100-200 token)
  • chunk_overlap: 50 字符(约 10%)
  • 分隔符优先级: 段落 → 句子 → 词语

⚠️ 遇到的问题与解决方案

问题 1: LangChain 版本兼容性

现象: 旧代码使用 from langchain.xxx 导入报错
解决: 使用新的模块结构

  • langchain_core: 核心基础类
  • langchain_openai: OpenAI 集成
  • langchain_community: 社区集成

问题 2: ChromaDB 持久化

现象: 每次运行都需要重新索引
解决: 指定 persist_directory 参数,自动保存和加载


📊 测试结果

✅ 8 个单元测试全部通过
- TestConfig: 配置加载测试
- TestDocumentLoader: 文档加载测试
- TestTextChunker: 分块测试

📈 Phase 1 局限性

  1. 分块太碎: 固定大小分块可能切断完整的语义
  2. 检索不准: 纯向量检索对关键词匹配不友好
  3. 无排序优化: 检索结果未经过重排序

Note

这些问题将在 Phase 2 (Advanced RAG) 中解决。


🔗 文件结构

src/stage_1/
├── __init__.py           # 包初始化
├── config.py             # 配置管理
├── document_loader.py    # 文档加载器
├── chunker.py            # 文本分块器
├── embedder.py           # 嵌入模型
├── vectorstore.py        # 向量存储
├── rag_chain.py          # RAG 问答链
├── main.py               # 主入口
└── tests/
    └── test_rag.py       # 单元测试

🚀 使用方法

# 1. 配置环境变量
cp .env.example .env
# 编辑 .env 填入你的 API Key

# 2. 运行 RAG 系统
cd /path/to/UltimateRAG
source venv/bin/activate
python -m src.stage_1.main --data ./data/documents

# 3. 开始问答
# 输入问题即可获得回答

📖 参考资料