😭 GraphRAG 功能强大,但官方的实现难以阅读或修改。
😊 本项目提供了一个更小、更快、更简洁的 GraphRAG,同时保留了核心功能(参见性能基准和已知问题)。
🎁 排除 tests 和提示词,nano-graphrag 大约只有 1100 行代码。
👌 小巧但可移植(支持 faiss、neo4j、ollama...),异步且完全类型化。
如果你正在寻找一个用于长期用户记忆的多用户 RAG 解决方案,可以看看这个项目:memobase :)
从源码安装(推荐)
# 先克隆此仓库
cd nano-graphrag
pip install -e .
从 PyPi 安装
pip install nano-graphrag
[!TIP]
请在环境中设置 OpenAI API 密钥:
export OPENAI_API_KEY="sk-..."。[!TIP]
如果你使用 Azure OpenAI API,请参考 .env.example 设置你的 Azure OpenAI 环境变量。然后通过GraphRAG(...,using_azure_openai=True,...)启用。[!TIP]
如果你使用 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",...)。参考示例脚本。[!TIP]
如果你没有任何 API 密钥,可以查看这个示例,它使用
transformers和ollama。如果你想使用其他 LLM 或嵌入模型,请查看高级用法。
下载查尔斯·狄更斯的《圣诞颂歌》副本:
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())
# 执行全局 GraphRAG 搜索
print(graph_func.query("这个故事的主要主题是什么?"))
# 执行局部 GraphRAG 搜索(我认为这是更好、更具扩展性的方式)
print(graph_func.query("这个故事的主要主题是什么?", param=QueryParam(mode="local")))
下次从相同的 working_dir 初始化 GraphRAG 时,它将自动重新加载所有上下文。
graph_func.insert(["TEXT1", "TEXT2",...])
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 哈希值作为键,因此不会有重复的文本块。
>
> 但是,每次插入时,图的社区都会重新计算,社区报告也会重新生成。
graph_func = GraphRAG(working_dir="./dickens", enable_naive_rag=True)
...
# 查询
print(rag.query(
"这个故事的主要主题是什么?",
param=QueryParam(mode="naive")
)
对于每个同步方法 NAME(...),都有一个对应的异步方法 aNAME(...)。
await graph_func.ainsert(...)
await graph_func.aquery(...)
...
GraphRAG 和 QueryParam 是 Python 中的 dataclass。使用 help(GraphRAG) 和 help(QueryParam) 查看所有可用参数!或者查看高级用法部分了解一些选项。
以下是你可以使用的组件:
| 类型 | 功能 | 实现位置 |
|---|---|---|
| LLM | OpenAI | 内置 |
| Amazon Bedrock | 内置 | |
| DeepSeek | 示例 | |
ollama |
示例 | |
| 嵌入模型 | OpenAI | 内置 |
| Amazon Bedrock | 内置 | |
| Sentence-transformers | 示例 | |
| 向量数据库 | nano-vectordb |
内置 |
hnswlib |
内置,示例 | |
milvus-lite |
示例 | |
| faiss | 示例 | |
| 图存储 | networkx |
内置 |
neo4j |
内置(文档) | |
| 可视化 | graphml | 示例 |
| 文本分块 | 按 token 大小 | 内置 |
| 按文本分割器 | 内置 |
内置 表示我们在 nano-graphrag 内部已有该实现。示例 表示我们在 examples 文件夹下的教程中有该实现。# 局部模式
-----报告-----
```csv
id, 内容
0, # FOX 新闻以及媒体和政治中的关键人物...
1, ...
```
...
# 全局模式
----分析师 3----
重要性分数:100
唐纳德·J·特朗普:经常被讨论与其政治活动相关...
...
你可以将这些上下文整合到你自定义的提示词中。
from nano_graphrag._op import chunking_by_seperators
GraphRAG(...,chunk_func=chunking_by_seperators,...)
async def my_llm_complete(
prompt, system_prompt=None, history_messages=[], **kwargs
) -> str:
# 如果有缓存 KV 数据库,则弹出
hashing_kv: BaseKVStorage = kwargs.pop("hashing_kv", None)
# 其余 kwargs 用于调用 LLM,例如 `max_tokens=xxx`
...
# 调用你的 LLM
response = await call_your_LLM(messages, **kwargs)
return response
替换默认的 LLM 函数:
# 如果需要,调整最大 token 数或最大异步请求数
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=...)
你可以参考这个[示例](./examples/using_deepseek_as_llm.py),它使用 [`deepseek-chat`](https://platform.deepseek.com/api-docs/) 作为 LLM 模型。
你可以参考这个[示例](./examples/using_ollama_as_llm.py),它使用 [`ollama`](https://github.com/ollama/ollama) 作为 LLM 模型。
#### JSON 输出
`nano-graphrag` 将使用 `best_model_func` 并附带参数 `"response_format": {"type": "json_object"}` 来输出 JSON。但一些开源模型可能产生不稳定的 JSON。
`nano-graphrag` 为你提供了一个后处理接口,用于将响应转换为 JSON。此函数的签名如下:
def YOUR_STRING_TO_JSON_FUNC(response: str) -> dict:
"将字符串响应转换为 JSON"
...
并通过 `GraphRAG(...convert_response_to_json_func=YOUR_STRING_TO_JSON_FUNC,...)` 传递你自己的函数。
例如,你可以参考 [json_repair](https://github.com/mangiucugna/json_repair) 来修复 LLM 返回的 JSON 字符串。
@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=...)
你可以参考这个[示例](./examples/using_local_embedding_model.py),它使用 `sentence-transformer` 在本地计算嵌入向量。
查看 FQA。
查看 ROADMAP.md
nano-graphrag 欢迎任何形式的贡献。在贡献之前请阅读此文档。
nano-graphrag 的项目如果你的项目使用了
nano-graphrag,欢迎提交 Pull Request,这将帮助其他人信任这个仓库 ❤️
nano-graphrag 没有实现 GraphRAG 的 covariates 功能。nano-graphrag 的全局搜索实现与原版不同。原版使用类似 map-reduce 的风格将所有社区信息填入上下文,而 nano-graphrag 只使用前 K 个重要且核心的社区(使用 QueryParam.global_max_consider_community 控制,默认为 512 个社区)。