
在企业数据资产日益膨胀的今天,“业务人员不懂SQL、数据工程师疲于取数”已成为制约决策效率的核心瓶颈。Text2SQL技术试图用大模型弥合这一鸿沟,然而现实远比想象残酷:曾在Spider 1.0上达到86%准确率的GPT-4,在更贴近真实企业数据的Spider 2.0上,整体成功率骤降至6%。纯黑盒方案的局限性暴露无遗——它本质上是一个“单次翻译”模型,生成错误SQL后既不验证也不修正,用户只能得到错误的查询结果。
本文将从架构设计、核心流程到工程实现,完整构建一个具备自我修正能力的Text2SQL智能体,全部代码基于Python + LangGraph,可直接落地。
传统Text2SQL是一次性的“翻译”,而智能体模式赋予了模型“思考与自我纠错”的能力。完整的执行闭环包含以下阶段:
我们基于LangGraph构建状态机,每个节点完成一个环节,边控制流转逻辑。
# graph.py - Text2SQL智能体工作流核心
from langgraph.graph import StateGraph, END
from typing import TypedDict, List
from pydantic import BaseModel
class AgentState(TypedDict):
question: str # 原始问题
rewritten: str # 改写后的问题
relevant_tables: List[str] # 召回的关联表
sql: str # 生成的SQL
execution_result: str # 执行结果/错误信息
is_valid: bool # SQL是否可执行
attempts: int # 尝试次数
max_attempts: int # 最大尝试次数
# 节点1: 问题改写
def rewrite_question(state: AgentState) -> AgentState:
prompt = f"将以下问题改写为更适合生成SQL的表述:{state['question']}"
rewritten = llm.invoke(prompt)
return {**state, "rewritten": rewritten}
# 节点2: Schema检索(向量召回)
def retrieve_schema(state: AgentState) -> AgentState:
# Chroma向量库检索最相关的K张表
tables = vector_store.similarity_search(state["rewritten"], k=5)
return {**state, "relevant_tables": [t.metadata["table_name"] for t in tables]}
# 节点3: SQL生成
def generate_sql(state: AgentState) -> AgentState:
schema_text = "\n".join(get_table_ddl(t) for t in state["relevant_tables"])
prompt = f"""
基于以下表结构,将问题转换为SQL:
表结构:{schema_text}
问题:{state['rewritten']}
仅输出SQL语句。
"""
sql = llm.invoke(prompt)
return {**state, "sql": sql}
# 节点4: 执行验证(事务回滚)
def execute_sql(state: AgentState) -> AgentState:
try:
conn.begin()
cursor.execute(state["sql"])
cursor.fetchall() # 仅验证可执行性
conn.rollback()
return {**state, "execution_result": "成功", "is_valid": True}
except Exception as e:
conn.rollback()
return {**state, "execution_result": str(e), "is_valid": False}
# 节点5: 反思修正
def reflect_and_fix(state: AgentState) -> AgentState:
if state["attempts"] >= state["max_attempts"]:
return {**state, "sql": f"-- 重试耗尽,最后错误:{state['execution_result']}"}
prompt = f"""
之前生成的SQL执行失败:
SQL: {state['sql']}
错误信息:{state['execution_result']}
请修正SQL,仅输出修正后的SQL。
"""
fixed_sql = llm.invoke(prompt)
return {**state, "sql": fixed_sql, "attempts": state["attempts"] + 1}
# 构建状态图
graph = StateGraph(AgentState)
graph.add_node("rewrite", rewrite_question)
graph.add_node("retrieve", retrieve_schema)
graph.add_node("generate", generate_sql)
graph.add_node("execute", execute_sql)
graph.add_node("reflect", reflect_and_fix)
graph.set_entry_point("rewrite")
graph.add_edge("rewrite", "retrieve")
graph.add_edge("retrieve", "generate")
graph.add_edge("generate", "execute")
# 条件边:验证通过则结束,否则进入反思
def should_continue(state: AgentState) -> str:
if state["is_valid"]:
return END
if state["attempts"] >= state["max_attempts"]:
return END
return "reflect"
graph.add_conditional_edges("execute", should_continue)
graph.add_edge("reflect", "execute") # 修正后重新执行验证
app = graph.compile()对于更复杂的查询场景,单一Agent难以胜任。多智能体框架通过角色分工实现专业化处理:
# 多智能体协作示例(基于smolagents的ReAct框架)
from smolagents import CodeAgent, Tool
class SchemaInspector(Tool):
name = "schema_inspector"
description = "探查数据库表结构,返回相关表和列"
def forward(self, question: str) -> str:
# 向量检索 + 列值采样
return relevant_schema
class SQLExecutor(Tool):
name = "sql_executor"
description = "执行SQL并返回结果或错误"
def forward(self, sql: str) -> str:
return execute_with_rollback(sql)
agent = CodeAgent(
tools=[SchemaInspector(), SQLExecutor()],
model=HuggingFaceModel("Qwen/Qwen2.5-Coder-7B-Instruct")
)
result = agent.run("查询上个月销售额最高的前10名销售人员")1. Schema级联检索:企业级数据库动辄数百张表,将全量DDL塞入上下文会导致Token爆炸。通过向量检索在毫秒级完成表召回,将Schema裁剪至5-8张核心表。
2. 沙盒验证:生成的SQL必须进入受限沙盒执行语法检查,确认无误后方可推向生产库。
3. 确定性回退:利用数据库的EXPLAIN机制进行执行代价预演,一旦发现全表扫描等灾难性操作,强制触发反思重写。
4. 人机协同熔断:涉及数据修改或高风险聚合查询时,系统应在执行前挂起并通过WebSocket推送二次确权请求。
本文从架构设计、LangGraph状态机实现到多智能体协作,完整构建了一个具备自修正能力的Text2SQL智能体。核心启示在于:AI生成SQL不是终点,执行验证-错误反馈-反思修正的闭环才是工业级可用的关键。工程化的Text2SQL系统必须用“白盒”思维将大模型的概率输出约束在可控范围内——让AI负责翻译,让确定性的规则和验证机制负责执行,让人类在关键节点拥有最终裁决权。这不仅是技术的选择,更是对生产环境每一行SQL负责的工程态度。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。