真实问题:接口成功,只是链路的一小段成功
一个典型现场是:后端日志里看到请求状态 200,前端却显示“生成失败”;或者模型已经返回文本,但系统没有把结果写入订单、工单、报价单或知识库。排查时如果只盯 HTTP 状态,很容易把责任推给前端或用户网络。实际上,AI API 接入通常至少有六层:客户端请求、模型接口、输出解析、业务校验、数据写入、通知回调。任意一层失败,用户都会感觉任务没完成。
永沃云枢在整理 AI API 接入案例时,建议把“模型成功”和“任务成功”分开。模型成功只说明 AI 模型接口按协议返回了内容;任务成功还要证明内容格式可用、业务规则通过、状态已落库、费用或额度记录一致、用户能看到最终结果。
适用场景
这个排查适合文本生成、结构化 JSON 输出、文档摘要、AI 自动化办公写回、客服工单生成、批量任务和异步回调。它也适合 Codex 接入后的日志复盘:让 Codex 根据 request_id 找出跨服务日志,但不要让它只凭最后一行 200 下结论。如果链路前面用了 CCSwitch 配置,还要确认 profile、模型名和 base_url 命中了预期模型,而不是误走备用接口。
分层排查步骤
第一步,给每次开发者 AI 调用生成 request_id,并贯穿前端、后端、模型调用、解析器和写库日志。第二步,把状态字段拆开记录,不要只有 success 一个布尔值。推荐至少保留 http_status、model_finish_reason、parser_status、business_status、write_status、callback_status 和 billing_status。第三步,按时间线重放一条失败请求,看哪一层开始从 ok 变成 failed。
第四步,检查输出解析。很多 200 失败是因为模型返回了自然语言,但业务期待 JSON;或者 JSON 字段存在,却为空、类型错、枚举值超出范围。第五步,检查业务写入。写库失败、幂等键冲突、状态机不允许跳转、用户取消后又收到结果,都会造成“模型成功但业务失败”。第六步,补一条用户可见状态,告诉用户任务是在生成、解析、复核还是失败,而不是统一显示系统错误。
失败表现与定位
如果日志里有 200,但没有 parser_status,说明缺少解析埋点。若 parser_status 失败,应回看提示词、JSON Schema 和示例输出,可参考 JSON 输出契约。如果解析成功但 write_status 失败,重点看数据库约束、权限、幂等键和事务回滚。若写入成功但前端看不到,检查回调、缓存和查询条件。若费用已扣但任务失败,需要把补偿策略写清楚,不能只在页面上提示重试。
试运行阶段不要只看成功率。抽样日志、输出质量和人工复核结果同样重要,相关方法可参考 AI API 试运行日志抽样 和 结构化输出失败重放。如果同样提示词偶尔成功偶尔失败,再参考 参数漂移排查。
常见问题 / FAQ
问:既然模型返回了文本,能不能直接展示给用户?要看场景。聊天可以展示,报价单、工单、合同摘要和自动化办公写回必须先过业务校验。问:所有失败都要重试吗?不应该。解析失败可以修复提示词后重放,写库失败要先判断是否已有部分结果,回调失败可以补发,业务规则失败则需要人工复核。问:日志会不会太多?只要 request_id 贯穿全链路,字段可以先少后多,关键是不要把不同层的失败混成一个错误码。
验收标准
- 任意一条任务都能用 request_id 找到模型调用、解析、写入、回调和费用状态。
- HTTP 200 与业务成功分开统计,告警文案不混淆。
- 结构化输出有 Schema、样本和失败重放记录。
- AI 自动化办公写回前有人工复核或 dry-run 入口。
- 站内说明连接到 AI API 接入专题、Codex 专题、CCSwitch 配置专题 和 AI 自动化办公专题。
最终目标不是让每次调用都“看起来成功”,而是让失败能被准确定位、能被用户理解、能被团队复盘。只有模型调用管理和业务状态都清楚,https://ai.jn83.com 上的接入链路才有持续维护的基础。
检查命令和字段样例
本地排查时,可以先不用接触生产数据库,只从应用日志和任务表导出的脱敏样本开始。按 request_id 搜索时,至少看三段时间:用户提交请求的时间、模型返回的时间、业务状态更新的时间。如果三段时间缺一段,就说明链路没有打通。字段命名也要保持稳定,例如模型层只写 model_status,解析层只写 parser_status,业务层只写 task_status,不要每个服务都叫 result,否则后面汇总会混乱。
验收时可以抽三类样本:完全成功、模型成功但解析失败、解析成功但写入失败。把这三类样本放进回归集,之后调整提示词、切换 AI 模型接口或更换 CCSwitch profile,都要重新跑一遍。这样才不会因为一次接口 200,就误判整条业务链路已经恢复。
如果要把这套方法落到生产里,建议把失败样本单独保存一份,连同原始响应、解析器日志和业务状态一起归档。以后每次改提示词、切换模型或改 CCSwitch 配置,都先拿这份样本跑一遍,确认不是某一层悄悄变了口径。