Files
lightrag/README-zh.md
2025-03-25 16:23:15 +08:00

44 KiB
Raw Blame History

LightRAG: Simple and Fast Retrieval-Augmented Generation

LightRAG Diagram

🎉 新闻

算法流程图

LightRAG索引流程图 图1LightRAG索引流程图 - 图片来源:Source LightRAG检索和查询流程图 图2LightRAG检索和查询流程图 - 图片来源:Source

安装

安装LightRAG核心

  • 从源代码安装(推荐)
cd LightRAG
pip install -e .
  • 从PyPI安装
pip install lightrag-hku

安装LightRAG服务器

LightRAG服务器旨在提供Web UI和API支持。Web UI便于文档索引、知识图谱探索和简单的RAG查询界面。LightRAG服务器还提供兼容Ollama的接口旨在将LightRAG模拟为Ollama聊天模型。这使得AI聊天机器人如Open WebUI可以轻松访问LightRAG。

  • 从PyPI安装
pip install "lightrag-hku[api]"
  • 从源代码安装
# 如有必要创建Python虚拟环境
# 以可编辑模式安装并支持API
pip install -e ".[api]"

有关LightRAG服务器的更多信息请参阅LightRAG服务器

快速开始

  • 视频演示展示如何在本地运行LightRAG。
  • 所有代码都可以在examples中找到。
  • 如果使用OpenAI模型请在环境中设置OpenAI API密钥export OPENAI_API_KEY="sk-..."
  • 下载演示文本"狄更斯的圣诞颂歌"
curl https://raw.githubusercontent.com/gusye1234/nano-graphrag/main/tests/mock_data.txt > ./book.txt

查询

使用以下Python代码片段在脚本中初始化LightRAG并执行查询

import os
import asyncio
from lightrag import LightRAG, QueryParam
from lightrag.llm.openai import gpt_4o_mini_complete, gpt_4o_complete, openai_embed
from lightrag.kg.shared_storage import initialize_pipeline_status
from lightrag.utils import setup_logger

setup_logger("lightrag", level="INFO")

async def initialize_rag():
    rag = LightRAG(
        working_dir="your/path",
        embedding_func=openai_embed,
        llm_model_func=gpt_4o_mini_complete
    )

    await rag.initialize_storages()
    await initialize_pipeline_status()

    return rag

def main():
    # 初始化RAG实例
    rag = asyncio.run(initialize_rag())
    # 插入文本
    rag.insert("Your text")

    # 执行朴素搜索
    mode="naive"
    # 执行本地搜索
    mode="local"
    # 执行全局搜索
    mode="global"
    # 执行混合搜索
    mode="hybrid"
    # 混合模式集成知识图谱和向量检索
    mode="mix"

    rag.query(
        "这个故事的主要主题是什么?",
        param=QueryParam(mode=mode)
    )

if __name__ == "__main__":
    main()

查询参数

class QueryParam:
    mode: Literal["local", "global", "hybrid", "naive", "mix"] = "global"
    """指定检索模式:
    - "local":专注于上下文相关信息。
    - "global":利用全局知识。
    - "hybrid":结合本地和全局检索方法。
    - "naive":执行基本搜索,不使用高级技术。
    - "mix":集成知识图谱和向量检索。混合模式结合知识图谱和向量搜索:
        - 同时使用结构化KG和非结构化向量信息
        - 通过分析关系和上下文提供全面的答案
        - 通过HTML img标签支持图像内容
        - 允许通过top_k参数控制检索深度
    """
    only_need_context: bool = False
    """如果为True仅返回检索到的上下文而不生成响应。"""
    response_type: str = "Multiple Paragraphs"
    """定义响应格式。示例:'Multiple Paragraphs'(多段落), 'Single Paragraph'(单段落), 'Bullet Points'(要点列表)。"""
    top_k: int = 60
    """要检索的顶部项目数量。在'local'模式下代表实体,在'global'模式下代表关系。"""
    max_token_for_text_unit: int = 4000
    """每个检索文本块允许的最大令牌数。"""
    max_token_for_global_context: int = 4000
    """全局检索中关系描述的最大令牌分配。"""
    max_token_for_local_context: int = 4000
    """本地检索中实体描述的最大令牌分配。"""
    ids: list[str] | None = None # 仅支持PG向量数据库
    """用于过滤RAG的ID列表。"""
    ...

top_k的默认值可以通过环境变量TOP_K更改。

LLM and Embedding注入

LightRAG 需要利用LLM和Embeding模型来完成文档索引和知识库查询工作。在初始化LightRAG的时候需要把阶段需要把LLM和Embedding的操作函数注入到对象中

使用类OpenAI的API
  • LightRAG还支持类OpenAI的聊天/嵌入API
async def llm_model_func(
    prompt, system_prompt=None, history_messages=[], keyword_extraction=False, **kwargs
) -> str:
    return await openai_complete_if_cache(
        "solar-mini",
        prompt,
        system_prompt=system_prompt,
        history_messages=history_messages,
        api_key=os.getenv("UPSTAGE_API_KEY"),
        base_url="https://api.upstage.ai/v1/solar",
        **kwargs
    )

