Skip to content

[Feature] 增加模型开关:逐模型启用/禁用(控制 /v1/models 暴露与请求路由) #161

Closed

Description

@weiminghaoo

需求

希望增加模型开关:在面板里对上游模型目录中的每个模型单独启用 / 禁用。被禁用的模型应当:

  1. 从 GET /v1/models 返回列表中隐藏;
  2. 对该模型的请求直接拒绝(不进入选号、不消耗账号额度),并返回明确的 OpenAI 兼容错误。

现状(已核对:当前无此能力)

仓库中与「模型」相关的管控目前只有三类,均为被动或只读,没有人工开关:

现有能力 位置 性质
模型级自动冷却 internal/pool/modelcooldown.go、internal/pool/modelview.go 上游 429 code=6004 / 11102 触发的被动避让,非人工开关
模型锁池视图 面板「账号池」下方「模型锁池」表、GET /status 的 model_locks 只读:展示哪些模型被锁、解锁倒计时,不可操作
模型与档位查询 面板「模型与档位」视图 只读信息(倍率 / 思考档 / 上下文 / 最大输出),支持筛选排序
非对话模型过滤 internal/upstream/client.go nonChatModel() 代码硬编码过滤,不可配置

具体核对结论:

  • GET /v1/models(internal/server/handler.go:277 → modelList() internal/server/handler.go:357)是纯动态透传——上游目录给什么就返回什么(cn: / global: 前缀),无任何白名单 / 黑名单过滤;
  • cmd/server/config.go 全部配置段(panel / logging / server / cooldown / schedule / global / upstream / features / prompt / upstash / pool / session_sticky)中没有任何 models 相关键(config.example.json 同);
  • 全仓检索 model_enabled / allow_models / disabled_models / 模型开关 等标识零命中;
  • 现有最近似粒度的开关是**账号级「禁用」**与 realm 级 global.enabled,都无法按模型细分。

期望行为

  1. 配置驱动:新增 models 配置段(建议 disabled_models,默认空数组 = 行为与现状完全一致,对老配置零影响——符合仓库既有的「缺省不改变老行为」约定,参见 config.go 中 CheckinEnabled / IncludeDisabledInTasks 的注释);
  2. /v1/models 过滤:被禁模型不出现在返回列表中(注意保持 cn: / global: 前缀协议与 resolveModel 对称);
  3. 请求侧拦截:命中禁用模型的请求在选号前直接拒绝,不消耗账号额度。internal/server/handler.go:538 的 realm, bareModel := resolveModel(peek.Model) 是唯一入口,适合作拦截点;
  4. 面板可视化:「模型与档位」视图目前是纯查询表,可在此为每行加一个开关列(或新增独立「模型管理」视图),直接读写上述配置;
  5. 热生效:建议复用 internal/livecfg 的不可变快照机制——SanitizeFingerprints / RecordClientInfo 就是现成先例(读路径深、热改需求强),避免要求重启进程。

设计建议与注意点

  • 推荐「黑名单(disabled)」而非「白名单(enabled)」:模型目录是动态拉取的,上游随时新增模型;白名单语义会让新模型默认不可用,且老配置升级后行为翻转。黑名单默认空则天然向后兼容。
  • key 建议用「realm + 裸模型名」:与 ModelLockRow / modelCooldowns 现有口径一致——同名模型在 cn 与 global 两域各自独立计数。
  • 隐藏与拦截建议同时做:仅从 /v1/models 隐藏,仍会让写死模型名的客户端继续消耗额度(这与 issue [Bug] /v1/models 漏掉「桌面端 UA」家族独有的模型(gpt-6-luna 能调用却不在列表) #102「能调用却不在列表」是同一类不一致,只是方向相反)。
  • 错误响应建议 OpenAI 兼容(如 404 model_not_found,或 400 + 明确文案),与现有错误风格保持一致。

使用场景

  • 上游按 UA / 账号下发了一批自己用不到的模型(如 gpt-6-luna 等桌面端家族),不希望它们污染客户端模型选择器;
  • 某模型实测输出被静默钳制、或积分倍率偏高,想临时下线避免误用;
  • 多协议客户端只认固定几个模型,想收敛列表。

说明:以上现状均基于 main 分支当前代码核对(config.example.json 与各 internal/ 包)。如已有相关计划或设计取舍,欢迎指正;如方向可行,我这边也可以尝试提 PR。

Activity

  1. misakano7545 commented on Oct 20, 2026

    @misakano7545

    等价能力已经有了,形态是「黑名单」而不是「逐模型勾选」。

    现状

    models.hidden(面板「设置 → 模型黑名单」):

    "models": { "hidden": ["deepseek-pro", "cn:legacy-model"] }
    • 裸名 → 两个域都隐藏;cn: / global: 前缀 → 只隐藏该域;
    • GET /v1/models 不列(modelList 过滤);
    • 点名调用直接 400 model_unavailable,不进选号、不消耗额度;
    • 面板保存即热生效(livecfg 快照整体替换),无需重启。

    也就是说你的三个诉求(列表隐藏 / 请求拒绝 / 明确错误)都满足了,差的只是 UI 形态:现在是一行逗号分隔的输入框,不是模型列表上的勾选框。

    顺带

    反向的需求(把客户端固定的模型名映射到真实模型)也做了:models.aliases,比如 "claude-opus-4=glm-5.2",出站/选号/账本用真实名,响应回显客户端原发名。


    上游 10-12 之后没再提交,27 个 PR 待 review;这些问题我在自己的 fork 里持续跟进并已修掉大半:https://github.com/misakano7545/workbuddy2api-panel 。交流群:https://t.me/wb2api

  2. linguo2625469 commented on Oct 21, 2026

    @linguo2625469
    Owner

    已实现:#225(models.hidden 模型黑名单:/v1/models 过滤 + 点名请求 400 拒绝,热生效)。(本条处置由 AI 辅助完成。)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions