在本教程中,我们将了解如何使用 smolagents.
让我们从最重要的问题开始:为什么不保持简单,使用标准的文本到 SQL 管道?
标准的文本到 SQL 管道很脆弱,因为生成的 SQL 查询可能不正确。更糟糕的是,查询可能不正确,但不会引发错误,反而会提供一些不正确/无用的输出,而不会引发警报。
👉 相反,代理系统能够严格检查输出结果,并决定是否需要更改查询,从而大大提高性能。
让我们建立这个代理!💪
首先,我们设置 SQL 环境:
复制的
从 sqlalchemy 导入 (
create_engine、
元数据
表、
列
字符串
整数
浮点数、
插入
检查
文本、
)
engine = create_engine("sqlite:///:memory:")
metadata_obj = MetaData()
# 创建城市 SQL 表
table_name = "收据"
receipts = Table(
table_name、
metadata_obj.Column("receipt_id", Integer, primary_key=True)
Column("receipt_id", Integer, primary_key=True)、
Column("customer_name", String(16), primary_key=True)、
Column("price", Float)、
列("小费",浮动)、
)
metadata_obj.create_all(engine)
行 = [
{"receipt_id":1, "customer_name":"Alan Payne", "price":12.06, "tip":1.20},
{"receipt_id":2, "customer_name":"Alex Mason", "价格":23.86, "tip":0.24},
{"receipt_id":3, "customer_name":"Woodrow Wilson", "价格":53.43, "tip":5.43},
{"receipt_id":4, "customer_name":"Margaret James", "price":21.11, "tip":1.00},
]
for row in rows:
stmt = insert(receipts).values(**row)
with engine.begin() as connection:
cursor = connection.execute(stmt)建立我们的代理 #
现在,让我们用工具检索我们的 SQL 表。
代理系统会将工具的描述属性嵌入 LLM 的提示中:为 LLM 提供如何使用工具的信息。这就是我们要描述 SQL 表的地方。
复制的
inspector = inspect(engine)
columns_info = [(col["name"], col["type"]) for col in inspector.get_columns("receipts")] 列_信息
table_description = "Columns:\n" + "\n".join([f" - {name}: {col_type}" for name, col_type in columns_info])
print(table_description)复制的
列: - receipt_id:INTEGER - customer_name: VARCHAR(16) - 价格FLOAT - 小费:FLOAT
现在,让我们来构建我们的工具。它需要具备以下条件:读取 工具文档 了解更多详情)
- 带有
参数部分列出参数。 - 输入和输出均有类型提示。
复制的
从 smolagents 导入工具
@tool
def sql_engine(query: str) -> str:
"""
允许对表执行 SQL 查询。返回结果的字符串表示。
表名为 "收据"。其描述如下
列:
- receipt_id:INTEGER
- customer_name: VARCHAR(16)
- 价格FLOAT
- 小费:FLOAT
参数:
query:要执行的查询。这应该是正确的 SQL。
"""
output = ""
with engine.connect() as con:
rows = con.execute(text(query))
for row in rows:
output += "\n" + str(row)
返回输出现在,让我们创建一个利用这一工具的代理。
我们使用 代码代理是 smolagents 的主要代理类:它是一个用代码编写操作的代理,可以根据 ReAct 框架迭代之前的输出。
模型是为代理系统提供动力的 LLM。HfApiModel 允许您使用 HF 的推理 API(通过无服务器端点或专用端点)调用 LLM,但您也可以使用任何专有 API。
复制的
from smolagents import CodeAgent, HfApiModel
agent = CodeAgent(
tools=[sql_engine]、
model=HfApiModel("meta-llama/Meta-Llama-3.1-8B-Instruct")、
)
agent.run("Can you give me the name of the client who got the most expensive receipt?")第 2 级:表连接 #
现在,让我们来增加挑战性!我们希望代理能处理多个表之间的连接。
因此,我们再制作一个表,记录每个收据 ID 的服务员姓名!
复制的
table_name = "服务员"
收据 = 表(
table_name、
metadata_obj.Column("receipt_id", Integer, primary_key=True)
Column("receipt_id", Integer, primary_key=True)、
Column("waiter_name", String(16), primary_key=True)、
)
metadata_obj.create_all(engine)
rows = [
{"receipt_id":1, "waiter_name":"Corey Johnson"}、
{"receipt_id":2, "waiter_name":"Michael Watts"}、
{"收据编号":3, "waiter_name":"Michael Watts"}、
{"收据编号":4, "waiter_name":"Margaret James"}、
]
for row in rows:
stmt = insert(receipts).values(**row)
with engine.begin() as connection:
cursor = connection.execute(stmt)因为我们更改了表格,所以要更新 SQLExecutorTool 与该表的描述一致,以便让 LLM 正确利用该表中的信息。
复制的
updated_description = """允许对表执行 SQL 查询。请注意,该工具的输出是执行输出的字符串表示。
它可以使用以下表格:"""
inspector = inspect(engine)
for table in ["receipts", "waiters"]:
columns_info = [(col["name"], col["type"]) for col in inspector.get_columns(table)] 列信息
table_description = f "表'{table}':/n"。
table_description += "Columns:\n" + "\n".join([f" - {name}: {col_type}" for name, col_type in columns_info])
updated_description += "\n\n" + table_description
print(updated_description)由于这个请求比前一个更难,我们将切换 LLM 引擎,使用功能更强大的 Qwen/Qwen2.5-Coder-32B-Instruct!
复制的
sql_engine.description = updated_description
agent = CodeAgent(
tools=[sql_engine]、
model=HfApiModel("Qwen/Qwen2.5-Coder-32B-Instruct")、
)
agent.run("Which waiter got more total money from tips?")它可以直接工作!设置出乎意料的简单,不是吗?
这个例子已经完成!我们已经触及了这些概念:
- 开发新工具。
- 更新工具说明。
- 改用更强的 LLM 有助于代理推理。
✅ 现在,你可以去构建你梦寐以求的文本到 SQL 系统了!✨
