智能体问题:工具调用失败

· 2 minutes read · 419 字 · 系列:AI / 个人助理智能体

当智能体的"手"不听使唤

如果说幻觉是智能体"脑子"的问题,那工具调用失败就是"手脚"的问题。智能体不仅要思考,还要行动——调用 API、查询数据库、操作文件系统。而但凡涉及外部系统交互,失败的维度比纯文本幻觉要多得多。

Arize AI 2026 年对生产环境智能体的故障分析指出:工具相关失败占 Agent 异常的 40% 以上,其中最危险的不是"调用失败"本身,而是失败后的错误处理——智能体对错误的理解和处理能力,往往比工具调用本身更不可靠。

三大失败模式

模式一:静默错误——最危险的失败

工具返回了错误信息,但智能体没有正确解读,把错误响应当做正常结果继续推理。

典型场景

// 智能体调用天气 API
{"tool": "get_weather", "arguments": {"city": "北京", "date": "2026-07-01"}}

// API 返回错误
{"error": "city_not_found", "message": "City name must be in English: Beijing"}

// 智能体把 json 当成了天气数据继续推理
"根据返回的数据,北京7月1日的湿度和 error 字段显示..."

这比调用直接报错更危险——至少报错时智能体知道出错了,还能重试。静默错误时,智能体浑然不知,把垃圾数据当成金子继续加工。

为什么会发生?

  1. 错误格式不统一:不同 API 的错误响应结构不同(HTTP 状态码、JSON error 字段、HTML 错误页……),智能体难以用统一逻辑识别
  2. Prompt 缺少错误处理指令:很多人在 system prompt 里只写了"使用 XX 工具查询",没写"如果工具返回错误,你应该……"
  3. 模型倾向"继续完成任务":遇到异常数据时,模型的训练倾向是给用户一个答案,而不是停下来讨论 API 报错

模式二:参数构造错误——最常见的失败

智能体理解了要调什么工具,但构造参数时出错。

常见错误类型

  • 格式错误:日期传 2026/07/01 而 API 要 2026-07-01
  • 类型错误:传字符串 "5" 而 API 要整数 5
  • 枚举错误:传 "medium" 而有效值只有 ["low", "mid", "high"]
  • 遗漏必填参数:忘了传 currency 字段
  • 语义错误:传了合法格式但语义不对,比如把 page_size=100 传给了限制最大 50 的分页接口

根因分析

模型对 API 的理解来自 prompt 中的工具描述(Function Schema)。如果描述不够精确——比如某个参数的合法值只写了 string 没有枚举——模型就只能"猜"。

更微妙的问题是参数间约束:参数 A 的值影响参数 B 的合法范围。比如 country=USstate 是两字母缩写,country=CNstate 是省份全名。这种上下文相关的约束,Function Schema 很难完整表达。

模式三:无限循环重试——最消耗资源的失败

工具调用失败 → 智能体重试 → 参数稍有不同但仍然错误 → 再次失败 → 再重试……

典型循环

尝试 1: get_weather(city="北京") → error: use English name
尝试 2: get_weather(city="Beijng") → error: invalid city name   (拼写错误)
尝试 3: get_weather(city="Beijing ") → error: invalid city name (多了空格)
尝试 4: get_weather(city="Peking") → error: invalid city name  (旧称)
尝试 5: get_weather(city="BJ") → error: invalid city name      (缩写)
...

每次重试都是一个完整 LLM 推理周期——消耗 token、时间和钱。更糟的是,有些智能体框架默认无限重试,直到 token 预算耗尽。

为什么会陷入循环?

  1. 错误反馈太模糊:“invalid city name” 没说正确的应该是什么
  2. 缺乏退出策略:智能体没有被教导"尝试 3 次后应该放弃或求助"
  3. 模型的"执着"倾向:一旦开始尝试,模型倾向于继续而非承认失败

工程对策

对策一:强类型 Schema 约束

工具定义尽可能精确,减少模型"猜"的空间:

# 宽松定义——容易出错
{"city": {"type": "string", "description": "城市名称"}}

