跳转至

练习 5:Tool 错误处理

对应 Stage 3 — Tool Use & Agent 入门 练习 5。

为什么这题重要

真实 agent 很少只走成功路径:API 会 timeout、第三方服务暂时不可用、user 传坏参数。这题故意让 fetch_weather(city) 第一次回结构化 error{"error": "network timeout", "retry_hint": "try again in 1s"})、第二次才成功;观察 ReAct loop 怎么把 error observation 交回 LLM、让模型自己决定 retry / 改 query / 放弃。

核心观念:tool error 是数据、不是 exception。回传结构化 dict、不要 raise。

怎么跑 — 两条路径

Path A(默认、本机免费)

pip install -r requirements.txt
ollama pull qwen2.5:3b
ollama serve
python starter.py

预算:$0。3 轮 loop ≈ 10-60 秒。

Path B(Anthropic、想看 cloud 高质量)

pip install -r requirements.txt
export ANTHROPIC_API_KEY=sk-ant-...
python starter_anthropic.py

预算:每次 ≈ $0.003(claude-haiku-4-5、3 轮 messages 累积)。

预期看到(Path A、本机,理想 retry 走法):

❓ 问题:Will it rain in Taipei today?(using Ollama qwen2.5:3b)
------------------------------------------------------------
[step 0] tool: fetch_weather({'city': 'Taipei'}) → {'error': 'network timeout', 'retry_hint': 'try again in 1s'}
[step 1] tool: fetch_weather({'city': 'Taipei'}) → {'city': 'Taipei', 'forecast': 'rain', 'temperature_c': 24}
------------------------------------------------------------
✅ 最终答案:It will rain in Taipei today (24°C).
✅ 练习 5 通过 — tool error 是 data 不是 exception、$0/run

不花钱验证程序逻辑(mock-based)

python test.py            # 验 Path A (Ollama) starter.py 逻辑
python test_anthropic.py  # 验 Path B (Anthropic) starter_anthropic.py 逻辑

两条 test 都用 unittest.mock、不打真 API、$0/run。

设计提醒

错误也应该是结构化数据,让 LLM 有 context 做决策:

Bad Good
raise Exception("failed") return {"error": "network timeout", "retry_hint": "try again in 1s"}
return "failed" return {"error": "...", "category": "transient", "retry_hint": "..."}
无限 retry max_iter safety + 业务层 retry quota

只回传 "failed" 让模型不知道下一步;加入 retry_hint、错误类型与可恢复建议,模型才有足够 context 做决策。retry 次数也要有限制,否则 agent 会在坏掉的工具前面无限打转。

两个 path 观察重点

附加观察:小 model(qwen2.5:3b)对 retry_hint 的 follow-up 可能不如 Claude 精细——可能会直接放弃、或无视 hint 重复同一个错。这恰好是教学点:production 写好 retry pattern 后,不同 model 对结构化 error 的“阅读力”差距,是选 model 的考量之一(Stage 7 production tier 会再回来讨论)。

观察项 Anthropic Claude haiku Ollama qwen2.5:3b
看到 retry_hint 就 retry 高机率 中机率(可能直接放弃)
连续失败后 graceful end 稳定 可能再 retry 第 3 次
错误类型分流(transient vs permanent) 较细致 较粗略

想看更聪明的答案?

预设用 claude-haiku-4-5(最便宜)。改成 sonnet:

MODEL=claude-sonnet-4-6 python starter_anthropic.py

或 Ollama path 换更大 model:

MODEL=qwen2.5:7b python starter.py

延伸

  • 加 retry quota:在 loop 加 error_count、超过 N 次就放弃
  • 加 circuit breaker:连续失败、暂时 stop call(避免 wave-after-wave 打死下游)
  • 错误类型分类:transient(429 / connection)vs permanent(401 / 400)、不同处理
  • Production 级:看 ../../stage-1/05-error-handling/ 的 API-level retry wrapper(exponential backoff + jitter)