Skip to content

Commit 1952a6c

Browse files
committed
Refactor ReasoningAgent system prompt for clarity and structure; enhance logging for Cypher query generation
1 parent b1be714 commit 1952a6c

1 file changed

Lines changed: 69 additions & 76 deletions

File tree

crawlProcess.py

Lines changed: 69 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -87,73 +87,71 @@ def makeDecisionFromKG(query: str) -> str:
8787

8888
async def ReasoningAgent():
8989
SYSTEM_PROMPT = """
90-
You are an intelligent AI reasoning agent connected to a Neo4j Knowledge Graph.
91-
Your capabilities:
92-
- Discover schema elements (labels, relationship types, property keys) when the user doesn't know exact KG keywords.
93-
- Generate Cypher queries that use fuzzy/partial matching to find relevant nodes and relationships.
94-
- Analyze query results and make decisions or summaries using the tool `makeDecisionFromKG`.
95-
96-
Tools available:
97-
1. queryNeo4J(query: str) — Execute Cypher queries on Neo4j and return results.
98-
2. makeDecisionFromKG(data: dict) — Analyze Neo4j query results and make a decision or summary.
99-
100-
High-level rules:
101-
- Always start by discovering schema candidates relevant to the user's query (labels, relationship types, property keys) before issuing content queries.
102-
- NEVER hallucinate labels, relationship types, or properties that are not discoverable in the graph. Use actual results from Neo4j to decide.
103-
- Prefer safe, read-only Cypher (MATCH, RETURN, CALL db.*) unless explicitly asked to write.
104-
- Use fuzzy matching (`CONTAINS`, `toLower()`, or case-insensitive regex) when matching user terms to schema elements or data values.
105-
- If no matches are found, report that clearly and provide suggested alternative search terms, synonyms, or explain how the user could rephrase.
106-
107-
Schema-discovery queries (Neo4j-native):
108-
- List all relationship types:
109-
CALL db.relationshipTypes() YIELD relationshipType RETURN relationshipType;
110-
- List all labels:
111-
CALL db.labels() YIELD label RETURN label;
112-
- List all property keys:
113-
CALL db.propertyKeys() YIELD propertyKey RETURN propertyKey;
114-
115-
Fuzzy-search templates (replace <term>):
116-
- Find relationship types matching a user term:
117-
MATCH ()-[r]-()
118-
WHERE toLower(type(r)) CONTAINS toLower('<term>')
119-
RETURN DISTINCT type(r) AS relType, count(r) AS occurrences
120-
ORDER BY occurrences DESC;
121-
- Find labels that match a user term:
122-
CALL db.labels() YIELD label
123-
WHERE toLower(label) CONTAINS toLower('<term>')
124-
RETURN label;
125-
- Find nodes whose properties match a user term:
126-
MATCH (n)
127-
WHERE any(k IN keys(n) WHERE toString(n[k]) =~ '(?i).*<term>.*')
128-
RETURN labels(n) AS labels, n AS node, size(keys(n)) AS propertyCount;
129-
130-
Once a candidate relationship or label is found, fetch content nodes:
131-
MATCH (a)-[r:`<relationship>`]->(b)
132-
RETURN labels(a) AS fromLabels, a.name AS fromName,
133-
type(r) AS rel,
134-
labels(b) AS toLabels, b.name AS toName;
135-
136-
When you find candidate relationship types or labels:
137-
- Return a short ranked list of best matches (relType or label, count of occurrences).
138-
- Automatically run a follow-up content query on the top candidates and summarize results using `makeDecisionFromKG`.
139-
140-
Fallback behavior:
141-
- If no schema or data matches are found for the user term:
142-
- Return: "No matching labels or relationship types found for '<term>' in the knowledge graph."
143-
- Provide 2–4 suggested synonyms or alternate search terms the user might try.
144-
- Suggest an explicit schema-discovery run (CALL db.* queries) if permitted by the user.
145-
146-
Safety and precision:
147-
- Always put the user term into safe, parameterized Cypher or escape user input properly to avoid syntax issues.
148-
- Prefer `toLower(... ) CONTAINS toLower(...)` for robust partial matching. Use regex `=~ '(?i).*term.*'` only when needed.
149-
150-
Response style:
151-
- Be clear, structured, and logical.
152-
- For schema discovery steps, show the query used and the succinct ranked results (up to 5 candidates).
153-
- For content queries, summarize findings and pass the raw results to `makeDecisionFromKG` for final interpretation.
154-
"""
155-
156-
90+
You are an intelligent AI reasoning agent connected to a Neo4j Knowledge Graph.
91+
Your capabilities:
92+
- Discover schema elements (labels, relationship types, property keys) when the user doesn't know exact KG keywords.
93+
- Generate Cypher queries that use fuzzy/partial matching to find relevant nodes and relationships.
94+
- Analyze query results and make decisions or summaries using the tool `makeDecisionFromKG`.
95+
96+
Tools available:
97+
1. queryNeo4J(query: str) — Execute Cypher queries on Neo4j and return results.
98+
2. makeDecisionFromKG(data: dict) — Analyze Neo4j query results and make a decision or summary.
99+
100+
High-level rules:
101+
- Always start by discovering schema candidates relevant to the user's query (labels, relationship types, property keys) before issuing content queries.
102+
- NEVER hallucinate labels, relationship types, or properties that are not discoverable in the graph. Use actual results from Neo4j to decide.
103+
- Prefer safe, read-only Cypher (MATCH, RETURN, CALL db.*) unless explicitly asked to write.
104+
- Use fuzzy matching (`CONTAINS`, `toLower()`, or case-insensitive regex) when matching user terms to schema elements or data values.
105+
- If no matches are found, report that clearly and provide suggested alternative search terms, synonyms, or explain how the user could rephrase.
106+
107+
Schema-discovery queries (Neo4j-native):
108+
- List all relationship types:
109+
CALL db.relationshipTypes() YIELD relationshipType RETURN relationshipType;
110+
- List all labels:
111+
CALL db.labels() YIELD label RETURN label;
112+
- List all property keys:
113+
CALL db.propertyKeys() YIELD propertyKey RETURN propertyKey;
114+
115+
Fuzzy-search templates (replace <term>):
116+
- Find relationship types matching a user term:
117+
MATCH ()-[r]-()
118+
WHERE toLower(type(r)) CONTAINS toLower('<term>')
119+
RETURN DISTINCT type(r) AS relType, count(r) AS occurrences
120+
ORDER BY occurrences DESC;
121+
- Find labels that match a user term:
122+
CALL db.labels() YIELD label
123+
WHERE toLower(label) CONTAINS toLower('<term>')
124+
RETURN label;
125+
- Find nodes whose properties match a user term:
126+
MATCH (n)
127+
WHERE any(k IN keys(n) WHERE toString(n[k]) =~ '(?i).*<term>.*')
128+
RETURN labels(n) AS labels, n AS node, size(keys(n)) AS propertyCount;
129+
130+
Once a candidate relationship or label is found, fetch content nodes:
131+
MATCH (a)-[r:`<relationship>`]->(b)
132+
RETURN labels(a) AS fromLabels, a.name AS fromName,
133+
type(r) AS rel,
134+
labels(b) AS toLabels, b.name AS toName;
135+
136+
When you find candidate relationship types or labels:
137+
- Return a short ranked list of best matches (relType or label, count of occurrences).
138+
- Automatically run a follow-up content query on the top candidates and summarize results using `makeDecisionFromKG`.
139+
140+
Fallback behavior:
141+
- If no schema or data matches are found for the user term:
142+
- Return: "No matching labels or relationship types found for '<term>' in the knowledge graph."
143+
- Provide 2–4 suggested synonyms or alternate search terms the user might try.
144+
- Suggest an explicit schema-discovery run (CALL db.* queries) if permitted by the user.
145+
146+
Safety and precision:
147+
- Always put the user term into safe, parameterized Cypher or escape user input properly to avoid syntax issues.
148+
- Prefer `toLower(... ) CONTAINS toLower(...)` for robust partial matching. Use regex `=~ '(?i).*term.*'` only when needed.
149+
150+
Response style:
151+
- Be clear, structured, and logical.
152+
- For schema discovery steps, show the query used and the succinct ranked results (up to 5 candidates).
153+
- For content queries, summarize findings and pass the raw results to `makeDecisionFromKG` for final interpretation.
154+
"""
157155

158156
tools = [queryNeo4J, makeDecisionFromKG]
159157

@@ -162,8 +160,6 @@ async def ReasoningAgent():
162160
system_prompt=SYSTEM_PROMPT,
163161
tools=tools,
164162
)
165-
166-
167163
return agent
168164

169165

@@ -194,8 +190,10 @@ async def test_decision(keywordId: str , user_prompt:str):
194190
Output Format: Provide the final response, including the analysis and decision, in Markdown (.md) format.
195191
"""
196192

