What is RAG?
RAG, or Retrieval Augmented Generation, is a cutting-edge technique that combines the power of large language models (LLMs) with external knowledge sources. It allows LLMs to access and process information from another knowledge base, enhancing their ability to generate more informative, accurate, and contextually relevant responses.
What is Retriever in RAG
A crucial component of RAG is the retriever, responsible for fetching relevant information from the knowledge base based on the user’s query. The retriever’s effectiveness significantly impacts the overall quality of the response generated.
How can we improve the Retrieving Process
There are a few different strategies that can be used to optimize the retriever.
- Vector Search: Employ semantic search techniques to understand the underlying meaning of the query, enabling more accurate information retrieval.
- Contextual Understanding: Leverage contextual information to refine search results and prioritize relevant documents.
- Feedback Loop: Implement a feedback mechanism to learn from user interactions and improve future retrievals.
- Hybrid Retrieval: Combine different retrieval methods, such as keyword-based, semantic search, and graph search to achieve better results.
Graph Databases
Graph databases are specialized database systems designed to store, manage, and query data represented as graphs. In a graph database, data is modeled as nodes, edges, and properties.
- Nodes represent entities or objects, such as people, products, or locations.
- Edges represent relationships or connections between nodes, such as “friends with”, “bought”, or “located in”.
- Properties are attributes or key-value pairs associated with nodes or edges, providing additional information like names, timestamps, or weights.
Knowledge Graphs
A knowledge graph is a structured representation of information, where entities and their relationships are interconnected. It provides a comprehensive view of the domain, making it easier to reason about and extract insights from the data.
Knowledge Graph RAG: Practical Guide
By integrating knowledge graphs with RAG, we can unlock the full potential of both technologies. Knowledge graphs can serve as a rich and structured knowledge base, enabling the retriever to efficiently locate relevant information. LLM can then leverage this information to generate more comprehensive and informative responses.
Setup and Installation
Installs the required Python libraries for working with LangChain, OpenAI, Neo4j, and other necessary tools.
!pip install langchain -q
!pip install langchain-community -q
!pip install langchain-openai -q
!pip install langchain-experimental -q
!pip install neo4j -q
Initialize OpenAI LLM
Sets up the OpenAI LLM model to generate responses.
from langchain_openai import ChatOpenAI
# set OpenAI API key
os.environ['OPENAI_API_KEY'] = "xxxxxxxxxxxxxxxxxxxxxxx"
# initialize the ChatOpenAI model
llm = ChatOpenAI(
model="gpt-3.5-turbo",
temperature=0
)
Initialize Embedding Model
Configures the OpenAI text embedding model for converting text data into vector representations.
from langchain_openai import OpenAIEmbeddings
embedding_model = OpenAIEmbeddings(model="text-embedding-3-small")
Load Data
from langchain.schema import Document
text = Document(page_content="""
Three students, A, B, and C, are tackling two subjects, X and Y. Each has a unique perspective, weaving their experiences into a shared academic journey. A, gifted in Mathematics, thrives on solving equations but struggles with the abstract world of poetry and storytelling. On the other hand, B shines in Literature, captivating others with a flair for creative writing, yet finds numbers daunting and formulas perplexing.
C, a generalist, performs decently in both subjects but often bridges gaps between A and B. While A helps B understand mathematical concepts, B guides A through essay writing. Meanwhile, C organizes group study sessions, offering real-world examples to connect ideas from X and Y, making both subjects more relatable. Their collaboration not only enhances their learning but fosters a sense of camaraderie, demonstrating the power of teamwork in overcoming challenges.
""")
Split Documents into Chunks
Divides the document into smaller chunks for processing using LangChain’s text splitter.
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(chunk_size=250,chunk_overlap=30)
chunks = splitter.split_documents([text])
Graph Initialization and Transformation
Sets up a Neo4j graph database, processes document chunks into nodes and relationships, and adds them to the graph.
from langchain_community.graphs import Neo4jGraph
os.environ["NEO4J_URI"] = "xxxxxxxxxxxxxxxxxx"
os.environ["NEO4J_USERNAME"] = "xxxxxxxxxxxxx"
os.environ["NEO4J_PASSWORD"] = "xxxxxxxxxxxxx"
# initialize Neo4j graph database
graph = Neo4jGraph()
from langchain_experimental.graph_transformers import LLMGraphTransformer
graph_transformer = LLMGraphTransformer(llm = llm)
graph_documents = graph_transformer.convert_to_graph_documents(chunks)
# add nodes and relationships to graph
graph.add_graph_documents(
graph_documents,
baseEntityLabel=True,
include_source=True
)
from langchain_experimental.graph_transformers import LLMGraphTransformer
# indexing enables fast searches within text-based properties
def create_fulltext_index(g):
cypher = "CREATE FULLTEXT INDEX entity IF NOT EXISTS FOR (e:__Entity__) ON EACH [e.id]"
g.query(cypher)
create_fulltext_index(graph)
Querying the Graph and Entity Retrieval
Uses a LangChain template to extract specific entities (e.g., students and subjects) from the text and retrieves relationships from the graph.
from langchain_core.prompts import ChatPromptTemplate
entity_prompt = ChatPromptTemplate.from_messages(
[
(
"system","You are extracting entities from the text.",
),
(
"human","Use the following information to extract entities"
"input: {question}",
),
]
)
from pydantic import BaseModel, Field
from typing import List
class Entities(BaseModel):
names: List[str] = Field(
...,
description="All the entities that appear in the text",
)
entity_chain = (
entity_prompt
| llm.with_structured_output(Entities)
)
Graph Retriever
Implements a function to query the graph for relevant data using full-text search and retrieves relationships between entities.
from langchain_community.vectorstores.neo4j_vector import remove_lucene_chars
def generate_full_text_query(input):
full_text_query = ""
words = [el for el in remove_lucene_chars(input).split() if el]
for word in words[:-1]:
full_text_query += f" {word}~2 AND"
full_text_query += f" {words[-1]}~2"
return full_text_query.strip()
def graph_retriever(question: str) -> str:
result = ""
entities = entity_chain.invoke({"question": question})
for entity in entities.names:
response = graph.query(
"""CALL db.index.fulltext.queryNodes('entity', $query, {limit:2})
YIELD node,score
CALL {
WITH node
MATCH (node)-[r:!MENTIONS]->(neighbor)
RETURN node.id + ' - ' + type(r) + ' -> ' + neighbor.id AS output
UNION ALL
WITH node
MATCH (node)<-[r:!MENTIONS]-(neighbor)
RETURN neighbor.id + ' - ' + type(r) + ' -> ' + node.id AS output
}
RETURN output LIMIT 20
""",
{"query": generate_full_text_query(entity)},
)
result += "\n".join([el['output'] for el in response])
return result
Semantic Search Retriever
Sets up a semantic search index with Neo4j to find documents and entities similar to a query.
from langchain_community.vectorstores import Neo4jVector
vector_index = Neo4jVector.from_existing_graph(
embedding_model,
search_type="hybrid",
node_label="Document",
text_node_properties=["text"],
embedding_node_property="embedding"
)
Combined Retriever (Graph Retriever + Semantic Retriever)
def retriever(question):
graph_search_result = graph_retriever(question)
semantic_search_result = [data.page_content for data in vector_index.similarity_search(question, k=2)]
final_data = f"Graph data:{graph_search_result}\nText data:{' '. join(semantic_search_result)}"
return final_data
Define Prompt Template for RAG
Creates a prompt template for generating answers based on retrieved data.
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages(
[
(
"system","Answer this question using the provided context only.",
),
(
"human","Context: {context}"
"Question: {question}",
),
]
)
Create RAG Chain
Combines the retriever, prompt, and LLM into a Retrieval-Augmented Generation (RAG) chain to answer questions using both graph data and semantic search results.
from langchain_core.runnables import RunnablePassthrough
chain = (
{
"context": retriever,
"question": RunnablePassthrough()
}
| prompt
| llm
)
Invoke RAG Chain with Example Questions
response = chain.invoke("who learn both X and Y subjects")
print(response.content)
Conclusion
Knowledge Graph RAG represents a significant advancement in the field of AI. By combining the power of LLMs with the structured knowledge of graph databases, we can create more intelligent and informative systems. As technology continues to evolve, we can expect to see even more innovative applications of Knowledge Graph RAG in the future.