Codex 源码解析 · 第 5 讲
Codex 源码解析系列 第 5 讲:Model Provider 抽象与多后端 基于 OpenAI Codex 源码 · 2026-09-29 💡 本讲一句话: Codex 把"连哪个模型后端"抽象成一个 ModelProvider trait:OpenAI/ChatGPT、Amazon Bedrock、Ollama、LM Studio 四种后端的认证方式、模型目录来源、401 恢复策略各不相同,但上层会话代码只面对同一组方法。读完这一讲,你就知道切后端时哪些行为会变、为什么缓存不会串号。 一、一个 trait,四种后端:ModelProvider 长什么样 第 4 讲我们把 config.toml 里的 model_providers 表读成了 ModelProviderInfo ——那只是"配置态"。真正在运行时被会话调用的是 codex-model-provider crate(约 3.2K 行)里的 ModelProvider trait,它把"这个后端是什么、能做什么、怎么认证、模型列表从哪来"四件事收进一个接口。先看 trait 本体: 📄 codex-rs/model-provider/src/provider.rs (第 148-309 行,节选) pub trait ModelProvider: fmt::Debug + Send + Sync { // 运行时 provider 抽象:Send+Sync 才能跨线程共享给会话 fn info(&self) -> &ModelProviderInfo; // 返回配置态元数据(名字/base_url/鉴权方式),是其他默认方法的原料 fn capabilities(&self) -> ProviderCapabilities { // 能力上限声明:命名工具/图像生成/联网搜索/远程压缩 ProviderCapabilities::default() // 默认全开、仅不支持远程压缩——新后端不实现就继承这个保守基线 } fn auth_manager(&self) -> Option<Arc<AuthManager>>; // provider 级凭证管理器:Bedrock 的 AWS profile 就走这里,没有则返回 None fn is_recoverable_auth_error(&self, error: &TransportError) -> bool { // 判断某次传输失败是否属于"可恢复认证错误" matches!(error, TransportError::Http { status, .. } if *status == http::StatusCode::UNAUTHORIZED) // 默认只认 HTTP 401——OpenAI 系后端的通用语义 } fn recover_from_unauthorized(&self) -> ModelProviderFuture<'_, Result<ProviderUnauthorizedRecovery>> { // provider 自有的凭证恢复钩子(如刷新 AWS STS) Box::pin(async { Ok(ProviderUnauthorizedRecovery::NotConfigured) }) // 默认"没配置恢复"——调用方收到后走通用重登录流程 } fn auth(&self) -> ModelProviderFuture<'_, Option<CodexAuth>>; // 取当前凭证快照:异步是因为 Bedrock 可能要现签 STS token fn api_provider(&self) -> ModelProviderFuture<'_, Result<Provider>> { // 把配置态转成请求态 Provider(base_url+headers) Box::pin(async move { // 装箱异步闭包:trait 方法要求返回 Pin<Box<dyn Future>>,这是标准写法 let auth = self.auth().await; // 先取凭证快照,auth_mode 决定 base_url 怎么解析 let mut prov…
阅读全文:Codex 源码解析 第 5 讲