模型目录与提供方 · 一个 CLI 接多家后端

模型能做什么由模型目录决定:每个模型一条 ModelInfo,上下文窗口、推理强度、工具形态、基础指令模板都写在里面,目录来自随附文件、磁盘缓存与服务端的 models 接口。请求发到哪、怎么认证由提供方决定:配置层的 ModelProviderInfo 描述端点与凭据,运行时的 ModelProvider 负责认证、能力上限与目录管理,所有后端都只说 Responses API 这一种协议。

作者 David更新于 第 18 篇(共 57 篇)

模型目录与提供方 · 一个 CLI 接多家后端

指令从哪来提到,基础指令取自模型目录里的模板。这一篇把两个常被混在一起的概念拆开:模型目录回答“这个模型能做什么、该怎么用”,提供方回答“请求发到哪、带什么凭据”。

用户看到的样子

选模型用 /model、-m(--model)或配置里的 model;换后端则在 [model_providers.<id>] 里定义提供方,再用 model_provider 指向它。--oss 配合 --local-provider 或 oss_provider 使用本机的 Ollama 与 LM Studio,Amazon Bedrock 是内置提供方。/fast 与 service_tier 切换服务档位,model_catalog_json 用一个 JSON 文件整体替换模型目录,codex debug models 打印当前目录,加 --bundled 只看随附目录。用法见模型与推理与配置项速查。

ModelInfo:目录里的一条

ModelInfo(codex-rs/protocol/src/openai_models.rs:404)有 47 个字段,大致分几组:身份与展示(slug、display_name、priority、visibility、supported_in_api),推理(default_reasoning_level、supported_reasoning_levels),工具形态(shell_type、apply_patch_tool_type、web_search_tool_type、tool_mode),上下文(context_window、max_context_window、auto_compact_token_limit、effective_context_window_percent、comp_hash、truncation_policy),请求形态(use_responses_lite、supports_reasoning_effort_updates),服务档位(service_tiers、default_service_tier),以及放基础指令模板的 model_messages。前几篇里的压缩阈值、Responses Lite、工具输出截断,以及基础指令本身,都是读这些字段决定的。core 的非测试代码里,写死的模型名只有实时语音的两个默认模型;审查、记忆这类辅助任务的默认模型写在提供方里。模型之间的差异,几乎全部以数据的形式放在目录里。

随附目录是 codex-rs/models-manager/models.json,0.158.0 里有 10 个模型:7 个出现在选择器里(gpt-6-astra、gpt-6-sol、gpt-6-luna、gpt-5.6-sol、gpt-5.6-terra、gpt-5.6-luna、gpt-5.5),3 个隐藏(两个 gpt-daybreak-* 与审批审查用的 codex-auto-review)。上下文窗口多为 272,000,max_context_window 多为 872,000。

目录从哪来

ModelsManager trait 有两个实现。StaticModelsManager 持有一份权威目录,不联网:配置了 model_catalog_json 时用它,Amazon Bedrock 也用它装自己的静态目录。OpenAiModelsManager 以随附目录起步,再叠加两层:CODEX_HOME 下的磁盘缓存 models_cache.json(有效期 300 秒,按客户端版本与“身份”匹配),以及提供方的 /models 接口(5 秒超时)。身份是对提供方路由、账号信息等算出的 SHA-256 摘要,按注释的说法,ChatGPT 的访问令牌不参与计算,令牌轮换不会让同一账号的缓存失效。

刷新策略有三种:Online 总是联网,Offline 只读缓存,OnlineIfUncached 缓存可用就不联网。根线程启动时用 OnlineIfUncached,子代理用 Offline。之后模型响应若带 X-Models-Etag 头,就和缓存的 ETag 比较,不同就按 Online 刷新,相同就只给缓存续期。拿到的远端目录,若在 ChatGPT 账号或 API key 目录发现的场景下,且含选择器可见的模型,就整体取代随附目录;否则按 slug 合并进随附目录。

按名字查元数据时走这个函数:

pub(crate) fn construct_model_info_from_candidates(
    model: &str,
    candidates: &[ModelInfo],
    config: &ModelsManagerConfig,
) -> ModelInfo {
    // First use the normal longest-prefix match. If that misses, allow a narrowly scoped
    // retry for namespaced slugs like `custom/gpt-5.3-codex`.
    let remote = find_model_by_longest_prefix(model, candidates)
        .or_else(|| find_model_by_namespaced_suffix(model, candidates));
    let model_info = if let Some(remote) = remote {
        ModelInfo {
            slug: model.to_string(),
            used_fallback_model_metadata: false,
            ..remote
        }
    } else {
        model_info::model_info_from_slug(model)
    };
    model_info::with_config_overrides(model_info, config)
}

