In this Story, I have a super quick tutorial showing you how to build a Multi-Strategy Graph Thinking to build a powerful agent chatbot for your business or personal use.
GraphRAG, which combines knowledge graph technology with RAG, is a hot spot in the field of LLM applications in the second half of this year.
I’ve been spending a lot of time poking around with GraphRag, and while they’re seriously cool, they’ve got some quirks.
One weekend, I built my own knowledge graph by creating nodes and edges, chunking the input document into tokens, recording the entities and relationships contained in each chunk, and utilising an LLM to generate the output.
Knowledge graphs can be fun, but they’re often broken. My knowledge graph relies on large language model (LLM) agents for graph traversal and retrieval — an approach that’s sensitive to how the traversal is initialised. It’s prone to entity linking errors and may not generalise well to custom (“bring-your-own”) knowledge graphs.
Many knowledge graphs are full of noisy, outdated, or missing information. It’s like trying to navigate using a broken map — with wrong street names and missing roads. These systems also struggle with complex questions that require multi-hop reasoning across multiple relationships, especially in large or intricate graphs. Worse, they often ignore other useful sources like text documents, which might contain better answers.
When a knowledge graph contains too much information, it can overwhelm large language models — especially those with limited context-handling capabilities. These models also struggle with specialised topics like medicine or temporal reasoning, which often require custom retrieval and reasoning strategies.
That’s where Bring Your Own Knowledge Graph comes in. It combines multiple retrieval strategies — such as entity linking, subgraph retrieval, and Cypher query execution — to gather richer and more relevant context. It also employs scoring-based methods to minimise the number of LLM calls while enhancing performance, dynamically fetching relevant graph data and providing the language model with improved contextual grounding for reasoning.
So, let me give you a quick demo of a live chatbot to show you what I mean.
Check Video
I will ask the chatbot a question: “What genre of film is associated with the place where Wynton Marsalis was born?” If you take a look at how the Agent generates the output, you’ll see that the agent loads the data from a CSV file and prints out how many nodes and edges the graph contains.
It utilises a knowledge graph to process the question, allowing the LLM to determine which entities, paths, and answer candidates are relevant, guided by the graph schema. It parses LLM artifacts and uses a fuzzy string matcher (FuzzyStringIndex) to connect the LLM's free-text entities to actual nodes in the graph.
Next it uses EntityLinker to match both the entities and the answer candidates back to the graph, ensuring that all reasoning is grounded in real dataAgenticRetriever, which uses the LLM to navigate the graph intelligently. It starts from the linked entities and selects which relations to follow, and PathRetriever goes beyond individual triplets and follows multi-hop reasoning paths.
Finally, it uses Bring Your Own Knowledge Graph to wrap everything together — linking, retrieving, and generating. It takes the question, runs all the necessary steps to gather graph-grounded evidence, and uses the LLM to generate a final answer.
What is BYOKG RAG?
“BYOKG (Bring Your Own Knowledge Graph)” is a framework designed to enhance knowledge graph question answering (KGQA) by integrating diverse external knowledge sources with large language models (LLMs). It leverages multiple graph retrieval strategies — including entity linking, subgraph extraction, and Cypher query execution — to gather relevant contextual information from various knowledge graphs.
BYOKG aims to enhance the accuracy, robustness, and generalisation of KGQA systems by integrating these retrieval techniques with the reasoning capabilities of LLMs, thereby enabling more precise and contextually grounded answers across diverse domains and knowledge bases.
How does it work?
As shown in the figure above, the BYOKG architecture consists of two core components: KG-Linker and Graph Retrievers.
**KG-Linker **is the core LLM-based component of the BYOKG-RAG framework that generates diverse graph artifacts instead of directly traversing knowledge graphs.
Given a user query, graph schema, and optional context, it uses a single LLM call to produce four key artifacts: extracted entities from the question, plausible relationship paths connecting those entities, executable graph queries (like OpenCypher), and draft candidate answers.
Graph Retrievers are the specialised toolkit in BYOKG-RAG that takes KG-Linker’s generated artifacts and performs actual graph operations on the knowledge graph.
It uses four main components: Entity Linking (maps entities to a graph using string/embedding matching), Path Retrieval (executes relation paths via graph traversal), Graph Query Retrieval (runs executable queries like OpenCypher), and Triplet Retrieval (finds relevant facts through agentic exploration or semantic scoring).
BYOKG RAG Vs GraphRag
BYOKG-RAG and GraphRAG are both frameworks for enhancing knowledge graph question answering, but they differ in design and flexibility.
BYOKG-RAG uses a multi-strategy retrieval approach — combining entity linking, agentic traversal, graph reranking, and text-based retrieval — that dynamically adapts to different KG structures and question types.
It is optimised for zero-shot and few-shot settings, requiring minimal training data, and includes a self-termination mechanism to stop retrieval once enough information is gathered.
In contrast, GraphRAG relies on supervised or fine-tuned retrievers trained on large labelled datasets to fetch relevant subgraphs in a single, static step. While GraphRAG can achieve high precision when trained effectively, it is less adaptable to new KGs or question types and often demands higher training costs.
Let’s start coding?
Before we dive into our application, we will create an ideal environment for the code to work. For this, we need to install the necessary Python libraries.
First, we will install the libraries that support the model. For this, we will do a pip install requirements. Since the demo uses the Claude models, you must first set the Bedrock API Key.
!pip install https://github.com/awslabs/graphrag-toolkit/archive/refs/tags/v3.10.7.zip#subdirectory=byokg-rag
The next step is the usual one, where we will import the relevant libraries, the significance of which will become evident as we proceed.
We initiate the code by importing classes from
The LocalKGStore class provides an interface to work with the knowledge graph
Graph Store
from graphrag_toolkit.byokg_rag.graphstore import LocalKGStore
graph_store = LocalKGStore()
graph_store.read_from_csv('freebase_tiny_kg.csv')
# Print graph statistics
schema = graph_store.get_schema()
number_of_nodes = len(graph_store.nodes())
number_of_edges = len(graph_store.get_triplets())
print(f"The graph has {number_of_nodes} nodes and {number_of_edges} edges.")
# Let's also see neighbor edges of node "Wynton Marsalis"
import random
sample_triplets = graph_store.get_one_hop_edges(["Wynton Marsalis"])
sample_triplets = random.sample(list(sample_triplets["Wynton Marsalis"].items()), 3)
print("Some neighboring edges of node 'Wynton Marsalis' are: ", sample_triplets)
They used a local knowledge graph to manage the knowledge graph data structure. I then read the data from the CSV file, which contains the structured triples (head, relation, tail) that define the knowledge graph.
They inspect the graph to extract the schema and calculate basic statistics, then they focus on the node "Wynton Marsalis" and retrieved its direct neighbours using the get_one_hop_edges() method.
This function returns all the edges connected to the node within one hop. They used Python random.sample() to randomly select three of these neighboring edges. Finally, I printed out these selected edges to showcase sample relationships connected to "Wynton Marsalis."
KG Linker
question = "What genre of film is associated with the place where Wynton Marsalis was born?"
answer = "Backstage Musical"
from graphrag_toolkit.byokg_rag.graph_connectors import KGLinker
from graphrag_toolkit.byokg_rag.llm import BedrockGenerator
# Initialize llm
llm_generator = BedrockGenerator(
model_name='us.anthropic.claude-3-5-sonnet-20240620-v1:0',
region_name='us-west-2')
kg_linker = KGLinker(graph_store=graph_store, llm_generator=llm_generator)
response = kg_linker.generate_response(
question=question,
schema=schema,
graph_context="Not provided. Use the above schema to understand the graph."
)
response
artifacts = kg_linker.parse_response(response)
artifacts
They ask the question, “What genre of film is associated with the place where Wynton Marsalis was born?” The expected answer was “Backstage Musical.” My goal was to enable the system to reason across multiple hops in the graph using semantic understanding from the LLM.
They use BedrockGenerator to connect to Amazon Bedrock and use the Claude 3.5 Sonnet model hosted in the us-west-2 region.
They built an GLinker instance that connects the graph data with LLM. The KGLinker serves as a bridge between structured knowledge and natural language understanding. I passed in the question, the graph schema (which outlines how entities and relations are organised), and a default message saying no explicit graph context is provided — encouraging the model to rely on schema-based reasoning.
They generate a structured LLM response using generate_response, which attempts to extract relevant paths or reasoning steps based on the question and parse the response, which extracted those meaningful artifacts such as entity paths or subgraph structures.
Entity Linking
from graphrag_toolkit.byokg_rag.indexing import FuzzyStringIndex
from graphrag_toolkit.byokg_rag.graph_retrievers import EntityLinker
# Add graph nodes text for string matching
string_index = FuzzyStringIndex()
string_index.add(graph_store.nodes())
retriever = string_index.as_entity_matcher()
entity_linker = EntityLinker(retriever=retriever)
linked_entities = entity_linker.link(artifacts["entity-extraction"], return_dict=False)
linked_answers = entity_linker.link(artifacts["draft-answer-generation"], return_dict=False)
linked_entities, linked_answers
They create an entity linking pipeline to connect free-text mentions from the LLM output back to actual nodes in the knowledge graph.
Then they developed the fuzzy matching capability by initialising aFuzzyStringIndex, which builds an index of all the graph node names from the graph_store and retriever function, and from this index usingas_entity_matcher(), which transforms the fuzzy index into a callable tool for entity resolution. I then created a EntityLinker using this retriever. The EntityLinker is responsible for converting LLM-generated entities into actual graph node IDs, enabling grounded graph traversal and reasoning.
after that they made the linker process both the "entity-extraction" and "draft-answer-generation" artifacts returned by the LLM in the earlier step. These artifacts contain names of entities and answer candidates that need to be matched to graph nodes. By passing them through the link() method.
Triplet Retrieval
from graphrag_toolkit.byokg_rag.graph_retrievers import AgenticRetriever
from graphrag_toolkit.byokg_rag.graph_retrievers import GTraversal, TripletGVerbalizer
graph_traversal = GTraversal(graph_store)
graph_verbalizer = TripletGVerbalizer()
triplet_retriever = AgenticRetriever(
llm_generator=llm_generator,
graph_traversal=graph_traversal,
graph_verbalizer=graph_verbalizer)
triplet_context = triplet_retriever.retrieve(query=question, source_nodes=linked_entities)
triplet_context
Next, they designed a triplet retriever that can reason over the knowledge graph by simulating an agent navigating from one entity to another based on the question’s intent. and developed an agentic retriever which combines an LLM with graph traversal tools.
To start, I initialised GTraversal, which gives the system the ability to walk through the knowledge graph starting from a given set of entities. They also built aTripletGVerbalizer, which turns each retrieved triplet (head, relation, tail) into a format that the LLM can easily understand and evaluate.
Then they create triplet_context retrieve() with the original question and the answer linked_entities as starting points. This method returned a set of triplets — each representing a meaningful fact or path — that the LLM believes are most useful to answer the question.
Next, they designed a triplet retriever that can reason over the knowledge graph by simulating an agent navigating from one entity to another based on the question’s intent. and developed an agentic retriever which combines an LLM with graph traversal tools.
To start, I initialised GTraversal, which gives the system the ability to walk through the knowledge graph starting from a given set of entities. They also built aTripletGVerbalizer, which turns each retrieved triplet (head, relation, tail) into a format that the LLM can easily understand and evaluate.
Then they create triplet_context retrieve() with the original question and the answer linked_entities as starting points. This method returned a set of triplets — each representing a meaningful fact or path — that the LLM believes are most useful to answer the question.
Path Retrieval
from graphrag_toolkit.byokg_rag.graph_retrievers import PathRetriever
from graphrag_toolkit.byokg_rag.graph_retrievers import GTraversal, PathVerbalizer
graph_traversal = GTraversal(graph_store)
path_verbalizer = PathVerbalizer()
path_retriever = PathRetriever(
graph_traversal=graph_traversal,
path_verbalizer=path_verbalizer)
metapaths = [[component.strip() for component in path.split("->")] for path in artifacts["path-extraction"]]
shortened_paths = []
for path in metapaths:
if len(path) > 1:
shortened_paths.append(path[:1])
for path in metapaths:
if len(path) > 2:
shortened_paths.append(path[:2])
metapaths += shortened_paths
path_context = path_retriever.retrieve(linked_entities, metapaths, linked_answers)
path_context
context = list(set(triplet_context + path_context))
print(f"Success! Ground-truth answer `{answer}` retrieved!") if answer in '\n'.join(context) else print("Failure..")
They create a path-based reasoning system that leverages metapaths — structured sequences of relations — to dig deeper into the knowledge graph and extract meaningful paths between entities.
Then they use PathRetriever to require both a graph_traversal component and a PathVerbalizer. I reused the same GTraversal instance from before to walk through the graph, and initialised it Path verbalizer to convert retrieved paths into a human-readable form that the LLM can interpret. I generated metapaths from the LLM’s output and added shorter versions to capture partial patterns.
They then retrieved relevant paths connecting the question entities to potential answers. Finally, they combined these with earlier triplet results and checked if the correct answer, “Backstage Musical,” appeared — marking the retrieval as a success or failure.
BYOKG RAG
from graphrag_toolkit.byokg_rag.byokg_query_engine import ByoKGQueryEngine
byokg_query_engine = ByoKGQueryEngine(
graph_store=graph_store,
kg_linker=kg_linker,
triplet_retriever=triplet_retriever,
path_retriever=path_retriever,
entity_linker=entity_linker
)
retrieved_context = byokg_query_engine.query(question)
answers, response = byokg_query_engine.generate_response(question, "\n".join(retrieved_context))
print("Retrieved context: ", "\n".join(retrieved_context))
print("Generated answers: ", answers)
print(f"Success! Ground-truth answer `{answer}` retrieved!") if answer in '\n'.join(answers) else print("Failure..")
Finally, they built a full Bring Your custom Knowledge Graph -RAG pipelineByoKGQueryEngine, which combines all components—graph store, linkers, and retrievers—to handle natural language questions. It retrieves relevant graph context and generates answers. I ran it on the question and checked if the correct answer "Backstage Musical" appeared. If found, it's a success; otherwise, a failure.
Conclusion :
BYOKG-RAG significantly advances knowledge graph question answering by integrating multiple retrieval strategies with large language models. Through extensive experiments across diverse benchmarks, it demonstrates superior performance and generalization without relying on training data, highlighting the importance of iterative and multi-strategy graph retrieval methods.
I would highly appreciate it if you
❣ Join my Patreon: https://www.patreon.com/GaoDalie_AI
Book an Appointment with me: https://topmate.io/gaodalie_ai
Support the Content (every Dollar goes back into the -video):https://buymeacoffee.com/gaodalie98d
Subscribe to the Newsletter for free:https://substack.com/@gaodalie
Top comments (0)