async def embedding_func(texts: list[str]) -> np.ndarray:
    return await openai_embed(
        texts,
        model="solar-embedding-1-large-query",
        api_key=os.getenv("UPSTAGE_API_KEY"),
        base_url="https://api.upstage.ai/v1/solar"
    )

async def initialize_rag():
    rag = LightRAG(
        working_dir=WORKING_DIR,
        llm_model_func=llm_model_func,
        embedding_func=EmbeddingFunc(
            embedding_dim=4096,
            max_token_size=8192,
            func=embedding_func
        )
    )

    await rag.initialize_storages()
    await initialize_pipeline_status()

    return rag
使用Hugging Face模型
  • 如果您想使用Hugging Face模型只需要按如下方式设置LightRAG

参见lightrag_hf_demo.py

# 使用Hugging Face模型初始化LightRAG
rag = LightRAG(
    working_dir=WORKING_DIR,
    llm_model_func=hf_model_complete,  # 使用Hugging Face模型进行文本生成
    llm_model_name='meta-llama/Llama-3.1-8B-Instruct',  # Hugging Face的模型名称
    # 使用Hugging Face嵌入函数
    embedding_func=EmbeddingFunc(
        embedding_dim=384,
        max_token_size=5000,
        func=lambda texts: hf_embed(
            texts,
            tokenizer=AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2"),
            embed_model=AutoModel.from_pretrained("sentence-transformers/all-MiniLM-L6-v2")
        )
    ),
)
使用Ollama模型 如果您想使用Ollama模型您需要拉取计划使用的模型和嵌入模型例如`nomic-embed-text`。

然后您只需要按如下方式设置LightRAG

# 使用Ollama模型初始化LightRAG
rag = LightRAG(
    working_dir=WORKING_DIR,
    llm_model_func=ollama_model_complete,  # 使用Ollama模型进行文本生成
    llm_model_name='your_model_name', # 您的模型名称
    # 使用Ollama嵌入函数
    embedding_func=EmbeddingFunc(
        embedding_dim=768,
        max_token_size=8192,
        func=lambda texts: ollama_embed(
            texts,
            embed_model="nomic-embed-text"
        )
    ),
)
  • 增加上下文大小

为了使LightRAG正常工作上下文应至少为32k令牌。默认情况下Ollama模型的上下文大小为8k。您可以通过以下两种方式之一实现这一点

  • 在Modelfile中增加num_ctx参数
  1. 拉取模型:
ollama pull qwen2
  1. 显示模型文件:
ollama show --modelfile qwen2 > Modelfile
  1. 编辑Modelfile添加以下行
PARAMETER num_ctx 32768
  1. 创建修改后的模型:
ollama create -f Modelfile qwen2m
  • 通过Ollama API设置num_ctx

您可以使用llm_model_kwargs参数配置ollama

rag = LightRAG(
    working_dir=WORKING_DIR,
    llm_model_func=ollama_model_complete,  # 使用Ollama模型进行文本生成
    llm_model_name='your_model_name', # 您的模型名称
    llm_model_kwargs={"options": {"num_ctx": 32768}},
    # 使用Ollama嵌入函数
    embedding_func=EmbeddingFunc(
        embedding_dim=768,
        max_token_size=8192,
        func=lambda texts: ollama_embedding(
            texts,
            embed_model="nomic-embed-text"
        )
    ),
)
  • 低RAM GPU

为了在低RAM GPU上运行此实验您应该选择小型模型并调整上下文窗口增加上下文会增加内存消耗。例如在6Gb RAM的改装挖矿GPU上运行这个ollama示例需要将上下文大小设置为26k同时使用gemma2:2b。它能够在book.txt中找到197个实体和19个关系。

LlamaIndex

LightRAG支持与LlamaIndex集成 (llm/llama_index_impl.py):

  • 通过LlamaIndex与OpenAI和其他提供商集成
  • 详细设置和示例请参见LlamaIndex文档

使用示例:

# 使用LlamaIndex直接访问OpenAI
import asyncio
from lightrag import LightRAG
from lightrag.llm.llama_index_impl import llama_index_complete_if_cache, llama_index_embed
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.llms.openai import OpenAI
from lightrag.kg.shared_storage import initialize_pipeline_status
from lightrag.utils import setup_logger

# 为LightRAG设置日志处理程序
setup_logger("lightrag", level="INFO")

async def initialize_rag():
    rag = LightRAG(
        working_dir="your/path",
        llm_model_func=llama_index_complete_if_cache,  # LlamaIndex兼容的完成函数
        embedding_func=EmbeddingFunc(    # LlamaIndex兼容的嵌入函数
            embedding_dim=1536,
            max_token_size=8192,
            func=lambda texts: llama_index_embed(texts, embed_model=embed_model)
        ),
    )

    await rag.initialize_storages()
    await initialize_pipeline_status()

    return rag

