1. 从 Copilot 到自托管我为什么把 Codex 搬回本地如果你每天写代码都离不开补全和对话大概率正在用 Copilot 这类云端助手。方便是真方便但用久了总会碰到几个绕不开的问题公司内网项目不敢把代码片段发出去、订阅按人头收费越滚越大、高峰期响应忽快忽慢、想换个模型还得改一堆客户端配置。Codex 这类可自托管的代码生成方案正好给了另一条路——把推理服务放在自己能控制的机器上编辑器只连本地或内网地址。不过真动手时你会发现本地化部署 Codex 的难点往往不在模型本身而在“Key 和通道怎么统一管”。我试过把不同工具的 Key 散落在各个配置文件里结果换一次额度就要翻五六个地方排查连通性更是灾难。这篇就聚焦一条完整路径用 Docker 自托管 Codex 服务同时用 TaoToken 统一 Key 接入把 config.toml 和 settings.json 都收敛到一处。适合谁手上有一台能跑容器的开发机或内网服务器、希望统一管理多 AI 工具 Key、又不想被单一云端订阅绑死的开发者。下面从环境准备一路走到验证请求命令和配置都能直接复制。2. TaoToken 前置先把统一 Key 和通道准备好在写 Docker Compose 之前得先解决“请求发给谁”的问题。自托管 Codex 服务本身负责推理调度但它对外调用模型能力时需要一个稳定的 API 入口和一把能复用的 Key。TaoToken 在这里扮演的就是统一网关的角色你在一处生成 Key之后 Codex 服务、编辑器插件、脚本都共用它换额度或加模型时只改一个地方。具体操作分三步。第一打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册并进入控制台第二在控制台里创建 API Key建议按用途命名比如codex-local方便后面区分第三记下 API 基地址https://taotoken.net/api注意这个地址不带任何查询参数配置里直接填它就行。注意Key 只在创建时完整显示一次复制后先存到本地密码管理器或环境变量文件里别直接写进会提交到 Git 的配置。如果你后面还要跑长期编码任务或 Agent 流程可以顺带了解下 Coding Plan它更适合高频、持续的调用场景只是本地验证连通性的话普通 Key 就够了。控制台入口在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。这几处建议先收藏排障时会反复用到。3. 可复制配置Docker Compose 骨架与两个关键文件这一节是全文的核心直接给能跑的骨架。整体结构是一个docker-compose.yml起 Codex 服务一个config.toml管服务端参数一个settings.json管编辑器侧接入。三者通过环境变量里的同一个 Key 串起来。先看目录结构建议这样组织避免配置散落codex-local/ ├── docker-compose.yml ├── config/ │ └── config.toml ├── editor/ │ └── settings.json └── .env.env文件只放敏感信息不进版本库# .env TAOTOKEN_API_KEYsk-你的Key TAOTOKEN_BASE_URLhttps://taotoken.net/api CODEX_PORT8787docker-compose.yml骨架如下重点是environment把 Key 和基地址注入容器volumes把 config.toml 挂进去version: 3.9 services: codex: image: codex-local:latest container_name: codex-local restart: unless-stopped ports: - ${CODEX_PORT}:8787 environment: - OPENAI_API_KEY${TAOTOKEN_API_KEY} - OPENAI_BASE_URL${TAOTOKEN_BASE_URL} - CODEX_LOG_LEVELinfo volumes: - ./config/config.toml:/app/config.toml:ro healthcheck: test: [CMD, curl, -f, http://localhost:8787/health] interval: 30s timeout: 5s retries: 3config/config.toml负责服务端行为模型名和超时按你实际订阅调整[server] host 0.0.0.0 port 8787 [provider] base_url https://taotoken.net/api api_key_env OPENAI_API_KEY timeout_seconds 60 [model] name codex-mini max_tokens 4096 temperature 0.2 [log] level infoeditor/settings.json是编辑器侧接入把请求指向本地服务而不是云端{ codex.endpoint: http://127.0.0.1:8787/v1, codex.apiKey: sk-你的Key, codex.model: codex-mini, codex.timeout: 60000, codex.enableInlineCompletion: true }三个文件的关系可以这样理解.env提供密钥config.toml决定服务怎么调模型settings.json决定编辑器怎么调服务。Key 只维护一份改额度时只动.env。4. 启动与验证确认 API 通道真的通了配置写完别急着开编辑器先用命令行确认服务本身活着、通道能通。启动命令docker compose up -d docker compose logs -f codex日志里看到server listening on 0.0.0.0:8787和provider base_url loaded就说明服务起来了。接着验证健康检查curl -s http://127.0.0.1:8787/health返回{status:ok}表示进程正常。但进程正常不代表通道通真正要验证的是它能不能通过 TaoToken 拿到模型响应。用下面这条请求打一次对话接口curl -s http://127.0.0.1:8787/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-你的Key \ -d { model: codex-mini, messages: [{role: user, content: 用 Python 写一个快速排序}], max_tokens: 256 }成功时你会拿到一段 JSONchoices[0].message.content里就是生成的代码。如果只想先确认模型侧通道也可以直接打 TaoToken 的模型对话入口 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 做一次对照测试两边都能出结果说明 Key 和基地址没问题。实测下来最容易出问题的不是服务本身而是编辑器侧还残留着旧配置。改完settings.json后记得重启编辑器让插件重新读取端点。5. 本篇常见错排查从 401 到超时逐个拆部署过程中报错基本集中在几类按下面顺序排查效率最高。第一类是401 Unauthorized。九成是 Key 没注入成功。先确认.env里没有多余空格或引号再进容器看环境变量docker compose exec codex env | grep OPENAI如果OPENAI_API_KEY是空的说明 compose 没读到.env检查文件是否和docker-compose.yml同目录。第二类是404或model not found。多半是config.toml里的模型名和实际订阅不匹配。把name改成你账号下可用的模型标识重启服务再试。第三类是连接超时。先排除服务没起来docker compose ps看状态是否healthy。如果服务正常但请求卡住检查base_url是否误加了路径后缀正确写法就是https://taotoken.net/api不要自己拼/v1。第四类是编辑器里补全不触发。确认settings.json的codex.endpoint指向127.0.0.1:8787而不是容器名容器端口映射写的是${CODEX_PORT}:8787宿主机访问要用映射后的端口。第五类是日志刷屏但没结果。把CODEX_LOG_LEVEL临时调成debug看请求是否真的发到了 provider。如果日志显示请求已发出但无响应多半是网络出口问题而不是配置问题。提示每次改完配置用docker compose restart codex重启再跑一遍第 4 节的 curl比直接开编辑器试错快得多。6. 收尾把 Key 收敛到一处迁移才可持续走到这里你已经有了一个能自托管的 Codex 服务编辑器侧也接上了本地端点。回头看整条路径真正省心的不是“本地部署”这四个字而是 Key 和通道被收敛到了.env和config.toml两处。以后加新工具、换模型、调额度都只动这两个文件不用再满项目找配置。如果你后续要跑更重的编码任务或 Agent 流程建议把 Coding Plan 也纳入统一管理入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 它和本地服务共用同一把 Key切换成本很低。ClaudeCodeAnthropic 相关接入在 https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 需要时按文档改base_url即可。最后留一个我踩过的坑别把.env和settings.json一起提交到仓库哪怕仓库是私有的。用.gitignore把.env排除掉编辑器配置里的 Key 改成读环境变量迁移到新机器时只补.env就能跑起来。