# AI 渠道与聚合网关接入设计 ## 1. 硬约束:真正零默认连接 新数据库的 Channel、ChannelRevision、CredentialVersion、EndpointConfig、ModelBinding 均为空。迁移可初始化角色、权限与无连接信息的协议 schema,但**不能初始化供应商、API Key、Base URL、默认官方域名或可调用示例渠道**。 - 后端没有 `BASE_URL || 官方地址` 之类兜底。 - SDK 必须在管理员配置经过验证后,显式传入 `baseURL`、凭据、超时和重试策略。 - 环境变量只保存数据库、存储、登录、加密主密钥等基础设施参数;**不能把开发机的 AI Key/URL 自动导入平台**。 - 七牛云 Kodo 的六项 `QINIU_*` 变量属于已确认的基础设施存储配置,不属于 AI 渠道连接;具体用途见 [安全运维第 9 节](securityAndOperations.md#9-配置边界)。使用它们不违反 AI 渠道零默认连接要求。 - 本轮用于文档生图的用户连接脚本不进入新平台的初始化配置、样例 seed、镜像或测试数据。 - 普通用户请求没有有效已发布渠道时返回 `CAPABILITY_UNAVAILABLE`,不发出 AI 网络请求、不创建资金预留。 - 管理员可保存未完成草稿,但草稿不进入有效模型目录;未填地址应保持 NULL,不把输入框 placeholder 当成实际值保存。 ![管理员零配置初态概念图](images/adminEmptyState.png) ## 2. 必须分开的概念 | 概念 | 含义 | 示例性质 | | --- | --- | --- | | Channel | 管理员配置的聚合平台账户/连接 | 渠道 A,不是源码写死的厂商 | | ChannelRevision | 某次发布的不可变配置 | 地址、协议、限流和能力版本 | | CredentialVersion | 加密保存的凭据版本 | 可轮换,不提供明文读取 API | | ProtocolProfile | 适配器实现与 wire 契约 | OpenAI Chat、Responses、图片、TTS、某版本 New API 视频 | | ProductModel | 用户可选的产品模型 | 产品名称、说明、能力与零售价 | | ModelBinding | 产品模型到渠道上游 ID 的绑定 | 同一产品模型可有多个经验证的等价绑定 | | Capability | 具体可执行的能力 | `video.firstLastFrame` 与 `video.text` 不是一个能力 | | EndpointConfig | 某协议所需的相对路径与受限配置 | 不是允许管理员执行任意 JS 的脚本 | 渠道、模型、协议、能力不能用一个 `provider` 字符串混装。一个聚合站支持文本,不代表它支持图片,更不代表支持本平台的视频协议。 ## 3. 管理员使用流程 1. 创建草稿,填写名称、连接地址、协议 profile 与凭据。 2. 服务端验证 URL、出站策略、路径和可用协议;凭据加密保存。 3. **只读连接检测**:安全查询可支持的元信息。`/models` 成功只表示该接口可用,不能证明媒体生成成功。 4. 导入候选模型,人工选择 ProductModel 和上游 model ID。 5. 配置能力、参数范围、媒体输入方式、响应与轮询 profile。 6. 对图片、音频、视频进行**独立、显式确认可能收费的真实验证**。检测按钮必须告知是否会消费上游额度。 7. 配置成本参考、零售积分价格、计价单位、档位与上限。 8. 校验 readiness,发布新版本;生产请求开始使用这个版本。 9. 后续轮换密钥、修改地址或协议均产生新版本;原执行不跟随当前配置漂移。 ![管理员渠道管理概念图](images/adminChannels.png) ### 发布门槛 该能力有启用的已验证适配器、有效地址与凭据、明确上游模型、受支持参数、媒体传输方式、可解析状态、可交付结果和有效价格;所有检查都通过才能开放。验证记录绑定具体配置摘要,换地址、协议或模型后不能沿用旧验证结论。 ## 4. 兼容 New API 的准确边界 “New API”是接入生态,不是保证所有部署具有相同媒体协议的规范。版本、插件、上游厂商及返回结构都可能不同;首发网关尚未指定版本,本文不能虚构一个通用视频路径。 | 能力 | 可实现的 profile | 需要真实核对 | | --- | --- | --- | | 文本 | Chat Completions;Responses 单独实现 | streaming、usage、结构化输出、上下文和工具调用是否支持 | | 图片生成 | OpenAI-shaped generations | URL/Base64、同步/任务式、数量、尺寸与质量 | | 图片编辑 | OpenAI-shaped edits 或特定扩展 | multipart、文件字段、掩码、参考数量 | | 语音合成 | OpenAI-shaped speech 或特定厂商 | 二进制/URL、声音目录、字符计费与时间戳 | | 转录/对齐 | 独立音频 profile(P1) | 文件上传、返回结构、语言与计价 | | 视频 | 按已验证网关版本实现任务式 profile | submit/status/content/cancel 的实际路径、字段、ID 和状态 | 协议 profile 可包含受限相对路径、字段映射、已允许的枚举和状态映射;不接受任意代码、任意 JSONPath 脚本、动态执行模板或自由 HTTP 代理。没有适配器的“自定义接口”必须先开发和验证,再开放给管理员选择。 模型发现结果只进入候选区。不能仅凭模型名包含 `video`、`gpt`、`tts` 推断能力,不能把不支持的关键参数静默删除。 ## 5. URL 与路径规则 - `baseUrl` 是管理员显式填写的、经规范化验证的 API 根路径,允许已批准的自建网关前缀。 - profile 的 endpoint 是相对路径,统一连接一次;不因尾部斜杠重复 `/v1`,不使用会丢掉根路径的错误 URL 连接方式。 - 不同能力确需不同根路径时,显式建立能力 endpoint 配置,而不是从一次报错中猜测。 - 禁止 URL 中嵌入用户名、密码、token、片段或任意查询参数;附加请求头使用白名单,Authorization 专用处理。 - 凭据仅发送给该版本批准的 origin 与路径范围;重定向默认拒绝,不能把 Bearer 自动带往 CDN 或另一个域名。 - 平台允许连接自建 New API 时,私网目标必须由运维级出站策略预先批准,后台管理员不能自行豁免 SSRF;云元数据和链路本地目标始终禁止。 ## 6. 凭据与加密 服务端使用 AES-256-GCM 或经审查的信封加密;每条凭据独立随机 nonce,保存 cipher、tag、主密钥版本与最小展示指纹。AAD 绑定 Channel ID、CredentialVersion ID、用途和环境,避免密文被复制到另一渠道使用。 主密钥在密钥管理系统或部署 Secret 中,**不与数据库备份放一起**。密钥轮换与重加密有操作流程和审计;丢失主密钥不能通过数据库恢复明文。 | 操作 | API 语义 | | --- | --- | | 写入新 key | write-only 字段,服务端加密后丢弃请求明文 | | 编辑其他字段 | 不传密钥字段表示保持;空字符串不解释为新密钥 | | 替换 key | 专用操作创建新 CredentialVersion | | 清空 key | 明确 `removeCredential` 操作并检查活动任务 | | 列表/详情读取 | 返回 `keyConfigured`、指纹与轮换时间,不返回 ciphertext 或明文 | | 测试连接 | 服务端授权后解密,敏感值不进入客户端错误和日志 | P0 不提供含密钥的配置导出。导入只接受管理员明确确认的规范文件,敏感导入单独受审计,不自动执行其中的脚本或网络地址。 ### 活动任务与轮换 普通替换默认保留旧凭据解密能力,直到绑定旧版本的任务完成和保留窗口结束。泄漏紧急撤销则立即阻止使用,并将相关任务列入核对;不把一个新凭据版本假装成同一授权身份。确需迁移查询权限时,要验证新旧账户可访问同一任务,并记录显式迁移授权。 ## 7. 有效模型目录 对用户投影的目录只含产品模型名称、能力、允许参数、价格、可用状态与已公开的供应商说明;不含 Base URL、上游鉴权头、平台密钥、进价或完整原始响应。 有效性取以下条件的交集:已发布、渠道允许新调用、凭据有效、binding 启用、profile 实现、能力实测、参数合法、媒体传输可用、价格有效、用户与工作区权限允许。缺一项就不允许创建计划。 参数 schema 和能力 schema 同源,驱动表单、服务端 preflight、报价及适配;不能每层再补不同默认值。报价前完成 canonical 参数补全;后续执行只能映射,不再解释。 ## 8. 路由、优先级与故障切换 P0 支持管理员为新请求选择默认 binding 或明确优先顺序;**媒体付费请求默认不自动切换**。 | 事实 | 处理 | | --- | --- | | 本地 preflight 发现渠道不支持 | 不创建付费副作用,提示管理员/用户更正 | | 尚未向远程发送,候选渠道被禁用 | 作废原报价或按已批准且同价等价绑定规则重新规划 | | adapter 能依据协议证明未受理 | 可按事前授权策略处理,不能仅依 HTTP 状态猜测 | | POST 超时、断连、未知响应 | `outcomeUnknown`,禁止自动换路重发 | | 已有 external job ID | 固定渠道版本继续 query;停用新任务不阻止旧任务恢复 | | 内容政策拒绝 | 不换渠道绕过 | | 用户选择了具体模型 | 不偷偷换模型系列、质量、分辨率或价格档位 | P1 的等价渠道切换要求:用户批准路由范围、相同产品语义和零售价、提交前可证明安全、审计实际 binding;否则返回新报价。聚合平台自身也可能重试/路由,本平台需确认其幂等语义,不假设它已经防止重复收费。 ## 9. 熔断与限流 借鉴 cc-switch 的 closed/open/halfOpen,但在服务端按 `channelRevision + capability` 管理,并协调多实例。区分网络、上游 5xx、鉴权失效、上游余额、用户内容拒绝;内容问题不能熔断整个渠道。 半开探测默认使用安全只读能力;若只有付费生成才能证明恢复,必须管理员批准并记录测试预算。限流同时考虑每用户、工作区、渠道、模态与全局容量。上游 429 不等于可以自动重发创建;安全查询可按 `Retry-After` 与退避调度。 ## 10. 适配器契约草案 以下只是设计类型,不是本轮已实现代码: ```ts type SubmitResult = | { disposition: 'accepted'; externalId: string; protocol: string } | { disposition: 'completed'; artifact: RemoteArtifact; usage?: UsageFact } | { disposition: 'rejectedBeforeAcceptance'; evidence: RejectionEvidence } | { disposition: 'outcomeUnknown'; diagnosticId: string }; interface MediaAdapter { validate(input: CanonicalInput, config: PublishedConnection): ValidatedInput; submit(input: ValidatedInput, identity: SubmissionIdentity): Promise; query(job: PersistedProviderJob): Promise; fetchResult(job: PersistedProviderJob): Promise; } ``` `PublishedConnection` 不允许缺地址;`RemoteArtifact` 不是可任意直连的 URL,下载前仍过出站授权。取消、按幂等键查询和恢复是明确可选能力;未实现必须返回“不支持”,不能伪成功。 SDK 的创建类请求自动重试关闭;只有协议明文支持、且经过实际验证的幂等键提交才可安全恢复同一请求。查询重试与创建重试永远分开配置。 ## 11. 可审计记录 记录渠道版本、credential 版本引用、profile 版本、产品模型与上游模型 ID、参数摘要、请求身份、external ID、接受事实、用量与规范化错误。原始响应仅按最小化策略脱敏短期留存,不将 Bearer、完整签名 URL、媒体 Base64 或所有响应头写日志。 管理后台需要看到:谁改了地址、谁替换了密钥、何时验证、谁发布、影响哪些新任务、还有多少旧任务。不能只记录一个 `updatedAt`。 ## 12. 接入验收 1. 空数据库调用任何模态均不出站,无隐式地址。 2. 普通用户无法创建、修改或诊断平台渠道。 3. `/models` 成功而视频协议失败时,视频仍不可上架。 4. 图片同步、Base64、URL、异步四类实际支持情况分别测试。 5. 同一渠道根路径含自定义前缀时不被重复/丢弃。 6. 管理员修改地址,运行中的任务不发生身份漂移。 7. DNS rebinding、重定向、恶意媒体 URL、私网与元数据目标被阻止。 8. 日志、导出、浏览器状态与错误中不出现密钥。 9. 付费测试需要确认;熔断恢复不静默消费额度。 10. SDK 默认重试、默认地址和环境自动读取均经过实际验证而非假定。