def main():
    # 初始化RAG实例
    rag = asyncio.run(initialize_rag())

    with open("./book.txt", "r", encoding="utf-8") as f:
        rag.insert(f.read())

    # 执行朴素搜索
    print(
        rag.query("这个故事的主要主题是什么?", param=QueryParam(mode="naive"))
    )

    # 执行本地搜索
    print(
        rag.query("这个故事的主要主题是什么?", param=QueryParam(mode="local"))
    )

    # 执行全局搜索
    print(
        rag.query("这个故事的主要主题是什么?", param=QueryParam(mode="global"))
    )

    # 执行混合搜索
    print(
        rag.query("这个故事的主要主题是什么?", param=QueryParam(mode="hybrid"))
    )

if __name__ == "__main__":
    main()

详细文档和示例,请参见:

对话历史

LightRAG现在通过对话历史功能支持多轮对话。以下是使用方法

# 创建对话历史
conversation_history = [
    {"role": "user", "content": "主角对圣诞节的态度是什么?"},
    {"role": "assistant", "content": "在故事开始时,埃比尼泽·斯克鲁奇对圣诞节持非常消极的态度..."},
    {"role": "user", "content": "他的态度是如何改变的?"}
]

# 创建带有对话历史的查询参数
query_param = QueryParam(
    mode="mix",  # 或其他模式:"local"、"global"、"hybrid"
    conversation_history=conversation_history,  # 添加对话历史
    history_turns=3  # 考虑最近的对话轮数
)

# 进行考虑对话历史的查询
response = rag.query(
    "是什么导致了他性格的这种变化?",
    param=query_param
)

自定义提示词

LightRAG现在支持自定义提示以便对系统行为进行精细控制。以下是使用方法

# 创建查询参数
query_param = QueryParam(
    mode="hybrid",  # 或其他模式:"local"、"global"、"hybrid"、"mix"和"naive"
)

# 示例1使用默认系统提示
response_default = rag.query(
    "可再生能源的主要好处是什么?",
    param=query_param
)
print(response_default)

# 示例2使用自定义提示
custom_prompt = """
您是环境科学领域的专家助手。请提供详细且结构化的答案,并附带示例。
---对话历史---
{history}

---知识库---
{context_data}

---响应规则---

- 目标格式和长度:{response_type}
"""
response_custom = rag.query(
    "可再生能源的主要好处是什么?",
    param=query_param,
    system_prompt=custom_prompt  # 传递自定义提示
)
print(response_custom)

关键词提取

我们引入了新函数query_with_separate_keyword_extraction来增强关键词提取功能。该函数将关键词提取过程与用户提示分开,专注于查询以提高提取关键词的相关性。

  • 工作原理

该函数将输入分为两部分:

  • 用户查询
  • 提示

然后仅对用户查询执行关键词提取。这种分离确保提取过程是集中和相关的,不受提示中任何额外语言的影响。它还允许提示纯粹用于响应格式化,保持用户原始问题的意图和清晰度。

  • 使用示例

这个示例展示了如何为教育内容定制函数,专注于为高年级学生提供详细解释。

rag.query_with_separate_keyword_extraction(
    query="解释重力定律",
    prompt="提供适合学习物理的高中生的详细解释。",
    param=QueryParam(mode="hybrid")
)

插入自定义知识

custom_kg = {
    "chunks": [
        {
            "content": "Alice和Bob正在合作进行量子计算研究。",
            "source_id": "doc-1"
        }
    ],
    "entities": [
        {
            "entity_name": "Alice",
            "entity_type": "person",
            "description": "Alice是一位专门研究量子物理的研究员。",
            "source_id": "doc-1"
        },
        {
            "entity_name": "Bob",
            "entity_type": "person",
            "description": "Bob是一位数学家。",
            "source_id": "doc-1"
        },
        {
            "entity_name": "量子计算",
            "entity_type": "technology",
            "description": "量子计算利用量子力学现象进行计算。",
            "source_id": "doc-1"
        }
    ],
    "relationships": [
        {
            "src_id": "Alice",
            "tgt_id": "Bob",
            "description": "Alice和Bob是研究伙伴。",
            "keywords": "合作 研究",
            "weight": 1.0,
            "source_id": "doc-1"
        },
        {
            "src_id": "Alice",
            "tgt_id": "量子计算",
            "description": "Alice进行量子计算研究。",
            "keywords": "研究 专业",
            "weight": 1.0,
            "source_id": "doc-1"
        },
        {
            "src_id": "Bob",
            "tgt_id": "量子计算",
            "description": "Bob研究量子计算。",
            "keywords": "研究 应用",
            "weight": 1.0,
            "source_id": "doc-1"
        }
    ]
}

rag.insert_custom_kg(custom_kg)

插入

基本插入

# 基本插入
rag.insert("文本")
批量插入
# 基本批量插入:一次插入多个文本
rag.insert(["文本1", "文本2",...])

