Agent Tool Execution:四种执行边界

比较模型直连工具、Tool Gateway、Sandbox Worker 与 Human Approval Queue 四种执行架构:谁验证参数、谁持有 credential、动作在哪里执行、怎样避免同一个副作用做两次、批准怎样和最终参数绑定,以及每种边界失守时用户看到什么、怎么恢复。

模型输出 tool call 只是一个 proposal。真正的系统设计从四个问题开始:谁验证参数、谁持有 credential、动作在哪里执行、同一个副作用怎样不做两次。 四个答案决定了一次错误的调用(参数被 prompt injection 改写、模型理解错意图、重试时重复提交)能波及多远。

本章讲的是「一次 tool call 从提议到执行」这一段。工具怎么通过 MCP 暴露给 Agent 见 MCP 工具平台架构;不可信代码关在哪一层见 Sandboxed Agent 执行架构;Agent 代表用户拿什么 token 见 Agent 身份与委托授权;跨小时的长任务怎么恢复见 Durable Agent 执行架构。

四种 Agent tool execution 架构

有约束的设计问题

一个企业内部助手要接四类工具:查天气、查内部文档这类只读、低风险、每轮对话调很多次的工具;几十个团队各自维护的业务 API,要按租户和用户限权、统一审计;运行模型写出来的 Python 分析用户上传的表格;以及退款、删除数据、对外发邮件这类做了就收不回来的动作。四类工具该走哪种执行边界?

四种执行架构

架构Credential 在哪里State owner适合主要风险
Direct Tool Callapp process 的 server-side secret storeapp runtime低风险、只读、少量工具blast radius 与 app 相同
Tool Gatewaygateway vault / delegated tokengateway policy + audit log多租户、统一 policy 和审计gateway 成为集中瓶颈
Sandbox Workerbroker 传 capability,worker 临时取 scoped tokenjob storecode、文件、浏览器等高风险执行escape、资源耗尽、结果污染
Approval Queueapproval service 保存 proposal 与决定approval record付款、删除、发布等高影响动作approval stale 或用户误判

必须画出的 envelope

Tool request 需要包含 tool name、schema-validated arguments、tenant/user scope、trace id、deadline 和 idempotency key。Credential 不放进 model context,也不由 browser 直接调用 provider。Sandbox 接收短期 capability,不接收长期 master key。Approval 发生在执行之前,而且批准内容必须与最终执行参数绑定。

一个具体的 envelope 长这样:

{
  "tool": "refund_order",
  "call_id": "call_7f3a",
  "arguments": { "order_id": "ord_1029", "amount_cents": 4500, "currency": "AUD" },
  "scope": { "tenant_id": "t_acme", "user_id": "u_88", "on_behalf_of": "u_88" },
  "trace_id": "tr_5c1e",
  "deadline_ms": 8000,
  "idempotency_key": "run_42:step_7:refund_order",
  "arguments_hash": "sha256:9b1d…"
}

每个字段都对应一个失败方式:没有 call_id,结果回不到对应的调用(OpenAI 的 function calling 用 call_id 把工具输出和那次调用对上,Anthropic 的 tool use 用 tool_use_id);没有 scope,工具只能用一个共享账号去查所有租户的数据;没有 deadline_ms,一个卡住的下游把整轮对话拖到超时;没有 idempotency_key,重试就是第二次退款;没有 arguments_hash,人批准的是 45 块、执行的可能是被改过的 4500 块。

一次调用的执行顺序

  1. 校验形状。 按 JSON Schema 校验参数,拒绝多余字段。OpenAI 的 function calling 支持在工具定义上设 strict: true,让模型输出严格匹配 schema;这只保证形状,不保证语义,amount_cents 是合法整数不代表这笔退款该退。
  2. 校验语义和权限。 用 scope 里的用户身份判断这个人能不能对这个订单做这件事,金额是否超过订单金额。这一步在服务端,不能交给模型或前端。
  3. 决定执行边界。 按工具的风险等级路由到直连、网关、沙箱或审批队列。
  4. 执行,带幂等键和超时。 先按幂等键查执行记录,已完成就直接返回上次的结果;下游支持幂等键的(例如 Stripe)把键原样传下去。
  5. 记录。 写执行记录和审计日志:谁、代表谁、哪个工具、脱敏参数、判定、结果大小、耗时。
  6. 把结果交回模型,当作不可信内容。 截断过大的输出,标明来源。工具结果里的「忽略之前的指令」只是文字,但模型可能照做;OWASP 把这类经由外部内容注入的攻击列为 LLM01。

顺序不能反:权限检查放在执行之后等于没有检查;幂等检查放在执行之后,重复的副作用已经发生了。

1. Direct Tool Call:工具就在应用进程里

模型返回 tool call,应用在同一个进程里调用函数,credential 从服务端 secret store 读。实现最简单,延迟最低,没有额外的一跳。

代价是 blast radius 和应用一样大:工具能访问的,就是应用进程能访问的全部数据和密钥;一个参数注入成功,影响的是应用的全部权限。只适合只读、低风险、参数空间很小的工具,例如查天气、查公开文档。即使是直连,credential 也不进 model context,工具返回的内容也要截断。

2. Tool Gateway:所有调用经过一个策略点

应用把 envelope 发给网关,网关做认证、按租户和工具的策略放行或拒绝、限流、记审计,再用自己保管的 credential 或用户委托的 token 调后端。几十个团队的 API 挂在同一个网关后面,策略和审计只写一份。

关键点在 token:网关调后端时用的应该是为这个后端、这个用户签发的 token,而不是客户端发来的那张。MCP 的授权规范对 MCP server 有同样的要求:必须验证 token 是签给自己的,不能把收到的 token 透传给上游 API。

