Query Tuner Agent
Part of the Zero to Operational for Amazon Neptune using Agentic AI series. This agent generates data for complex query patterns in your Neptune cluster.
Agent Goals
The next agent in our workflow is the Query Tuner Agent. Here we provide the agent with an openCypher query, and a connection to the Neptune cluster containing data.
NOTE: This agent is currently the least optimized and most likely to change. I am working with the Neptune team to identify ways we can make the Neptune explain plans more friendly to LLM interpretation.
Our Sample Workflow
In our series, we started with the topic Anti-Money Laundering and Financial Crime Investigation. The Query Generation Agent created queries from the questions we wanted to answer in our use case, and the Scenario Data Generator Agent populated our graph with sample data so this agent has something to optimize on. This "agent" would probably be better defined as two tightly coupled agent, the first analyzing the explain plan for ways to optimize it (Analyzer Subagent) and the second experimenting with permutations of that query assessing 1/ that query succeeds and the results are the same, and 2/ that the query is faster than the original (Tuning Subagent). The output of these agents are extremely verbose and too technical, so I'm going to omit the outputs for now, but I will revisit this article when I have a better solution. The output of this task is a set of queries that are equivalent to the original provided query ranked by fastest to slowest.
Important notes:
- The verbosity of the explain plans often leads the LLM to get confused, so please validate any alternative queries and the performance ranking this generates at the scale of your production data.
- Several of the tasks required here, such as validating two results sets are equivalent, are not well suited for LLM agents so we have built tools that are more precise for doing so and advised the agent to use these tools.
- In the Tuning Subagent prompt below, note the parts of the prompt intended to eliminate false negatives. For example, if a query has a LIMIT and the number is fewer than the top equivalent results (e.g., LIMIT 5 but there are 7 equivalent top results), often an alternative query will have different results (e.g., a different 5 of the 7 from the original). So we include instructions to rerun the query with higher limits and compare the results, and if they are equivalent then consider the query valid.
- For long queries that create extremely complex explain plans, you may get an error that the message is to large for the context window. There is no solution to this at the current time.
Agent Components
Let's look at the key components of the Scenario Data Generator agent. The prompts shown here were tested with Anthropic Claude 3.7 and 4.0.
System Prompt
Analyzer Subagent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Amazon Neptune is a graph database. You are an expert in understanding explain plans produced by Amazon Neptune and identifying what the query achieves and if there are any areas to investigate for optimizing the query.
The text in the documentation tags is important to understand explain plans:
<documentation>
Use the HTTP Request tool to retrieve and understand the DFE Operators in the Explain plan from https://docs.aws.amazon.com/neptune/latest/userguide/access-graph-opencypher-explain.html#access-graph-opencypher-dfe-operators
Use the HTTP Request tool to retrieve and understand the explain plan columns from https://docs.aws.amazon.com/neptune/latest/userguide/access-graph-opencypher-explain.html#access-graph-opencypher-explain-columns
Use the HTTP Request tool to retrieve and understand the basic example of understanding explain output from https://docs.aws.amazon.com/neptune/latest/userguide/access-graph-opencypher-explain.html#access-graph-opencypher-explain-basic-example
</documentation>
You will use the query expain plan tool to pass in the query provided to the Neptune database and return back the explain plan.
You will summarize the provided explain plan as a series of steps that are being performed by Neptune. These steps will be listed in order. Order is determined using these rules:
- Start with the table titled subQuery1
- Each table starts at "ID" 0. The next step in order is listed in the column "Out #1". If there is a number in "Out #2" as well, this represents a parallel execution path. This row is the input into the row with both of those IDs.
- If the Arguments value for the row says "subQuery=", insert the table containing that same header in this location. The ID column only has the context of the current table, so start at "ID" 0 and when you see the step DFEDrain, that functions as the output of this step.
- The "Units Out" column and "Time (ms)" column are important for each step. If the Units Out is much higher than most of the steps, or Time (ms) is much higher than most, then point this out in your summary for the step.
- Identify the steps with many more "Units Out" or much longer "Time (ms)" than most. Suggest ways you might modify the query to reduce the number of units out or shorten the time taken.
** IMPORTANT **
When providing suggestions to optimize the query, under no circumstances should you suggest any of the following:
1. creating custom indexes
2. using APOC functions.
3. functions that do not exist as part of the openCypher specification
4. use of shortestPath, allShortestPath, ALL, NONE or ANY functions
5. use of bi-directional search patterns
6. use of Neptune ML functions or query
Tuning Subagent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
You are a Query Tuning Agent that optimizes OpenCypher queries for Amazon Neptune. Follow these steps EXACTLY:
1. FIRST EXECUTION:
- When given a query to optimize, you MUST first run the original query using run_opencypher_query
- You MUST save this result as the baseline for all comparisons
- You MUST use query_explain_tool to get the baseline execution plan
2. GENERATING ALTERNATIVES:
- Generate ONE alternative query at a time
- Use the get_graph_schema tool to get the graph schema and use that to design the alternative queries.
- For each alternative:
- Use validate_query_results_tool with the original query and your alternative
- If the validate_query_results_tool returns is_valid=False AND the query contains a LIMIT clause, for testing equality try increasing the LIMIT clause to a larger number and retry this process up to 3 times.
- Only proceed if validate_query_results_tool returns is_valid=True
- If is_valid=False, discard that alternative and try a different approach
- If you changed the LIMIT to a larger number, return it to the original number.
- Document why you're making each specific change
3. VALIDATION AND COMPARISON:
- For each valid alternative:
* Use the query_explain_tool to get the explain plan for the alternative query
* Compare the explain plan with the baseline
* Document specific performance improvements
* Note any tradeoffs or potential issues
4. FINAL RECOMMENDATION:
- Recommend ONLY alternatives that:
* Passed validation (is_valid=True)
* Show clear performance improvements
* Maintain the exact same results as original query
You MUST STOP and discard any alternative as soon as validate_query_results_tool returns is_valid=False.
# Overall Rules
- When using the run_opencypher_query tool, only pass the query itself and not the descriptive text surrounding it. Also remove all newline characters.
# Outputs
- List the original query and all alternative queries that are valid along with the time they took to execute, in order from fastest to slowest.
# Example interaction
User: Optimize this query: [query]
Assistant: First, let me execute the original query and save the baseline...
[runs query and explain]
Now, let me try an alternative with [specific optimization]...
[uses validate_query_results_tool]
[if valid, continues analysis; if invalid, tries different approach]
Tools
Neptune MCP Server : get_graph_schema and run_opencypher_query tools
Strands Agent Community Tools : http_request (to get Neptune documentation)
Custom Tools: query_explain_tool (will eventually be part of Neptune MCP Server)** and validate_query_results_tool
Query Explain Tool (prototype code, do not use directly in production. The Neptune class is a wrapper around the boto3 neptune-data service):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class NeptuneTools:
def __init__(self, connection_url):
self.__neptune = Neptune(connection_url=connection_url)
def query_explain_tool(self, query: str) -> str:
"""
Executes a Cypher query in Neptune to retrieve an explain plan
Parameters
----------
query : string
A Cypher query to run against a Neptune graph
Returns
-------
string
The query explain plan describing its step by step performance
"""
raw_explain = self.__neptune.run_open_cypher_explain_query(query,'detailed')
# print(f"query_explain_tool output -> {raw_explain}")
if not "result" in raw_explain:
return "No Result Returned from the tool"
else:
return raw_explain["result"]Validate Query Results Tool (prototype code, do not use directly in production):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def validate_query_results_tool(self, original_query: str, alternative_query: str) -> dict:
"""
Tool that executes both queries and validates their results match exactly.
Returns:
{
"is_valid": bool,
"error": str # Only if is_valid=False
}
"""
def sort_nested(obj):
if isinstance(obj, dict):
return tuple(sorted((k, sort_nested(v)) for k, v in obj.items()))
elif isinstance(obj, list):
return tuple(sorted(sort_nested(item) for item in obj))
else:
return obj
# Execute original query
orig_results = self.__neptune.run_open_cypher_query(original_query)['results']
# Execute alternative query
alt_results = self.__neptune.run_open_cypher_query(alternative_query)['results']
# Compare results
try:
orig_set = {sort_nested(r) for r in orig_results}
alt_set = {sort_nested(r) for r in alt_results}
is_valid = orig_set == alt_set
except:
is_valid = False
if not is_valid:
return {
"is_valid": False,
"error": "Results do not match original query"
}
return {
"is_valid": True
}User Message Template
Analyzer Subagent
1
2
Here is the query to analyze:
{query}
Tuning Subagent
1
2
3
4
Original Query:
{original_query}
Optimization Plan:
{original_optimization_text}
NOTE: {original_optimization_text} is the output of the Analyzer Subagent.
Costs
The costs here can vary widely by query complexity, result set size, and number of alternatives attempted. At the current time you can estimate a cost of approximately 2.00 USD per query due to the number of tokens generated by the explain plan, but I am working to reduce this impact. Each query uses approximately 600K input tokens, 6K output tokens, 36K cache read input tokens, and 5K cache write output tokens.
What's Next
If you are just getting started building a graph solution on Amazon Neptune, create this agent using your favorite agentic AI framework (personally I use Strands Agents SDK ) and LLM and use it create a conceptual model for your graph. In the next article, we will describe a set of agents that will use this schema to populate your Neptune cluster with sample data. Have you implemented ways to improve this or have ideas on how to do so? Share them in the comments or reach out to me directly on LinkedIn .
Disclaimer
These prompts and agent ideas are not supported products in their own right, but educational examples to help Neptune customers use build their applications. Before introducing these prompts and agents into our organization, the methods described should be thoroughly tested, secured, and optimized according to your business's security standards & policies.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article