# 带有自定义批量大小配置的批量插入
rag = LightRAG(
    working_dir=WORKING_DIR,
    addon_params={
        "insert_batch_size": 4  # 每批处理4个文档
    }
)

rag.insert(["文本1", "文本2", "文本3", ...])  # 文档将以4个为一批进行处理

addon_params中的insert_batch_size参数控制插入过程中每批处理的文档数量。这对于以下情况很有用:

  • 管理大型文档集合的内存使用
  • 优化处理速度
  • 提供更好的进度跟踪
  • 如果未指定默认值为10
带ID插入

如果您想为文档提供自己的ID文档数量和ID数量必须相同。

# 插入单个文本并为其提供ID
rag.insert("文本1", ids=["文本1的ID"])

# 插入多个文本并为它们提供ID
rag.insert(["文本1", "文本2",...], ids=["文本1的ID", "文本2的ID"])
使用管道插入

apipeline_enqueue_documentsapipeline_process_enqueue_documents函数允许您对文档进行增量插入到图中。

这对于需要在后台处理文档的场景很有用,同时仍允许主线程继续执行。

并使用例程处理新文档。

rag = LightRAG(..)

await rag.apipeline_enqueue_documents(input)
# 您的循环例程
await rag.apipeline_process_enqueue_documents(input)
插入多文件类型支持

textract支持读取TXT、DOCX、PPTX、CSV和PDF等文件类型。

import textract

file_path = 'TEXT.pdf'
text_content = textract.process(file_path)

rag.insert(text_content.decode('utf-8'))
引文功能

通过提供文件路径,系统确保可以将来源追溯到其原始文档。

# 定义文档及其文件路径
documents = ["文档内容1", "文档内容2"]
file_paths = ["path/to/doc1.txt", "path/to/doc2.txt"]

# 插入带有文件路径的文档
rag.insert(documents, file_paths=file_paths)

存储

使用Neo4J进行存储
  • 对于生产级场景,您很可能想要利用企业级解决方案
  • 进行KG存储。推荐在Docker中运行Neo4J以进行无缝本地测试。
  • 参见:https://hub.docker.com/_/neo4j
export NEO4J_URI="neo4j://localhost:7687"
export NEO4J_USERNAME="neo4j"
export NEO4J_PASSWORD="password"

# 为LightRAG设置日志记录器
setup_logger("lightrag", level="INFO")

# 当您启动项目时请确保通过指定kg="Neo4JStorage"来覆盖默认的KGNetworkX。

# 注意默认设置使用NetworkX
# 使用Neo4J实现初始化LightRAG。
async def initialize_rag():
    rag = LightRAG(
        working_dir=WORKING_DIR,
        llm_model_func=gpt_4o_mini_complete,  # 使用gpt_4o_mini_complete LLM模型
        graph_storage="Neo4JStorage", #<-----------覆盖KG默认值
    )

    # 初始化数据库连接
    await rag.initialize_storages()
    # 初始化文档处理的管道状态
    await initialize_pipeline_status()

    return rag

参见test_neo4j.py获取工作示例。

使用Faiss进行存储
  • 安装所需依赖:
pip install faiss-cpu

如果您有GPU支持也可以安装faiss-gpu

  • 这里我们使用sentence-transformers,但您也可以使用维度为3072OpenAIEmbedding模型。
async def embedding_func(texts: list[str]) -> np.ndarray:
    model = SentenceTransformer('all-MiniLM-L6-v2')
    embeddings = model.encode(texts, convert_to_numpy=True)
    return embeddings

# 使用LLM模型函数和嵌入函数初始化LightRAG
rag = LightRAG(
    working_dir=WORKING_DIR,
    llm_model_func=llm_model_func,
    embedding_func=EmbeddingFunc(
        embedding_dim=384,
        max_token_size=8192,
        func=embedding_func,
    ),
    vector_storage="FaissVectorDBStorage",
    vector_db_storage_cls_kwargs={
        "cosine_better_than_threshold": 0.3  # 您期望的阈值
    }
)
使用PostgreSQL进行存储