(codex-rs/models-manager/src/manager.rs:782)

匹配是“最长前缀”:请求的名字以目录里某个 slug 开头就算命中,取最长的那个,结果保留请求时的名字。查不到时用回退元数据:窗口 272,000、工具输出按 10,000 字节截断、used_fallback_model_metadata 为真,每一轮开始时界面都会收到一条 “Model metadata for … not found” 的警告。最后 with_config_overrides 套上配置:model_context_window(不超过 max_context_window)、model_auto_compact_token_limit、tool_output_token_limit、自定义基础指令,以及 personality = "none" 时删掉模板里的 # Personality 一节。选择器里的列表由 build_available_models 生成:按 priority 排序,不走 Codex 后端的登录方式只保留 supported_in_api 的模型,第一个可见的模型标为默认,随附目录里就是 gpt-6-astra。

是否联网由 refresh_available_models 开头的两道判断决定:

        if self.uses_api_key_auth()
            && !self.endpoint_client.has_command_auth()
            && (!self.endpoint_client.supports_api_key_models()
                || !self.api_key_model_discovery_enabled.load(Ordering::SeqCst))
        {
            return Ok(());
        }

(codex-rs/models-manager/src/manager.rs:488)

第二道是 should_refresh_models:当前登录走 Codex 后端(ChatGPT 登录等)、提供方配置了命令式认证、或者满足 API key 目录发现的条件,三者有一个成立才联网。用 API key 时(登录方式是 API key,或提供方配了 env_key、experimental_bearer_token),目录发现还要求功能开关 api_key_model_discovery 打开,它处于开发阶段,默认关闭。

《Codex 中文手册》写着 model_catalog_url 可以指定 Codex 格式模型目录的地址,没有提到前提条件。按 0.158.0 的代码,用 API key 认证时(包括给提供方配了 env_key),只有打开开发中的 api_key_model_discovery 才会去取这个地址,否则连之前的缓存也不用,只用随附目录;配置了命令式认证(auth)的提供方不受这个开关限制。

提供方:配置一层,运行时一层

图表加载中…

配置层是 ModelProviderInfo(codex-rs/model-provider-info/src/lib.rs:135),描述端点(base_url、model_catalog_url、query_params)、凭据(env_key、experimental_bearer_token、命令式的 auth、网关的 gateway_oauth、AWS 的 aws)、请求头、重试与超时,以及 requires_openai_auth、supports_websockets 等开关。协议字段 wire_api 的枚举只剩 Responses 一个值,写 "chat" 会在解析配置时报错,提示改成 responses。内置的提供方有五个:

    // We do not want to be in the business of adjucating which third-party
    // providers are bundled with Codex CLI, so we only include the OpenAI and
    // open source ("oss") providers by default. Users are encouraged to add to
    // `model_providers` in config.toml to add their own providers.
    [
        (OPENAI_PROVIDER_ID, openai_provider),
        (AMAZON_BEDROCK_PROVIDER_ID, amazon_bedrock_provider),
        (
            AMAZON_BEDROCK_RUNTIME_PROVIDER_ID,
            amazon_bedrock_runtime_provider,
        ),
        (
            OLLAMA_OSS_PROVIDER_ID,
            create_oss_provider(DEFAULT_OLLAMA_PORT, WireApi::Responses),
        ),
        (
            LMSTUDIO_OSS_PROVIDER_ID,
            create_oss_provider(DEFAULT_LMSTUDIO_PORT, WireApi::Responses),
        ),
    ]

(codex-rs/model-provider-info/src/lib.rs:652)

