首页 / 文章 / 实用笔记:Python中的文本转SQL代理——LLM工具调用教程

实用笔记:Python中的文本转SQL代理——LLM工具调用教程

《实用笔记》操作指南:Python中的文本转SQL代理——LLM工具调用教程:适用于采用该模式的团队的契约、校验规则及可直接插入的代码片段。

2929 词

本指南将逐步构建从原始材料到可运行系统的完整流程,内容为:使用仅包含代码的工具在 Python 中构建文本转 SQL 智能体。重点在于可操作的步骤、明确的检查点,以及可直接放入代码仓库而无需猜测其用途的代码。 为便于整体把握,在修改代码之前需先明确输入参数、各步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行相应步骤,而无需猜测其中的隐藏状态。 可将此阶段视为输入与经过验证的输出之间的契约。需为相关成果命名、定义成功标准,并杜绝无声的半完成状态。

划分:定义与实现

在研究《分割:定义与实现》时,首先需列出契约内容:所需输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。 每次调用时都要记录请求ID、模型ID和延迟时间。如果没有这些记录,间歇性的服务提供商错误就会被视为应用程序的缺陷。

所需准备

在处理“你需要什么”这一环节时,首先写下合同条款:所需的输入参数、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将配置信息与应用程序代码分开存放。环境文件、密钥存储以及功能开关应集中于一个位置,这样操作人员无需查看整个系统结构即可进行审计。 在每次调用时记录请求ID、模型ID以及延迟时间。如果没有这些记录,间歇性的服务错误就会被视为应用程序的故障。

pip install acruxcore

1. 初始化一个值得查询的数据库

在完成“1. 建立可供查询的数据库”这一任务时,首先需明确接口规范:所需的输入参数、成功标识以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 同时记录正常流程与异常恢复流程。重试机制、人工审核环节以及错误消息处理都是产品功能的一部分,而非后续需要补充的内容。 每次调用时都要记录请求ID、模型ID以及响应延迟时间。如果没有这些记录,间歇性的服务错误就会被视为应用程序的缺陷。 在完成“1. 建立可供查询的数据库”这一任务时,首先需明确接口规范:所需的输入参数、成功标识以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将这一阶段视为输入与验证后输出之间的契约。为相关组件命名,定义成功判定标准,杜绝无声的半完成状态。

conn.executescript("""
    CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, category TEXT, price REAL, stock INTEGER);
    CREATE TABLE orders (id INTEGER PRIMARY KEY, product_id INTEGER REFERENCES products(id),
                          quantity INTEGER, order_date TEXT, customer TEXT);
""")
conn.executemany("INSERT INTO products VALUES (?, ?, ?, ?, ?)", PRODUCTS)
conn.executemany("INSERT INTO orders VALUES (?, ?, ?, ?, ?)", ORDERS)
python seed_db.py
# Seeded store.db: 8 products, 15 orders.

2. 在控制面板中注册模型

  1. 将模型视为可测量的表面在控制面板中注册效果最佳。在扩大范围之前,先记录一份理想的输出样本、一个故障案例以及回滚说明;同时在功能结果旁标注处理时间以及令牌或查询成本。提前了解成本情况,可避免从演示环境过渡到共享环境时出现意外费用。在教授循环逻辑之前,先锁定解释器及依赖项文件。笔记本电脑与持续集成环境之间的差异是API演示中最常见的隐性故障原因。

3. 在控制面板中编写提示词

  1. 在控制面板中编写提示语时,最好将其视为可测量的界面。在扩大范围之前,先记录一个成功的案例、一个失败案例以及回滚说明。 将配置置于应用程序代码之外。环境文件、密钥存储和功能标志应集中存放于一个位置,这样操作人员无需查看整个架构即可进行审计。 在讲解循环逻辑之前,先锁定解释器及依赖项的版本。笔记本电脑与持续集成环境之间的差异是API演示中最常见的隐性故障原因。
You are a data analyst for an online store. Answer questions about products and
sales by querying a SQLite database with the query_database tool. Never guess —
always query.
Schema:
CREATE TABLE products (id INTEGER PRIMARY KEY, name TEXT, category TEXT, price REAL, stock INTEGER);
CREATE TABLE orders (id INTEGER PRIMARY KEY, product_id INTEGER REFERENCES products(id), quantity INTEGER, order_date TEXT, customer TEXT);Write a single read-only SQLite SELECT, call query_database with it, then answer
in one or two sentences using only the rows it returns. Prices are in USD;
revenue = quantity * price; order_date is YYYY-MM-DD.

