Agent 调用工具经常失败或选错工具,怎么排查和优化?

#RAG#Agent#面试八股

Agent 调用工具经常失败或选错工具,怎么排查和优化?

工具调用(Tool Calling)是 Agent 最容易出问题的一环:模型要读懂工具描述、选对工具、填对参数、看懂返回结果,任何一步偏了,整条链路就断。 排查的关键不是反复改提示词,而是把一次调用拆成断点,逐个定位在哪一环断了。

1. 结论:先分类症状,再对症下药

症状典型表现高概率根因优先修复
不调用直接凭记忆回答提示没要求用工具、工具不在候选集加"必须核实"约束、检查工具注册
选错工具该查订单却去查物流描述重叠、命名含糊重写描述、加反例、收敛工具数
参数错类型不符、缺必填schema 太松、字段名歧义严格 schema + 枚举 + 默认值
编造工具名调用了不存在的方法工具清单太长、示例过时运行时校验 + 明确报错清单
忽略返回拿到数据仍说"查不到"返回值结构复杂、关键信息埋太深结构化裁剪、显式摘要字段
重复调用同一参数连调三次无去重、结果不满足预期相同调用短路、结果显式回显

2. 机制:把链路切成四个断点

① 描述可读性        ② 选型             ③ 填参             ④ 用结果
工具文档 ──▶ 模型挑工具 ──▶ 模型生成参数 ──▶ 运行时执行 ──▶ 模型读返回
   │             │               │               │             │
   └─ 名称/描述   └─ 候选集过大   └─ schema 松     └─ 报错不友好  └─ 返回太长

排查顺序固定为:看 trace 里模型原始输出 → 校验参数 → 看工具真实返回 → 看下一轮模型是否采纳。四步里哪一步和预期不符,问题就在那。

3. 代码:让错误自己说话

多数"调用失败"其实是错误信息对模型不可用。工具抛一个 NullPointerException,模型只能瞎猜;返回一句可操作的原因,它下一次往往就能改对。

from pydantic import BaseModel, Field, ValidationError
from typing import Literal

class QueryOrderArgs(BaseModel):
    order_id: str = Field(pattern=r"^[A-Z]\d{4}$", description="订单号,形如 A1029")
    detail: Literal["summary", "full"] = Field(default="summary", description="返回详细程度")

def query_order(raw_args: dict) -> dict:
    try:
        args = QueryOrderArgs(**raw_args)                  # ③ 严格校验,错误可回传
    except ValidationError as exc:
        return {"ok": False, "error": "invalid_arguments",
                "detail": exc.errors()[0]["msg"],           # 例如 "String should match pattern..."
                "hint": "order_id 必须以大写字母开头,后接 4 位数字",
                "retryable": True}

    row = db.get_order(args.order_id)
    if row is None:
        return {"ok": False, "error": "not_found",
                "detail": f"订单 {args.order_id} 不存在",
                "hint": "先用 search_order 按手机号后四位查订单号",
                "retryable": False}

    return {"ok": True, "data": {"status": row.status, "amount": row.amount,
                                 "paid_at": row.paid_at.isoformat()}}

工具描述同样是"接口文档",写法有讲究:

{
  "name": "query_order",
  "description": "按订单号查询订单状态与金额。仅当用户提供了订单号时使用;只有手机号时请先用 search_order。",
  "parameters": {
    "type": "object",
    "properties": {
      "order_id": {"type": "string", "pattern": "^[A-Z]\\d{4}$", "description": "订单号,例如 A1029"}
    },
    "required": ["order_id"],
    "additionalProperties": false
  }
}

description 里写清"什么时候用、什么时候不用",比堆十个示例更能降低误选。

4. 优化清单

优化项做法预期收益
收敛工具数单次暴露 ≤ 10 个,其余按意图分组动态挂载选型准确率显著上升
命名规范化动词_对象:query_order、refund_order减少同义混淆
强制结构化关闭自由文本参数,全部 JSON Schema参数错误率下降
返回裁剪工具侧只返关键字段,原始数据给 id减少上下文污染
幂等与去重相同 (工具, 参数) 短期缓存减少重复副作用
失败可读统一 {ok, error, hint, retryable}自愈率提升
并行调用无依赖的多个查询一次发起降低延迟

5. 常见追问

问:工具太多怎么办? 三层处理:按会话意图只挂载相关工具组;给工具加命名空间(crm.query_order);提供一个 list_tools 元工具让模型按需发现。别指望模型在 50 个工具里精准挑一个。

问:怎么量化"选错工具"? 建一个工具选择评测集(问题 → 期望工具 + 期望参数),跑准确率与参数正确率两个指标,每次改描述或加工具都回归一次。低于 95% 就先别加新工具。

问:写操作怎么保证安全? 幂等键 + 二次确认 + 白名单。高风险动作(退款、删库)走人工审批节点,Agent 只负责准备参数和说明理由。

问:模型并行调用多个工具,结果顺序乱了怎么办? 按 tool_call_id 回填,不要依赖数组顺序;工具内部无状态,避免依赖调用先后。

问:观测上要记什么? 每次调用记:工具名、参数、耗时、返回码、返回大小、是否被下一轮采纳。这五项能覆盖绝大多数线上问题定位。

小结

工具调用不稳定的根因,八成在"描述含糊、schema 太松、报错无用"这三件事上,而不是模型不够强。排查按"模型原始输出 → 参数校验 → 工具返回 → 下一轮采纳"四个断点走,优化按"收敛工具数、严格 schema、结构化错误、裁剪返回"四条做,再把工具选择准确率纳入回归,稳定性就能稳步提升。

笔记加载中…