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、工具返回或环境变量贴入公开问题。

是否重试

读取和摘要等只读任务可以在确认失败后重试。写文件、发送消息、更新业务状态的任务,必须先检查动作是否已发生。运行时断开不代表之前的工具都没执行。

当服务端不确定结果时,把任务标为“需要核对”,而不是自动重新提交。工具的幂等设计见自定义工具