4. 通过代码定义工具——并让其自行发布

  1. 将工具在代码中定义——并让其自行发布,这种做法在将其视为可度量的对象时效果最佳。在扩大范围之前,需记录一份理想的运行日志、一个故障案例以及回滚说明。 同时记录正常流程与恢复流程。重试机制、人工审核环节以及错误处理都是产品本身的一部分,而非后续需要补充的内容。 在讲解循环逻辑之前,先锁定解释器及依赖项的版本。笔记本电脑与持续集成环境之间的差异是API演示中最常见的隐性故障原因。
  2. 将工具在代码中定义——并让其自行发布,这种做法在将其视为可度量的对象时效果最佳。在扩大范围之前,需记录一份理想的运行日志、一个故障案例以及回滚说明。 应将此阶段视为输入与已验证输出之间的契约。为相关产物命名,明确成功标准,杜绝隐性部分完成的情况。
from acruxcore import AcruxCore, acrux
@acrux.tool
async def query_database(sql: str) -> list[dict]:
    """Run a read-only SQL SELECT against the store database.    Args:
        sql: A single read-only SQLite SELECT statement.
    """
    statement = sql.strip().rstrip(";").strip()
    if not statement.lower().startswith("select"):
        raise ValueError("Only read-only SELECT statements are allowed.")
    if ";" in statement:
        raise ValueError("Only a single statement is allowed.")
    conn = sqlite3.connect(f"file:{DB_PATH}?mode=ro", uri=True)
    conn.row_factory = sqlite3.Row
    try:
        return [dict(row) for row in conn.execute(statement).fetchall()]
    finally:
        conn.close()
{
  "name": "query_database",
  "description": "Run a read-only SQL SELECT against the store database.",
  "parameters": {
    "type": "object",
    "properties": {
      "sql": {"type": "string", "description": "A single read-only SQLite SELECT statement."}
    },
    "required": ["sql"]
  }
}
async with AcruxCore() as hub:
    await hub.tools.sync([query_database])

5. 让控制面板决定工具的文本表述

在修改代码之前,需先明确输入参数、该步骤的负责人以及终止条件。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。应在功能结果旁记录执行时间以及令牌或查询成本。提前显示成本可避免在从演示环境切换到共享环境时出现意外费用。应将客户端构建与消息循环分开,这样即便更换服务提供商,也无需重写对话状态机。

@acrux.tool
async def check_disclosure_policy(field: str) -> dict:
    # No docstring, on purpose. See below — the absence is the mechanism.
    sensitive = field.strip().lower() in {"customer", "customer_name", "email"}
    return {
        "field": field,
        "may_disclose": not sensitive,
        "guidance": (
            "Do not name an individual customer. Report aggregate figures only."
            if sensitive
            else "This column may be shown to the user."
        ),
    }
{
  "name": "check_disclosure_policy",
  "description": null,
  "parameters": {
    "type": "object",
    "properties": {"field": {"type": "string"}},
    "required": ["field"]
  }
}
Published: ToolSyncResult(tool_id='2572965e-…', version_number=2, committed=False, alias='production', superseded_source=None)

6. 运行它

第6点:在修改代码之前,先运行程序并确定输入参数、该步骤的负责人以及终止条件。操作员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。配置信息应置于应用程序代码之外,环境文件、密钥存储以及功能标志应集中存放于一个操作员可以审核的位置,无需阅读整个系统结构。将客户端构建部分与消息处理循环分开,这样就可以更换提供方,而无需重写对话状态机。

async def ask(hub: AcruxCore, question: str) -> str:
    rendered = await hub.prompts.render("sql-analyst-agent", "production")
    messages = [*rendered.messages, {"role": "user", "content": question}]
    result = await hub.gateway.run_prompt_with_tools(
        rendered,
        messages=messages,
        tools=[query_database, check_disclosure_policy],
        trace={"name": "sql-analyst-agent", "session_id": "sql-agent-demo"},
    )
    print(f"  (trace {result.trace_id})")
    return result.content