注释只提到 OpenAI 与开源两类,列表里却还有两个 Amazon Bedrock 提供方。用户定义的提供方由 merge_configured_model_providers 并进来:五个内置 ID 都是保留的,重新定义会报错并建议改名(例如 openai-custom),只有两个 Bedrock ID 允许覆盖 base_url、auth、aws 与 http_headers;OpenAI 的地址要改用 openai_base_url。项目目录里的配置写了 openai_base_url、model_provider、model_providers 会被忽略,按注释的说法,来自仓库内容的配置不该决定用户的凭据发往哪里;requirements.toml 则可以强制指定提供方。选中顺序是:托管要求、启动时的覆盖(如 --oss 选中的本地提供方)、配置里的 model_provider,都没有就是 openai。没写 base_url 时,to_api_provider 按登录方式选默认地址:ChatGPT 一类登录走 https://chatgpt.com/backend-api/codex,其余走 https://api.openai.com/v1。

运行时一层是 ModelProvider trait,由 create_model_provider 创建:两个 Bedrock ID 得到 AmazonBedrockModelProvider,其余都是 ConfiguredModelProvider。它负责解析认证(先用提供方自己的 env_key 或 experimental_bearer_token;提供方不要求 OpenAI 认证、也没配认证命令时不带凭据;否则用认证命令或登录得到的凭据),在 401 之后尝试恢复,创建上面说的目录管理器,并给出 ProviderCapabilities:命名空间工具、图片生成、网络搜索、外部网页访问、远程压缩五项,注释称之为“provider-owned upper bound”,配置只能在此基础上再关,不能打开提供方标为不支持的功能。ConfiguredModelProvider 只对 OpenAI 与 Azure 声明支持远程压缩 V2,这就是上下文压缩里选实现的依据;判断看的是显示名而不是 ID:name 为 OpenAI(内置的 openai 就是),或名字是 azure、base_url 含 openai.azure. 等特征串。

Fast 是什么

Fast 就是请求里的 service_tier: "priority"。它经过两道过滤:会话层的 get_service_tier(codex-rs/core/src/session/mod.rs:1075)只放行 flex,或者在 fast_mode 开关打开(稳定功能,默认开启)时放行 default 与模型目录声明过的档位;请求层的 service_tier_for_request 再去掉 default 与模型不支持的值,Bedrock 一律不带档位,Guardian 审查请求也会清掉它。随附目录只给 gpt-6-sol 与 gpt-6-luna 设了默认档位 priority,但套用这个默认值的是 TUI(effective_service_tier),core 只认配置或请求里明确给出的档位,所以 codex exec 不会自动用 Fast。走 Codex 后端时,请求还会带一个 x-codex-routing-hint 头,内容是模型名与档位。

本地模型与 Amazon Bedrock

Ollama 与 LM Studio 两个内置提供方的地址默认是 http://localhost:11434/v1 与 http://localhost:1234/v1,可以用实验性的环境变量 CODEX_OSS_PORT、CODEX_OSS_BASE_URL 改。--oss 启动时先决定用哪一家(--local-provider、oss_provider,TUI 里都没有时检测本机服务或让用户选,codex exec 直接报错),没给 -m 就用 gpt-oss:20b 或 openai/gpt-oss-20b;Ollama 还要检查版本不低于 0.13.4(支持 Responses API 的最低版本),本地没有所请求的模型就拉取,LM Studio 缺模型就下载并在后台加载。

Amazon Bedrock 有两个内置提供方:amazon-bedrock 走区域内的 Mantle 端点,amazon-bedrock-runtime 走 Bedrock Runtime 端点。它们用 AWS 的认证方式,目录是静态的,由随附目录里的 OpenAI 模型改名而来(如 openai.gpt-6-sol),并统一清掉服务档位、把网络搜索改成纯文本形态、多 agent 固定为 V1,还去掉 ultra 推理强度并关闭 Responses Lite。

和《从 LLM 到 Coding Agent》对照

错误恢复建议主模型过载时自动降级到备用模型重发。Codex 没有这样做:服务端报过载时得到的 ServerOverloaded 不在可重试之列,本轮直接结束,提示是 “Selected model is at capacity. Please try a different model.”,换不换模型交给用户。接近“回退”的是线程启动时的 allow_provider_model_fallback(app-server 的实验参数):提供方的静态目录里没有所请求的模型时,改用目录的默认模型。成本追踪建议按模型维护价目表、在客户端累加花费;Codex 的 ModelInfo 没有任何价格字段,core 里也没有按价格计算的代码,用量只以 token 数和服务端经响应头下发的额度快照呈现(见模型客户端)。


上一篇:指令从哪来 · AGENTS.md、系统提示词与协作模式 · 下一篇:任务类型与 Plan 模式 · 一轮里跑的不只是对话

本页目录