对于生产级场景您很可能想要利用企业级解决方案。PostgreSQL可以为您提供一站式解决方案作为KV存储、向量数据库pgvector和图数据库apache AGE

  • PostgreSQL很轻量整个二进制发行版包括所有必要的插件可以压缩到40MB参考Windows发布版它在Linux/Mac上也很容易安装。
  • 如果您是初学者并想避免麻烦推荐使用docker请从这个镜像开始请务必阅读概述https://hub.docker.com/r/shangor/postgres-for-rag
  • 如何开始?参考:examples/lightrag_zhipu_postgres_demo.py
  • 为AGE创建索引示例如有必要将下面的dickens改为您的图名)
    load 'age';
    SET search_path = ag_catalog, "$user", public;
    CREATE INDEX CONCURRENTLY entity_p_idx ON dickens."Entity" (id);
    CREATE INDEX CONCURRENTLY vertex_p_idx ON dickens."_ag_label_vertex" (id);
    CREATE INDEX CONCURRENTLY directed_p_idx ON dickens."DIRECTED" (id);
    CREATE INDEX CONCURRENTLY directed_eid_idx ON dickens."DIRECTED" (end_id);
    CREATE INDEX CONCURRENTLY directed_sid_idx ON dickens."DIRECTED" (start_id);
    CREATE INDEX CONCURRENTLY directed_seid_idx ON dickens."DIRECTED" (start_id,end_id);
    CREATE INDEX CONCURRENTLY edge_p_idx ON dickens."_ag_label_edge" (id);
    CREATE INDEX CONCURRENTLY edge_sid_idx ON dickens."_ag_label_edge" (start_id);
    CREATE INDEX CONCURRENTLY edge_eid_idx ON dickens."_ag_label_edge" (end_id);
    CREATE INDEX CONCURRENTLY edge_seid_idx ON dickens."_ag_label_edge" (start_id,end_id);
    create INDEX CONCURRENTLY vertex_idx_node_id ON dickens."_ag_label_vertex" (ag_catalog.agtype_access_operator(properties, '"node_id"'::agtype));
    create INDEX CONCURRENTLY entity_idx_node_id ON dickens."Entity" (ag_catalog.agtype_access_operator(properties, '"node_id"'::agtype));
    CREATE INDEX CONCURRENTLY entity_node_id_gin_idx ON dickens."Entity" using gin(properties);
    ALTER TABLE dickens."DIRECTED" CLUSTER ON directed_sid_idx;
    
    -- 如有必要可以删除
    drop INDEX entity_p_idx;
    drop INDEX vertex_p_idx;
    drop INDEX directed_p_idx;
    drop INDEX directed_eid_idx;
    drop INDEX directed_sid_idx;
    drop INDEX directed_seid_idx;
    drop INDEX edge_p_idx;
    drop INDEX edge_sid_idx;
    drop INDEX edge_eid_idx;
    drop INDEX edge_seid_idx;
    drop INDEX vertex_idx_node_id;
    drop INDEX entity_idx_node_id;
    drop INDEX entity_node_id_gin_idx;
    
  • Apache AGE的已知问题发布版本存在以下问题

    您可能会发现节点/边的属性是空的。 这是发布版本的已知问题:https://github.com/apache/age/pull/1721

    您可以从源代码编译AGE来修复它。

删除

#  删除实体:通过实体名称删除实体
rag.delete_by_entity("Project Gutenberg")

#  删除文档通过文档ID删除与文档相关的实体和关系
rag.delete_by_doc_id("doc_id")

编辑实体和关系

LightRAG现在支持全面的知识图谱管理功能允许您在知识图谱中创建、编辑和删除实体和关系。

创建实体和关系
# 创建新实体
entity = rag.create_entity("Google", {
    "description": "Google是一家专注于互联网相关服务和产品的跨国科技公司。",
    "entity_type": "company"
})

# 创建另一个实体
product = rag.create_entity("Gmail", {
    "description": "Gmail是由Google开发的电子邮件服务。",
    "entity_type": "product"
})

# 创建实体之间的关系
relation = rag.create_relation("Google", "Gmail", {
    "description": "Google开发和运营Gmail。",
    "keywords": "开发 运营 服务",
    "weight": 2.0
})
编辑实体和关系
# 编辑现有实体
updated_entity = rag.edit_entity("Google", {
    "description": "Google是Alphabet Inc.的子公司成立于1998年。",
    "entity_type": "tech_company"
})

# 重命名实体(所有关系都会正确迁移)
renamed_entity = rag.edit_entity("Gmail", {
    "entity_name": "Google Mail",
    "description": "Google Mail前身为Gmail是一项电子邮件服务。"
})

# 编辑实体之间的关系
updated_relation = rag.edit_relation("Google", "Google Mail", {
    "description": "Google创建并维护Google Mail服务。",
    "keywords": "创建 维护 电子邮件服务",
    "weight": 3.0
})

所有操作都有同步和异步版本。异步版本带有前缀"a"(例如,acreate_entityaedit_relation)。

实体操作

  • create_entity:创建具有指定属性的新实体
  • edit_entity:更新现有实体的属性或重命名它

关系操作

  • create_relation:在现有实体之间创建新关系
  • edit_relation:更新现有关系的属性

这些操作在图数据库和向量数据库组件之间保持数据一致性,确保您的知识图谱保持连贯。

数据导出功能

概述

LightRAG允许您以各种格式导出知识图谱数据用于分析、共享和备份目的。系统支持导出实体、关系和关系数据。

导出功能

基本用法

# 基本CSV导出默认格式
rag.export_data("knowledge_graph.csv")

# 指定任意格式
rag.export_data("output.xlsx", file_format="excel")

支持的不同文件格式

# 以CSV格式导出数据
rag.export_data("graph_data.csv", file_format="csv")

# 导出数据到Excel表格
rag.export_data("graph_data.xlsx", file_format="excel")

