Une implémentation GraphRAG simple et facile à pirater
? GraphRAG est bon et puissant, mais l'implémentation officielle est difficile/douloureuse à lire ou à pirater .
? Ce projet fournit un GraphRAG plus petit, plus rapide et plus propre , tout en restant la fonctionnalité de base (voir benchmark et problèmes).
? Hors tests
et invites, nano-graphrag
représente environ 1 100 lignes de code .
? Petit mais portable (faiss, neo4j, ollama...), asynchrone et entièrement typé.
Installer à partir des sources (recommandé)
# clone this repo first
cd nano-graphrag
pip install -e .
Installer depuis PyPi
pip install nano-graphrag
Conseil
Veuillez définir la clé API OpenAI dans l'environnement : export OPENAI_API_KEY="sk-..."
.
Conseil
Si vous utilisez l'API Azure OpenAI, reportez-vous au .env.example pour définir votre Azure OpenAI. Passez ensuite GraphRAG(...,using_azure_openai=True,...)
pour l'activer.
Conseil
Si vous utilisez l'API Amazon Bedrock, assurez-vous que vos informations d'identification sont correctement définies via des commandes telles que aws configure
. Activez-le ensuite en configurant comme ceci : 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",...)
. Reportez-vous à un exemple de script.
Conseil
Si vous n'avez pas de clé, consultez cet exemple utilisant transformers
et ollama
. Si vous souhaitez utiliser un autre LLM ou modèle d'intégration, cochez Avancées.
téléchargez une copie de A Christmas Carol de Charles Dickens :
curl https://raw.githubusercontent.com/gusye1234/nano-graphrag/main/tests/mock_data.txt > ./book.txt
Utilisez l'extrait python ci-dessous :
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" )))
La prochaine fois que vous initialiserez un GraphRAG
à partir du même working_dir
, il rechargera automatiquement tous les contextes.
graph_func . insert ([ "TEXT1" , "TEXT2" ,...])
nano-graphrag
prend en charge l'insertion incrémentielle, aucun calcul ou donnée dupliqué ne sera ajouté :
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
utilise le hachage md5 du contenu comme clé, il n'y a donc pas de morceau dupliqué.Cependant, à chaque insertion, les communautés du graphique seront recalculées et les rapports de communauté seront régénérés.
nano-graphrag
prend également en charge l'insertion et les requêtes RAG naïves :
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" )
)
Pour chaque méthode NAME(...)
, il existe une méthode asynchrone correspondante aNAME(...)
await graph_func . ainsert (...)
await graph_func . aquery (...)
...
GraphRAG
et QueryParam
sont dataclass
en Python. Utilisez help(GraphRAG)
et help(QueryParam)
pour voir tous les paramètres disponibles ! Ou consultez la section Avancées pour voir quelques options.
Voici les composants que vous pouvez utiliser :
Taper | Quoi | Où |
---|---|---|
LLM | OpenAI | Intégré |
Socle amazonien | Intégré | |
Recherche profonde | exemples | |
ollama | exemples | |
Intégration | OpenAI | Intégré |
Socle amazonien | Intégré | |
Transformateurs de phrases | exemples | |
Base de données vectorielles | nano-vectordb | Intégré |
hnswlib | Exemples intégrés | |
milvus-lite | exemples | |
faisss | exemples | |
Stockage de graphiques | networkx | Intégré |
neo4j | Intégré(doc) | |
Visualisation | graphique | exemples |
Morceau | par taille de jeton | Intégré |
par séparateur de texte | Intégré |
Built-in
signifie que nous avons cette implémentation dans nano-graphrag
. examples
signifie que nous avons cette implémentation dans un didacticiel sous le dossier exemples.
Consultez des exemples/références pour voir quelques comparaisons entre les composants.
Toujours bienvenue pour contribuer à plus de composants.
GraphRAG(...,always_create_working_dir=False,...)
ignorera l'étape de création du répertoire. Utilisez-le si vous basculez tous vos composants vers des stockages autres que des fichiers. graph_func.query
renvoie la réponse finale sans streaming.
Si vous souhaitez interagir avec nano-graphrag
dans votre projet, vous pouvez utiliser param=QueryParam(..., only_need_context=True,...)
, qui renverra uniquement le contexte récupéré du graphique, quelque chose comme :
# 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...
...
Vous pouvez intégrer ce contexte dans votre invite personnalisée.
nano-graphrag
utilise les invites de l'objet dict nano_graphrag.prompt.PROMPTS
. Vous pouvez jouer avec et remplacer n'importe quelle invite à l'intérieur.
Quelques invites importantes :
PROMPTS["entity_extraction"]
est utilisé pour extraire les entités et les relations d'un bloc de texte.PROMPTS["community_report"]
est utilisé pour organiser et résumer la description du cluster de graphiques.PROMPTS["local_rag_response"]
est le modèle d'invite système de la génération de recherche locale.PROMPTS["global_reduce_rag_response"]
est le modèle d'invite système de la génération de recherche globale.PROMPTS["fail_response"]
est la réponse de secours lorsque rien n'est lié à la requête de l'utilisateur. nano-graphrag
vous permet de personnaliser votre propre méthode de découpage, consultez l'exemple.
Passez à la méthode de segmentation de texte intégrée :
from nano_graphrag . _op import chunking_by_seperators
GraphRAG (..., chunk_func = chunking_by_seperators ,...)
Dans nano-graphrag
, nous avons besoin de deux types de LLM, un excellent et un bon marché. Le premier est utilisé pour planifier et répondre, le second est utilisé pour résumer. Par défaut, le meilleur est gpt-4o
et le moins cher est gpt-4o-mini
Vous pouvez implémenter votre propre fonction LLM (voir _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
Remplacez celui par défaut par :
# 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 = ...)
Vous pouvez vous référer à cet exemple qui utilise deepseek-chat
comme modèle LLM
Vous pouvez vous référer à cet exemple qui utilise ollama
comme modèle LLM
nano-graphrag
utilisera best_model_func
pour générer du JSON avec les paramètres "response_format": {"type": "json_object"}
. Cependant, certains modèles open source peuvent produire un JSON instable.
nano-graphrag
introduit une interface de post-traitement vous permettant de convertir la réponse en JSON. La signature de cette fonction est ci-dessous :
def YOUR_STRING_TO_JSON_FUNC ( response : str ) -> dict :
"Convert the string response to JSON"
...
Et transmettez votre propre fonction par GraphRAG(...convert_response_to_json_func=YOUR_STRING_TO_JSON_FUNC,...)
.
Par exemple, vous pouvez vous référer à json_repair pour réparer la chaîne JSON renvoyée par LLM.
Vous pouvez remplacer les fonctions d'intégration par défaut par n'importe quelle instance _utils.EmbedddingFunc
.
Par exemple, celui par défaut utilise l'API d'intégration OpenAI :
@ 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 ])
Remplacez la fonction d'intégration par défaut par :
GraphRAG ( embedding_func = your_embed_func , embedding_batch_num = ..., embedding_func_max_async = ...)
Vous pouvez vous référer à un exemple qui utilise sentence-transformer
pour calculer localement les intégrations.
Vous pouvez remplacer tous les composants liés au stockage par votre propre implémentation, nano-graphrag
utilise principalement trois types de stockage :
base.BaseKVStorage
pour stocker des paires de données clé-json
GraphRAG(.., key_string_value_json_storage_cls=YOURS,...)
base.BaseVectorStorage
pour l'indexation des incorporations
nano-vectordb
comme backend.hnswlib
intégré, consultez cet exemple.milvus-lite
comme backend (non disponible sous Windows).GraphRAG(.., vector_db_storage_cls=YOURS,...)
base.BaseGraphStorage
pour stocker le graphique de connaissances
networkx
comme backend.Neo4jStorage
intégré pour les graphiques, consultez ce tutoriel.GraphRAG(.., graph_storage_cls=YOURS,...)
Vous pouvez vous référer à nano_graphrag.base
pour voir les interfaces détaillées de chaque composant.
Vérifiez FQA.
Voir ROADMAP.md
nano-graphrag
est ouvert à tout type de contribution. Lisez ceci avant de contribuer.
nano-graphrag
Bienvenue dans les pull request si votre projet utilise
nano-graphrag
, cela aidera les autres à faire confiance à ce dépôt❤️
nano-graphrag
n'a pas implémenté la fonctionnalité covariates
de GraphRAG
nano-graphrag
implémente la recherche globale différente de l'original. L'original utilise un style de type map-reduce pour remplir toutes les communautés dans leur contexte, tandis que nano-graphrag
n'utilise que les communautés principales et centrales top-K (utilisez QueryParam.global_max_consider_community
pour contrôler, par défaut 512 communautés).