如何利用 Function Calling 实现 LLM 自动调用本地数据库执行 SQL 查询
把 LLM 当成数据库的“自然语言接口”,核心不在于让它写 SQL,而在于通过 Function Calling 把执行权交还给本地环境。很多人直接把 Schema 丢给 AI 让它写 SQL,然后手动复制到 Navicat 运行,这太低效了。
我目前在项目里跑的一套闭环流程是:LLM 识别意图 → 输出结构化参数 → 本地 Python 脚本执行 → 结果回传 LLM → 自然语言总结。
关键配置技巧:精准定义 Tool 描述
AI 能不能准确调用,全看 tools 列表里的 description 写得够不够具体。如果你只写“查询数据库”,它经常会乱写字段名。我建议把表结构快照直接写在函数描述里。
{
"name": "execute_sql_query",
"description": "执行只读SQL查询。可用表:users(id, name, email, created_at), orders(id, user_id, amount, status)。注意:必须使用 LIMIT 限制结果集,禁止执行 DROP/DELETE 操作。",
"parameters": {
"type": "object",
"properties": {
"sql": {
"type": "string",
"description": "标准的 PostgreSQL SQL 查询语句"
}
},
"required": ["sql"]
}
}本地执行端的避坑指南
最容易踩的坑是权限失控。千万不要给 LLM 连接数据库的 root 权限。我创建了一个名为 ai_readonly 的数据库用户,仅授予 SELECT 权限。
执行逻辑建议采用这种结构:
import psycopg2
from openai import OpenAI
client = OpenAI()
def run_query(sql):
# 建立只读连接
conn = psycopg2.connect(dbname="mydb", user="ai_readonly", password="password", host="localhost")
cur = conn.cursor()
try:
cur.execute(sql)
return cur.fetchall()
except Exception as e:
return f"SQL Error: {str(e)}"
finally:
cur.close()
conn.close()
# 处理 LLM 返回的 tool_calls
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "帮我看看上个月订单金额最高的前三个用户是谁?"}],
tools=tools
)
if response.choices[0].message.tool_calls:
for tool_call in response.choices[0].message.tool_calls:
# 提取 SQL 并运行
import json
args = json.loads(tool_call.function.arguments)
result = run_query(args['sql'])
# 将结果喂回给 AI 转化为人话
# ... 再次调用 API 传入 tool 响应 ...效率提升点:上下文压缩
如果查询结果集太大,直接塞回给 LLM 会瞬间撑爆 Token 窗口,甚至导致 AI 迷失。我的处理方式是:在 run_query 之后,先判断结果行数。如果超过 20 行,只截取前 5 行并告知 AI “结果过多,已截断”,强制它在 SQL 中使用更精准的过滤条件,而不是在内存里过滤。
这种方案比传统的 RAG 强在能够处理聚合计算(如 SUM, AVG),而不需要把整个数据库向量化。
免费 AI 工具箱 · 全部完全免费
全部回复 (0)
还没有回复,来发第一条吧!