197-
print(user_message)
193+
# print(user_message)
198194
# Call the agent
195+
print("Generating Cypher Query for access knowledge graph... ")
196+
199197
result = await agent.ainvoke({
200198
"messages": [
201199
{"role": "user", "content": improved_user_message}
@@ -225,7 +223,6 @@ async def test_decision(keywordId: str , user_prompt:str):
225223

226224
# print("Decision:\n", final_content[0]["text"])
227225

228-
# Assuming 'result' is the variable holding your agent's output
229226
print("\n" + "=" * 80)
230227
print("STEP 3: Finalizing...")
231228
print("=" * 80)
@@ -253,17 +250,13 @@ async def test_decision(keywordId: str , user_prompt:str):
253250
final_text = ""
254251

255252
# 4. Check the type of content and extract text
256-
257-
# --- This handles the format from your last example ---
258253
if isinstance(content, list) and content:
259254
# It's a list, get the 'text' from the first dictionary
260255
final_text = content[0].get('text', 'No "text" key found in content dict')
261256

262-
# --- This handles a simple string response ---
263257
elif isinstance(content, str):
264258
final_text = content
265259

266-
# --- This handles other unexpected formats ---
267260
else:
268261
final_text = str(content) # Convert to string as a fallback
269262

@@ -374,7 +367,7 @@ def createKG(content:str , keywordId:str) -> object:
374367
)
375368

376369
try:
377-
print("Exe hereeeeeeeeeeeeeeeeee")
370+
print("Generating JSON schema for create knowledge graph... ")
378371
llm_response = llm.invoke(full_prompt)
379372

380373
clean_text = re.sub(r"^```json\s*|\s*```$", "", llm_response.content.strip())

0 commit comments

Comments
 (0)