Agent SDK
取消、错误与故障排查
区分调用错误和任务失败,处理提前断流、审批等待与进程清理。
先识别失败发生在哪一层
| 阶段 | 常见原因 | 首先检查 |
|---|---|---|
| 找到命令 | 路径错误、文件不可执行 | WithCLIPath、运行身份 |
| 初始化 | 运行时版本不兼容、配置失败 | stderr、初始化超时 |
| 模型请求 | 凭据、模型、服务连接 | 同一身份下的运行时配置 |
| 工具与审批 | 拒绝、用户未确认、外部服务卡住 | ToolUseID、权限回调和 MCP 状态 |
| 输出读取 | 进程退出、断流、context 取消 | Go error、最终 result 是否出现 |
| 业务交付 | 空文件、内容不完整、格式错误 | 实际交付物和业务验证 |
Go error 为 nil 只代表接口完成返回;result.IsError 仍可能为 true。把这两条判断合并成“没有异常就是成功”会漏掉运行时任务失败。
使用错误匹配
switch {
case errors.Is(err, context.DeadlineExceeded):
log.Print("超过等待期限")
case errors.Is(err, context.Canceled), errors.Is(err, client.ErrAborted):
log.Print("操作被取消")
case errors.Is(err, client.ErrUnsupportedCapability):
log.Print("当前运行时不支持该操作")
case err != nil:
log.Printf("调用失败:%v", err)
}
具体诊断可通过 errors.As 获取 CLINotFoundError、CLIConnectionError、StreamClosedBeforeTerminalError 等类型。不要仅比较错误文本,因为文本可能随版本变化。
停止当前任务
Session.Interrupt 表达中断当前执行;InterruptWithReason 还可携带原因。用于中断的 context 应独立于已被取消的请求,否则中断请求可能来不及发送。
stopCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := session.Interrupt(stopCtx); err != nil {
return fmt.Errorf("发送中断失败:%w", err)
}
发送中断后,继续由会话读取者确认终态或断开。不要同时启动第二个 Recv 循环。用户只是停止本轮时不必删除整个 Session;不再使用连接时,再 Close 释放资源。
清理已取消的会话
closeCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := session.Close(closeCtx); err != nil {
log.Printf("关闭会话失败:%v", err)
}
等待输出的 context 取消,不应被宿主当作进程已回收的证明。清理错误需要记录,尤其是服务器关闭、工作进程被替换和跨 OS 身份运行的场景。
流提前结束
Stream.Result 在没有 result 的情况下遇到 EOF,会检查底层退出状态,并可能返回 StreamClosedBeforeTerminalError。该错误携带最后消息、会话与流停止诊断,有助于区分“没有输出”和“输出到一半断开”。
排错时收集经过脱敏的 stderr 和 WithDiagnostics 事件,记录运行时版本、Session ID、最后消息类型。不要直接把整条 Raw、工具返回或环境变量贴入公开问题。
是否重试
读取和摘要等只读任务可以在确认失败后重试。写文件、发送消息、更新业务状态的任务,必须先检查动作是否已发生。运行时断开不代表之前的工具都没执行。
当服务端不确定结果时,把任务标为“需要核对”,而不是自动重新提交。工具的幂等设计见自定义工具。