# 以markdown格式导出数据
rag.export_data("graph_data.md", file_format="md")

# 导出数据为文本
rag.export_data("graph_data.txt", file_format="txt")

附加选项

在导出中包含向量嵌入(可选):

rag.export_data("complete_data.csv", include_vector_data=True)

导出数据包括

所有导出包括:

  • 实体信息名称、ID、元数据
  • 关系数据(实体之间的连接)
  • 来自向量数据库的关系信息

实体合并

合并实体及其关系

LightRAG现在支持将多个实体合并为单个实体自动处理所有关系

# 基本实体合并
rag.merge_entities(
    source_entities=["人工智能", "AI", "机器智能"],
    target_entity="AI技术"
)

使用自定义合并策略:

# 为不同字段定义自定义合并策略
rag.merge_entities(
    source_entities=["约翰·史密斯", "史密斯博士", "J·史密斯"],
    target_entity="约翰·史密斯",
    merge_strategy={
        "description": "concatenate",  # 组合所有描述
        "entity_type": "keep_first",   # 保留第一个实体的类型
        "source_id": "join_unique"     # 组合所有唯一的源ID
    }
)

使用自定义目标实体数据:

# 为合并后的实体指定确切值
rag.merge_entities(
    source_entities=["纽约", "NYC", "大苹果"],
    target_entity="纽约市",
    target_entity_data={
        "entity_type": "LOCATION",
        "description": "纽约市是美国人口最多的城市。",
    }
)

结合两种方法的高级用法:

# 使用策略和自定义数据合并公司实体
rag.merge_entities(
    source_entities=["微软公司", "Microsoft Corporation", "MSFT"],
    target_entity="微软",
    merge_strategy={
        "description": "concatenate",  # 组合所有描述
        "source_id": "join_unique"     # 组合源ID
    },
    target_entity_data={
        "entity_type": "ORGANIZATION",
    }
)

合并实体时:

  • 所有来自源实体的关系都会重定向到目标实体
  • 重复的关系会被智能合并
  • 防止自我关系(循环)
  • 合并后删除源实体
  • 保留关系权重和属性

缓存

清除缓存

您可以使用不同模式清除LLM响应缓存

# 清除所有缓存
await rag.aclear_cache()

# 清除本地模式缓存
await rag.aclear_cache(modes=["local"])

# 清除提取缓存
await rag.aclear_cache(modes=["default"])

# 清除多个模式
await rag.aclear_cache(modes=["local", "global", "hybrid"])

# 同步版本
rag.clear_cache(modes=["local"])

有效的模式包括:

  • "default":提取缓存
  • "naive":朴素搜索缓存
  • "local":本地搜索缓存
  • "global":全局搜索缓存
  • "hybrid":混合搜索缓存
  • "mix":混合搜索缓存

LightRAG初始化参数

参数
参数 类型 说明 默认值
working_dir str 存储缓存的目录 lightrag_cache+timestamp
kv_storage str 文档和文本块的存储类型。支持的类型:JsonKVStorageOracleKVStorage JsonKVStorage
vector_storage str 嵌入向量的存储类型。支持的类型:NanoVectorDBStorageOracleVectorDBStorage NanoVectorDBStorage
graph_storage str 图边和节点的存储类型。支持的类型:NetworkXStorageNeo4JStorageOracleGraphStorage NetworkXStorage
chunk_token_size int 拆分文档时每个块的最大令牌大小 1200
chunk_overlap_token_size int 拆分文档时两个块之间的重叠令牌大小 100
tiktoken_model_name str 用于计算令牌数的Tiktoken编码器的模型名称 gpt-4o-mini
entity_extract_max_gleaning int 实体提取过程中的循环次数,附加历史消息 1
entity_summary_to_max_tokens int 每个实体摘要的最大令牌大小 500
node_embedding_algorithm str 节点嵌入算法(当前未使用) node2vec
node2vec_params dict 节点嵌入的参数 {"dimensions": 1536,"num_walks": 10,"walk_length": 40,"window_size": 2,"iterations": 3,"random_seed": 3,}
embedding_func EmbeddingFunc 从文本生成嵌入向量的函数 openai_embed
embedding_batch_num int 嵌入过程的最大批量大小(每批发送多个文本) 32
embedding_func_max_async int 最大并发异步嵌入进程数 16
llm_model_func callable LLM生成的函数 gpt_4o_mini_complete
llm_model_name str 用于生成的LLM模型名称 meta-llama/Llama-3.2-1B-Instruct
llm_model_max_token_size int LLM生成的最大令牌大小影响实体关系摘要 32768默认值由环境变量MAX_TOKENS更改
llm_model_max_async int 最大并发异步LLM进程数 4默认值由环境变量MAX_ASYNC更改
llm_model_kwargs dict LLM生成的附加参数
vector_db_storage_cls_kwargs dict 向量数据库的附加参数,如设置节点和关系检索的阈值 cosine_better_than_threshold: 0.2默认值由环境变量COSINE_THRESHOLD更改
enable_llm_cache bool 如果为TRUE将LLM结果存储在缓存中重复的提示返回缓存的响应 TRUE
enable_llm_cache_for_entity_extract bool 如果为TRUE将实体提取的LLM结果存储在缓存中适合初学者调试应用程序 TRUE
addon_params dict 附加参数,例如{"example_number": 1, "language": "Simplified Chinese", "entity_types": ["organization", "person", "geo", "event"], "insert_batch_size": 10}:设置示例限制、输出语言和文档处理的批量大小 example_number: 所有示例, language: English, insert_batch_size: 10
convert_response_to_json_func callable 未使用 convert_response_to_json
embedding_cache_config dict 问答缓存的配置。包含三个参数:enabled:布尔值,启用/禁用缓存查找功能。启用时,系统将在生成新答案之前检查缓存的响应。similarity_threshold浮点值0-1相似度阈值。当新问题与缓存问题的相似度超过此阈值时将直接返回缓存的答案而不调用LLM。use_llm_check:布尔值,启用/禁用LLM相似度验证。启用时在返回缓存答案之前将使用LLM作为二次检查来验证问题之间的相似度。 默认:{"enabled": False, "similarity_threshold": 0.95, "use_llm_check": False}

