In the previous challenge, you created a tool that used the Neo4jVector
Store and Retriever to identify movies with similar plots to the user’s input.
This approach may be relatively easy to set up, but as you learned in Vectors & Semantic Search module of the Neo4j & LLM Fundamentals course, this approach can have its drawbacks.
Semantic Search using Vector Similarity relies on relative proximity in vector space, which may not provide a precise match.
Graph-enhanced semantic search combines the nuanced understanding of data from vector search with the contextual insights provided by graph features, leading to search results with greater depth and relevance by considering the relationships and hierarchies between entities within a broader knowledge network.
In this challenge, you will create a tool that uses the structure of the graph to generate a Cypher statement to answer a question.
To complete this challenge, you must:
-
Create a Graph Cypher QA Chain
-
Register the Chain as a Tool
Creating a Graph Cypher QA Chain
To create a QA Chain that generates Cypher, you must import the GraphCypherQAChain
.
In the tools/
folder, create a new file called cypher.py
.
Copy the following code to import the GraphCypherQAChain
and the Neo4jGraph
store object created in Connecting to Neo4j lesson.
Unresolved directive in lesson.adoc - include::https://raw.githubusercontent.com/neo4j-graphacademy/app-python/main/solutions/tools/cypher.py[tag=import]
The GraphCypherQAChain
provides a static .from_llm()
method for creating a new instance.
The method requires one positional parameter, the llm
and the GraphStore as the named graph
parameter.
Unresolved directive in lesson.adoc - include::https://raw.githubusercontent.com/neo4j-graphacademy/app-python/main/solutions/tools/cypher.py[tag=cypher-qa]
The chain will use the schema generated by the Neo4jGraph
class to write a Cypher statement and execute it against the database.
Registering the Graph Cypher QA Chain as a Tool
Follow the instructions in the previous step to create a new Tool
and append it to the tools
list in agent.py
.
Start by importing the tool.
Unresolved directive in lesson.adoc - include::https://raw.githubusercontent.com/neo4j-graphacademy/app-python/main/solutions/tools/cypher.py[tag=importcypherqa]
Append a new Tool
to the tools
array.
Give the tool a name
, and a description
.
The description should describe the information that can be retrieved from the database.
The recommendations
dataset holds information on movies, actors, and user reviews that the LLM may find useful in generating a response.
Finally, define the cypher_qa
as the function to call using the func
named parameter.
Unresolved directive in lesson.adoc - include::https://raw.githubusercontent.com/neo4j-graphacademy/app-python/main/solutions/tools/cypher.py[tag=tool]
Testing the Tool
You can test the new Cypher generation tool by asking the bot a question about a Movie. For example, you could ask "Who directed Toy Story?".
You can check that the new tool has been called in the console.
Console Output
> Entering new AgentExecutor chain... { "action": "Cypher QA", "action_input": "Who directed Toy Story?" }
> Entering new GraphCypherQAChain chain... Generated Cypher: MATCH (d:Director)-[:DIRECTED]->(m:Movie) WHERE m.title = "Toy Story" RETURN d.name AS director Full Context: [{'director': 'John Lasseter'}]
> Finished chain.
Observation: {'query': 'Who directed Toy Story?', 'result': 'John Lasseter directed Toy Story.'} Thought:{ "action": "Final Answer", "action_input": "John Lasseter directed Toy Story." }
> Finished chain.
With minimal configuration, the LLM can generate more complex questions. For example, Did the same director direct Toy Story and Toy Story 2?
Console Output
> Entering new AgentExecutor chain... { "action": "Cypher QA", "action_input": "Did the same director direct Toy Story and Toy Story 2?" }
> Entering new GraphCypherQAChain chain... Generated Cypher: MATCH (d:Director)-[:DIRECTED]->(m:Movie) WHERE m.title IN ['Toy Story', 'Toy Story 2'] WITH d, collect(m.title) AS movies WHERE size(movies) = 2 RETURN d.name AS director, movies Full Context: [{'director': 'John Lasseter', 'movies': ['Toy Story', 'Toy Story 2']}]
> Finished chain.
Observation: {'query': 'Did the same director direct Toy Story and Toy Story 2?', 'result': 'Yes, the same director, John Lasseter, directed both Toy Story and Toy Story 2.'} Thought:{ "action": "Final Answer", "action_input": "Yes, the same director, John Lasseter, directed both Toy Story and Toy Story 2." }
> Finished chain.
Did it work for you? Once you have completed the steps, click the button below to mark the lesson as completed.
Summary
In this lesson, you created a tool capable of generating a Cypher statement to answer a specific question and execute it against the database. But the Cypher it generates isn’t perfect.
In the next lesson, you will learn how to handle edge cases by fine-tuning the prompt used to generate the Cypher statement.