资讯详情

使用 smolagents 构建 Text-to-SQL 代码智能体:从单表查询到多表联表

📅 2026/9/19 23:17:53 | 华诺云谱 👁 阅读
使用 smolagents 构建 Text-to-SQL 代码智能体:从单表查询到多表联表
使用 smolagents 构建 Text-to-SQL 代码智能体从单表查询到多表联表【免费下载链接】smolagents smolagents: a barebones library for agents that think in code.项目地址: https://gitcode.com/gh_mirrors/smo/smolagents导读本文基于 smolagents 官方示例教程对应仓库文档 docs/source/ko/examples/text_to_sql.md并附可运行参考实现 examples/text_to_sql.py带你用 smolagents 从零实现一个以代码为思考方式的 SQL 智能体它能用自然语言提问、自动生成 SQL、执行查询、并根据执行结果反复自我修正。读完本文你将掌握三条核心技能用tool装饰器封装自定义 SQL 工具、用CodeAgentInferenceClientModel驱动推理循环、以及通过升级工具描述与模型来应对多表 JOIN 等复杂查询。为什么不用传统 Text-to-SQL 流水线标准的 text-to-SQL 流水线一条自然语言 → 一条 SQL 的直出映射在实际使用中往往不够稳定模型可能生成错误 SQL更糟的是它可能没有报错地返回一个错误或无用的结果——因为流水线没有任何机制去检查输出是否合理。而基于智能体agent的架构天然解决了这个问题智能体可以批判性地检查执行结果并自主决定是否需要重写查询、换一种写法再试一次。这正是 smolagents 的价值所在——它把生成 → 执行 → 检查 → 修正的闭环交给模型自己驱动显著提升查询成功率。环境准备与依赖安装首先安装必要的依赖包!pip install smolagents python-dotenv sqlalchemy --upgrade -qsmolagents本文主角极简的代码思考式智能体库python-dotenv从.env文件加载环境变量sqlalchemy用于定义表结构、执行 SQL 查询本文使用其 SQLite 内存引擎。调用推理服务需要有效的 Hugging Face 令牌通过环境变量HF_TOKEN提供。用python-dotenv加载from dotenv import load_dotenv load_dotenv()从源码看InferenceClientModel在未显式传入token时会自动回退读取HF_TOKEN环境变量见 src/smolagents/models.py因此上面的加载步骤是让智能体有模型可用的前提。用 SQLAlchemy 搭建内存版 SQL 环境教程使用 SQLite 内存数据库sqlite:///:memory:这样无需外部数据库服务即可演示完整流程。先导入 SQLAlchemy 相关组件并创建引擎与元数据对象from sqlalchemy import ( create_engine, MetaData, Table, Column, String, Integer, Float, insert, inspect, text, ) engine create_engine(sqlite:///:memory:) metadata_obj MetaData() def insert_rows_into_table(rows, table, engineengine): for row in rows: stmt insert(table).values(**row) with engine.begin() as connection: connection.execute(stmt) table_name receipts receipts Table( table_name, metadata_obj, Column(receipt_id, Integer, primary_keyTrue), Column(customer_name, String(16), primary_keyTrue), Column(price, Float), Column(tip, Float), ) metadata_obj.create_all(engine) rows [ {receipt_id: 1, customer_name: Alan Payne, price: 12.06, tip: 1.20}, {receipt_id: 2, customer_name: Alex Mason, price: 23.86, tip: 0.24}, {receipt_id: 3, customer_name: Woodrow Wilson, price: 53.43, tip: 5.43}, {receipt_id: 4, customer_name: Margaret James, price: 21.11, tip: 1.00}, ] insert_rows_into_table(rows, receipts)这里定义了一张名为receipts小票的表包含四列receipt_id小票 ID整数主键、customer_name顾客名最长 16 字符的字符串主键、price消费金额、tip小费金额并插入了 4 条样本数据。核心技巧把表结构喂给智能体智能体的 LLM 并不了解你的表结构所以必须把表的 schema 显式描述出来。教程通过 SQLAlchemy 的inspect接口自动提取列信息并格式化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)输出如下Columns: - receipt_id: INTEGER - customer_name: VARCHAR(16) - price: FLOAT - tip: FLOAT这段自动生成的描述随后会被写进工具的 docstring成为 LLM 提示词的一部分——这是整个 Text-to-SQL 智能体知道表长什么样的关键。创建自定义工具sql_enginesmolagents 中工具Tool是智能体与外部世界交互的接口。创建一个工具需要满足两个条件详见 docs/source/ko/tutorials/tools.mddocstring 中包含参数列表Args:部分与工具功能描述输入和输出都有类型提示type hints。使用tool装饰器将普通函数转换为工具from smolagents import tool tool def sql_engine(query: str) - str: 테이블에 SQL 쿼리를 수행할 수 있습니다. 결과를 문자열로 반환합니다. 테이블 이름은 receipts이며, 설명은 다음과 같습니다: Columns: - receipt_id: INTEGER - customer_name: VARCHAR(16) - price: FLOAT - tip: FLOAT Args: query: 수행할 쿼리입니다. 올바른 SQL이어야 합니다. output with engine.connect() as con: rows con.execute(text(query)) for row in rows: output \n str(row) return output工具的行为要点函数体通过engine.connect()建立连接执行传入的 SQLtext(query)把每一行结果追加到字符串中返回返回类型是str——这意味着智能体拿到的是查询结果的字符串表示它会读懂这个字符串判断结果是否符合预期工具的description属性会被系统注入到 LLM 的提示词中这正是tool底层实现所保证的装饰器会解析函数的 docstring 与类型标注动态构造Tool子类见 src/smolagents/tools.pyLLM 据此学会何时调用、如何调用这个工具。底层原理tool 做了什么从源码看tool装饰器src/smolagents/tools.py会通过get_json_schema解析函数签名生成 JSON Schema从中提取工具名、描述、输入参数与返回类型动态创建一个SimpleTool子类把name、description、inputs、output_type等属性一一赋值把原函数包装为forward方法。这意味着工具的 docstring 质量直接决定 LLM 对工具的理解程度——这正是教程反复强调在描述里写明表结构的原因。组装 CodeAgent 并跑通第一个查询smolagents 的主智能体类是CodeAgent它以代码的形式书写动作而不是 JSON 工具调用并遵循 ReAct 框架行动-观察循环反复迭代、根据之前的输出结果自我改进。模型model则是驱动整个智能体的 LLM。使用InferenceClientModel可以经由 Hugging Face 的 Inference API 以 serverless无服务器或 Dedicated Endpoint 方式调用 LLM也可以替换为其他私有 APIfrom smolagents import CodeAgent, InferenceClientModel agent CodeAgent( tools[sql_engine], modelInferenceClientModel(model_idmeta-llama/Llama-3.1-8B-Instruct), ) agent.run(Can you give me the name of the client who got the most expensive receipt?)agent.run(...)收到自然语言问题后会循环执行让 LLM 生成一段 Python 代码 → 代码调用sql_engine工具 → 观察执行结果 → 判断是否已得到答案 → 未完成则继续生成下一步代码直到得出最终答案。InferenceClientModel 关键参数从源码文档字符串src/smolagents/models.py可以确认InferenceClientModel支持以下常用参数参数默认值说明model_idQwen/Qwen3-Next-80B-A3B-Thinking使用的 Hugging Face 模型 ID也可以是已部署 Inference Endpoint 的 URLproviderauto推理服务商名称如hyperbolic、together等设为 auto 时按用户设置自动选择传入base_url时该参数失效token无HF API 认证令牌未传入时回退到HF_TOKEN环境变量或 HF CLI 配置timeout120API 请求超时时间秒api_keyNonetoken的别名与 OpenAI 客户端风格对齐两者不能同时传入bill_toNone计费账号需为当前用户所属且已订阅 Enterprise Hub 的组织base_urlNone自定义推理服务的基础 URL例如显式指定服务商与令牌的写法model InferenceClientModel( model_idQwen/Qwen3-Next-80B-A3B-Thinking, providerhyperbolic, tokenyour_hf_token_here, max_tokens5000, )升级挑战多表 JOIN 与动态工具描述单表查询已经跑通现在让智能体面对更复杂的问题——跨多张表的连接JOIN查询。添加第二张表 waiters为每个receipt_id记录对应的服务员姓名创建waiters表table_name waiters waiters Table( table_name, metadata_obj, Column(receipt_id, Integer, primary_keyTrue), Column(waiter_name, String(16), primary_keyTrue), ) metadata_obj.create_all(engine) rows [ {receipt_id: 1, waiter_name: Corey Johnson}, {receipt_id: 2, waiter_name: Michael Watts}, {receipt_id: 3, waiter_name: Michael Watts}, {receipt_id: 4, waiter_name: Margaret James}, ] insert_rows_into_table(rows, waiters)关键操作更新工具的 description表结构变了工具的说明就必须跟着变否则 LLM 依然以为只有一张receipts表。教程演示了如何用inspect动态生成多表描述并直接赋值给工具updated_description Allows you to perform SQL queries on the table. Beware that this tools output is a string representation of the execution output. It can use the following tables: inspector inspect(engine) for table in [receipts, waiters]: columns_info [(col[name], col[type]) for col in inspector.get_columns(table)] table_description fTable {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) sql_engine.description updated_description这里有两个值得注意的工程细节动态生成用inspect(engine)遍历所有表自动拼接描述避免手写硬编码表多了也易于维护直接改属性sql_engine.description updated_description覆盖默认描述——因为tool生成的SimpleTool实例中description是普通类属性运行时修改即刻生效。换用更强的模型新任务哪位服务员收到的小费总额最高需要 JOIN 与聚合推理教程选择切换到更强大的Qwen/Qwen3-Next-80B-A3B-Thinking模型agent CodeAgent( tools[sql_engine], modelInferenceClientModel(model_idQwen/Qwen3-Next-80B-A3B-Thinking), ) agent.run(Which waiter got more total money from tips?)执行后智能体应当能自动写出形如SELECT w.waiter_name, SUM(r.tip) FROM receipts r JOIN waiters w ON r.receipt_id w.receipt_id GROUP BY w.waiter_name ...的 JOIN 查询并基于返回结果给出答案。整个升级过程无需改动任何工具逻辑只改了描述与模型——这正是智能体方案的灵活性所在。配套可运行示例仓库中提供了与教程对应的完整可运行脚本 examples/text_to_sql.py其内容与本教程的单表查询部分一致注意其中模型 ID 写作meta-llama/Meta-Llama-3.1-8B-Instruct两种写法在 HF Hub 上指向同一模型按实际可用 ID 填写即可。可以直接在本地运行验证pip install smolagents python-dotenv sqlalchemy export HF_TOKENhf_xxx python examples/text_to_sql.py总结与进阶方向通过本教程你掌握了 smolagents 中 Text-to-SQL 智能体的完整构建链路创建新工具用tool装饰器 docstring 类型标注封装sql_engine把 SQL 执行能力暴露给智能体更新工具描述表结构变化时用inspect动态重写description保持 LLM 对数据库认知的时效性升级模型增强推理面对 JOIN 等复杂任务切换到更强 LLM如Qwen/Qwen3-Next-80B-A3B-Thinking即可显著提升成功率。更深一层看这套模式可以直接迁移到真实生产场景把 SQLite 内存引擎替换为 PostgreSQL/MySQL 连接串把表描述生成逻辑接入真实的 schema 元数据再配合 docs/source/ko/conceptual_guides/react.md 中介绍的 ReAct 循环原理、以及 docs/source/ko/tutorials/tools.md 中更丰富的工具编写技巧即可构建属于你自己的企业级自然语言查询系统。【免费下载链接】smolagents smolagents: a barebones library for agents that think in code.项目地址: https://gitcode.com/gh_mirrors/smo/smolagents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。