声明:本文为学习笔记与工程化延伸,核心脉络来自阿里云开发者技术号发布的《AI coding 智能体设计》,在此基础上按“可落地教程”的方式重组,并补充了工具闭环的最小实现骨架与失败恢复清单;如有出入,以原文与官方文档为准。原文链接见文末参考。

如果你只问我一句:AI coding 智能体和普通 Chat 的分水岭是什么?
我会回答:不是“它能写多漂亮的代码”,而是它有没有稳定跑起来这条链路——工具调用闭环

这一篇我们只讲工程本质:工具怎么注册、怎么被模型选择、怎么执行、怎么回填、失败了怎么恢复。


01|先把“工具闭环”画出来:你才能知道问题卡在哪

用户需求
  │
  ├─ 把工具列表(schema/权限/描述)发给模型
  │
  ├─ 模型输出:要么 final answer,要么 toolCall(name,args)
  │
  ├─ 执行 toolCall:读文件/搜索/运行命令/调用 MCP…
  │
  ├─ 回填 tool output(Observation)到上下文
  │
  └─ 模型基于 Observation 再推理 → 直到完成

很多“看起来像幻觉”的问题,其实是闭环断了:

  • 工具没注册 → 模型看不到工具
  • 工具能看到但没权限 → 调不起来
  • 工具能调用但输出没回填 → 模型只能硬编
  • 工具输出太长/太乱 → 模型抓不到关键证据

02|MCP 在闭环里扮演什么角色?

在《AI coding 智能体设计》的语境下:
**MCP(Model Context Protocol)**是把外部能力(工具/提示词命令)以标准接口接入到智能体的方式之一。

你可以简单理解:

  • 工具(Tool):读文件、搜索、运行命令、访问 API…(“手”)
  • MCP:把这些“手”做成可插拔模块(“标准接口”)

工程上最关键的一点是:模型并不会“自己执行工具”
它只会输出“我要调用某个工具”的结构化意图;真正执行、沙箱、权限、超时、输出裁剪,都在智能体侧。


03|工具注册:别只给工具名,要给“可被选择的描述”

工具注册不是把函数塞进列表那么简单。你需要给模型足够信息,让它在正确时机选到正确工具:

  • 工具名(稳定、可预测)
  • 工具描述(什么时候用、什么时候别用)
  • 参数 schema(类型、必填、示例)
  • 权限范围(允许读哪些目录、允许执行哪些命令)
  • 输出约束(最大长度、是否结构化)

以开源项目为例,《AI coding 智能体设计》提到 Gemini-CLI 的内置核心工具位于 packages/core/src/tools/,并通过配置侧创建 registry;也可以通过配置项限制可用工具集合(核心思想:默认全可用 → 允许按白名单收敛)。这类设计非常值得借鉴。


04|最小实现骨架:一个 tool-calling loop(伪代码)

下面这段伪代码可以帮助你把闭环跑起来(只用于理解结构):

type ToolCall = { name: string; arguments: Record<string, unknown> };

async function agentLoop(userPrompt: string) {
  const tools = buildToolSchemas(); // name/desc/params
  let messages = [{ role: "user", content: userPrompt }];

  while (true) {
    const resp = await llm({
      messages,
      tools, // 把工具 schema 交给模型
    });

    if (resp.toolCall) {
      const call: ToolCall = resp.toolCall;
      const out = await runToolWithGuards(call); // 权限/超时/裁剪
      messages.push({ role: "tool", name: call.name, content: out }); // 回填
      continue;
    }

    return resp.finalText;
  }
}

闭环的关键点在 runToolWithGuards
没有护栏的工具闭环,会把“能自动化”变成“不可控”。


05|执行护栏(Guards):四个必须做的防爆设计

  1. 权限白名单

    • 读文件:限定在项目根目录/指定目录
    • 执行命令:限定可执行命令集合(或完全禁用)
  2. 超时与资源限制

    • 每次工具调用设 timeout
    • 限制输出大小,避免把 stdout 当日志黑洞
  3. 输出裁剪与结构化

    • 输出太长要截断 + 给摘要
    • 优先输出结构化(JSON/表格/要点)
  4. 可观测性(日志/追踪)

    • 记录:toolName、args、耗时、exitCode、输出长度、错误原因
    • 这会极大提升你排错与迭代 prompt 的效率

06|失败恢复:让智能体“会停、会问、会降级”

工具闭环最容易出事故的不是成功路径,而是失败路径。建议你至少实现下面 4 类恢复策略:

失败 1:工具不可用/未注册
  • 现象:模型只会“建议你手动执行”
  • 处理:回到 registry,补工具;或提供替代工具(例如从 ShellTool 降级为 ReadFileTool)
失败 2:权限不足/被拒绝
  • 现象:反复调用同一工具,反复失败
  • 处理:让智能体输出“需要的最小权限”并请求确认;默认降级为只读分析
失败 3:输出过长/噪声过大
  • 现象:工具输出很长,模型抓不到重点
  • 处理:裁剪输出;先总结再回填;只回填关键片段(例如 error stack 的前后 80 行)
失败 4:工具结果与预期不一致
  • 现象:命令执行成功但结果为空/不相关
  • 处理:让智能体给出“下一步最小探测动作”(再读 1 个文件/再搜 1 个关键字),而不是开始硬编

一句话:失败恢复的目标是让它变得可控
能停、能问、能降级、能继续推进。


07|你可以直接套用的“工具闭环验收清单”

发布/上线前自检:

  • 模型能看到工具 schema(工具名、描述、参数)
  • 至少 3 个只读工具可用(读文件/搜索/列目录)
  • 每次工具调用都有超时与输出长度限制
  • 工具输出会回填到上下文(且可追踪)
  • 失败时不会无限重试(有重试上限/降级路径)
  • 写操作需要确认点或白名单(默认只读)

08|系列导航(收藏用)

  • 系列 01:从 Chat 到 Agent:4 个关键零件
  • 系列 02:命令系统:从提示词模板到可扩展子命令
  • 系列 03:@路径上下文:如何给材料而不喂爆上下文
  • 系列 04(本文):MCP 与工具闭环:注册、调用、回填与失败恢复
  • 系列 05:上下文治理:清空/压缩/摘要与预算控制
  • 系列 06:SubAgent:上下文隔离与模块化协作
  • 系列 07:规约驱动:让交付可复现的 Spec 工作流
  • 系列 08:迷你 CLI:从伪代码到最小可运行骨架

参考与致谢

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