错误处理

点击查看错误处理详情

API包括全面的错误处理

  • 文件未找到错误404
  • 处理错误500
  • 支持多种文件编码UTF-8和GBK

LightRAG API

LightRAG服务器旨在提供Web UI和API支持。有关LightRAG服务器的更多信息请参阅LightRAG服务器

知识图谱可视化

LightRAG服务器提供全面的知识图谱可视化功能。它支持各种重力布局、节点查询、子图过滤等。有关LightRAG服务器的更多信息请参阅LightRAG服务器

iShot_2025-03-23_12.40.08

评估

数据集

LightRAG使用的数据集可以从TommyChien/UltraDomain下载。

生成查询

LightRAG使用以下提示生成高级查询相应的代码在example/generate_query.py中。

提示
给定以下数据集描述

{description}

请识别5个可能会使用此数据集的潜在用户对于每个用户列出他们会使用此数据集执行的5个任务然后对于每个用户任务组合生成5个需要对整个数据集有高级理解的问题

按以下结构输出结果
- 用户1[用户描述]
    - 任务1[任务描述]
        - 问题1
        - 问题2
        - 问题3
        - 问题4
        - 问题5
    - 任务2[任务描述]
        ...
    - 任务5[任务描述]
- 用户2[用户描述]
    ...
- 用户5[用户描述]
    ...

批量评估

为了评估两个RAG系统在高级查询上的性能LightRAG使用以下提示具体代码可在example/batch_eval.py中找到。

提示
---角色---
您是一位专家负责根据三个标准评估同一问题的两个答案**全面性****多样性****赋能性**
---目标---
您将根据三个标准评估同一问题的两个答案**全面性****多样性****赋能性**

- **全面性**答案提供了多少细节来涵盖问题的所有方面和细节
- **多样性**答案在提供关于问题的不同视角和见解方面有多丰富多样
- **赋能性**答案在多大程度上帮助读者理解并对主题做出明智判断

对于每个标准选择更好的答案答案1或答案2并解释原因然后根据这三个类别选择总体赢家

这是问题
{query}

这是两个答案

**答案1**
{answer1}

**答案2**
{answer2}

使用上述三个标准评估两个答案并为每个标准提供详细解释

以下列JSON格式输出您的评估

{{
    "全面性": {{
        "获胜者": "[答案1或答案2]",
        "解释": "[在此提供解释]"
    }},
    "赋能性": {{
        "获胜者": "[答案1或答案2]",
        "解释": "[在此提供解释]"
    }},
    "总体获胜者": {{
        "获胜者": "[答案1或答案2]",
        "解释": "[根据三个标准总结为什么这个答案是总体获胜者]"
    }}
}}

总体性能表

