串行调用 3 个 API 总翻车?这 3 种错误处理策略让 Skill 稳如泰山
本文收录于GithubAI-From-Zero 项目 —— 一个从零开始系统学习 AI 的知识库。如果觉得有帮助欢迎 ⭐ Star 支持一个Skill需要串行调用三个外部API如何正确处理局部失败一、最常见的错误一刀切的错误处理串行调用三个API最容易犯的错是把三个await直接写在一起然后用一个try/catch包住——这意味着任何一步失败都会中断后续步骤也无法区分是哪一步出了问题更无法决定是否要重试或跳过。说人话就是想象你要做一顿饭需要买菜、洗菜、炒菜三个步骤。如果你采用一刀切的做法买菜时发现超市关门了你就直接放弃整顿饭连家里已有的食材都不用了。但实际上你可能家里还有存货或者可以去其他地方买或者干脆做个简单的面条。在OpenClaw的Skill上下文里Skill的结果最终会被Brain读取并决定下一步行动所以错误信息本身也是有价值的输出——不应该只抛异常而应该把每一步的成功或失败状态都结构化地返回给Brain让LLM来决定如何处理局部失败。二、策略一强依赖链任意失败即中止适用场景步骤之间有严格的数据依赖中间结果缺失无法继续。典型例子获取用户信息 → 查询订单 → 获取物流详情每步都依赖前一步的结果// Skill: 获取用户信息 → 查询订单 → 获取物流详情asyncfunctiongetOrderTrackingSkill(userId){letuser,orders,tracking;// 步骤一获取用户try{userawaitfetchUser(userId);}catch(err){return{success:false,failedAt:fetchUser,error:err.message};}// 步骤二查询订单依赖 user.accountIdtry{ordersawaitfetchOrders(user.accountId);}catch(err){return{success:false,failedAt:fetchOrders,error:err.message};}// 步骤三物流详情依赖 orders[0].trackingIdtry{trackingawaitfetchTracking(orders[0]?.trackingId);}catch(err){return{success:false,failedAt:fetchTracking,error:err.message};}return{success:true,user,orders,tracking};}关键优势明确标注failedAtBrain能知道具体哪步失败精准错误提示可以给用户更具体的反馈而不是模糊的操作失败保留部分数据即使失败也可能包含有用的中间结果三、策略二弱依赖局部失败用降级值填充适用场景某些步骤失败不影响整体流程可以用默认值或空值继续。典型例子生成早报日历 天气 邮件摘要各自独立// Skill: 生成早报日历 天气 邮件摘要各自独立asyncfunctionmorningBriefingSkill(){// 三个步骤并发发起但各自独立捕获错误const[calendarResult,weatherResult,emailResult]awaitPromise.allSettled([fetchCalendarEvents(),fetchWeather(),fetchEmailSummary(),]);// 结构化每一步的结果constbriefing{calendar:calendarResult.statusfulfilled?calendarResult.value:{error:calendarResult.reason?.message||Unknown error,data:[]},weather:weatherResult.statusfulfilled?weatherResult.value:{error:weatherResult.reason?.message||Unknown error,data:null},email:emailResult.statusfulfilled?emailResult.value:{error:emailResult.reason?.message||Unknown error,data:[]},};// 告诉 Brain 哪些部分有问题constpartialFailuresObject.entries(briefing).filter(([,v])v.error).map(([k,v])${k}:${v.error});return{success:partialFailures.length0,partialFailures,briefing};}关键工具Promise.allSettled不会短路一个Promise reject不会影响其他Promise完整结果等待所有Promise完成每个都标记fulfilled或rejected灵活处理可以根据业务需求选择串行或并发执行注意虽然示例使用并发但如果业务要求串行换回逐步await即可错误处理结构不变。四、策略三带重试的串行调用适用场景外部API不稳定瞬时失败应该重试而不是立刻上报错误。重试工具函数asyncfunctionwithRetry(fn,{maxRetries3,baseDelay500}{}){letlastError;for(letattempt0;attemptmaxRetries;attempt){try{returnawaitfn();}catch(err){lastErrorerr;// 不重试客户端错误4xx只重试服务端/网络错误if(err.status400err.status500)throwerr;if(attemptmaxRetries-1){constdelaybaseDelay*Math.pow(2,attempt);// 指数退避awaitsleep(delay);}}}throwlastError;}constsleepmsnewPromise(resolvesetTimeout(resolve,ms));在Skill中的应用asyncfunctionrobustSkill(input){conststep1awaitwithRetry(()callApiA(input),{maxRetries:3});conststep2awaitwithRetry(()callApiB(step1.id),{maxRetries:2});conststep3awaitwithRetry(()callApiC(step2.data),{maxRetries:3});return{step1,step2,step3};}重试策略要点指数退避避免频繁重试加重服务器负担区分错误类型4xx错误客户端错误不重试5xx错误服务端错误重试限制重试次数避免无限重试导致任务长时间阻塞五、把错误结构化返回给Brain是关键OpenClaw的Brain是ReAct循环——它读Skill的输出然后决定下一步Thought和Action。如果Skill直接throw异常Brain只能知道Skill执行失败如果Skill把失败信息结构化返回Brain可以做更细粒度的决策。Skill返回格式的最佳实践// Skill 返回格式的约定供 Brain 解析return{success:false,failedAt:fetchOrders,// Brain 可以据此决策completedSteps:[fetchUser],// 已完成的步骤partialData:{user},// 部分数据仍可用error:Orders API timeout,// 人类可读的错误描述retryable:true,// 是否值得重试suggestedAction:ask_user_for_alternative_account// 建议的下一步行动};结构化错误的优势信息类型传统异常结构化返回Brain能做什么失败位置调用栈failedAt字段精准定位问题已完成步骤无completedSteps避免重复执行部分数据无partialData利用已有信息重试建议无retryable字段自动重试或询问用户下一步建议无suggestedAction智能决策六、设计哲学Skill输出要对LLM友好这个设计哲学和OpenClaw的Skill是Markdown自然语言说明书的理念一致——Skill不只是执行代码它的输出要对LLM友好让Brain能读懂发生了什么而不是只看到一个二进制的成功/失败。对比两种设计思路传统API设计成功返回数据失败抛异常Agent-friendly设计总是返回结构化结果包含成功/失败的详细信息实际效果差异当用户问我的订单到哪了传统设计Skill失败 → Brain收到异常 → 回复抱歉查询失败了结构化设计Skill返回{success: false, failedAt: fetchOrders, partialData: {user: {...}}, error: No orders found}Brain理解用户存在但没有订单 → 回复您还没有下单需要帮您创建订单吗七、选择策略的决策树面对串行API调用如何选择合适的错误处理策略三个API调用是否有数据依赖 ├─ 是 → 是否允许部分成功 │ ├─ 否 → 使用策略一强依赖链 │ └─ 是 → 使用策略二弱依赖降级 └─ 否 → API是否稳定 ├─ 否 → 使用策略三带重试 └─ 是 → 使用策略二并发独立错误处理实用建议优先考虑业务语义技术方案服务于业务需求总是结构化返回无论选择哪种策略都要返回详细的状态信息为Brain提供决策依据错误信息要包含足够的上下文测试各种失败场景确保Skill在各种异常情况下都能优雅降级在Agent时代错误处理不再是简单的try/catch而是为智能决策提供高质量输入的关键环节。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2417975.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!