智能体的模型列表为什么要从三处来源合成:一次让 GPT-6.1 Sol 选不上的发布延迟

智能体的模型列表为什么要从三处来源合成:一次让 GPT-6.1 Sol 选不上的发布延迟

原文:OpenClaw Blog - 《Use new models in OpenClaw without an update》(https://openclaw.ai/blog/use-new-models-in-openclaw-without-an-update)

一、先说问题:模型发布了,你的 Agent 用不上

做 Agent 开发的人对这一幕不会陌生。厂商今天发了一个新模型,你打开自己的客户端准备试,下拉框里没有它。你去查文档、翻更新日志,发现客户端本身没坏,只是它还不知道这个模型存在。

OpenClaw 团队 11 月 6 日的这篇博客,就从这个具体的尴尬场景写起。他们讲了 GPT-6.1 Sol 发布时的真实情况:用 ChatGPT 登录方式接入 OpenClaw 的用户选不到 Sol。原因很机械------OpenClaw 内置的 Codex 是 0.158.0,而 ChatGPT 只把 Sol 提供给 0.159.2 及以上版本。想改这个版本号,只能由他们发一次新版本。

这里的成本被他们说得很直白:发布当天正是大家最想试模型的时候,而让人等的原因是他们自己。

二、旧的模型列表为什么必然滞后

要理解这次改造,先看清旧结构的问题。

过去每个 provider 插件把模型清单写在自己的 manifest 文件里,而这个文件是随 OpenClaw 包一起发出去的。插件绑定发布版本,所以清单也绑定发布版本。

这个结构带来的后果是:只要厂商新增一个模型,你就得等 OpenClaw 裁一次新版本、你更新一次客户端。在这条链路上,厂商的节奏、上游项目的节奏、你自己的升级节奏三者必须对齐,任何一环慢了,模型就用不上。

这次改造的工作量是大约五周、约 80 个 pull request,把「OpenClaw 怎么知道有哪些模型」这件事重做了一遍。

三、新结构:三处来源各管一段

现在的模型列表由三个地方补水(原文用 hydrate 这个词),每处负责一类信息:

来源 回答的问题 更新频率 覆盖范围
托管目录 catalog.openclaw.ai 公开世界里有这个模型吗 每 4 小时重建 约 1000 个模型
你的 provider 账号 你的账号能不能用它 登录或刷新时 账号实际可用的 chat 模型
本机安装的 Codex 本次请求该由哪个二进制跑 启动时探测 取决于安装版本

三块拼起来才是完整的答案。只看目录会漏掉账号私有模型,只看账号会漏掉能力元数据,只看 Codex 版本会卡在「清单能拉到、turn 跑不起来」的错位上。

四、来源一:每四小时重建一次的托管目录

目录放在 catalog.openclaw.ai,有一个任务每 4 小时重建一次。数据来源是 models.dev,OpenClaw 把自己的 manifest 叠在上面,补上价格,然后发布。

有两个细节值得记下来。

第一是热切换。运行中的 Gateway 在后台检查是否有新目录,发现新的就直接切。

  • 切换前:Gateway 下载完新目录,仍继续用旧目录,直到你重启。
  • 切换后:新的 turn 用新目录,已经在进行的 turn 用启动时的那份跑完。

这个「turn 内模型列表与价格始终匹配」的设计很实用。如果中途换目录,同一个 turn 前半段按一个价、后半段按另一个价,成本核算就没法看了。

第二是退役模型的清理。发布器会移除厂商已经下架或不再提供的模型。他们举的例子是 NVIDIA 在 API 上停掉两个模型,而目录里还挂着。

一次把目录打挂的事故

9 月 21 日,models.dev 把 kimi-for-coding 这一条拆成了两个新条目。OpenClaw 的发布器把「缺少某个 provider」当成致命错误,于是每次运行都失败。那段时间 GPT-6 Sol 和 Luna 进不了已有安装。

现在的处理是:缺少 provider 只记一条警告,只有那一个 provider 拿不到新数据,其他不受影响。

这一条几乎是所有「聚合外部数据源」的系统的必修课。一个来源改名、一个字段缺失,不应该让整批更新停摆。

五、来源二:账号能列出来的,就能选

目录知道公开世界有什么,你的账号知道你能用什么。这是两个不同的集合。

登录某个 provider 之后,OpenClaw 向它请求你账号的模型列表,把上面的每个 chat 模型都显示出来,包括比你安装版本更新的模型,也包括只有你这个账号能访问的模型。

原文给了一张对照表,把「改之前」和「改之后」放在一起:

  • OpenAI API key:改之前报 Unknown model: openai/gpt-5.2,虽然账号里列着它;改之后能显示也能跑。
  • Anthropic API key:改之前新 Claude 模型要等 OpenClaw 发版;改之后 Anthropic 的模型列表一返回就出现。
  • Claude Code:改之前是团队自己维护的固定清单;改之后用 Claude Code 为你账号报告的菜单。
  • GitHub Copilot:改之前 kimi-k3 第一轮就以 unsupported_api_for_model 失败;改之后读每个模型接受哪个 endpoint,用对应的那个。
  • Grok 订阅:改之前 grok-4.7-build-fast 只有 off 和 ultra 两档思考;改之后按它的 listing 给出 low、medium、high、xhigh。
  • Ollama:改之前你 pull 完模型也不出现;改之后下次刷新就出现。
  • OpenCode Go:改之前账号可服务的四个模型缺失;改之后全部出现。

这张表里最有信息量的是 Copilot 和 Grok 两行。它们暴露的是一个更隐蔽的问题:思考档位和请求格式。

OpenClaw 以前靠模型名字去猜思考档位和请求格式。这个做法对老模型勉强能用,对任何没见过的新模型就会猜错。而 provider 的 listing 里本来就写明了这些能力,直接读就可以。

顺带一提,Ollama 那条也很典型:本地拉下来的模型不在静态清单里,只要清单是编译进包里的,它就永远不会出现。

六、来源三:Codex 版本错位,一个更值钱的反例

第三处来源是原文标题里那个 Sol 问题的正解,但它的价值其实在于中间那次失败的尝试。

第一步:上报最新的 Codex 版本

最直接的修法是:向 npm 问一下最新的 Codex 版本号,拉模型列表时把那个数字报上去。Sol 果然出现在选择器里了。

第二步:发现问题被搬到了更糟的位置

实际结果是:列表请求报的是 0.161.0,而 turn 仍然跑在内置的 0.160.0 上。那个二进制会在每个请求里上报自己的版本号。

于是,需要更新版本的模型会出现在选择器里,然后第一条消息就 HTTP 400。他们把这次改动回滚了,并用一句话总结了这个错误:失败点从选择器搬到了第一条消息,后者更糟。

这条教训对做客户端或多组件系统的人都成立------真正需要关心的不是「这个模型是否显示出来」,而是「声明能力的那个组件」和「执行请求的那个组件」是不是同一个。如果两者不同,那么把前者的版本号伪造高,只会把错误推迟到更难排查的地方。

第三步:现在上线的做法

现在的逻辑是这样的:先在 PATH 里找一个 Codex;如果它是稳定版、比内置版本新、并且是同一个大版本,就和它做一次真正的手握手;握手通过,就用同一个二进制去拉模型列表、跑 turn;任何一步失败,退回内置 Codex。

原文贴了一台装了 Codex 0.162.1 的 Mac 上的 Gateway 日志:

复制代码
[agent/embedded] Codex app-server: using installed ~/.local/bin/codex 0.162.1 (newer than bundled 0.161.0)

注意这条路径的设计取舍:它只使用你已经安装的东西,从不替你安装任何东西。这既避免了静默下载未知二进制,也让「更新版本」这件事留在用户手上。

七、列表变短的问题,比列表变长更麻烦

找到模型是一个问题,让模型一直留在屏幕上、别无故消失,是另一个问题。原文列了三个会让列表缩水的场景:

场景 改之前 改之后
OpenRouter 超时一次 466 个变 3 个,要手动刷新才回来 自动重试:先 30 秒,之后间隔拉长到最多 30 分钟
Gateway 切换到新目录 599 个变 54 个,生产环境持续最多 4 分钟 全程保持 599,旧列表保留到新列表完整
修改默认模型 68---142 秒,重载所有大插件时卡住 0.6---1.4 秒,复用已加载的插件

第二行那个「599 变 54」值得琢磨。这不是数据错了,而是切换过程中出现了中间态:新目录还没下完,旧目录已经不用了。他们的处理方式是不暴露中间态------等新列表完整了再换。这是典型的双缓冲思路,只是用在了一条模型列表上。

选择器也改成了立即打开:先显示 OpenClaw 已知的模型,剩下的在后台补齐。以前要等发现流程跑完,最长 5 秒。

八、一千个模型之后:推荐清单

所有模型都显示出来之后,新问题来了:列表太长。光 OpenRouter 一家就有 466 个。

他们的办法是让目录给每个 provider 带一份简短的推荐清单,选择器把它放在最前面,但搜索仍然覆盖全部模型。推荐清单是人工维护、每天根据自身经验和各种 benchmark 更新。

原文举了自己一个 Gateway 上的例子:OpenAI 分组里,当前模型在最前,然后是两个推荐模型,剩下的 33 个收在一行后面。

这里的分层其实跟前面三处来源是同一个思路:默认值要短,全集要全,两者不能混成一层。

九、一个最小验证脚本

原文建议用 openclaw models list --refresh 直接看你的安装当前能触达哪些模型。如果你想在自己项目里把这件事做成可观测的,可以写一个很小的比对脚本。

下面这段是我自己写的,不是官方代码,用来验证「目录里的模型」和「我账号实际能调的模型」差多少------差异部分就是本文第三节那三处来源没对齐的地方。

python 复制代码
# diff_sources.py ------ 对比「托管目录」与「账号可用」两份模型清单
# 说明:示例脚本,非官方实现;接口与字段以官方文档为准
import json
import pathlib
import sys


def load_catalog(path: str) -> set[str]:
    """读取一份模型目录快照,返回模型 slug 集合。

    参数:
        path: 目录 JSON 的本地路径(形如 catalog 快照)
    返回:
        所有模型的 slug 集合;字段缺失的条目按 slug 缺失跳过
    """
    data = json.loads(pathlib.Path(path).read_text(encoding="utf-8"))
    models = data.get("models") or data.get("data") or []
    slugs = set()
    for m in models:
        slug = m.get("slug") or m.get("id")
        if slug:
            slugs.add(slug)
    return slugs


def diff(account: set[str], catalog: set[str]) -> dict:
    """比较账号清单与目录清单的差集。

    返回:
        only_account ------ 账号可用但目录没有(通常是私有或新模型)
        only_catalog ------ 目录有但账号调不了(通常是权限或 provider 未开通)
    """
    return {
        "only_account": sorted(account - catalog),
        "only_catalog": sorted(catalog - account),
    }


if __name__ == "__main__":
    # 用法: python diff_sources.py catalog.json account.json
    if len(sys.argv) != 3:
        raise SystemExit("usage: diff_sources.py <catalog.json> <account.json>")

    report = diff(load_catalog(sys.argv[2]), load_catalog(sys.argv[1]))
    for key, items in report.items():
        print(f"{key}: {len(items)}")
        for slug in items[:20]:
            print(f"  {slug}")

调用链很短:load_catalog 把两份 JSON 都归一化成 slug 集合,diff 做双向差集,主流程按类别打印前 20 条。

字段名用了 slug 和 id 两种兜底,是因为不同来源的命名习惯不一样;真实接入时,这两个键名务必以官方文档为准。打印只取前 20 条,是为了在差异几百条时也能读得下去。

十、四条可以带走的结论

原文结尾总结了四条,我认为对做 Agent 客户端或 gateway 的人都能直接用上:

  • 列出模型的版本必须同时是运行模型的版本。只换前者会把故障从一个明显的位置推到一个更隐蔽的位置。
  • 能力要从 listing 读,不要从名字猜。以名字为规则的判断,在遇到第一个没见过的模型时就会失效。
  • 保留上一份可用列表。一次失败的刷新或一次目录切换,都不该让选择器里的模型比之前更少。
  • 一个来源坏了不该阻塞其他来源。models.dev 上一个 provider 改名,曾经让所有 provider 的目录更新停摆。

这两件仍然需要发版的事也很实在:没装新版 Codex 时,内置版本依然决定你能看到哪些 ChatGPT 模型;比目录更新的模型还没有价格,成本显示为未知,会先用保守的默认限额运行。

把「模型列表」当成一个多源合成、可热切换、失败可降级的子系统来设计,这件事本身就是这次改造最值得借鉴的地方------它看起来只是下拉框里的几行字,实际牵扯发布节奏、缓存一致性、能力元数据和降级策略四个方向。

相关推荐
freewebsys13 分钟前
【原始POSTMAN】最老一个版本的postman 大家还记得吗?官方已经不支持没有升级了,下载了组件用AI直接升级了下可以使用了!
人工智能
云南新人和数采集团24 分钟前
云南靠谱软件开发公司选型指南:以昆明新腾科技为例
大数据·人工智能·科技
发现你走远了1 小时前
05-权限不是开关:工具调用如何在放行、拦截与追问之间做决定
人工智能·agent·claude
AllData公司负责人1 小时前
AI大模型数据开发底座系列说明书:AllData集成DB-GPT开源项目建设 AI 多模态分析底座,涵盖模态解析/智能大屏/MCP 扩展!
大数据·数据库·人工智能·gpt·数据采集·数据接入·模态解析
syyjhchou3 小时前
自己搭企业内部中转站,怎么让请求更容易命中缓存
人工智能·后端·语言模型·aigc
张然Adolf3 小时前
人工智能电力系统应用新手实战指南
人工智能
高洁013 小时前
数据同化与动态状态估计:让孪生持续贴合现实
人工智能·python·深度学习·transformer·迁移学习
feasibility.3 小时前
一物降一物?AI逆向没有终局:REA拆App,BLA设套,LASIK清场
人工智能·爬虫·github·逆向·skill·rea
IT古董4 小时前
AI 资讯日报 | 2026年10月25日:Kimi K3.1 Pro开源逼近前沿,OpenAI改离线训练,Claude合并Cowork,神经网络黑箱获新解,具身智能竞技场落幕
人工智能·神经网络·开源