Agent 工具调用可靠性——为什么 70% 的工具调用会失败

我统计过自己 Agent 项目的工具调用日志——70% 的失败率让人崩溃。怎么救?

真实失败率

我做的一个 Agent 项目,累计 10000 次工具调用统计:

状态 占比
成功 28%
参数错误 32%
工具选错 18%
超时/异常 12%
死循环(同工具反复调) 7%
其他 3%

首轮成功率只有 28%——意味着 72% 的调用需要”补救”。

这和很多 Agent 演示给人的”丝滑”印象差距巨大。

七大类失败原因

1. 参数错误(32%)

最常见的失败——模型生成的参数不对。

例子:

  • get_weather(city="上海") → 实际 schema 要求 location: str,应该传 "Shanghai"
  • search(query="AI") → 参数太模糊,实际需要更具体的 query

根因:

  • Tool description 不清晰
  • 参数 schema 类型不明确(enum / optional / default)
  • 模型对业务术语理解不准

2. 工具选错(18%)

模型调了不该调的工具。

例子:

  • 用户问”今天天气” → 模型调了 get_news 而不是 get_weather
  • 用户问”查订单” → 模型调了 search_docs 而不是 query_orders

根因:

  • 工具之间功能边界模糊
  • 工具 description 写得像”另一个工具”

3. 超时/异常(12%)

工具本身慢或挂了。

根因:

  • 后端 API 慢
  • 网络问题
  • 工具代码 bug

4. 死循环(7%)

模型反复调同一工具,陷入循环。

1
2
3
4
调 get_weather(city="上海") → 返回结果
调 get_weather(city="上海") → 返回结果
调 get_weather(city="上海") → 返回结果
... (无限循环)

根因:

  • 模型没意识到已经调过了
  • 工具返回结果没被”消化”

5. 工具本身设计问题

  • 工具能力太弱(返回信息不全)
  • 工具能力太强(能做太多事,模型不知道用哪个)
  • 工具 schema 设计不合理(嵌套过深)

提升可靠性的 8 个实战技巧

技巧 1:写好 Tool Description

最有效的一招——能直接提升 20%+ 准确率。

差的写法:

1
2
"name": "search",
"description": "搜索"

好的写法:

1
2
"name": "search_internal_knowledge",
"description": "在公司内部知识库中搜索文档,用于回答用户关于公司政策、产品规格、技术规范的提问。当用户问题涉及具体公司信息时调用,不要用于一般性知识问答。必须传入 query 参数,例如 '年假政策' 或 '产品A 规格'。"

关键:

  • 明确”什么时候用 / 什么时候不用”
  • 给出参数示例
  • 用自然语言描述,而不是功能列表

技巧 2:参数验证 + 自动重试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def safe_tool_call(func, validator, max_retries=2):
def wrapper(*args, **kwargs):
for i in range(max_retries):
try:
# 1. 参数验证
validation_error = validator(kwargs)
if validation_error:
raise ValueError(f"参数错误:{validation_error}")

# 2. 调用
result = func(*args, **kwargs)
return result
except Exception as e:
if i == max_retries - 1:
raise
# 让模型知道错了,自动修正
yield {"error": str(e), "suggestion": "请检查参数"}
return wrapper

思路:参数错时,把错误信息反馈给模型,让它修正后重试。

技巧 3:工具数量控制

单个 Agent 的工具不要超过 20 个——多了模型选择困难。

我做过测试:

工具数 选对工具的准确率
5 个 92%
10 个 85%
20 个 68%
50 个 41%

超过 20 个工具,准确率断崖式下降。

解决:用 “Router Agent” 分流——多个小 Agent,每个管 10 个工具。

技巧 4:工具分组 + Router

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 顶层 Router Agent:决定调哪个子 Agent
router = Agent(
name="router",
tools=[
Tool(name="go_to_customer_service", ...),
Tool(name="go_to_tech_support", ...),
Tool(name="go_to_sales", ...),
]
)

# 子 Agent:各自管具体工具
customer_service = Agent(
name="customer_service",
tools=[check_order, refund, contact_human]
)

比单 Agent 100 个工具好得多。

技巧 5:循环检测

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def detect_loop(state, threshold=3):
"""检测最近 N 步是否在调同一工具"""
recent = state["messages"][-threshold*2:]
tool_calls = [m for m in recent if m.tool_calls]

if len(tool_calls) < threshold:
return False

# 最近 N 次都是同一工具
last_n = tool_calls[-threshold:]
same_tool = all(t.tool_calls[0].function.name == last_n[0].tool_calls[0].function.name
for t in last_n)

return same_tool

检测到循环时,主动打断,让模型”换个思路”。

技巧 6:超时 + 降级

1
2
3
4
5
6
def execute_with_timeout(func, args, timeout=10, fallback=None):
try:
result = asyncio.wait_for(func(*args), timeout=timeout)
return result
except asyncio.TimeoutError:
return fallback or {"error": "工具超时,已使用降级方案"}

超时不要让 Agent 卡死——降级返回简化结果。

技巧 7:工具测试覆盖

每个工具必须有单元测试:

1
2
3
4
5
6
7
8
9
10
def test_get_weather():
# 正常调用
assert get_weather("上海") is not None

# 边界情况
assert get_weather("") == {"error": "城市不能为空"}

# 异常情况
with pytest.raises(NetworkError):
get_weather_with_mock_error()

工具不可靠,Agent 一定不可靠。

技巧 8:可观测性

每次工具调用必须记录:

1
2
3
4
5
6
7
8
logger.info({
"tool": tool_name,
"args": args,
"result": result[:200], # 截断
"duration_ms": duration,
"success": success,
"error": error
})

没有日志,出问题就是黑盒。

进阶:让 Agent 自己修复错误

Self-Healing Agent——Agent 调工具失败时,自己诊断、修正、重试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
RECOVERY_PROMPT = """
刚才调用工具 {tool_name} 失败了,错误是:
{error}

调用参数是:
{args}

请分析:
1. 错误原因是什么?
2. 如何修正参数?
3. 是否应该换其他工具?

给出修正后的调用,或者建议下一步。
"""

def recover(error, tool_call, llm):
prompt = RECOVERY_PROMPT.format(
tool_name=tool_call.function.name,
error=error,
args=tool_call.function.arguments
)
new_call = llm(prompt)
return new_call

实测:Self-Healing 能把首轮成功率从 28% 提升到 65%——接近 2.5 倍提升。

我的 Agent 优化记录

我做了 6 个月的 Agent 优化,首轮成功率提升:

1
2
3
4
5
6
Month 1: 28% (baseline)
Month 2: 35% (Tool Description 优化)
Month 3: 48% (Router + 分组)
Month 4: 55% (参数验证 + 自动重试)
Month 5: 62% (Self-Healing)
Month 6: 71% (循环检测 + 超时降级)

2.5 倍提升——全是工程优化,没有”模型魔法”。

写在最后

Agent 的可靠性,不是 LLM 决定的——是工程决定的。

模型准确率再高,工程不做好,Agent 还是不可用。

这是”AI 工程化”和”AI 演示”的根本区别——演示里 Agent 跑得丝滑,生产里 Agent 跑得崩溃。

Agent 工程的本质,是”在 70% 不可靠的工具上,搭建 99% 可靠的系统”。