AGC 模型目录改为启动期从上游同步:规范更新与里程碑/实施计划
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m22s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m2s
Project CI / Backend tests (pull_request) Successful in 4m44s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Failing after 6m33s
Project CI / Native shell tests (pull_request) Successful in 6m8s
Project CI / Frontend tests (pull_request) Successful in 2m14s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 8m20s
Project CI / Repository checks (pull_request) Successful in 2m48s
Project CI / AI game creator shell web tests (pull_request) Successful in 2m2s

- 更新《AGC 平台模型目录与对话选择》主规范:目录只保留上游原始模型名与启用状态,新增启动期上游同步、失败关闭与存量旧结构重建口径
- 更新 server-rs 与 SpacetimeDB 数据契约中 agc_model_catalog 一节
- 新增里程碑《AGC 模型目录上游同步》与对应实施计划
- 更新 docs/README 索引条目
This commit is contained in:
2026-09-24 11:37:12 +08:00
parent 87e52860a7
commit 819505dc2b
5 changed files with 125 additions and 14 deletions
@@ -1,4 +1,6 @@
# AGC 后台模型别名与对话选择
# AGC 平台模型目录与对话选择
更新时间:`2026-09-24`。本次变更退役了 2026-09-05 版写死的初始目录与“别名”概念:目录初始值改为启动期从上游 LLM Router 同步,客户端与后台直接使用上游原始模型名;本文件仍是该专题的唯一主规范。
## 本地自定义 LLM
@@ -30,25 +32,37 @@
自定义连接固定使用 OpenAI Responses 协议(`apiKind` 只接受 `openai_responses`),设置页把协议展示为只读项;推理档沿用对话输入盒中按回合生效的选择器,设置页只读展示当前档位,不新增第二处写入入口。
## 官方路由契约
## 平台模型目录
### 目录的来源与初始化
- 目录只描述“平台开放给 AGC 的模型白名单 + 启用状态 + 默认项”。每项只有上游原始模型名 `model` 与 `enabled`,不再有稳定标识、别名或“实际模型名”的二次映射;默认项由 `defaultModel` 指定,且必须指向启用项。列表最多 200 项。
- 目录事实源是私有 `agc_model_catalog` 单例表,使用 revision 乐观锁,多 api-server 实例共享同一事实。
- api-server(API/All 角色)启动时检查目录:缺失、无法按当前结构解析、或校验不通过,三种情况都算“未初始化”。此时调用上游 `GET {LLM Router 地址}/models`(OpenAI 兼容列表,Bearer 使用与账号 provisioning 同一份 Router 管理员 Token),读取 `data[].id`,按上游返回顺序重建目录:每项 `enabled = true`,`defaultModel` 取第一个模型,并以存量 revision 写回(`revision` 自增)。并发启动的多个实例里只有一个写入成功,其余按冲突静默接受既有目录。
- 同步失败(网络、鉴权、非 2xx、空列表、响应超过大小上限、缺少管理员 Token、写回失败)只记录 error 日志,不写任何替代目录、不使用任何内置模型名;本次启动保持未初始化,下一次启动继续重试,直到目录里有数据。
- 目录未初始化时 `GET /api/llm/models`、`/api/llm/responses`、`/api/llm/chat/completions` 与后台 `GET/PUT /admin/api/agc-models` 一律失败关闭(`503`),错误文案明确指向“模型目录未初始化”。恢复路径是修复上游可达性后重启,或由运维清空该行后再重启。
- 存量旧结构目录(`id`/`alias`/`modelId`/`defaultModelId`)在部署后首次启动时按“未初始化”重建,owner 之前的启用与默认选择需要重新设置一次。
- 上游变化不自动跟随:目录只在未初始化时重建;上游新增或移除模型时,由 owner 在后台增删条目或调整启用、默认项。
- `GET/PUT /admin/api/agc-models` 仅 owner 可用,DTO 为 `{revision, defaultModel, models: [{model, enabled}]}`,`model` 必填、唯一、不含首尾空白、不超过 200 字节;PUT 携带上次读取的 revision,冲突返回 `409`。
- `GET /api/llm/models` 保持既有 DTO 形状 `{defaultModelId, models: [{id, displayName}], revision}`,启用项的 `id` 与 `displayName` 都是上游原始模型名(因此存量客户端无需跟随发版),不返回目录凭据或上游原始数据。
- 请求侧:AGC `POST /api/llm/responses` 与内部 chat 代理的上游 `model` 就是启用项里的上游原始模型名;目录校验通过后原样透传。`platform-default` 或未提供时使用目录默认项;不在启用项里的模型(含历史稳定标识)返回 `422`,不回退其它模型。
### 客户端行为
- 后台 owner 在“AGC 模型”维护列表;每项包含稳定 `id`、必填 `alias`、服务端 `modelId`、`enabled`。默认项必须启用。标识唯一,别名唯一,列表最多 32 项。
- 配置保存到私有 `agc_model_catalog` 单例表,使用 revision 乐观锁,重启及多 api-server 实例共享同一事实。缺少配置时使用初始目录,高质量对应 `gpt-6-astra`,快速对应 `gpt-5.6-luna`。
- `GET/PUT /admin/api/agc-models` 仅 owner 可用,返回完整配置;PUT 携带上次读取的 revision,冲突拒绝覆盖。
- `GET /api/llm/models` 返回启用项的 `id/displayName`、`defaultModelId` 和目录 `revision`,不返回实际模型名、Router 目录、凭据或能力原始数据。
- 客户端缓存最近 `revision`,在项目切换 / 对话表面挂载 / 下拉展开 / 窗口聚焦时条件刷新:`revision` 未变化不更新界面,同一时刻只保留一个在途请求,刷新失败保留上一次有效目录与本地选择。发起对话前用同一份快照校验所选模型仍启用,已停用或删除则回退默认模型并提示。
- 手动刷新立即显示进行中状态;真实刷新成功后显示完成反馈,即使 `revision` 未变化也有反馈。失败沿用有效缓存时仍显示失败,不能报告刷新成功;HTTP 状态和超时使用可辨认的提示。
- 模型目录与其它客户端 JSON API 的成功、失败响应体读取均复用 `readClientHttpResponseText` 的 15 秒上限;响应头已返回但响应体卡住时必须结束本次等待、释放目录在途请求并允许重试,迟到的响应不得覆盖新目录。
- AGC Responses 请求的 `model` 是稳定目录标识。服务端按当前目录映射实际模型名;未知、停用项拒绝,不回退其它模型。旧客户端无 AGC 标记时使用后台默认项。
- 输入框右下角选择模型,只显示别名;选择保存到客户端配置 `selectedModelId` 与 `selectedModelIsDefault`(当前选择是否来自平台默认项),从下一次请求生效。加载失败或选项停用时禁用提交并允许刷新,不显示实际 ID 作为兜底文案。
- 输入框右下角选择模型,显示目录 `displayName`(即上游原始模型名);选择保存到客户端配置 `selectedModelId` 与 `selectedModelIsDefault`(当前选择是否来自平台默认项),从下一次请求生效。加载失败或选项停用时禁用提交并允许刷新。
- `selectedModelIsDefault` 为真表示选择由平台默认项驱动(首次进入、默认项变化、所选模型失效回退),后台默认项变化时客户端跟随切换并提示;用户手动选择后置为假,不再被默认项变化覆盖。
- 首页聊天框架的右下角同样提供模型选择入口(与项目对话右侧一致)。首页入口与项目对话共用同一份目录缓存、挂载即加载(失败时沿用上一次成功目录),选择仅影响后续创建/发送的轮次,不阻塞「开启创作」,因此模型目录不可用时仍可创建项目并使用后台默认项。
- 首页聊天框架的右下角同样提供模型选择入口(与项目对话右侧一致)。首页入口与项目对话共用同一份目录缓存、挂载即加载(失败时沿用上一次成功目录),选择仅影响后续创建/发送的轮次,不阻塞「开启创作」,因此模型目录不可用时仍可创建项目(真正发送对话仍要求目录可用)。
- 项目右侧对话的模型选择器在对话进行中保持可交互:切换模型只写回客户端配置并作用于下一轮,当前回合不受影响;发送按钮仍由 `controlBusy` / `modelReady` 把关。
- 自定义开关关闭时,设置页不包含模型管理或模型选择,使用官方代理锁定。
## 验收
- 目录领域校验、未知/停用模型拒绝、客户端响应不包含实际模型名。
- 空目录 + 上游可达:启动后目录自动填充为上游模型列表(`revision` 自增一次),`/api/llm/models` 的 `id`/`displayName` 即上游原始模型名,默认项为列表首项,界面不再出现任何内置模型名。
- 空目录 + 上游不可达或缺少管理员 Token:启动只记录 error,不产生替代目录;AGC 相关接口与后台目录接口返回 `503`“模型目录未初始化”;下一次启动同步成功后自动恢复。
- 目录领域校验(空列表、超过 200 项、重名、默认项未启用)、未知或停用模型 `422`、客户端响应只含模型名与目录元数据。
- 后台鉴权、持久化 revision 冲突处理;客户端选择保存后重新读取,设置保存不覆盖选择。
- 目录 `revision` 条件刷新与并发触发去重、发送前回退默认模型、刷新失败可恢复。
- 响应体超时保留有效缓存、再次刷新重新请求、迟到响应不覆盖新目录;手动刷新进行中、同版本成功与缓存兜底失败反馈。