Eine einfache, leicht zu hackende GraphRAG-Implementierung
? GraphRAG ist gut und leistungsstark, aber die offizielle Implementierung ist schwer/schmerzhaft zu lesen oder zu hacken .
? Dieses Projekt bietet ein kleineres, schnelleres und saubereres GraphRAG , behält aber die Kernfunktionalität bei (siehe Benchmark und Probleme).
? Ohne tests
und Eingabeaufforderungen umfasst nano-graphrag
etwa 1100 Codezeilen .
? Klein und doch tragbar (faiss, neo4j, ollama...), asynchron und vollständig typisiert.
Von der Quelle installieren (empfehlen)
# clone this repo first
cd nano-graphrag
pip install -e .
Von PyPi installieren
pip install nano-graphrag
Tipp
Bitte legen Sie den OpenAI-API-Schlüssel in der Umgebung fest: export OPENAI_API_KEY="sk-..."
.
Tipp
Wenn Sie die Azure OpenAI-API verwenden, lesen Sie .env.example, um Ihr Azure OpenAI festzulegen. Übergeben Sie dann GraphRAG(...,using_azure_openai=True,...)
zur Aktivierung.
Tipp
Wenn Sie die Amazon Bedrock-API verwenden, stellen Sie bitte sicher, dass Ihre Anmeldeinformationen mithilfe von Befehlen wie aws configure
ordnungsgemäß festgelegt sind. Aktivieren Sie es dann, indem Sie es wie folgt konfigurieren: 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",...)
. Sehen Sie sich ein Beispielskript an.
Tipp
Wenn Sie keinen Schlüssel haben, sehen Sie sich dieses Beispiel für die Verwendung transformers
und ollama
an. Wenn Sie ein anderes LLM- oder Einbettungsmodell verwenden möchten, überprüfen Sie die Fortschritte.
Laden Sie ein Exemplar von A Christmas Carol von Charles Dickens herunter:
curl https://raw.githubusercontent.com/gusye1234/nano-graphrag/main/tests/mock_data.txt > ./book.txt
Verwenden Sie das folgende Python-Snippet:
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" )))
Wenn Sie das nächste Mal ein GraphRAG
aus demselben working_dir
initialisieren, werden alle Kontexte automatisch neu geladen.
graph_func . insert ([ "TEXT1" , "TEXT2" ,...])
nano-graphrag
unterstützt inkrementelles Einfügen, es werden keine doppelten Berechnungen oder Daten hinzugefügt:
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
verwendet den MD5-Hash des Inhalts als Schlüssel, sodass kein duplizierter Block vorhanden ist.Bei jedem Einfügen werden jedoch die Communities des Diagramms neu berechnet und die Community-Berichte werden neu generiert
nano-graphrag
unterstützt auch naive RAG-Einfügungen und -Abfragen:
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" )
)
Für jede Methode NAME(...)
gibt es eine entsprechende asynchrone Methode aNAME(...)
await graph_func . ainsert (...)
await graph_func . aquery (...)
...
GraphRAG
und QueryParam
sind dataclass
in Python. Verwenden Sie help(GraphRAG)
und help(QueryParam)
um alle verfügbaren Parameter anzuzeigen! Oder sehen Sie sich den Abschnitt „Erweiterte Optionen“ an, um einige Optionen zu sehen.
Nachfolgend finden Sie die Komponenten, die Sie verwenden können:
Typ | Was | Wo |
---|---|---|
LLM | OpenAI | Eingebaut |
Amazonas-Grundgestein | Eingebaut | |
DeepSeek | Beispiele | |
ollama | Beispiele | |
Einbetten | OpenAI | Eingebaut |
Amazonas-Grundgestein | Eingebaut | |
Satztransformatoren | Beispiele | |
Vektordatenbank | nano-vectordb | Eingebaut |
hnswlib | Eingebaut, Beispiele | |
milvus-lite | Beispiele | |
faiss | Beispiele | |
Diagrammspeicher | networkx | Eingebaut |
neo4j | Integriert (doc) | |
Visualisierung | graphml | Beispiele |
Chunking | nach Tokengröße | Eingebaut |
durch Textsplitter | Eingebaut |
Built-in
bedeutet, dass wir diese Implementierung in nano-graphrag
haben. examples
bedeutet, dass wir diese Implementierung in einem Tutorial im Beispielordner haben.
Schauen Sie sich Beispiele/Benchmarks an, um einige Vergleiche zwischen Komponenten zu sehen.
Es ist jederzeit willkommen, weitere Komponenten beizusteuern.
GraphRAG(...,always_create_working_dir=False,...)
überspringt den Schritt zum Erstellen des Verzeichnisses. Verwenden Sie es, wenn Sie alle Ihre Komponenten auf Nicht-Dateispeicher umstellen. graph_func.query
gibt die endgültige Antwort ohne Streaming zurück.
Wenn Sie nano-graphrag
in Ihr Projekt einbinden möchten, können Sie param=QueryParam(..., only_need_context=True,...)
verwenden, wodurch nur der vom Diagramm abgerufene Kontext zurückgegeben wird, etwa so:
# 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...
...
Sie können diesen Kontext in Ihre benutzerdefinierte Eingabeaufforderung integrieren.
nano-graphrag
verwendet Eingabeaufforderungen aus dem Diktierobjekt nano_graphrag.prompt.PROMPTS
. Sie können damit spielen und jede darin enthaltene Eingabeaufforderung ersetzen.
Einige wichtige Hinweise:
PROMPTS["entity_extraction"]
wird verwendet, um die Entitäten und Beziehungen aus einem Textblock zu extrahieren.PROMPTS["community_report"]
wird verwendet, um die Beschreibung des Diagrammclusters zu organisieren und zusammenzufassen.PROMPTS["local_rag_response"]
ist die System-Eingabeaufforderungsvorlage der lokalen Suchgenerierung.PROMPTS["global_reduce_rag_response"]
ist die System-Eingabeaufforderungsvorlage der globalen Suchgenerierung.PROMPTS["fail_response"]
ist die Fallback-Antwort, wenn nichts mit der Benutzerabfrage zusammenhängt. nano-graphrag
können Sie Ihre eigene Chunking-Methode anpassen, sehen Sie sich das Beispiel an.
Wechseln Sie zur integrierten Textsplitter-Chunking-Methode:
from nano_graphrag . _op import chunking_by_seperators
GraphRAG (..., chunk_func = chunking_by_seperators ,...)
Im nano-graphrag
benötigen wir zwei Arten von LLM, ein großartiges und ein günstiges. Ersteres wird zum Planen und Reagieren verwendet, letzteres dient der Zusammenfassung. Standardmäßig ist die beste Version gpt-4o
und die günstige Version ist gpt-4o-mini
Sie können Ihre eigene LLM-Funktion implementieren (siehe _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
Ersetzen Sie die Standardeinstellung durch:
# 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 = ...)
Sie können sich auf dieses Beispiel beziehen, das deepseek-chat
als LLM-Modell verwendet
Sie können sich auf dieses Beispiel beziehen, das ollama
als LLM-Modell verwendet
nano-graphrag
verwendet best_model_func
, um JSON mit den Parametern "response_format": {"type": "json_object"}
auszugeben. Es gibt jedoch einige Open-Source-Modelle, die möglicherweise instabiles JSON erzeugen.
nano-graphrag
führt eine Post-Process-Schnittstelle ein, mit der Sie die Antwort in JSON konvertieren können. Die Signatur dieser Funktion ist unten:
def YOUR_STRING_TO_JSON_FUNC ( response : str ) -> dict :
"Convert the string response to JSON"
...
Und übergeben Sie Ihre eigene Funktion durch GraphRAG(...convert_response_to_json_func=YOUR_STRING_TO_JSON_FUNC,...)
.
Sie können beispielsweise auf json_repair verweisen, um die von LLM zurückgegebene JSON-Zeichenfolge zu reparieren.
Sie können die Standardeinbettungsfunktionen durch jede _utils.EmbedddingFunc
-Instanz ersetzen.
Standardmäßig wird beispielsweise die OpenAI-Einbettungs-API verwendet:
@ 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 ])
Ersetzen Sie die Standardeinbettungsfunktion durch:
GraphRAG ( embedding_func = your_embed_func , embedding_batch_num = ..., embedding_func_max_async = ...)
Sie können sich auf ein Beispiel beziehen, das sentence-transformer
verwendet, um Einbettungen lokal zu berechnen.
Sie können alle speicherbezogenen Komponenten durch Ihre eigene Implementierung ersetzen. nano-graphrag
verwendet hauptsächlich drei Arten von Speicher:
base.BaseKVStorage
zum Speichern von Schlüssel-JSON-Datenpaaren
GraphRAG(.., key_string_value_json_storage_cls=YOURS,...)
base.BaseVectorStorage
zur Indizierung von Einbettungen
nano-vectordb
als Backend.hnswlib
Speicher, sehen Sie sich dieses Beispiel an.milvus-lite
als Backend implementiert (nicht verfügbar unter Windows).GraphRAG(.., vector_db_storage_cls=YOURS,...)
base.BaseGraphStorage
zum Speichern von Wissensgraphen
networkx
als Backend.Neo4jStorage
für Graphen, schauen Sie sich dieses Tutorial an.GraphRAG(.., graph_storage_cls=YOURS,...)
Detaillierte Schnittstellen für die einzelnen Komponenten finden Sie in nano_graphrag.base
.
Überprüfen Sie die FQA.
Siehe ROADMAP.md
nano-graphrag
ist offen für jede Art von Beitrag. Lesen Sie dies, bevor Sie einen Beitrag leisten.
nano-graphrag
verwendetenWillkommen bei Pull Requests, wenn Ihr Projekt
nano-graphrag
verwendet. Dies wird anderen helfen, diesem Repo zu vertrauen❤️
nano-graphrag
hat die covariates
von GraphRAG
nicht implementiertnano-graphrag
implementiert die globale Suche anders als das Original. Das Original verwendet einen Map-Reduce-ähnlichen Stil, um alle Communities in einen Kontext zu füllen, während nano-graphrag
nur die wichtigen und zentralen Top-K-Communities verwendet (verwenden Sie QueryParam.global_max_consider_community
zur Steuerung, standardmäßig 512 Communities).