MG-03-006 供应商适配器
状态说明:以当前有效边界为准。供应执行规则与历史实现证据保留;客户身份、售价、结算、全量旧跨仓契约及图像开放计划不代表当前验收范围。
1. 目标
Provider 差异必须留在适配器,调度器只理解 Supply、规范化请求、能力、成本和统一
错误,不允许出现 if provider == omega 等平台分支。
2. 接口拆分
不要建立一个要求所有 Provider 实现全部媒体能力的巨型接口。
CatalogAdapter
type CatalogAdapter interface {
TestConnection(ctx context.Context, channel Connection) error
DiscoverModels(ctx context.Context, channel Connection) ([]DiscoveredModel, error)
}可选:
type PriceDiscoveryAdapter interface {
DiscoverPrices(ctx context.Context, channel Connection) ([]DiscoveredPrice, error)
}VideoAdapter
生产接口以 internal/video/provider.Adapter 为准(下列为省略包前缀的签名):
type Adapter interface {
Validate(context.Context, SupplySnapshot, domain.Request) *ProviderError
Submit(context.Context, AttemptSnapshot, *Connection, domain.Request) (Submission, error)
Poll(context.Context, ProviderTaskReference, *Connection) (PollResult, error)
}目录使用 internal/provider/catalog.Adapter 和可选 PriceDiscoveryAdapter;错误分类在各原生实现内部完成,不另建 ClassifyError 公共接口。
新协议的文件组织、注册及验收流程见 原生接入规范。JS 安装与绑定入口已退役;历史执行器暂留用于兼容。
ImageSyncAdapter
type ImageSyncAdapter interface {
Validate(ctx context.Context, supply SupplySnapshot, req image.Request) error
Generate(ctx context.Context, attempt AttemptSnapshot, req image.Request) (image.Result, error)
ClassifyError(err error, response *ProviderResponse) ProviderError
}异步图像 Provider 额外实现 ImageAsyncAdapter 的 Submit/Poll。
3. 模型发现
模型发现流程:
- 后端解密 Credential;
- 由 Provider Adapter 调用模型列表接口;
- 返回原始模型 ID、展示名和 Provider 元数据;
- 与上次快照比较新增、移除和变更;
- 管理员选择导入;
- 导入创建 disabled Supply Draft;
- 补齐能力、成本和测试证据后才可启用。
发现到模型不代表该模型已验证或可生产。
模型接口没有价格时不得推测价格。价格来源按以下优先级:
- 管理员明确覆盖;
- Provider 价格接口;
- 适配器经过审查的目录;
- 未知,禁止自动调度。
4. 错误分类
统一错误:
type ProviderError struct {
Category ErrorCategory
Scope ErrorScope
Retryable bool
Code string
Message string
RetryAfter time.Duration
}适配器必须覆盖:
- HTTP 状态;
- Provider 错误码;
- 响应体状态;
- 提交超时;
- 查询任务错误;
- 内容审核;
- 真人政策;
- 余额、认证和限流;
- 模型不存在;
- Provider 返回成功但字段缺失。
不能只按 HTTP 4xx/5xx 粗略判断。
5. 提交幂等与不确定性
- 如果 Provider 支持 Client Request ID 或 Idempotency Key,必须使用 Attempt ID;
- Provider POST 超时后,适配器必须指示是否能通过请求号查询;
- 无法确认受理时返回
submission_uncertain; - 调度器不得把未知提交当作普通失败;
- Provider Task ID 和查询所需 Credential Version 必须持久化。
6. 素材
- 异步视频和图像使用平台临时素材 URL,避免用户 URL 在排队或重试时过期;
- Provider 要求 upload-ref 时,适配器负责上传并保存 Provider 临时引用;
- Adapter 不得改变素材顺序或静默删除字段;
- 降级变换在 Adapter 之前由已发布 Degradation Rule 执行;
- 外部 URL 获取由平台统一执行 SSRF 和大小校验。
7. 结果
适配器返回规范化结果引用:
provider_url
content_type
expected_size
provider_metadataProvider URL 只交给 Result Worker,不直接作为长期公开结果。Result Worker 转存、 校验并创建平台 MediaAsset 后,任务才成功。
同步图像可以在响应时间内完成校验和存储;如果返回 Base64,禁止写入日志。
8. 真实测试证据
每个生产 Supply 至少保存:
- Provider 模型 ID;
- 请求 Profile;
- 脱敏请求 Fixture;
- 脱敏成功响应 Fixture;
- 错误分类 Fixture;
- 能力边界测试;
- 价格来源和时间;
- 是否失败扣费;
- 视频真人政策证据;
- 结果 URL 有效期和下载行为;
- 测试时间和执行人。
缺少证据的 Supply 保持 disabled。
9. 从 new-api 复用
每个 Provider 适配任务先审查:
- 请求 DTO 是否可以脱离 Gin/new-api Context;
- 是否依赖旧 Channel、ModelMapping、Group、Priority 或 Weight;
- 是否正确保留显式零值;
- 错误处理是否足够区分内容与 Provider 故障;
- 是否泄漏 Key、URL 或响应体;
- 是否支持模型发现;
- 是否包含可复用的查询和结果解析。
只移植协议逻辑,使用新项目接口重新包装。禁止把旧调度模型一并复制。