错误码与重试
本页列出 WebAgent 的错误码矩阵,说明哪些可以重试、哪些要直接抛给用户、哪些要回去改代码。
所有错误返回结构一致:
json
{
"code": "rate_limit_exceeded",
"detail": "Per-key concurrency limit (10) reached.",
"extra": { "limit": 10, "active": 10 }
}HTTP 状态码告诉你类别,code 字段是稳定契约——switch 在 code 上,不要在 detail 上(英文文案会随时间变)。
错误码矩阵
| 状态 | code | 重试? | 怎么处理 |
|---|---|---|---|
| 400 | bad_request | ❌ | 改请求体。对照 OpenAPI 检查字段。 |
| 401 | unauthorized | ❌ | key 缺失 / 格式错 / 过期 / 撤销超过 1 小时宽限期。新建一个。 |
| 402 | insufficient_credits | ❌ | Settings → Billing 充值,或开自动续费。 |
| 402 | budget_exceeded | ❌ | 任务级 max_cost_usd 上限触发。提高额度或拆分任务。 |
| 403 | forbidden | ❌ | key 有效,但当前 project 不授权访问该资源。 |
| 403 | safety_boundary_violated | ❌ | Agent 出于安全拒绝。读 extra.reason,改写指令。 |
| 404 | session_not_found、task_not_found、profile_not_found 等 | ❌ | id 错了,或资源已删除。 |
| 409 | conflict | ❌ | 状态不一致(如对终态 task 调 cancel)。重读状态再决定。 |
| 422 | validation_error | ❌ | schema 校验失败——extra.errors[] 列出有问题的字段。 |
| 429 | rate_limit_exceeded | ✅ | 遵守 Retry-After;没有就指数退避。 |
| 429 | too_many_concurrent_sessions | ✅ | 等手头 session 释放,或升级套餐。 |
| 5xx | internal_error | ✅ | 同样调用,指数退避,3–5 次封顶。 |
| (网络错) | — | ✅ | 连接重置 / 超时——幂等重试。 |
✅ = 不需要思考就能重试。❌ = 不改东西继续报。
推荐的重试策略
python
import time, random
def with_retries(fn, *, attempts=4, base=0.5, cap=8.0):
for i in range(attempts):
try:
return fn()
except WebAgentError as e:
if e.code not in {"rate_limit_exceeded",
"too_many_concurrent_sessions",
"internal_error"}:
raise # 不可重试
if i == attempts - 1:
raise
sleep_s = min(cap, base * 2**i) + random.uniform(0, 0.25)
time.sleep(e.retry_after_seconds or sleep_s)Python / TypeScript SDK 默认就内置了这套循环;上面的表是给你直接调 API 时用的。
幂等键(Idempotency-Key)
所有写入接口(POST /sessions、POST /sessions/{sid}/tasks、POST /messages 等)都接受 Idempotency-Key 头:
http
POST /v1/projects/proj_demo_0001/do_anything/sessions
Idempotency-Key: 9b2f7c1e-…-uuid24 小时内带同一个 UUID 重发,会拿到完全相同的响应(同样的 session_id、同样的状态码)——网络抖动也安全。每个逻辑动作生成一个 UUID,不是每次重试生成一个。
任务执行期间的错误
Agent 执行过程中报错不一定让任务整个失败——很多是可恢复的:
- 工具错误——通过
task.action.failed推送;agent 自己决定重试 / 换工具 / 整体失败。 - Captcha / 2FA——通过
task.input_request推送;你用POST /intervene回答。 - 硬上限触发——任务转
failed,error.code = budget_exceeded或duration_exceeded,已花的 credits 仍计费。 - 安全拒绝——任务转
failed,error.code = safety_boundary_violated,被拒绝那一步不计费。
四种都通过 SSE 流 看得见。
SSE 专属故障
| 现象 | 原因 | 解决 |
|---|---|---|
| 流卡 60 s 以上 | 网络断 / 代理缓冲 | 带 Last-Event-ID: <最后一个 id> 重连。 |
Last-Event-ID 不生效 | 缓冲过期(> 1 小时) | GET /sessions/{sid}/tasks/{tid} 重读状态,从当前继续。 |
| 重连后事件重复 | at-least-once 投递 | 按 id 去重(每个 task 内单调递增)。 |
下一步
- API 概览——所有接口都共享这套约定。
- Sessions 与 Tasks——上面的生命周期就是规范。