AI 求职每日一课 · 2026-09-16封面缘起核心代码面试来源
AI JOB COURSE · WEEK 2 · DAY 3

工具执行层:
注册、超时与错误

把昨日 Tool Schema 接入固定注册表,完成一个可中止、可分类、可观测的服务端执行器。

30预计分钟
4错误类型
6练习测试
02

为什么今天学这个

前后依赖前天跑通 Function Calling 循环,昨天写好 Tool Schema;今天解决模型提出调用后,服务端怎样安全执行。
  • 注册表限定允许调用的能力。
  • 超时与取消保护连接、并发和总预算。
  • 结构化错误区分修正输入、退避重试和人工处理。
03

三个核心要点

  • 模型只有提议权:工具名只映射到预先注册函数,身份和依赖由服务端注入。
  • 超时必须贯穿调用链:把 AbortSignal 传给 HTTP、数据库或 SDK,而不只是停止等待。
  • 错误稳定分类:模型拿安全 code/message,内部监控保留受控堆栈。
记忆钩子:白名单决定能不能做,deadline 决定做多久,错误码决定下一步。
04

最小可运行执行器

const registry = new Map();
registry.set("create_reminder_v1", handler);

async function executeTool(call, timeoutMs = 200) {
  const fn = registry.get(call.name);
  if (!fn) return fail("UNKNOWN_TOOL");
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  try { return await fn(call.arguments, { signal: controller.signal }); }
  catch { return fail(controller.signal.aborted ? "TIMEOUT" : "INTERNAL_ERROR"); }
  finally { clearTimeout(timer); }
}

完整可复制代码、输入和预期输出见 Markdown 版;把 timeoutMs 改为 10 应得到 TIMEOUT。

05

生产环境会怎么翻车

  • 动态执行工具名:提示注入升级成代码执行;改为固定注册表。
  • 只 race 不取消:接口超时但底层仍占资源;把 AbortSignal 传到底。
  • 所有失败都重试:业务拒绝和未知状态被重复放大;稳定分类并设预算。
  • 日志泄密:字段级脱敏,只记录必要元数据。
06

动手练习与验收

20–30 分钟增加 get_weather,并写 6 个可重复测试。
  • 已注册工具成功;未知工具拒绝。
  • 缺参数返回 INVALID_ARGUMENT。
  • 10ms 超时返回 TIMEOUT,底层收到 abort。
  • 日志只含 call ID、工具名、耗时和错误码。
07

面试表达

30 秒回答

工具执行放在服务端固定注册表中,执行前做 Schema、身份和业务校验,执行时把统一 deadline 和 AbortSignal 传到底层,最后返回稳定的成功或错误结构。

追问重点

  • 按用户派生可用工具,不让模型决定资源身份。
  • 副作用超时先用幂等键对账,不能直接重试。
  • trace、调用 ID、版本、耗时与错误码形成审计链。
08

今日自测

基础
为什么不能动态 eval?
模型输出不可信,固定注册表才限定能力。
取舍
Promise.race 等于取消吗?
不等于;底层任务可能继续运行。
场景
支付超时能自动重试吗?
先凭幂等键查状态,再决定。
09

权威来源与明日预告

明天:幂等与重试,为写操作加业务幂等键、指数退避和状态对账。
P 切换投影一屏一页模式