# 精确定义——大幅减少错误
{
  "city": {
    "type": "string",
    "enum": ["Beijing", "Shanghai", "Guangzhou", "Shenzhen", ...],
    "description": "城市英文名,仅支持以下列表中的值"
  },
  "date": {
    "type": "string",
    "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
    "description": "日期,格式必须为 YYYY-MM-DD"
  }
}

越严格越好——这不仅约束模型,还为后续校验提供了依据。

对策二:错误处理 Prompt 模板

在 System Prompt 中明确错误处理流程:

当你收到工具的错误响应时:
1. 识别错误类型(参数错误 / 服务不可用 / 权限不足)
2. 如果是参数错误:修正参数后重试一次
3. 如果重试仍然失败:向用户说明错误,不要继续尝试
4. 如果是服务不可用:告知用户并建议稍后重试
5. 绝对不要把错误响应当做正常数据继续推理
6. 同一个工具最多调用 3 次

这几条规则可以消除大部分静默错误和无限循环问题。

对策三:超时和重试熔断

MAX_RETRIES = 3
RETRY_BACKOFF = [1, 3, 5]  # 递增等待秒数

for attempt in range(MAX_RETRIES):
    result = call_tool(tool_name, params)
    if not is_error(result):
        return result
    if attempt < MAX_RETRIES - 1:
        time.sleep(RETRY_BACKOFF[attempt])
        # 基于错误信息修正参数
        params = fix_params_from_error(result, params)
    else:
        raise ToolExhaustedError(f"{tool_name} 失败 {MAX_RETRIES} 次")

核心原则:有限重试 + 递增退避 + 强制熔断

对策四:错误信息结构化

让工具的错误响应足够具体,包含修复指导:

// 差的错误信息
{"error": "invalid_parameter"}

// 好的错误信息
{
  "error": "invalid_parameter",
  "parameter": "city",
  "reason": "City name must be in English",
  "hint": "Try: Beijing, Shanghai, Guangzhou",
  "received": "北京"
}

这样的错误信息让智能体不仅能"知道错了"还能"知道怎么改"。

对策五:工具调用后置校验

在工具返回后增加一层自动校验:

def validate_tool_output(tool_name, output):
    # 类型校验
    if tool_name == "get_weather" and output.get("temperature"):
        temp = output["temperature"]
        if not (-60 <= temp <= 60):
            return f"温度 {temp}°C 超出物理可能范围,数据可能有误"

    # 错误响应检测
    if "error" in output or "Error" in str(output):
        return f"工具返回了错误: {output}"

    return None  # 通过校验

更深层的设计问题

工具设计的"防呆"原则

很多工具调用失败不是因为智能体笨,而是因为工具设计不友好。好的工具 API 设计应该遵循:

  1. 最小惊讶原则:默认行为符合直觉
  2. 容错输入"Beijing ""Beijing" 应该等价
  3. 丰富错误信息:错误响应应该包含足够信息让调用方自我修正
  4. 幂等设计:同一调用执行多次结果一致,避免重复执行的副作用

“不调用"也是一种能力

人类在工作时不是每个问题都要动手——很多时候"判断不需要操作"本身就是正确决策。智能体也需要这种能力:

  • 信息不足时先查询,不要盲目操作
  • 操作不可逆时先确认
  • 连续失败时及时上报,不要硬撑

这需要在 Agent 框架层面设计"思考-判断-行动"的三段式流程,而非简单的"思考-行动"两段式。

小结

工具调用失败不像幻觉那样"高端”——它更多是工程问题而非智能问题。但正因为如此,它也更容易被系统性解决

  • 强 Schema 压缩参数构造错误
  • 错误处理 Prompt 减少静默错误
  • 熔断机制 防止无限循环
  • 结构化错误信息 加速自我修正
  • 后置校验 最后一道防线

做好这些工程规范,工具调用的可靠性可以从 60% 提升到 95% 以上。剩下的问题是——当智能体执行的是一个跨越 10 步、20 步的长链路任务时,如何保证它不从中间断掉?下一篇我们聊:可靠性与中途崩溃

© 2026 CAO ZUOHUA. All rights reserved.