技术

Agent 生成的 SQL,为什么不能直接运行

执行层要把模型意图变成经过校验、授权、限额和审计的真实操作。本文给出 SQL、代码与工具调用的统一执行网关、失败语义和上线门禁。

技术 #Data Agent#Tool Calling#SQL#沙箱#最小权限#审计

模型输出一条 SQL,只说明它提出了一个候选动作,并不表示已经获得生产数据库的执行权。即使是 SELECT,也可能扫描数 TB、读取敏感列、触发外部函数,或者因为错误 Join 返回一份看似合理的结果。

执行层的任务,是把自然语言意图转换成一个受控操作:在运行前校验,在运行时限制,在运行后核验,并为每次副作用留下可追踪记录。

执行网关从动作提案到审计记录的控制链

生成与授权必须分开。模型可以建议“创建工单”或“运行查询”,真正的工具网关根据身份、策略、参数和风险决定是否允许。

执行请求需要结构化契约

不要让执行器直接接收一段自由文本。一个最小请求应包含:任务与步骤 ID、调用者与委派身份、工具名和版本、结构化参数、输入产物、语义版本、允许动作、预算、超时、幂等键、审批引用和输出契约。

工具返回也要标准化:状态、执行 ID、结果引用、行数与截断、成本、Schema、数据水位、警告、可重试标志和审计引用。模型只看到完成下一步所需的结果摘要;凭证、内部错误栈和不相关敏感数据留在可信运行时。

运行前先过三道门

语法与静态检查

解析 SQL 或代码为语法树,拒绝不支持的语句、动态执行、未限定目标和危险库。只靠正则匹配 DROP 不够:写操作可能隐藏在存储过程、多语句、外部函数或工具参数里。

语义与数据检查

确认表、字段、指标版本、粒度、Join 基数和时间范围符合计划。执行层不重新发明业务口径,但要验证请求引用的契约仍存在、版本兼容、输入数据已就绪。

策略与资源检查

根据最终用户或受限服务身份检查资源、行列范围、用途、地域、环境、读写类型和审批。再估算扫描量、运行时间、并发与外部调用成本。未知成本不是零成本;无法估算时使用更严格限额或要求审批。

沙箱不是一个开关

SQL、Python 和外部 API 需要不同隔离:

  • SQL:只读事务、允许对象清单、查询超时、扫描上限、结果行数和敏感列控制。
  • 代码:短期容器、固定依赖、CPU/内存/磁盘上限、无默认外网、只挂载任务所需文件。
  • 文件工具:限定工作目录、文件类型、大小与恶意内容扫描,防止路径穿越。
  • 外部 API:目标域名和动作清单、短期凭证、参数校验、速率限制和幂等策略。

隔离环境也要可复现。记录运行镜像、依赖、随机种子、输入版本与工具版本;否则“代码执行成功”无法转化为可复核结果。

查询成功之后还要验证

HTTP 200、进程退出码 0 或 SQL 完成,只代表工具没有报告执行失败。结果仍需检查:返回 Schema 是否符合合同、是否为空或被截断、数据水位是否满足任务、关键不变量是否成立、单位与分母是否正确。

对高影响查询,可以先 EXPLAIN 或运行限量探测,再执行完整版本。对工程变更,先生成差异、运行测试和影响分析;授权后执行,再回读目标状态。生成成功、提交成功和最终生效应是不同状态。

重试必须理解副作用

只读且确定性的查询在瞬时故障后通常可以限次重试。写操作则必须使用逻辑操作 ID,并核对下游是否真正支持幂等。超时并不等于失败;在未知状态下直接重发,可能创建两个工单、发送两封邮件或重复写入。

失败至少分为:调用者输入错误、策略拒绝、资源超限、可重试基础设施故障、工具确定性失败、结果验证失败和状态未知。每类错误都有不同去向,不能统一让模型“再试一次”。

审计记录什么,也要知道不记录什么

审计事件应连接任务、用户、委派身份、计划步骤、工具版本、参数摘要、策略决定、审批、执行 ID、结果引用和最终状态。高风险动作保存可验证的参数快照。

普通日志不应记录密钥、完整敏感结果或无需保留的提示词。审计系统本身需要访问控制、完整性保护和保留策略;“有日志”不等于日志足以追责。

最小上线测试

上线前至少验证:

  • 越权表、列、行和工具调用全部被阻断;
  • 注释、别名、子查询和多语句不能绕过静态规则;
  • 扫描量、超时、输出行数和并发上限有效;
  • 沙箱无法访问未授权文件、网络和环境变量;
  • 相同幂等键不会造成重复副作用;
  • 超时后的未知状态会先查询而不是盲目重试;
  • 取消任务能在执行端真正停止,而非只停止聊天界面;
  • 结果截断、空集、缺失数据和验证失败会被正确标记。

执行层成熟的标志,不是 Agent 能调用多少工具,而是每个动作都能回答:谁授权、在什么边界内运行、用了多少资源、产生了什么结果、失败后怎样恢复。只有这样,模型输出才可能安全地进入真实系统。