Langchain includes functionality to integrate directly with Neo4j, including allowing you to run Cypher statements, query vector indexes and use Neo4j as a conversation memory store.
In this lesson, you will learn how to connect to and use a Neo4j database as a conversation memory store.
Storing conversation history in a Neo4j database allows you to analyze the conversation history to understand trends and improve outcomes.
Connecting to a Neo4j instance
The following code will connect to a Neo4j database and run a simple query.
from langchain_community.graphs import Neo4jGraph
graph = Neo4jGraph(
url="bolt://localhost:7687",
username="neo4j",
password="pleaseletmein"
)
result = graph.query("""
MATCH (m:Movie{title: 'Toy Story'})
RETURN m.title, m.plot, m.poster
""")
print(result)
You can connect to the Neo4j sandbox created for you when you joined the course.
Update the code above to use the url
, username
and password
of your Neo4j sandbox.
- Connection URL
-
bolt://{sandbox-ip}:{sandbox-boltPort}
- Username
-
{sandbox-username}
- Password
-
{sandbox-password}
Run the query - you should see data about the movie Toy Story.
The Neo4jGraph
class is a wrapper to the Neo4j Python driver.
It simplifies connecting to Neo4j and integrating with the Langchain framework.
Schema
When you connect to the Neo4j database, the object loads the database schema into memory - this enables Langchain to access the schema information without having to query the database.
You can access the schema information using the schema
property.
print(graph.schema)
Refreshing the schema
You can refresh the schema by calling thegraph.refresh_schema()
method.Conversation History
In the previous lesson, you created a program that used the ChatMessageHistory
component to store conversation history in memory.
You will now update this program to store the conversation history in your Neo4j sandbox using the Neo4jChatMessageHistory
component.
Reveal the code
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.schema import StrOutputParser
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
chat_llm = ChatOpenAI(openai_api_key="sk-...")
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a surfer dude, having a conversation about the surf conditions on the beach. Respond using surfer slang.",
),
("system", "{context}"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{question}"),
]
)
memory = ChatMessageHistory()
def get_memory(session_id):
return memory
chat_chain = prompt | chat_llm | StrOutputParser()
chat_with_message_history = RunnableWithMessageHistory(
chat_chain,
get_memory,
input_messages_key="question",
history_messages_key="chat_history",
)
current_weather = """
{
"surf": [
{"beach": "Fistral", "conditions": "6ft waves and offshore winds"},
{"beach": "Bells", "conditions": "Flat and calm"},
{"beach": "Watergate Bay", "conditions": "3ft waves and onshore winds"}
]
}"""
while True:
question = input("> ")
response = chat_with_message_history.invoke(
{
"context": current_weather,
"question": question,
},
config={
"configurable": {"session_id": "none"}
}
)
print(response)
Session ID
You must create and assign a session ID to each conversation to identify them.
The session ID can be any unique value, such as a Universally Unique Identifier (UUID).
You can generate a random UUID using the Python uuid.uuid4
function.
Create a new SESSION_ID
constant in your chat model program.
from uuid import uuid4
SESSION_ID = str(uuid4())
print(f"Session ID: {SESSION_ID}")
This session ID will be used to identify the conversation in Neo4j.
Neo4j Chat Message History
Create a Neo4jGraph
object to connect to your Neo4j sandbox.
from langchain_community.graphs import Neo4jGraph
graph = Neo4jGraph(
url="bolt://localhost:7687",
username="neo4j",
password="pleaseletmein"
)
Remember to update the connection details with your Neo4j sandbox details.
Click to reveal your Sandbox connection details
- Connection URL
-
bolt://{sandbox-ip}:{sandbox-boltPort}
- Username
-
{sandbox-username}
- Password
-
{sandbox-password}
Previously, the get_memory
function returned an instance of ChatMessageHistory
.
The get_memory
function should now return an instance of Neo4jChatMessageHistory
.
You should pass the session_id
and the graph
connection you created as parameters.
from langchain_community.chat_message_histories import Neo4jChatMessageHistory
def get_memory(session_id):
return Neo4jChatMessageHistory(session_id=session_id, graph=graph)
Finally, you must add the SESSION_ID
to the config
when you invoke
the chat model.
response = chat_with_message_history.invoke(
{
"context": current_weather,
"question": question,
},
config={
"configurable": {"session_id": SESSION_ID}
}
)
Click to reveal the complete code.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.schema import StrOutputParser
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.graphs import Neo4jGraph
from langchain_community.chat_message_histories import Neo4jChatMessageHistory
from uuid import uuid4
SESSION_ID = str(uuid4())
print(f"Session ID: {SESSION_ID}")
chat_llm = ChatOpenAI(openai_api_key="sk-...")
graph = Neo4jGraph(
url="bolt://localhost:7687",
username="neo4j",
password="pleaseletmein"
)
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"You are a surfer dude, having a conversation about the surf conditions on the beach. Respond using surfer slang.",
),
("system", "{context}"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{question}"),
]
)
def get_memory(session_id):
return Neo4jChatMessageHistory(session_id=session_id, graph=graph)
chat_chain = prompt | chat_llm | StrOutputParser()
chat_with_message_history = RunnableWithMessageHistory(
chat_chain,
get_memory,
input_messages_key="question",
history_messages_key="chat_history",
)
current_weather = """
{
"surf": [
{"beach": "Fistral", "conditions": "6ft waves and offshore winds"},
{"beach": "Bells", "conditions": "Flat and calm"},
{"beach": "Watergate Bay", "conditions": "3ft waves and onshore winds"}
]
}"""
while True:
question = input("> ")
response = chat_with_message_history.invoke(
{
"context": current_weather,
"question": question,
},
config={
"configurable": {"session_id": SESSION_ID}
}
)
print(response)
Run the program and have a conversation with the chat model. The conversation history will now be stored in your Neo4j sandbox.
Conversation History Graph
The conversation history is stored using the following data model:
![A graph data model showing 2 nodes Session and Message connected by a LAST_MESSAGE relationship. There is a circular NEXT relationship on the Message node.](images/Neo4jChatMessageHistory.png)
The Session
node represents a conversation session and has an id
property.
The Message
node represents a message in the conversation and has the following properties:
-
content
- The message content -
type
- The message type:human
,ai
, orsystem
The LAST_MESSAGE
relationship connects the Session
node to the conversation’s last Message
node. The NEXT
relationship connects Message
nodes in the conversation.
You can return the graph of the conversation history using the following Cypher query:
MATCH (s:Session)-[:LAST_MESSAGE]->(last:Message)<-[:NEXT*]-(msg:Message)
RETURN s, last, msg
You can return the conversation history for a single session by filtering on the Session.id
property.
MATCH (s:Session)-[:LAST_MESSAGE]->(last:Message)
WHERE s.id = 'your session id'
MATCH p = (last)<-[:NEXT*]-(msg:Message)
UNWIND nodes(p) as msgs
RETURN DISTINCT msgs.type, msgs.content
Check Your Understanding
Neo4j Langchain integration
Select all statements about the Langchain Neo4j integration that are True.
-
✓ You can connect to a Neo4j database
-
✓ The database schema is loaded automatically
-
✓ You can run Cypher queries
-
✓ Vectors can be queried
-
✓ You can use Neo4j as a conversation memory store
Hint
The key goal is to simplify connecting to Neo4j and integrating with the Langchain framework.
Solution
All the statements are true.
Summary
In this lesson, you learned how to use a Neo4j database as a conversation memory store.
In the next lesson, you will learn how to create an agent to give an LLM access to different tools and data sources.