Files
yingqing/docs/todo/模型调用与动态Fallback-完成说明.md

206 lines
7.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 模型调用与动态 Fallback 完成说明
> 状态:已完成
>
> 最后核对:2026-07-21
>
> 用途:说明当前模型调用、重试、动态切换、计费和日志流程。
## 1. 当前调用流程
```text
用户选择模型 / 系统默认模型
→ 创建一个 AITask
→ 预留一次积分
→ 调用主模型
→ 明确失败:按配置重试主模型,仍失败且允许时动态 Fallback
→ 远端结果不确定:停止自动重试和 Fallback
→ 成功:保存结果并结算一次
→ 最终失败或结果不确定:释放一次预留
```
主模型始终是用户本次选择的模型;Fallback 不修改用户选择、默认模型或下次调用。
## 2. Retry 与 Fallback
- `Retry`:再次调用当前模型。
- `Fallback`:切换到其他兼容模型。
- `调用审计`:记录每次真实调用,不参与模型评分或自动学习。
当前默认值:
| 能力 | 主模型重试 | 单次超时 | 总时限 |
|---|---:|---:|---:|
| 文本 | 2 次,等待 1 / 3 秒 | 120 秒;流式 300 秒 | 480 秒 |
| 图片 | 1 次,等待 3 秒 | 300 秒 | 900 秒 |
| 配音 | 1 次,等待 2 秒 | 60 秒 | 180 秒 |
| 视频提交 | 1 次,等待 3 秒 | 120 秒 | 300 秒 |
| 视频成片 | 不重新提交 | 单次轮询 60 秒 | 以供应商终态为准,无本地硬总时限 |
单个逻辑任务最多尝试 3 个模型、发出 5 次真实请求。
### 2.1 远端结果确定性保护
统一执行器先判断本次失败是否能确认供应商没有成功处理:
- 明确失败:保留现有 Retry 与动态 Fallback。
- 结果不确定:记录当前一次失败后立即停止,不查询候选、不等待退避、不再次调用 Provider。
- `ReadTimeout`、请求发送后连接中断、HTTP `502/504`、响应缺失且无法确认结果,按结果不确定处理。
- DNS、连接拒绝、建立连接超时和明确 `429` 仍按现有策略重试或 Fallback。
- 结果不确定记录在 `AIModelAttempt.response_summary.outcome_unknown=true`,不新增表字段。
- 该保护不改变超时数值、普通用户提示、模型选择、动态排序或视频长轮询规则。
## 3. 配置位置
全局策略在:
```text
core/backend/.env
core/backend/airshelf/settings/base.py → MODEL_ROUTING_POLICY
```
控制重试、提交超时、最多模型数、最多调用数和后处理退避。视频取得远端任务 ID 后不设本地成片硬总时限。修改后必须同时重启 API 与 Celery Worker。
每个模型的开关保存在数据库 `ModelConfig.metadata.routing`
```json
{
"fallback_on_failure": false,
"fallback_candidate": true
}
```
- `fallback_on_failure`:当前模型失败后是否允许切到其他模型。
- `fallback_candidate`:当前模型是否允许被其他失败模型选中。
- 开关按模型独立配置,不在代码中写死供应商或模型名单。
## 4. 火山 / 豆包直连现状
文本、配音、视频都已接入统一 Fallback 代码,但当前直连模型统一配置为:
```text
fallback_on_failure = false
fallback_candidate = true
```
当前行为:
- 允许原模型重试。
- 不允许从直连模型主动切出。
- 已启用且能力匹配时,可以作为其他模型的候选。
- 以后只改模型 metadata 即可开启,无需重新开发路由代码。
## 5. 动态候选规则
候选每次失败后实时读取数据库,必须同时满足:
- 供应商已启用。
- 模型已启用。
- `fallback_candidate=true`
- 能力一致:`text``image``audio``video`
- 操作要求一致:流式、结构化、图片编辑、参考素材数量、比例、分辨率、时长、音色映射等。
- 本任务尚未尝试过。
排序规则:
```text
火山 / 豆包直连
→ YunQi
→ 其他 OpenAI API 兼容供应商
→ 同层级按 ModelConfig.updated_at 从新到旧
```
除现有火山 / 豆包专用适配器外,新增供应商只支持 OpenAI API 兼容协议。
## 6. 任务与计费
一次用户操作始终只有:
- 一个 `AITask`
- 一次积分预留。
- 一次最终扣费或释放。
每次真实模型调用只新增一条 `AIModelAttempt`,不会单独预留或扣费。
- Fallback 成功:按原逻辑任务结算一次。
- 全部失败:释放原预留,用户扣费为 0。
- 多次尝试产生的上游费用累计为平台成本,不转换成多笔用户扣费。
## 7. 调用日志
`AIModelAttempt` 记录:
- 调用顺序。
- 供应商与真实模型快照。
- 首次调用、重试或 Fallback。
- 成功 / 失败、耗时和错误分类。
- Provider 任务 ID、用量和平台成本。
- 脱敏请求 / 响应摘要。
管理员在 `/admin/tasks` 的任务详情查看完整调用链。普通用户端保持静默,不显示内部供应商、真实候选、失败原因或尝试次数。
公开别名保持不变:
- Gemini 3.1 Pro → `AirShelf Script`
- `gpt-image-2``AirShelf Image`
- 火山 / 豆包直连继续显示原公开名称。
## 8. 视频特殊规则
- 只有尚未取得远端任务 ID,且明确提交失败时,才允许重试或 Fallback。
- 提交读取超时或响应缺少任务 ID 视为“远端状态未知”,禁止重复提交。
- 获得远端任务 ID 后固定使用真正提交成功的模型轮询和结算。
- 普通轮询超时只继续轮询,不切模型、不重新提交。
- 本地等待时长不产生失败终态;只有供应商明确返回 `failed``expired``cancelled` 才失败并释放预留。
- Worker 有限轮询用尽后只停止本轮兜底,业务任务仍保持生成中;用户重新打开页面可继续查询。
- 供应商最终成功时正常转存资产并结算一次,即使成片超过 30 分钟。
- 下载、上传、TOS 或资产保存失败只重试后处理,不重新调用模型。
旧版 30 分钟硬终止误判任务可使用以下管理命令核对:
```text
python manage.py reconcile_video_timeouts --task-id <AITask UUID>
python manage.py reconcile_video_timeouts --task-id <AITask UUID> --apply
```
默认只读;`--apply` 仅恢复远端已成功结果,不重新提交模型、不追扣用户积分,并保证重复执行不会重复创建版本或资产。
## 9. 已接入入口
- 脚本生成、脚本优化、单镜优化。
- 显式实体提取、脚本实体同步兼容入口。
- 独立图片生成 / 编辑、模特上身图、平台套图。
- 商品 / 人物 / 场景基础资产、项目与模特三视图。
- 故事板分镜生成。
- 配音生成。
- 视频片段生成。
- 自由创作 / 免费视频生成。
## 10. 发布要求
- 数据库迁移:`0028_seed_model_routing_metadata``0029_aimodelattempt`
- API 与 Celery Worker 必须使用同一版后端镜像。
- API 与 Worker 必须读取同一份路由配置。
- 发布后至少冒烟验证文本、图片、配音、视频和 `/admin/tasks` 调用链。
- 回滚代码时不要直接反向执行 `0028`,避免删除已维护的模型路由 metadata。
## 11. 关键代码
```text
core/backend/apps/ai/routing_policy.py 全局策略读取与校验
core/backend/apps/ai/generation_errors.py 错误分类与远端结果确定性判断
core/backend/apps/ai/model_routing.py 能力匹配与动态候选排序
core/backend/apps/ai/routing_executor.py 重试、Fallback 与调用审计
core/backend/apps/ai/models.py AITask / AIModelAttempt
core/backend/apps/ai/services.py 各业务入口编排
core/backend/apps/ai/free_video.py 自由视频提交与轮询
core/backend/apps/ai/script_agent.py 脚本流式调用
```
## 12. 非本次范围
- 未修改 `/admin/providers` 页面。
- 未实现用户反馈学习、模型评分或自动调权。
- 未写死备用模型链。
- 未支持新增非 OpenAI API 私有协议供应商。