dvwn commited on
Commit
79168b4
·
1 Parent(s): a218c12

Update SQL Agent Auto-Correct Mechanism

Browse files
Files changed (1) hide show
  1. src/nl2sql/sql_agent.py +95 -39
src/nl2sql/sql_agent.py CHANGED
@@ -1,5 +1,5 @@
1
  # Path: src/nl2sql/sql_agent.py
2
- # SQL Agent for handling NL2SQL conversion
3
  from src.database.db_manager import get_db_connection, get_schema_context
4
  from langchain_core.prompts import PromptTemplate
5
  from src.nl2sql.hf_engine import get_llm
@@ -18,11 +18,38 @@ User Question:
18
 
19
  SQL Query:"""
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  prompt_template = PromptTemplate(
22
  input_variables = ["schema", "question"],
23
  template = SQL_PROMPT_TEMPLATE
24
  )
25
 
 
 
 
 
 
26
  # Clean the output
27
  def clean_sql(raw_sql: str) -> str:
28
  """
@@ -41,53 +68,82 @@ def clean_sql(raw_sql: str) -> str:
41
  return cleaned.strip()
42
 
43
  # Function to handle NL2SQL conversion
44
- def nl2sql_agent(user_question: str) -> dict:
45
  """
46
- Complete flow execution:
47
- Get Schema context -> Generate SQL query -> Execute SQL query -> Return results
48
  """
49
  # Fetch database schema context using RAG
50
  print(f"Fetching RAG schema context for: '{user_question}'...")
51
  schema = get_schema_context(question = user_question)
52
 
53
  # Generate SQL query using the schema context and user question
54
- print("Generating SQL query via LLM...")
55
  llm = get_llm()
56
 
57
  # LangChain Pipeline: Pipe prompt into LLM
58
  chain = prompt_template | llm
59
- raw_response = chain.invoke({
60
- "schema": schema,
61
- "question": user_question
62
- })
63
-
64
- # Parse & clean the generated SQL query
65
- generated_sql = clean_sql(raw_response)
66
- print(f"Generated SQL: \n{generated_sql}")
67
-
68
- # Execute the generated SQL query and fetch results
69
- connection = get_db_connection()
70
- if not connection:
71
- return {
72
- "query": generated_sql,
73
- "error": "Could not establish database connection",
74
- "status": "failed"
75
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
- try:
78
- cursor = connection.cursor()
79
- cursor.execute(generated_sql)
80
- results = cursor.fetchall()
81
- return {
82
- "query": generated_sql,
83
- "results": results,
84
- "status": "success"
85
- }
86
- except Exception as e:
87
- return {
88
- "query": generated_sql,
89
- "error": str(e),
90
- "status": f"error executing SQL: {e}"
91
- }
92
- finally:
93
- connection.close()
 
1
  # Path: src/nl2sql/sql_agent.py
2
+ # SQL Agent for handling NL2SQL conversion with Auto-Correct functionality
3
  from src.database.db_manager import get_db_connection, get_schema_context
4
  from langchain_core.prompts import PromptTemplate
5
  from src.nl2sql.hf_engine import get_llm
 
18
 
19
  SQL Query:"""
20
 
21
+ REFINEMENT_PROMPT_TEMPLATE = """You are an expert SQLite developer.
22
+ You previously generated a SQL query to answer the user's question, but it resulted inan error when executed on the database.
23
+
24
+ Schema Context:
25
+ {schema}
26
+
27
+ User Question:
28
+ {question}
29
+
30
+ Previous Generated SQL:
31
+ {failed_sql}
32
+
33
+ Database Error Message:
34
+ {error_message}
35
+
36
+ Your task is to fix the SQL query based on the exact error message and the schema.
37
+ Pay close attention to column names, table relationships, and SQLite syntax.
38
+ Return ONLY the raw, corrected SQL query.
39
+ Do not include any explanations, markdown formatting, or code blocks.
40
+
41
+ Corrected SQL Query:"""
42
+
43
  prompt_template = PromptTemplate(
44
  input_variables = ["schema", "question"],
45
  template = SQL_PROMPT_TEMPLATE
46
  )
47
 
48
+ refinement_prompt = PromptTemplate(
49
+ input_variables = ["schema", "question", "failed_sql", "error_message"],
50
+ template = REFINEMENT_PROMPT_TEMPLATE
51
+ )
52
+
53
  # Clean the output
54
  def clean_sql(raw_sql: str) -> str:
55
  """
 
68
  return cleaned.strip()
69
 
70
  # Function to handle NL2SQL conversion
71
+ def nl2sql_agent(user_question: str, max_retries: int = 3) -> dict:
72
  """
73
+ Complete flow execution with Auto-correction:
74
+ Get Schema context -> Generate SQL query -> Execute SQL query -> If Error, Refine & Retry ->Return results
75
  """
76
  # Fetch database schema context using RAG
77
  print(f"Fetching RAG schema context for: '{user_question}'...")
78
  schema = get_schema_context(question = user_question)
79
 
80
  # Generate SQL query using the schema context and user question
 
81
  llm = get_llm()
82
 
83
  # LangChain Pipeline: Pipe prompt into LLM
84
  chain = prompt_template | llm
85
+ refinement_chain = refinement_prompt | llm
86
+
87
+ current_sql = ""
88
+ error_message = ""
89
+
90
+ # Auto-correction Loop
91
+ for attempt in range(1, max_retries + 1):
92
+ if attempt == 1:
93
+ print("Generating initial SQL query...")
94
+ raw_response = chain.invoke({
95
+ "schema": schema,
96
+ "question": user_question
97
+ })
98
+ else:
99
+ print(f"\n--- Attempt {attempt}/{max_retries}: Refining SQL query based on error ---")
100
+ print(f"Feeding error back to LLM: {error_message}")
101
+ raw_response = refinement_chain.invoke({
102
+ "schema": schema,
103
+ "question": user_question,
104
+ "failed_sql": current_sql,
105
+ "error_message": error_message
106
+ })
107
+
108
+ # Parse & clean the generated SQL query
109
+ generated_sql = clean_sql(raw_response)
110
+ current_sql = generated_sql
111
+ print(f"Generated SQL: \n{generated_sql}")
112
+
113
+ # Execute the generated SQL query and fetch results
114
+ connection = get_db_connection()
115
+ if not connection:
116
+ return {
117
+ "query": generated_sql,
118
+ "error": "Could not establish database connection",
119
+ "status": "failed"
120
+ }
121
+
122
+ try:
123
+ cursor = connection.cursor()
124
+ cursor.execute(generated_sql)
125
+ results = cursor.fetchall()
126
+
127
+ if attempt > 1:
128
+ print(f"SQL query executed successfully after {attempt} attempts.")
129
+
130
+ return {
131
+ "query": generated_sql,
132
+ "results": results,
133
+ "status": "success",
134
+ "attempts": attempt
135
+ }
136
+ except Exception as e:
137
+ error_message = str(e)
138
+ print(f"Error executing SQL: {error_message}")
139
+
140
+ if attempt == max_retries:
141
+ print("Max retries reached. Returning error.")
142
+ finally:
143
+ connection.close()
144
 
145
+ return {
146
+ "query": current_sql,
147
+ "error": error_message,
148
+ "status": f"Error executing SQL after {max_retries} attempts"
149
+ }