代价是网关成为集中依赖:它挂了所有工具都不可用,它慢了所有工具都慢。要按无状态服务多副本部署,策略从配置中心读,按工具设独立的超时和并发上限,一个慢后端不能占满网关的全部连接。

3. Sandbox Worker:不可信代码在隔离环境里跑

模型写的代码、要打开的文件、要访问的网页,都在一次性的隔离环境里执行。broker 给 worker 一个短期 capability(例如只能读这一个上传文件、只能写一个输出目录、15 分钟后过期,数字为假设),worker 不持有任何长期密钥。结果写回 job store,由 broker 取回再交给模型。

这一种的风险是边界本身:逃逸、资源耗尽(死循环、fork 炸弹、写满磁盘)、结果污染(代码输出里夹带给模型的指令)。沙箱启动失败时必须硬失败,不能退回到在应用进程里直接跑。选哪一层隔离(操作系统沙箱、加固容器、微型虚拟机、带浏览器的专用 VM)见 Sandboxed Agent 执行架构,那一章也有互动 Lab:/system-design-lab/sandboxed-agent-execution-architectures。

4. Approval Queue:先存提案,人批准后再执行

高影响的动作不直接执行,而是把完整 envelope 存成一条 proposal,给人看参数的可读版本,人点批准后才执行。MCP 的工具规范写明应当始终有人在回路里、能拒绝工具调用;OpenAI 构建 Agent 的安全指南也建议对 MCP 工具保持开启 tool approval,让用户审查每一次操作。

两个细节决定这一层是否真的有效:

  • 批准绑定参数。 批准记录里存 arguments_hash,执行前重新计算并比对,不一致就拒绝,要求重新审批。否则批准的和执行的可能不是同一件事。
  • 批准有有效期。 proposal 设过期时间(例如 15 分钟,假设),过期要重新提。订单状态、账户余额会变,一小时前合理的退款现在可能已经退过了。

等人批准可能要几小时,执行进程不能一直挂着等。等待状态要持久化,由 checkpoint 或工作流引擎保管,见 Durable Agent 执行架构。

四种架构共同的底线

  • Credential 永远不进 model context。 模型看到的只有工具名和参数。
  • 工具结果是不可信输入。 截断、标来源、不把它拼进 system 或 developer 指令。OpenAI 的安全指南建议不要把不可信变量放进 developer message,并用结构化输出约束节点之间的数据流。
  • 每个副作用带稳定的幂等键。 键由「运行 ID + 步骤 + 工具」派生,重试时不变。
  • 每次调用都有超时和输出上限。 超时后向模型返回明确的错误,而不是无限等待。
  • 审计记脱敏参数,不记原始 token。

故障与恢复

架构故障用户看到什么恢复
Direct网页内容里的注入让模型调用了一个本不该调用的工具助手做了用户没要求的事高风险工具不放在直连层;工具结果当不可信内容;只读工具才直连
Direct一个工具调用卡住整轮对话超时每个调用单独的 deadline,超时返回错误给模型
Gateway网关把客户端 token 透传给后端后端用错误的受众 token 执行,越权网关为每个后端单独换 token;后端拒绝受众不对的 token
Gateway一个慢后端占满网关连接所有工具都变慢按工具的并发上限和超时隔离(bulkhead),见 Circuit Breaker
Sandbox模型写的代码死循环或写满磁盘任务超时,节点变慢CPU、内存、磁盘、墙钟时间上限;超限杀掉并返回错误
Sandbox沙箱启动失败,代码退回到应用进程执行表面上一切正常,实际边界消失沙箱不可用时硬失败,不做降级执行
Approval人批准后,参数在执行前被改写批准了 45 块,退了 4500 块执行前比对 arguments_hash,不一致就拒绝
Approval批准几小时后才执行,订单已经退过重复退款批准有效期;执行前重新读业务状态;幂等键
所有网络超时后重试同一个副作用做了两次执行前查幂等键记录,下游也带幂等键

怎么选

  • 只读、低风险、参数空间小、调用频繁:Direct Tool Call,credential 在服务端,结果截断。
  • 多个团队、多个租户的业务 API,要统一限权和审计:Tool Gateway,按后端换 token,按工具隔离超时和并发。
  • 运行模型生成的代码、处理用户上传的文件、操作浏览器:Sandbox Worker,短期 capability,边界失败即失败。
  • 不可逆或高影响的动作(钱、删除、对外发布):Approval Queue,批准绑定参数哈希,带有效期,等待状态持久化。
  • 一个工具可以同时走两层:退款经过网关做权限和审计,再进审批队列等人。

回到开头的企业助手:查天气和查文档直连;各团队业务 API 走网关;表格分析走沙箱;退款、删除、对外发邮件走网关 + 审批队列。

面试时这样回答

  1. 复述约束:列出工具,按「只读 / 有副作用 / 执行不可信代码 / 不可逆」分级,并问清多租户和审计要求。
  2. 点名执行路径:模型提议 → schema 校验 → 服务端按用户权限校验 → 按风险路由(直连、网关、沙箱、审批)→ 幂等检查后执行 → 审计 → 结果作为不可信内容交回模型。
  3. 说清状态和 credential 归谁:credential 在 secret store 或网关,模型看不到;执行记录和幂等键在 job store;批准在 approval record,绑定参数哈希。
  4. 说一个代价和一个故障:例如审批让高风险动作慢几分钟到几小时,换来不可逆操作有人把关;故障选「批准后参数被改写」,修法是执行前比对哈希。

一手证据