农业 计算机科学 法律 混合
NaiveRAG LightRAG NaiveRAG LightRAG NaiveRAG LightRAG NaiveRAG LightRAG
全面性 32.4% 67.6% 38.4% 61.6% 16.4% 83.6% 38.8% 61.2%
多样性 23.6% 76.4% 38.0% 62.0% 13.6% 86.4% 32.4% 67.6%
赋能性 32.4% 67.6% 38.8% 61.2% 16.4% 83.6% 42.8% 57.2%
总体 32.4% 67.6% 38.8% 61.2% 15.2% 84.8% 40.0% 60.0%
RQ-RAG LightRAG RQ-RAG LightRAG RQ-RAG LightRAG RQ-RAG LightRAG
全面性 31.6% 68.4% 38.8% 61.2% 15.2% 84.8% 39.2% 60.8%
多样性 29.2% 70.8% 39.2% 60.8% 11.6% 88.4% 30.8% 69.2%
赋能性 31.6% 68.4% 36.4% 63.6% 15.2% 84.8% 42.4% 57.6%
总体 32.4% 67.6% 38.0% 62.0% 14.4% 85.6% 40.0% 60.0%
HyDE LightRAG HyDE LightRAG HyDE LightRAG HyDE LightRAG
全面性 26.0% 74.0% 41.6% 58.4% 26.8% 73.2% 40.4% 59.6%
多样性 24.0% 76.0% 38.8% 61.2% 20.0% 80.0% 32.4% 67.6%
赋能性 25.2% 74.8% 40.8% 59.2% 26.0% 74.0% 46.0% 54.0%
总体 24.8% 75.2% 41.6% 58.4% 26.4% 73.6% 42.4% 57.6%
GraphRAG LightRAG GraphRAG LightRAG GraphRAG LightRAG GraphRAG LightRAG
全面性 45.6% 54.4% 48.4% 51.6% 48.4% 51.6% 50.4% 49.6%
多样性 22.8% 77.2% 40.8% 59.2% 26.4% 73.6% 36.0% 64.0%
赋能性 41.2% 58.8% 45.2% 54.8% 43.6% 56.4% 50.8% 49.2%
总体 45.2% 54.8% 48.0% 52.0% 47.2% 52.8% 50.4% 49.6%

复现

所有代码都可以在./reproduce目录中找到。

步骤0 提取唯一上下文

首先,我们需要提取数据集中的唯一上下文。

代码
def extract_unique_contexts(input_directory, output_directory):

    os.makedirs(output_directory, exist_ok=True)

    jsonl_files = glob.glob(os.path.join(input_directory, '*.jsonl'))
    print(f"找到{len(jsonl_files)}个JSONL文件。")

    for file_path in jsonl_files:
        filename = os.path.basename(file_path)
        name, ext = os.path.splitext(filename)
        output_filename = f"{name}_unique_contexts.json"
        output_path = os.path.join(output_directory, output_filename)

        unique_contexts_dict = {}

        print(f"处理文件:{filename}")

        try:
            with open(file_path, 'r', encoding='utf-8') as infile:
                for line_number, line in enumerate(infile, start=1):
                    line = line.strip()
                    if not line:
                        continue
                    try:
                        json_obj = json.loads(line)
                        context = json_obj.get('context')
                        if context and context not in unique_contexts_dict:
                            unique_contexts_dict[context] = None
                    except json.JSONDecodeError as e:
                        print(f"文件{filename}{line_number}行JSON解码错误{e}")
        except FileNotFoundError:
            print(f"未找到文件:{filename}")
            continue
        except Exception as e:
            print(f"处理文件{filename}时发生错误:{e}")
            continue

        unique_contexts_list = list(unique_contexts_dict.keys())
        print(f"文件{filename}中有{len(unique_contexts_list)}个唯一的`context`条目。")

        try:
            with open(output_path, 'w', encoding='utf-8') as outfile:
                json.dump(unique_contexts_list, outfile, ensure_ascii=False, indent=4)
            print(f"唯一的`context`条目已保存到:{output_filename}")
        except Exception as e:
            print(f"保存到文件{output_filename}时发生错误:{e}")

    print("所有文件已处理完成。")

步骤1 插入上下文

对于提取的上下文我们将它们插入到LightRAG系统中。

代码
def insert_text(rag, file_path):
    with open(file_path, mode='r') as f:
        unique_contexts = json.load(f)

    retries = 0
    max_retries = 3
    while retries < max_retries:
        try:
            rag.insert(unique_contexts)
            break
        except Exception as e:
            retries += 1
            print(f"插入失败,重试({retries}/{max_retries}),错误:{e}")
            time.sleep(10)
    if retries == max_retries:
        print("超过最大重试次数后插入失败")

步骤2 生成查询

我们从数据集中每个上下文的前半部分和后半部分提取令牌,然后将它们组合为数据集描述以生成查询。

代码
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')

def get_summary(context, tot_tokens=2000):
    tokens = tokenizer.tokenize(context)
    half_tokens = tot_tokens // 2

    start_tokens = tokens[1000:1000 + half_tokens]
    end_tokens = tokens[-(1000 + half_tokens):1000]

    summary_tokens = start_tokens + end_tokens
    summary = tokenizer.convert_tokens_to_string(summary_tokens)

    return summary

步骤3 查询

对于步骤2中生成的查询我们将提取它们并查询LightRAG。

代码
def extract_queries(file_path):
    with open(file_path, 'r') as f:
        data = f.read()

    data = data.replace('**', '')

    queries = re.findall(r'- Question \d+: (.+)', data)

    return queries

Star历史

Star History Chart

贡献

感谢所有贡献者!

🌟引用

@article{guo2024lightrag,
title={LightRAG: Simple and Fast Retrieval-Augmented Generation},
author={Zirui Guo and Lianghao Xia and Yanhua Yu and Tu Ao and Chao Huang},
year={2024},
eprint={2410.05779},
archivePrefix={arXiv},
primaryClass={cs.IR}
}

感谢您对我们工作的关注!