Skip to content

fix(models): 模型发现遇到别名冲突时跳过该项而非整批回滚 - #910

Merged
chenyme merged 3 commits into
chenyme:mainfrom
741075810:pr/model-discovery-alias-skip
Aug 13, 2026
Merged

fix(models): 模型发现遇到别名冲突时跳过该项而非整批回滚#910
chenyme merged 3 commits into
chenyme:mainfrom
741075810:pr/model-discovery-alias-skip

Conversation

@741075810

Copy link
Copy Markdown
Contributor

问题

ModelRepository.UpsertDiscovered 在事务内对每个发现到的上游模型调用 ensureModelPublicIDNotAlias,冲突时直接 return err。由于该调用位于 Transaction 闭包内,一个模型的别名冲突会让整批发现回滚,同批次里本身无冲突的新模型一并被丢弃。

触发条件不罕见:preserveModelRouteAlias 会在路由改名时自动把旧的 public_id 登记为兼容别名。此后 discoveredRouteDefaults 为该上游模型算出的规范 public_id 正好等于这个别名,冲突稳定复现 —— 于是一次历史改名可以永久堵死该 provider 的全部后续模型发现

实际观察到的现象:某部署把 Build/grok-4.5 改名为 Build/build-grok-4.5model_route_aliases 留下 ('Build/grok-4.5', 15)。之后上游 /models 开始返回 grok-4.6account_model_capabilities 里数千个账号都记录了该能力(账号快照走 ReplaceAccountCapabilities,不经过别名检查,因此成功),但 model_routes 中 provider=grok_build 始终只有改名后的那条和 composer 两条,grok-4.6 一直进不去,对外 /v1/models 也看不到,只能手工建路由绕过。日志里表现为反复的 model_etag_refresh_failed,错误都是同一条 repository: conflict: 模型公开 ID "Build/grok-4.5" 已被路由 15 保留为兼容名称

改动

别名冲突时跳过该模型、继续处理同批其余模型;非冲突错误仍然向上返回,保持原有失败语义。冲突项本来就无法插入,跳过不改变可达状态,只是不再牵连同批其他模型。

测试

新增 TestUpsertDiscoveredAliasCollisionDropsWholeBatch,按真实部署的顺序复现:先发现 grok-4.5,改名留下兼容别名,再以 ["grok-4.5", "grok-4.6"] 触发发现。

修复前该用例失败:UpsertDiscovered 返回 repository: conflict: 模型公开 ID "Build/grok-4.5" 已被路由 1 保留为兼容名称,且 grok-4.6 未落库。修复后通过。

本地:go build ./...go vet ./...go test ./... 全绿。

说明

这与 #906 不是同一处:#906 修的是 NormalizeAccountModelCapabilities(账号能力快照里补回 grok-4.5),本 PR 修的是 UpsertDiscovered(公开路由目录进不去新模型)。两者互补 —— 账号能力表能写成功正是因为它不经过别名检查,而路由表被别名卡死,所以 #906 合入后本问题依然存在。

741075810 and others added 3 commits August 13, 2026 11:45
…f aborting the batch

UpsertDiscovered calls ensureModelPublicIDNotAlias inside the transaction and
returns on conflict, so one alias collision rolls back the whole batch and
silently drops unrelated new models. preserveModelRouteAlias registers the old
public ID as a compatibility alias on every route rename, so a single historical
rename can permanently hide every future model of that provider.

Skip the conflicting entry and keep the rest of the batch. Non-conflict errors
still propagate. The skipped entry could not have been inserted anyway, so
reachable state is unchanged.
@chenyme
chenyme merged commit d4e6453 into chenyme:main Aug 13, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants