diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml
index 7c12e0a278..aa05436996 100644
--- a/.github/workflows/linting.yaml
+++ b/.github/workflows/linting.yaml
@@ -27,4 +27,4 @@ jobs:
pip install pre-commit
- name: Run pre-commit
- run: pre-commit run --all-files
+ run: pre-commit run --all-files --show-diff-on-failure
diff --git a/README-zh.md b/README-zh.md
index e69de29bb2..d345562f07 100644
--- a/README-zh.md
+++ b/README-zh.md
@@ -0,0 +1,1424 @@
+# LightRAG: Simple and Fast Retrieval-Augmented Generation
+
+
+
+## 🎉 新闻
+
+- [X] [2025.03.18]🎯📢LightRAG现已支持引文功能。
+- [X] [2025.02.05]🎯📢我们团队发布了[VideoRAG](https://github.com/HKUDS/VideoRAG),用于理解超长上下文视频。
+- [X] [2025.01.13]🎯📢我们团队发布了[MiniRAG](https://github.com/HKUDS/MiniRAG),使用小型模型简化RAG。
+- [X] [2025.01.06]🎯📢现在您可以[使用PostgreSQL进行存储](#using-postgresql-for-storage)。
+- [X] [2024.12.31]🎯📢LightRAG现在支持[通过文档ID删除](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#delete)。
+- [X] [2024.11.25]🎯📢LightRAG现在支持无缝集成[自定义知识图谱](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#insert-custom-kg),使用户能够用自己的领域专业知识增强系统。
+- [X] [2024.11.19]🎯📢LightRAG的综合指南现已在[LearnOpenCV](https://learnopencv.com/lightrag)上发布。非常感谢博客作者。
+- [X] [2024.11.11]🎯📢LightRAG现在支持[通过实体名称删除实体](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#delete)。
+- [X] [2024.11.09]🎯📢推出[LightRAG Gui](https://lightrag-gui.streamlit.app),允许您插入、查询、可视化和下载LightRAG知识。
+- [X] [2024.11.04]🎯📢现在您可以[使用Neo4J进行存储](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#using-neo4j-for-storage)。
+- [X] [2024.10.29]🎯📢LightRAG现在通过`textract`支持多种文件类型,包括PDF、DOC、PPT和CSV。
+- [X] [2024.10.20]🎯📢我们为LightRAG添加了一个新功能:图形可视化。
+- [X] [2024.10.18]🎯📢我们添加了[LightRAG介绍视频](https://youtu.be/oageL-1I0GE)的链接。感谢作者!
+- [X] [2024.10.17]🎯📢我们创建了一个[Discord频道](https://discord.gg/yF2MmDJyGJ)!欢迎加入分享和讨论!🎉🎉
+- [X] [2024.10.16]🎯📢LightRAG现在支持[Ollama模型](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#quick-start)!
+- [X] [2024.10.15]🎯📢LightRAG现在支持[Hugging Face模型](https://github.com/HKUDS/LightRAG?tab=readme-ov-file#quick-start)!
+
+
+ 算法流程图
+
+
+
+*图1:LightRAG索引流程图 - 图片来源:[Source](https://learnopencv.com/lightrag/)*
+
+*图2:LightRAG检索和查询流程图 - 图片来源:[Source](https://learnopencv.com/lightrag/)*
+
+ 使用类OpenAI的API
+
+* LightRAG还支持类OpenAI的聊天/嵌入API:
+
+```python
+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`
+
+```python
+# 使用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:
+
+```python
+# 使用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. 拉取模型:
+
+```bash
+ollama pull qwen2
+```
+
+2. 显示模型文件:
+
+```bash
+ollama show --modelfile qwen2 > Modelfile
+```
+
+3. 编辑Modelfile,添加以下行:
+
+```bash
+PARAMETER num_ctx 32768
+```
+
+4. 创建修改后的模型:
+
+```bash
+ollama create -f Modelfile qwen2m
+```
+
+* **通过Ollama API设置`num_ctx`**
+
+您可以使用`llm_model_kwargs`参数配置ollama:
+
+```python
+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文档](lightrag/llm/Readme.md)
+
+**使用示例:**
+
+```python
+# 使用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()
+```
+
+**详细文档和示例,请参见:**
+
+- [LlamaIndex文档](lightrag/llm/Readme.md)
+- [直接OpenAI示例](examples/lightrag_llamaindex_direct_demo.py)
+- [LiteLLM代理示例](examples/lightrag_llamaindex_litellm_demo.py)
+
+ 概述和使用
+
+LightRAG提供了TokenTracker工具来跟踪和管理大模型的token消耗。这个功能对于控制API成本和优化性能特别有用。
+
+#### 使用方法
+
+```python
+from lightrag.utils import TokenTracker
+
+# 创建TokenTracker实例
+token_tracker = TokenTracker()
+
+# 方法1:使用上下文管理器(推荐)
+# 适用于需要自动跟踪token使用的场景
+with token_tracker:
+ result1 = await llm_model_func("你的问题1")
+ result2 = await llm_model_func("你的问题2")
+
+# 方法2:手动添加token使用记录
+# 适用于需要更精细控制token统计的场景
+token_tracker.reset()
+
+rag.insert()
+
+rag.query("你的问题1", param=QueryParam(mode="naive"))
+rag.query("你的问题2", param=QueryParam(mode="mix"))
+
+# 显示总token使用量(包含插入和查询操作)
+print("Token usage:", token_tracker.get_usage())
+```
+
+#### 使用建议
+- 在长会话或批量操作中使用上下文管理器,可以自动跟踪所有token消耗
+- 对于需要分段统计的场景,使用手动模式并适时调用reset()
+- 定期检查token使用情况,有助于及时发现异常消耗
+- 在开发测试阶段积极使用此功能,以便优化生产环境的成本
+
+#### 实际应用示例
+您可以参考以下示例来实现token统计:
+- `examples/lightrag_gemini_track_token_demo.py`:使用Google Gemini模型的token统计示例
+- `examples/lightrag_siliconcloud_track_token_demo.py`:使用SiliconCloud模型的token统计示例
+
+这些示例展示了如何在不同模型和场景下有效地使用TokenTracker功能。
+
+ 基本插入
+
+```python
+# 基本插入
+rag.insert("文本")
+```
+
+ 批量插入
+
+```python
+# 基本批量插入:一次插入多个文本
+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数量必须相同。
+
+```python
+# 插入单个文本,并为其提供ID
+rag.insert("文本1", ids=["文本1的ID"])
+
+# 插入多个文本,并为它们提供ID
+rag.insert(["文本1", "文本2",...], ids=["文本1的ID", "文本2的ID"])
+```
+
+使用管道插入
+
+`apipeline_enqueue_documents`和`apipeline_process_enqueue_documents`函数允许您对文档进行增量插入到图中。
+
+这对于需要在后台处理文档的场景很有用,同时仍允许主线程继续执行。
+
+并使用例程处理新文档。
+
+```python
+rag = LightRAG(..)
+
+await rag.apipeline_enqueue_documents(input)
+# 您的循环例程
+await rag.apipeline_process_enqueue_documents(input)
+```
+
+插入多文件类型支持
+
+`textract`支持读取TXT、DOCX、PPTX、CSV和PDF等文件类型。
+
+```python
+import textract
+
+file_path = 'TEXT.pdf'
+text_content = textract.process(file_path)
+
+rag.insert(text_content.decode('utf-8'))
+```
+
+引文功能
+
+通过提供文件路径,系统确保可以将来源追溯到其原始文档。
+
+```python
+# 定义文档及其文件路径
+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
+
+```python
+export NEO4J_URI="neo4j://localhost:7687"
+export NEO4J_USERNAME="neo4j"
+export NEO4J_PASSWORD="password"
+
+# 为LightRAG设置日志记录器
+setup_logger("lightrag", level="INFO")
+
+# 当您启动项目时,请确保通过指定kg="Neo4JStorage"来覆盖默认的KG:NetworkX。
+
+# 注意:默认设置使用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`,但您也可以使用维度为`3072`的`OpenAIEmbedding`模型。
+
+```python
+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发布版](https://github.com/ShanGor/apache-age-windows/releases/tag/PG17%2Fv1.5.0-rc0),它在Linux/Mac上也很容易安装。
+* 如果您是初学者并想避免麻烦,推荐使用docker,请从这个镜像开始(请务必阅读概述):https://hub.docker.com/r/shangor/postgres-for-rag
+* 如何开始?参考:[examples/lightrag_zhipu_postgres_demo.py](https://github.com/HKUDS/LightRAG/blob/main/examples/lightrag_zhipu_postgres_demo.py)
+* 为AGE创建索引示例:(如有必要,将下面的`dickens`改为您的图名)
+ ```sql
+ 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来修复它。
+ >
+
+ 创建实体和关系
+
+```python
+# 创建新实体
+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
+})
+```
+
+ 编辑实体和关系
+
+```python
+# 编辑现有实体
+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
+})
+```
+
+ 合并实体及其关系
+
+LightRAG现在支持将多个实体合并为单个实体,自动处理所有关系:
+
+```python
+# 基本实体合并
+rag.merge_entities(
+ source_entities=["人工智能", "AI", "机器智能"],
+ target_entity="AI技术"
+)
+```
+
+使用自定义合并策略:
+
+```python
+# 为不同字段定义自定义合并策略
+rag.merge_entities(
+ source_entities=["约翰·史密斯", "史密斯博士", "J·史密斯"],
+ target_entity="约翰·史密斯",
+ merge_strategy={
+ "description": "concatenate", # 组合所有描述
+ "entity_type": "keep_first", # 保留第一个实体的类型
+ "source_id": "join_unique" # 组合所有唯一的源ID
+ }
+)
+```
+
+使用自定义目标实体数据:
+
+```python
+# 为合并后的实体指定确切值
+rag.merge_entities(
+ source_entities=["纽约", "NYC", "大苹果"],
+ target_entity="纽约市",
+ target_entity_data={
+ "entity_type": "LOCATION",
+ "description": "纽约市是美国人口最多的城市。",
+ }
+)
+```
+
+结合两种方法的高级用法:
+
+```python
+# 使用策略和自定义数据合并公司实体
+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响应缓存:
+
+```python
+# 清除所有缓存
+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"`:混合搜索缓存
+
+ 参数
+
+| **参数** | **类型** | **说明** | **默认值** |
+|--------------|----------|-----------------|-------------|
+| **working_dir** | `str` | 存储缓存的目录 | `lightrag_cache+timestamp` |
+| **kv_storage** | `str` | Storage type for documents and text chunks. Supported types: `JsonKVStorage`,`PGKVStorage`,`RedisKVStorage`,`MongoKVStorage` | `JsonKVStorage` |
+| **vector_storage** | `str` | Storage type for embedding vectors. Supported types: `NanoVectorDBStorage`,`PGVectorStorage`,`MilvusVectorDBStorage`,`ChromaVectorDBStorage`,`FaissVectorDBStorage`,`MongoVectorDBStorage`,`QdrantVectorDBStorage` | `NanoVectorDBStorage` |
+| **graph_storage** | `str` | Storage type for graph edges and nodes. Supported types: `NetworkXStorage`,`Neo4JStorage`,`PGGraphStorage`,`AGEStorage` | `NetworkXStorage` |
+| **doc_status_storage** | `str` | Storage type for documents process status. Supported types: `JsonDocStatusStorage`,`PGDocStatusStorage`,`MongoDocStatusStorage` | `JsonDocStatusStorage` |
+| **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)
+
+ 提示
+
+```python
+给定以下数据集描述:
+
+{description}
+
+请识别5个可能会使用此数据集的潜在用户。对于每个用户,列出他们会使用此数据集执行的5个任务。然后,对于每个(用户,任务)组合,生成5个需要对整个数据集有高级理解的问题。
+
+按以下结构输出结果:
+- 用户1:[用户描述]
+ - 任务1:[任务描述]
+ - 问题1:
+ - 问题2:
+ - 问题3:
+ - 问题4:
+ - 问题5:
+ - 任务2:[任务描述]
+ ...
+ - 任务5:[任务描述]
+- 用户2:[用户描述]
+ ...
+- 用户5:[用户描述]
+ ...
+```
+
+ 提示
+
+```python
+---角色---
+您是一位专家,负责根据三个标准评估同一问题的两个答案:**全面性**、**多样性**和**赋能性**。
+---目标---
+您将根据三个标准评估同一问题的两个答案:**全面性**、**多样性**和**赋能性**。
+
+- **全面性**:答案提供了多少细节来涵盖问题的所有方面和细节?
+- **多样性**:答案在提供关于问题的不同视角和见解方面有多丰富多样?
+- **赋能性**:答案在多大程度上帮助读者理解并对主题做出明智判断?
+
+对于每个标准,选择更好的答案(答案1或答案2)并解释原因。然后,根据这三个类别选择总体赢家。
+
+这是问题:
+{query}
+
+这是两个答案:
+
+**答案1:**
+{answer1}
+
+**答案2:**
+{answer2}
+
+使用上述三个标准评估两个答案,并为每个标准提供详细解释。
+
+以下列JSON格式输出您的评估:
+
+{{
+ "全面性": {{
+ "获胜者": "[答案1或答案2]",
+ "解释": "[在此提供解释]"
+ }},
+ "赋能性": {{
+ "获胜者": "[答案1或答案2]",
+ "解释": "[在此提供解释]"
+ }},
+ "总体获胜者": {{
+ "获胜者": "[答案1或答案2]",
+ "解释": "[根据三个标准总结为什么这个答案是总体获胜者]"
+ }}
+}}
+```
+
+ 代码
+
+```python
+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("所有文件已处理完成。")
+
+```
+
+ 代码
+
+```python
+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("超过最大重试次数后插入失败")
+```
+
+ 代码
+
+```python
+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
+```
+
+ 代码
+
+```python
+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
+```
+
+
+
+
+
+## 🌟引用
+
+```python
+@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}
+}
+```
+
+**感谢您对我们工作的关注!**
diff --git a/README.assets/b2aaf634151b4706892693ffb43d9093.png b/README.assets/b2aaf634151b4706892693ffb43d9093.png
new file mode 100644
index 0000000000..ac38781127
Binary files /dev/null and b/README.assets/b2aaf634151b4706892693ffb43d9093.png differ
diff --git a/README.assets/iShot_2025-03-23_12.40.08.png b/README.assets/iShot_2025-03-23_12.40.08.png
new file mode 100644
index 0000000000..c4250b1203
Binary files /dev/null and b/README.assets/iShot_2025-03-23_12.40.08.png differ
diff --git a/README.md b/README.md
index eb2575e731..c3a436501e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
| + |
-
-"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),e$=RegExp("^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$"),IA={},DA={};function t$(i){return he.call(DA,i)?!0:he.call(IA,i)?!1:e$.test(i)?DA[i]=!0:(IA[i]=!0,!1)}function uu(i,c,p){if(t$(c))if(p===null)i.removeAttribute(c);else{switch(typeof p){case"undefined":case"function":case"symbol":i.removeAttribute(c);return;case"boolean":var h=c.toLowerCase().slice(0,5);if(h!=="data-"&&h!=="aria-"){i.removeAttribute(c);return}}i.setAttribute(c,""+p)}}function du(i,c,p){if(p===null)i.removeAttribute(c);else{switch(typeof p){case"undefined":case"function":case"symbol":case"boolean":i.removeAttribute(c);return}i.setAttribute(c,""+p)}}function ma(i,c,p,h){if(h===null)i.removeAttribute(p);else{switch(typeof h){case"undefined":case"function":case"symbol":case"boolean":i.removeAttribute(p);return}i.setAttributeNS(c,p,""+h)}}function lr(i){switch(typeof i){case"bigint":case"boolean":case"number":case"string":case"undefined":return i;case"object":return i;default:return""}}function LA(i){var c=i.type;return(i=i.nodeName)&&i.toLowerCase()==="input"&&(c==="checkbox"||c==="radio")}function n$(i){var c=LA(i)?"checked":"value",p=Object.getOwnPropertyDescriptor(i.constructor.prototype,c),h=""+i[c];if(!i.hasOwnProperty(c)&&typeof p<"u"&&typeof p.get=="function"&&typeof p.set=="function"){var S=p.get,A=p.set;return Object.defineProperty(i,c,{configurable:!0,get:function(){return S.call(this)},set:function(z){h=""+z,A.call(this,z)}}),Object.defineProperty(i,c,{enumerable:p.enumerable}),{getValue:function(){return h},setValue:function(z){h=""+z},stopTracking:function(){i._valueTracker=null,delete i[c]}}}}function pu(i){i._valueTracker||(i._valueTracker=n$(i))}function MA(i){if(!i)return!1;var c=i._valueTracker;if(!c)return!0;var p=c.getValue(),h="";return i&&(h=LA(i)?i.checked?"true":"false":i.value),i=h,i!==p?(c.setValue(i),!0):!1}function fu(i){if(i=i||(typeof document<"u"?document:void 0),typeof i>"u")return null;try{return i.activeElement||i.body}catch{return i.body}}var r$=/[\n"\\]/g;function cr(i){return i.replace(r$,function(c){return"\\"+c.charCodeAt(0).toString(16)+" "})}function qf(i,c,p,h,S,A,z,q){i.name="",z!=null&&typeof z!="function"&&typeof z!="symbol"&&typeof z!="boolean"?i.type=z:i.removeAttribute("type"),c!=null?z==="number"?(c===0&&i.value===""||i.value!=c)&&(i.value=""+lr(c)):i.value!==""+lr(c)&&(i.value=""+lr(c)):z!=="submit"&&z!=="reset"||i.removeAttribute("value"),c!=null?Vf(i,z,lr(c)):p!=null?Vf(i,z,lr(p)):h!=null&&i.removeAttribute("value"),S==null&&A!=null&&(i.defaultChecked=!!A),S!=null&&(i.checked=S&&typeof S!="function"&&typeof S!="symbol"),q!=null&&typeof q!="function"&&typeof q!="symbol"&&typeof q!="boolean"?i.name=""+lr(q):i.removeAttribute("name")}function PA(i,c,p,h,S,A,z,q){if(A!=null&&typeof A!="function"&&typeof A!="symbol"&&typeof A!="boolean"&&(i.type=A),c!=null||p!=null){if(!(A!=="submit"&&A!=="reset"||c!=null))return;p=p!=null?""+lr(p):"",c=c!=null?""+lr(c):p,q||c===i.value||(i.value=c),i.defaultValue=c}h=h??S,h=typeof h!="function"&&typeof h!="symbol"&&!!h,i.checked=q?i.checked:!!h,i.defaultChecked=!!h,z!=null&&typeof z!="function"&&typeof z!="symbol"&&typeof z!="boolean"&&(i.name=z)}function Vf(i,c,p){c==="number"&&fu(i.ownerDocument)===i||i.defaultValue===""+p||(i.defaultValue=""+p)}function Di(i,c,p,h){if(i=i.options,c){c={};for(var S=0;S
title"))),bn(A,h,p),A[En]=i,an(A),h=A;break e;case"link":var z=GC("link","href",S).get(h+(p.href||""));if(z){for(var q=0;q