export ACRUXCORE_API_KEY=<your personal api key>
export ACRUXCORE_BASE_URL=https://api.acruxcore.com/api/v1
python sql_agent.py
Q: Which product generated the most total revenue, and how much?
  (trace 606dbd38-cb34-4cc3-a1a1-ec4dc9af87b2)
A: The **Aeron Chair** generated the most total revenue at **$4,185.00**.
Q: How many total units were ordered in June 2026?
  (trace d1ace20b-ae00-4c4d-9294-a613327e1583)
A: In June 2026, a total of **93 units** were ordered.Q: Who is our biggest customer by total spend?
  (trace ea57a392-9af2-41b6-bfd8-48297ee17a8c)
A: Our biggest customer by total spend has spent $6,995.00. I'm unable to disclose the
   specific customer name due to privacy policy, but I can confirm this is our top
   customer by total spending.

7. 查看追踪信息

对于第7点:在修改代码之前,先阅读跟踪日志,明确输入参数、该步骤的负责人以及退出条件。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。需同时记录正常流程和异常恢复流程。重试机制、人工审核环节以及错误处理都是产品本身的组成部分,而非后续需要补充的功能。应将客户端构建逻辑与消息循环分离,这样就可以在不重写对话状态机的情况下更换服务提供方。对于第7点:在修改代码之前,先阅读跟踪日志,明确输入参数、该步骤的负责人以及退出条件。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。应将此阶段视为输入参数与经过验证的输出结果之间的契约,为相关工件命名,明确成功判定标准,杜绝无声的半完成状态。

8. 将多次运行合并为一次会话

在处理第8组任务时,遇到会话相关情况时,首先记下契约内容:所需输入、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外费用。 每次调用都要记录请求ID、模型ID和延迟时间。如果没有这些记录,间歇性的服务提供商错误就会被视为应用程序故障。

9. 好处:无需修改代码即可更换模型

在处理第9部分“收益:无需修改代码即可更改模型”时,首先需明确相关规范:所需的输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合要求。 应将配置信息与应用程序代码分开。环境文件、密钥存储以及功能开关应集中存放于一个位置,这样操作人员无需查看整个系统结构即可进行审计。 每次调用时都要记录请求ID、模型ID以及响应延迟时间。如果没有这些记录,偶尔出现的服务端错误就会被误认为是应用程序的故障。

你的代码真的需要拥有该工具吗?

在探讨“代码是否应该拥有该工具?”这一问题时,首先需明确契约内容:所需输入、成功信号以及部分失败时的处理方式。这份清单能确保后续的代码修改保持一致性。 同时记录正常流程与异常恢复流程。重试机制、人工审核环节以及错误处理都属于产品功能的一部分,而非后续的优化工作。 每次调用时都要记录请求ID、模型ID以及延迟时间。如果没有这些记录,间歇性的服务错误就会被视为应用程序的缺陷。 在探讨“代码是否应该拥有该工具?”这一问题时,首先需明确契约内容:所需输入、成功信号以及部分失败时的处理方式。这份清单能确保后续的代码修改保持一致性。 将此阶段视为输入与验证后输出之间的契约。为相关成果命名,定义成功判定标准,并拒绝默许部分完成的情况。

下一步该做什么

下一步该往何处发展,最好将其视为一个可衡量的指标。在扩大范围之前,先记录一份理想的运行日志、一个故障案例以及回滚说明。

在功能结果旁记录执行时间以及令牌或查询成本。提前了解这些成本,就能避免在从演示环境过渡到共享环境时出现意外账单。

在讲解循环逻辑之前,先锁定解释器及依赖项文件。笔记本电脑与持续集成环境之间的差异是API演示中最常见的隐性故障来源。

操作检查清单

操作检查清单作为可衡量的指标来使用效果最佳。在扩大范围之前,先记录一份理想的运行日志、一个故障案例以及回滚说明。

优先选择小型且可测试的单元,而非庞大的脚本。当某个步骤出现故障时,故障应能指向单一的责任模块,而非复杂的流程链。

在讲解循环之前,先锁定解释器及依赖项的版本。笔记本电脑与持续集成环境之间的差异是API演示中最常见的隐性故障原因。

