一个简单、易于破解的 GraphRAG 实现
? GraphRAG 很好而且很强大,但是官方的实现很难/很难阅读或破解。
?该项目提供了更小、更快、更干净的 GraphRAG ,同时保留了核心功能(请参阅基准测试和问题)。
?不包括tests
和提示, nano-graphrag
大约有1100 行代码。
?小而便携(faiss、neo4j、ollama...)、异步且完全类型化。
从源安装(推荐)
# clone this repo first
cd nano-graphrag
pip install -e .
从 PyPi 安装
pip install nano-graphrag
提示
请在环境中设置 OpenAI API 密钥: export OPENAI_API_KEY="sk-..."
。
提示
如果您使用的是 Azure OpenAI API,请参阅 .env.example 来设置您的 azure openai。然后通过GraphRAG(...,using_azure_openai=True,...)
启用。
提示
如果您使用 Amazon Bedrock API,请确保通过aws configure
等命令正确设置您的凭证。然后通过如下配置启用它: GraphRAG(...,using_amazon_bedrock=True, best_model_id="us.anthropic.claude-3-sonnet-20240229-v1:0", cheap_model_id="us.anthropic.claude-3-haiku-20240307-v1:0",...)
。请参阅示例脚本。
提示
如果您没有任何密钥,请查看此使用transformers
和ollama
的示例。如果您想使用其他法学硕士或嵌入模型,请检查高级。
下载查尔斯·狄更斯的《圣诞颂歌》副本:
curl https://raw.githubusercontent.com/gusye1234/nano-graphrag/main/tests/mock_data.txt > ./book.txt
使用下面的 python 代码片段:
from nano_graphrag import GraphRAG , QueryParam
graph_func = GraphRAG ( working_dir = "./dickens" )
with open ( "./book.txt" ) as f :
graph_func . insert ( f . read ())
# Perform global graphrag search
print ( graph_func . query ( "What are the top themes in this story?" ))
# Perform local graphrag search (I think is better and more scalable one)
print ( graph_func . query ( "What are the top themes in this story?" , param = QueryParam ( mode = "local" )))
下次您从同一working_dir
初始化GraphRAG
时,它将自动重新加载所有上下文。
graph_func . insert ([ "TEXT1" , "TEXT2" ,...])
nano-graphrag
支持增量插入,不会添加重复计算或数据:
with open ( "./book.txt" ) as f :
book = f . read ()
half_len = len ( book ) // 2
graph_func . insert ( book [: half_len ])
graph_func . insert ( book [ half_len :])
nano-graphrag
使用内容的md5哈希作为密钥,因此不存在重复的块。但是,每次插入时,都会重新计算图的社区并重新生成社区报告
nano-graphrag
也支持 naive RAG 插入和查询:
graph_func = GraphRAG ( working_dir = "./dickens" , enable_naive_rag = True )
...
# Query
print ( rag . query (
"What are the top themes in this story?" ,
param = QueryParam ( mode = "naive" )
)
对于每个方法NAME(...)
,都有一个相应的异步方法aNAME(...)
await graph_func . ainsert (...)
await graph_func . aquery (...)
...
GraphRAG
和QueryParam
是 Python 中的dataclass
。使用help(GraphRAG)
和help(QueryParam)
查看所有可用参数!或者查看“高级”部分以查看一些选项。
以下是您可以使用的组件:
类型 | 什么 | 在哪里 |
---|---|---|
法学硕士 | 开放人工智能 | 内置 |
亚马逊基岩 | 内置 | |
深度搜索 | 例子 | |
ollama | 例子 | |
嵌入 | 开放人工智能 | 内置 |
亚马逊基岩 | 内置 | |
句子转换器 | 例子 | |
矢量数据库 | nano-vectordb | 内置 |
hnswlib | 内置,示例 | |
milvus-lite | 例子 | |
费斯 | 例子 | |
图存储 | networkx | 内置 |
neo4j | 内置(文档) | |
可视化 | 图形 | 例子 |
分块 | 按代币大小 | 内置 |
通过文本分割器 | 内置 |
Built-in
意味着我们在nano-graphrag
内部拥有该实现。 examples
意味着我们在示例文件夹下的教程中有该实现。
检查示例/基准以查看组件之间的一些比较。
始终欢迎贡献更多组件。
GraphRAG(...,always_create_working_dir=False,...)
将跳过目录创建步骤。如果您将所有组件切换到非文件存储,请使用它。graph_func.query
返回最终答案,无需流式传输。
如果您想在项目中交互nano-graphrag
,您可以使用param=QueryParam(..., only_need_context=True,...)
,它只会返回从图中检索到的上下文,如下所示:
# Local mode
-----Reports-----
```csv
id, content
0, # FOX News and Key Figures in Media and Politics...
1, ...
```
...
# Global mode
----Analyst 3----
Importance Score: 100
Donald J. Trump: Frequently discussed in relation to his political activities...
...
您可以将该上下文集成到您的自定义提示中。
nano-graphrag
使用来自nano_graphrag.prompt.PROMPTS
dict 对象的提示。您可以使用它并替换里面的任何提示。
一些重要提示:
PROMPTS["entity_extraction"]
用于从文本块中提取实体和关系。PROMPTS["community_report"]
用于组织和总结图集群的描述。PROMPTS["local_rag_response"]
是本地搜索生成的系统提示模板。PROMPTS["global_reduce_rag_response"]
是全局搜索生成的系统提示模板。PROMPTS["fail_response"]
是当没有任何内容与用户查询相关时的后备响应。nano-graphrag
允许您自定义自己的分块方法,请查看示例。
切换到内置文本分割器分块方法:
from nano_graphrag . _op import chunking_by_seperators
GraphRAG (..., chunk_func = chunking_by_seperators ,...)
在nano-graphrag
中,我们需要两种类型的法学硕士,一种是优秀的,一种是廉价的。前者用于计划和应对,后者用于总结。默认情况下,好的型号是gpt-4o
,便宜的型号是gpt-4o-mini
您可以实现自己的LLM功能(参考_llm.gpt_4o_complete
):
async def my_llm_complete (
prompt , system_prompt = None , history_messages = [], ** kwargs
) -> str :
# pop cache KV database if any
hashing_kv : BaseKVStorage = kwargs . pop ( "hashing_kv" , None )
# the rest kwargs are for calling LLM, for example, `max_tokens=xxx`
...
# YOUR LLM calling
response = await call_your_LLM ( messages , ** kwargs )
return response
将默认值替换为:
# Adjust the max token size or the max async requests if needed
GraphRAG ( best_model_func = my_llm_complete , best_model_max_token_size = ..., best_model_max_async = ...)
GraphRAG ( cheap_model_func = my_llm_complete , cheap_model_max_token_size = ..., cheap_model_max_async = ...)
你可以参考这个使用deepseek-chat
作为LLM模型的例子
你可以参考这个例子,使用ollama
作为LLM模型
nano-graphrag
将使用best_model_func
输出 JSON,参数为"response_format": {"type": "json_object"}
。然而,有一些开源模型可能会产生不稳定的 JSON。
nano-graphrag
引入了一个后处理接口,供您将响应转换为 JSON。该函数的签名如下:
def YOUR_STRING_TO_JSON_FUNC ( response : str ) -> dict :
"Convert the string response to JSON"
...
并通过GraphRAG(...convert_response_to_json_func=YOUR_STRING_TO_JSON_FUNC,...)
传递您自己的函数。
例如,您可以参考json_repair来修复LLM返回的JSON字符串。
您可以将默认嵌入函数替换为任何_utils.EmbedddingFunc
实例。
例如,默认使用 OpenAI 嵌入 API:
@ wrap_embedding_func_with_attrs ( embedding_dim = 1536 , max_token_size = 8192 )
async def openai_embedding ( texts : list [ str ]) -> np . ndarray :
openai_async_client = AsyncOpenAI ()
response = await openai_async_client . embeddings . create (
model = "text-embedding-3-small" , input = texts , encoding_format = "float"
)
return np . array ([ dp . embedding for dp in response . data ])
将默认嵌入函数替换为:
GraphRAG ( embedding_func = your_embed_func , embedding_batch_num = ..., embedding_func_max_async = ...)
您可以参考使用sentence-transformer
在本地计算嵌入的示例。
你可以将所有与存储相关的组件替换为你自己的实现, nano-graphrag
主要使用三种存储:
base.BaseKVStorage
用于存储 key-json 对数据
GraphRAG(.., key_string_value_json_storage_cls=YOURS,...)
用于索引嵌入的base.BaseVectorStorage
nano-vectordb
作为后端。hnswlib
存储,请查看这个示例。milvus-lite
作为后端的示例(在 Windows 中不可用)。GraphRAG(.., vector_db_storage_cls=YOURS,...)
base.BaseGraphStorage
用于存储知识图谱
networkx
作为后端。Neo4jStorage
用于图形,请查看本教程。GraphRAG(.., graph_storage_cls=YOURS,...)
您可以参考nano_graphrag.base
查看各个组件的详细接口。
检查常见问题解答。
请参阅路线图.md
nano-graphrag
对任何形式的贡献持开放态度。在贡献之前请阅读本文。
nano-graphrag
的项目如果您的项目使用
nano-graphrag
,欢迎拉取请求,这将有助于其他人信任这个仓库❤️
nano-graphrag
没有实现GraphRAG
的covariates
功能nano-graphrag
实现了与原来不同的全局搜索。原始使用类似map-reduce的风格将所有社区填充到上下文中,而nano-graphrag
仅使用top-K重要和中心社区(使用QueryParam.global_max_consider_community
来控制,默认为512个社区)。