Claude 发起一次工具调用——网页搜索、代码执行、MCP server、自定义函数——spinner 就这么一直转。五分钟过去还是 pending,没报错、没超时,就这么挂着。刷新页面常常回到同样的挂起状态。根因几乎都是这几种之一:tool server 没回 tool_result、回的格式不对、或者工具本身耗时超过了 Claude UI 的超时窗。判断准了就好修。
常见原因
按命中率从高到低。
1. Tool server 压根没回
对接口集成和 MCP server 来说,Claude 在等一个 tool_result content block。Server 崩了、自身超时了、或者就是没发回响应,Claude UI 就会一直显示 pending。
怎么判断:去 tool server 日志按时间戳找请求。完全没日志 = 请求没到。有请求但没响应 = server 中途崩了。
2. Tool result 回了但格式不对
Anthropic API 要的是带 tool_use_id 和 content 的 tool_result block。如果你的集成回了一个纯字符串、回成了 text block、或者漏了 tool_use_id,Claude 没法 match 回来,UI 就一直 pending。
怎么判断:看原始 API 响应。block 应该长成 { "type": "tool_result", "tool_use_id": "toolu_...", "content": "..." } 这样。
3. 网页搜索或代码执行超过单次超时
内置工具(web search、code interpreter)有单次调用超时。某次查询没在时间内返回结果,就静默挂着、不报错。
怎么判断:等 90 秒。还是 pending,多半已经悄悄超时了。刷新对话,调用要么消失、要么变成报错。
4. MCP server 调用中途断连
用 MCP 接的工具(文件系统、GitHub、自定义 server)调用中途断连,UI 就会停在「飞行中」。重连之后也续不上原来那一次。
怎么判断:设置 → Connectors → 看各 MCP server 状态,哪个显示 disconnected 或 reconnecting,多半就是它。
5. 浏览器标签页被切到后台导致连接被挂起
Chrome 和 Safari 会挂起后台标签页的长连接。如果你正切走时这个工具调用还在流式传输,传输可能被掐了。
怎么判断:把标签页切回前台等 10 秒,看是否恢复。不恢复就刷新。
6. 并发多个工具调用,UI 状态被搞乱
Claude 一次并发触发多个工具调用、其中一个乱序返回,UI 有时会跟错哪些还在 pending、哪些已经完成。
怎么判断:看工具调用链。最新那个已经有结果了、更早的反而还在 pending,那就是 UI 跟踪错位。
开始前
- 弄清楚工具是内置(网页搜索、代码执行)、MCP 接的、还是自定义 API 集成,修复路径不同。
- 自定义工具或 MCP 工具的话,把 server 日志准备好。
- 决定是直接 cancel 重试,还是等——cancel 会丢失部分进度。
需要收集的信息
- 是哪个工具被调用(名字、集成、或者内置标签)。
- 调用大致时间戳(便于日志对齐)。
- 标签页状态:前台还是后台、浏览器、OS。
- 同一对话里别的工具调用是否正常。
- API 集成情况下,你 server 实际返回的原始 HTTP 响应。
- MCP 情况下,设置里 connector 的状态。
一步一步修复
Step 1:先刷新对话页面
大概三成的 pending 调用刷一下就清掉了。连接重连、Claude 重读对话状态。如果服务端其实已完成,会显示结果;如果真的挂了,会重新显示为 pending 或者一条报错。
Step 2:等满超时窗口
内置工具的超时一般是 60-120 秒。定个表等到时间。最后变成报错或「无结果」也算正确结局,缩窄 prompt 范围重试就好。
Step 3:看状态页和 connector 状态
新开一个标签页打开 status.anthropic.com。如果 web search 或 code execution 在降级中,那个工具的每次调用都会挂。另外:设置 → Connectors → 确认没有显示 disconnected 的。
Step 4:自定义集成,去看 server 响应
Anthropic API 要 tool_result block 才能闭环:
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "toolu_01ABC...",
"content": "结果字符串或结构化内容"
}
]
}
如果你 server 回的是纯字符串或者漏了 tool_use_id,Claude 没法 match。把响应形态修对,对话就能继续。
Step 5:MCP 的话,重连 server
某个 connector 显示 disconnected:设置 → Connectors → 点它 → Reconnect。然后在新一轮提问里重试这个 prompt(不是在挂掉的那轮)。重连不会让卡死的那次调用回头完成。
Step 6:取消、缩窄范围重试
等了、刷了、重连了都没用,那就 cancel 挂起的调用:
停掉当前工具调用。再试一次,但不要搜整个仓库,
只搜 apps/web/src/billing/ 目录。
范围小了,通常就能在超时之内完成。
Step 7:长耗时工具改成异步轮询
工具单次跑超过 60 秒(大数据任务、慢 API)的,重新设计成:先返回 job ID,让 Claude 轮询:
1. 调用 A:起任务,返回 { "job_id": "abc123" }
2. 调用 B:按 job_id 查状态,返回 done 或 pending
这样根本不会撞到 UI 超时。
怎么验证修好了
- 在一个新对话里再发同一条 prompt,能很快完成就说明修好了。
- 自定义集成,发一条带相同
tool_use_id形态的tool_result测试消息,Claude 能接受即对。 - MCP 跑一次简单调用(列文件、查用户),能很快回结果即对。
- 重试时标签页保持前台,排除浏览器挂起的干扰。
长期预防
- 自定义 tool server 自身超时设得比 Claude UI 超时短(45 秒以内),任何情况都要在窗口内返回结果或报错。
- MCP server 加 health check 和瞬时故障自动重连。
- 内置工具的 prompt 范围要收得紧:「搜最近关于 X 的帖子」而不是「把网上关于 X 的所有内容全部找出来」。
- 工具密集的对话期间 DevTools Network 保持打开,能早点发现形态不匹配。
- 把期望的
tool_result形态写进 tool server 的 README,以后新集成不至于回退。
容易踩的坑
- 一连刷新 5 次,一次就够,多了无益。
- 把工具结果当纯文本返回、不是
tool_resultblock——自定义集成里很容易漏。 - 忘了
tool_use_id是 per-call 不是 per-tool,每次调用 ID 都新生成。 - 让自定义工具一跑跑 5 分钟不返回任何东西,Claude UI 不会等到。
- 把 MCP 显示「connected」当成 server 健康——做一次真实调用才算数。
常见问答
- Claude 工具调用超时是多久? 内置工具大约 60-120 秒。自定义集成看你 server,API 本身没硬上限,但 Claude.ai UI 有。
- 能不能 cancel 一个 pending 的调用? 点 spinner 上的停止按钮。不管用就刷新页面,调用会清掉。
- 它自己最后能完成吗? 如果 server 最后回了合法的
tool_result,能。不回就永远不能——刷新。 - 这种情况 API 上会有吗? 走原生 API 时是你自己控制循环,请求挂会挂在你客户端里、不会挂在 Claude UI 里。诊断路径类似。
- 是 Claude bug 吗? 偶尔是——UI 确实会丢失调用状态。但更常见是下游工具没正确响应。