Skip to content
English

降级与容错 ​

真实环境里的失败不是异常分支,而是常态:供应商限流、embedding 服务超时、索引尚未就绪、资料被删除、预算不够、用户取消。容错的目标不是让每个请求都成功,而是让失败可解释、可回退,并且不伪造结果。

先分类失败 ​

失败典型原因能否重试
模型调用超时、限流、5xx、鉴权失败限流与瞬时故障可有界重试;鉴权失败不重试
工具执行参数无效、未授权、业务拒绝、副作用失败只读查询可重试;写操作必须有幂等键
检索embedding 超时、索引未就绪、无命中可退回关键词或整篇读取
资料文件缺失、空资料、revision 过期不重试,明确说明资料不可用
预算与取消上下文超限、用户取消、期限到达不重试,按原合同结束

分类决定后续动作。把所有失败都当成“再试一次”,会放大限流、重复副作用,并掩盖真正的配置问题。

三种处理方式 ​

  1. 有界重试:只用于瞬时、幂等、可取消的调用。次数、间隔和总期限都要有上限,并继续传播 signal。
  2. 降级:缩小能力范围,但保留真实来源和身份。例如检索失败时退回关键词,向量不可用时退回整篇读取。
  3. 明确失败:无法安全降级时直接说明失败或提出澄清,不编造结果。

降级不等于换一条更宽松的权限路径,也不等于绕过校验。身份、授权、预算和取消在任何降级路径上都应继续生效。

一张处理矩阵 ​

场景建议动作不要做
模型限流有界重试,保留原请求与取消无限重试或换用未授权模型
模型鉴权失败明确报错,记录配置来源静默退回通用回答
工具参数无效返回校验错误,必要时澄清自动改写用户意图再次执行
写操作超时按幂等键核对真实提交直接重试造成重复写入
embedding 失败退回关键词检索用旧向量冒充新结果
索引未就绪整篇读取或关键词检索把“未就绪”当成“没有资料”
检索无命中明确说明没有资料用常识补写事实
预算超限减少候选或分次读取截断规则或证据
用户取消停止后续调用并保留原因把取消记录为成功

超时与取消 ​

  • 每一层使用独立超时,并让总期限覆盖整条调用链;内层超时不应晚于外层。
  • 取消通过 signal 传播;已经发生的外部副作用不能假装回滚。
  • 超时与取消是不同结果。超时可以重试,取消通常不应重试。
  • 流式输出中断时,不要补发成功结束标记。

不要做的降级 ​

  • 为了提高成功率而放宽授权、跳过来源校验或使用客户端自报身份。
  • 把检索失败包装成“没有这项资料”,让用户误以为事实不存在。
  • 把旧索引副本、旧缓存或上一次回答当成当前事实。
  • 在取消后继续调用工具或模型,并丢弃迟到结果。
  • 用固定兜底文案覆盖所有失败,导致问题无法被发现。

观测 ​

建议记录:失败阶段、工具或检索器 ID、错误码、尝试次数、是否降级、降级原因、总耗时和取消原因。不要记录密钥、完整提示词和未脱敏个人资料。

日志应能回答“这次为什么降级”,而不只是“这次成功了没有”。降级次数持续上升时,应先查依赖健康度,而不是继续调提示词。

用 MockGPT 验证 ​

失败路径应当可重复验证。MockGPT 离线验证 可以注入 HTTP 错误、网络拒绝、流中断与取消,用来确认:

  • 重试次数是否被限制;
  • 降级是否真的发生,而不是静默成功;
  • 写操作失败后是否按幂等键核对;
  • 取消后是否停止后续调用。

真实依赖的健康检查仍由部署环境负责,模拟只验证代码分支。

一个判断顺序 ​

ts
type Outcome =
  | { kind: 'answer'; sources: string[] }
  | { kind: 'unknown'; reason: 'no-material' }
  | { kind: 'degraded'; reason: 'retrieval-unavailable' }
  | { kind: 'failed'; reason: string };

async function answer(question: string): Promise<Outcome> {
  const sources = await retrieve(question).catch(() => undefined);
  if (!sources) return { kind: 'degraded', reason: 'retrieval-unavailable' };
  if (!sources.length) return { kind: 'unknown', reason: 'no-material' };
  return { kind: 'answer', sources };
}

示例只表达顺序:先区分“检索不可用”和“确实没有资料”,再决定回答、降级或失败。真实的授权、预算和取消检查仍由各自的接口完成。

常见问题 ​

现象原因处理
限流时请求越来越多重试没有上限或没有退避设置次数、间隔与总期限
失败被当成“没有资料”降级原因未区分分开 retrieval-unavailable 与 no-material
写操作重复超时后直接重试使用幂等键并核对真实提交
取消后仍有输出未传播 signal在每层调用前检查取消
降级长期不被发现只记录成功指标单独统计降级与失败原因

下一步 ​

接口参考、使用示例与开发指南。