在网关处进行身份验证,在数据层再次授权。仅凭承载令牌无法界定租户边界。

在耗时步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次对同一LLM调用收费。

锁定依赖项的版本,并记录用于运行演示的镜像摘要。可重复性远比经验知识更重要。

在升级技术栈之前,先冻结各版本,为关键路径保存标准操作记录,并确认回滚步骤。共享环境需要设置速率限制、进行租户检查,同时明确密钥轮换的负责人。与其追求花哨的一次性演示,不如注重扎实的可靠性。

a664c3276a43的批量处理说明:不要将提供者密钥放入代码仓库,为每个会话设置令牌使用上限,并将转录内容存储在评估测试文件旁,以便后续更换模型时仍能保持可比性。

在处理强化措施第0条时,先列出相关规范:所需输入、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改始终符合要求。优先选择小型、可测试的单元,而非冗长的脚本;当某一步骤失败时,故障应能指向单一责任点,而非复杂的流程问题。

强化措施细节0/766:针对此条要求,需测量执行时间、错误类型以及令牌消耗情况,然后依据固定的评估标准而非主观判断来决定是否保留该修改。

强化措施1作为可测量的界面来处理时效果最佳。在扩大范围之前,先记录一份理想的运行结果、一个故障案例以及回滚说明。在功能结果旁同时记录执行时间以及令牌或查询成本。提前了解这些成本信息,就能避免在系统从演示环境过渡到共享环境时出现意外费用。

强化细节1/766:为该措施测量实际执行时间、错误类型以及令牌消耗情况,然后依据固定的评估标准而非主观经验来决定是否保留该变更。

对于强化措施2,在修改代码之前需明确输入参数、负责该步骤的人员以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测系统的隐藏状态。需同时记录正常流程和故障恢复流程。重试机制、人工审核环节以及错误处理方式都是产品本身的组成部分,而非后续需要补充的内容。

强化措施细节2/766:记录该代码段的运行时间、错误类型以及代币消耗情况,然后依据固定的评估标准而非个人经验来决定是否保留该修改。

在处理强化措施笔记3时,首先写下合约的详细内容:所需的输入参数、成功标志,以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 将此阶段视为输入与验证后输出之间的契约,为相关组件命名,明确成功判定标准,并杜绝无声的半完成状态。

强化措施细节3/766:记录该代码段的运行时间、错误类型以及代币消耗情况,然后依据固定的评估标准而非个人经验来决定是否保留该修改。

强化措施4作为可测量的表面来处理时效果最佳。在扩大范围之前,先记录一份理想的运行日志、一个故障案例以及回滚说明。 将配置置于应用程序代码之外。环境文件、密钥存储和功能标志应集中存放于一个位置,以便操作员无需查看整个系统结构即可进行审计。

强化措施细节4/766:针对该措施需测量耗时、错误类型以及令牌使用情况,然后依据固定的问题集而非个人经验来判断是否保留该变更。

对于强化措施5,在修改代码之前需明确输入参数、该步骤的负责人以及完成标准。操作员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏的状态。 优先选择小型、可测试的单元,而非庞大的脚本。当某个步骤出现故障时,故障原因应能指向单一责任主体,而非复杂的流程链。

强化措施细节5/766:为该笔记记录运行时间、错误类型以及代币消耗情况,然后依据固定的问题清单而非个人经验来判断是否保留该变更。

在处理强化措施笔记6时,首先写下合约的必要输入参数、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改更加规范。在功能结果旁记录时间以及代币或查询成本,提前了解成本情况可以避免从演示环境过渡到共享环境时出现意外费用。

强化措施细节6/766:为该笔记记录运行时间、错误类型以及代币消耗情况,然后依据固定的问题清单而非个人经验来判断是否保留该变更。

强化措施7作为可测量的界面来处理时效果最佳。在扩大范围之前,需记录一份成功的测试案例、一个故障案例以及回滚说明。同时将正常流程与恢复流程记录下来。重试机制、人工审核环节以及死信处理都是产品本身的一部分,而非后续补充的内容。

强化细节7/766:针对此措施需测量处理时间、错误类型以及令牌消耗情况,然后依据固定的评估标准而非个人经验来决定是否保留该变更。