本节使用 Chinook SQLite 数据库,封装一个 SQL 查询工具,让 Agent 根据自然语言问题生成 SQL、执行查询并组织最终答案。
很多业务数据已经存在关系型数据库里。与其把整张表塞进 prompt,不如给 Agent 一个受控的 SQL 查询工具,让它按需查询。
| 方式 | 优点 | 风险 |
|---|---|---|
| 把数据复制进 prompt | 简单直接 | 上下文有限,数据容易过期 |
| 让 Agent 调 SQL 工具 | 按需查询真实数据 | 需要限制权限并处理错误 SQL |
让 Agent 从自然语言问题出发,生成 SQL 查询 Chinook.db,再用查询结果回答“哪个 S 开头艺术家最受欢迎”。
Notebook 使用 LangChain Community 的 SQLDatabase 工具类连接本地 SQLite 文件。
from langchain_community.utilities import SQLDatabase
db = SQLDatabase.from_uri("sqlite:///resources/Chinook.db")Chinook 是常见的示例音乐数据库,包含 Artist、Album、Track、InvoiceLine 等表,适合演示 SQL Agent。
工具接收一段 SQL 字符串,执行 db.run(query)。如果 SQL 出错,工具返回错误信息,让模型有机会修正查询。
@tool
def sql_query(query: str) -> str:
"""Obtain information from the database using SQL queries"""
try:
return db.run(query)
except Exception as e:
return f"Error: {e}"
sql_query.invoke("SELECT * FROM Artist LIMIT 10")课程工具没有做权限限制。生产环境中应限制只读查询、限制表范围、加超时和行数上限,避免模型生成危险 SQL。
把 sql_query 作为唯一工具交给 Agent。模型会根据问题决定写什么 SQL,并把 SQL 作为工具参数。
agent = create_agent(
model=deepseek_model(),
tools=[sql_query],
)
question = HumanMessage(
content="Who is the most popular artist beginning with 'S' in this database?"
)
response = agent.invoke({"messages": [question]})模型不是直接知道数据库答案,而是先推断需要查询哪些表和字段,再调用 sql_query 获得结果。
Notebook 特意打印倒数第三条消息里的 tool call 参数,用来查看模型实际发送给数据库的 SQL。
print(response["messages"][-3].tool_calls[0]["args"]["query"])
print(response["messages"][-1].content)SQL Agent 的调试重点是查询是否正确。最终答案看起来合理,不代表 SQL 一定查对了表、join 或排序。
SELECT。LIMIT、超时和错误分类。SQL 工具让 Agent 能访问结构化业务数据;但 SQL 的正确性和安全性必须在工具边界处理,不能只依赖模型自觉。