ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Qwen Code ACP 模型路由身份(Model Route Identity)设计与实现解析

Qwen Code ACP 模型路由身份(Model Route Identity)设计与实现解析 Qwen Code ACP 模型路由身份Model Route Identity设计与实现解析【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读Qwen Code 通过 ACPAgent Client Protocol对外暴露模型选择能力其模型 ID 的传统线格式为modelId(authType)。当用户在同一认证类型下配置了多个相同 model ID、但baseUrl不同的模型例如同一模型名指向不同中转端点时这些路由会塌缩成一个选择器导致客户端无法区分当前激活的是哪一条路由也无法把一次选择准确回传到目标端点。本文基于 docs/design/acp-model-route-identity.md 设计文档结合 packages/cli/src/utils/acpModelUtils.ts 与 packages/cli/src/acp-integration/session/Session.ts 等源码实现完整讲解「不透明路由选择器opaque route selector」的生成规则、解析回退、持久化边界与兼容性策略帮助读者理解并正确接入这一机制。问题背景ACP 边界上的身份丢失Qwen Code 的核心配置层qwen-code/qwen-code-core早已将(authType, modelId, configured baseUrl)三元组视为注册表的身份标识。问题只发生在身份跨越 ACP 边界时ACP 的模型选择器只是一段字符串modelIdQwen Code 传统上将其格式化为modelId(authType)当两个已配置模型拥有相同的modelId与authType、但baseUrl不同时二者会生成完全相同的modelId(authType)选择器在客户端下拉列表中塌缩为一行客户端既无法识别当前激活的是哪一行也无法把一次「选中某行」的操作精确回传到正确的端点。设计上还必须保持一个关键区分配置值configured baseUrl必须与解析后的端点resolved endpoint分离。因为注册之后 provider 默认值可能填充baseUrl若拿解析结果当身份配置重排或默认值变化都会导致身份漂移。设计方案确定性不透明路由选择器设计文档给出的核心方案是从既有已配置模型列表构造 ACP 模型选项按需替换冲突 ID。具体规则如下当modelId(authType)唯一时保留原 ID维持既有正常路径的线格式不变当多个选项共享同一 ID 时每个选项替换为确定性的qwen-route:v1:digest选择器摘要由非机密模型元数据 公开端点身份去掉凭据、query、fragment 后的端点推导经清洗后仍无法区分的路由直接拒绝而不是退回到数组顺序——避免配置重排后旧选择器被重新映射到别的路由展示层继续使用ModelInfo.name与 provider 元数据路由 ID 只是一个不透明的机器选择器。这一策略在源码中体现为 packages/cli/src/utils/acpModelUtils.ts 的buildAcpModelOptions它对候选模型过滤掉fastOnly、voiceOnly、imageOnly的条目统计每个 legacy ID 的出现次数仅当计数为 1 时沿用formatAcpModelId即${modelId}(${authType})否则进入摘要分支。摘要的判别输入discriminator由五元组序列化而来const discriminator [ legacyModelId, model.label, model.envKey ?? null, model.registryBaseUrl undefined, getRouteEndpointIdentity(model.registryBaseUrl ?? model.baseUrl), ] as const;随后对判别键做 SHA-256 摘要并以 base64url 编码、截取前 16 个字符拼上固定前缀${ACP_ROUTE_ID_PREFIX}${createHash(sha256) .update(discriminatorKey) .digest(base64url) .slice(0, 16)}其中ACP_ROUTE_ID_PREFIX定义为qwen-route:v1:版本号保证了未来可平滑演进。端点身份清洗凭据与参数不进摘要摘要的输入必须不含机密信息否则选择器本身就可能泄露端点中的 token 或账号密码。源码中的getRouteEndpointIdentity对baseUrl做了严格清洗优先通过URL解析依次清空username、password、search、hash只保留清理后的href对无法被URL解析的裸字符串走sanitizeProviderBaseUrl兜底先剥离 authority 中的 userinfo前的账号密码再截断?/#之后的查询与片段。sanitizeProviderBaseUrl还处理了未转义 userinfo 的边界情况通过findUnescapedUserInfoFallbackAt判断冒号后是否纯数字端口避免把端口误判为密码分隔符。测试 packages/cli/src/utils/acpModelUtils.test.ts 中的用例直接验证了这一承诺构造https://user:secrettwo.example/v1?tokenvalue这类带凭据与查询串的地址后断言所有产出的选择器拼接结果中不包含secret字样。同一测试还验证了「凭据无关」特性对https://user:secret-0...?token0与https://user:secret-1...?token1两种带不同凭据的地址生成的选择器与不带凭据版本完全一致——端点身份只绑定到公开端点凭据属于运行期账户选择不参与路由标识。拒绝无法区分的冲突路由当多个路由共享 legacy ID且清洗后的判别输入仍完全相同时例如连label、envKey都与端点完全相同buildAcpModelOptions会直接抛出错误ACP model routes for legacyModelId need distinct names, envKey values, or public endpoints.设计文档明确这是有意为之与其用数组顺序隐式区分配置重排后会悄悄重映射旧选择器不如要求用户显式给出可区分的 name / envKey / 公开端点。测试rejects colliding routes that differ only by secret URL partspackages/cli/src/utils/acpModelUtils.test.ts专门覆盖了「仅凭据不同仍判冲突」的场景。统一出口所有客户端看到同一份 ID设计文档要求同一个选项构造器同时服务于 ACP 会话模型session models、配置选项config options、live provider 状态与 daemon workspace provider 状态保证每个客户端看到相同的 ID而服务端保留精确的注册表判别信息。源码印证了这一设计。在 packages/cli/src/acp-integration/acpAgent.ts 中buildAvailableModelsNewSessionResponse[models]通过buildAcpModelOptions构造availableModels并用getCurrentAcpModelId计算当前激活行的选择器buildConfigOptionsSessionConfigOption同样以modelOptions为数据源currentValue与每个options[i].value都使用同一套选择器buildWorkspaceProvidersStatus在构造 daemon workspace provider 状态时复用同一函数并对每条 provider 计算isCurrent当前 authType 当前选择器同时命中供 Web Shell 精确识别当前路由。getCurrentAcpModelId的匹配逻辑也值得注意当registryBaseUrl明确传入时它优先在选项中做精确端点匹配只有一个匹配项时返回该选择器无法确定时才回退为传统modelId(authType)格式。对于 runtime 模型isRuntimeModel且带runtimeSnapshotIdeffectiveModelId会使用快照 ID 而非裸 model ID选择器生成与解析同样走这套管线。切换模型解析、拒绝与规范化持久化session/set_model的处理入口在 packages/cli/src/acp-integration/session/Session.ts 的setModel方法其流程与设计文档逐条对应精确解析resolveAcpModelOption(rawModelId, config.getAllConfiguredModels())优先把输入当作选择器在当前已配置模型列表中精确匹配拒绝过期选择器如果输入以qwen-route:v1:开头但解析不到任何选项直接抛Unknown or stale model route: rawModelId——不透明选择器绝不会被当成字面 model ID 使用兼容回退解析失败的非选择器输入走parseAcpModelOption后者兼容${modelId}(${authType})与纯 model ID 两种旧格式对于仍存在歧义的 legacy ID保留「首条匹配」的旧行为切换与鉴权把解析出的baseUrlresolvedRoute.baseUrl透传给config.switchModel若切换目标是QWEN_OAUTH且认证类型发生变化还会要求缓存凭据requireCachedCredentials: true规范化持久化切换成功后仅持久化三组规范值到 settingsmodel.name实际 model IDruntime 模型写快照 IDmodel.baseUrl配置注册表端点隐式默认时写空字符串墓碑值tombstonesecurity.auth.selectedType实际认证类型不透明选择器绝不落盘设计文档明确「The opaque selector is never written tosettings.json」源码中settings.setValue的三个键与此严格对应通知客户端通过qwen/notify/session/model-update扩展通知extNotification把currentModelId即当前不透明选择器广播给已连接的客户端且该通知是 fire-and-forget 的失败不影响切换本身。兼容性与线格式稳定性设计文档列出的兼容性约束在实现中逐项落实ACP schema 不变modelId仍是字符串选择器只是字符串的一种取值唯一 ID 保持原样unique-model(USE_OPENAI)这类既有线格式原样保留不会为不冲突的模型引入噪音旧请求继续可用modelId(authType)与裸 ID 输入仍被parseAcpModelOption接受歧义时保持旧的 first-match 语义泛化 ACP 客户端只需回显Zed 等第三方客户端无需理解qwen-route:v1:的语义只要把它当作普通字符串回传即可CLI TUI 设置与选择行为不变选择器的生成与解析只在 ACP 边界发生不影响 TUI 的模型列表与settings.json读写。此外packages/cli/src/utils/acpModelUtils.ts 的注释还提示了一个跨端契约VSCode webview 侧在packages/vscode-ide-companion/src/webview/utils/discontinuedModel.ts镜像了这套编码规则用于识别已下线的 Qwen OAuth 注册表模型若前缀、认证类型等编码演进该文件需同步更新。验证体系测试如何锁定行为设计文档的 Verification 清单在测试中均有对应覆盖验证目标测试位置重复路由获得不同且稳定的选择器且不泄露 URL 凭据packages/cli/src/utils/acpModelUtils.test.tsuses opaque ids only to disambiguate colliding model routes等选择器在模型列表重排后保持稳定绑定到端点身份而非数组顺序同一文件中对[...models].reverse()的断言会话模型状态与配置选项发布相同选择器packages/cli/src/acp-integration/acpAgent.test.tsqwen-route:v1:前缀断言选择第二条路由切换携带其baseUrl、持久化规范值、以不透明选择器通知客户端packages/cli/src/acp-integration/session/Session.test.ts 的setModel测试组拒绝未知/过期选择器同一文件的modelId: qwen-route:v1:abcdefghijklmnop用例daemon provider 状态标识当前精确路由packages/cli/src/serve/workspace-providers-status.test.ts唯一 ID 与 legacy 选择保持可用packages/cli/src/acp-integration/model-configuration.test.ts测试对「稳定性」的刻画很关键同一组模型无论是正序还是倒序传入每个路由都绑定到相同的qwen-route:v1:摘要因为摘要只依赖元数据与公开端点与数组下标无关同时端点路径变化如one.example/first改为one.example/changed会导致摘要改变避免旧选择器被误映射到新端点。实践要点小结识别冲突同一modelId(authType)下存在多个不同baseUrl的已配置模型时ACP 侧必然出现qwen-route:v1:选择器——这是设计使然不是异常不要解析选择器客户端应把选择器当作不透明字符串回显不要尝试解码其中的摘要不要持久化选择器settings.json中只写model.name/model.baseUrl/security.auth.selectedType三组规范值选择器每次由buildAcpModelOptions从已配置模型列表重新推导警惕过期路由服务端对qwen-route:v1:前缀且解析失败的输入直接报错客户端应捕获Unknown or stale model route并刷新模型列表让路由可区分若构建选项时抛错提示「need distinct names, envKey values, or public endpoints」说明冲突路由连公开信息都无法区分需要为模型配置不同的label、envKey或公开端点。该机制的核心价值在于把「身份」与「展示」「凭据」彻底解耦——身份由非机密元数据与公开端点唯一确定展示交给ModelInfo.name凭据留在运行期账户体系里从而在保持 ACP 线格式不变的前提下让 Web Shell、Zed 等所有 ACP 客户端都能精确地识别、切换并回传每一条模型路由。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表