☰
卷疯了!Codex 再出新功能,关机也可以继续跑任务:Handoff 迁移到远程主机实操
2026/10/12 14:25:08 网站建设 项目流程

1. Codex Handoff 到底解决了什么痛点:关机后任务中断的完整场景复盘

Codex 是 OpenAI 推出的命令行编程智能体,能在终端里读写文件、跑测试、执行重构。Handoff 是它近期加入的接力能力:把本地正在跑的会话、未提交改动、上下文状态整体迁移到一台远程 Linux 主机上继续执行。适合谁?适合下班要合盖走人、但任务还没跑完的开发者,也适合本地机器性能吃紧、想把重活丢给云主机的团队。

我平时的节奏是这样的:晚上十点本地开一个 Codex 会话,让它重构一个模块并跑全量单测。跑到一半要回家,以前只能 Ctrl+C 中断,第二天重新描述上下文,AI 还得重新读一遍代码库,中间调试状态全丢。Handoff 出现后,这个流程变成:在对话框里说一句“把当前任务迁到远程主机继续跑”,本地打包未提交改动和会话历史,通过 SSH 推到远程,远程接管执行。合上笔记本,任务在服务器上继续。

这里的关键词是“会话历史”和“未提交改动”。传统换机协作要先 git commit、push,再到另一台机器 pull,然后重新向 AI 描述“我刚才在做什么”。Handoff 把这三步压缩成一次迁移动作,会话 ID、变量状态、中间调试信息一起走。对长任务尤其重要——比如一个要跑四十分钟的测试套件,或者一个多轮迭代的重构,中断一次成本极高。

但 Handoff 不是魔法,它依赖三个前置条件:远程主机装好 Codex 运行环境、本地到远程的 SSH 免密通道畅通、双端模型服务配置一致。任何一环出问题,迁移都会卡住。下面按“环境准备 → 通道配置 → 模型接入 → 触发迁移 → 验证结果 → 排错”的顺序拆开讲,每一步都给可复制的命令和配置。

需要先说明一点:Handoff 迁移的是任务执行位置,不是把本地编辑器搬走。你本地该写的代码还是本地写,它解决的是“执行阶段”的连续性。理解这一点,后面的配置逻辑就顺了。

2. TaoToken 前置准备:统一 Key 与 API 通道,让迁移后模型调用不断档

Handoff 迁移过去之后,远程主机上的 Codex 要能正常调用模型,否则任务迁过去也跑不动。这里最容易踩的坑是:本地用一套 Key,远程用另一套,迁移后环境变量没同步,直接 401。我的做法是用 TaoToken 做统一的 API 通道,本地和远程共用同一个 Base URL 和 Key,迁移前后模型调用完全一致。

TaoToken 是一个多模型聚合服务,提供标准的 OpenAI Compatible API 格式。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api 。它的作用是让你用一套 Key 调度不同模型,本地和远程配置同一份,省去双端对账的麻烦。

前置准备分三步。第一步,拿到 API Key。进入控制台 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,在令牌管理里创建一个新令牌。创建时绑定你要用的模型分组,不确定就先留空。复制生成的 Key,形如sk-xxxxxxxx。

第二步,确认模型 ID。去模型对话页面 https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 或接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 查当前可用的模型名称。Codex 场景下常用的编码模型按文档实时列表为准,不要凭记忆写死。

第三步,规划配置存放位置。Codex 读取模型配置的方式因版本而异,常见的是环境变量或配置文件。我建议把 Base URL、Key、Model ID 三项写进一个统一的地方,本地和远程都引用它。这样 Handoff 迁移时,远程主机只要环境变量一致,模型调用就不会断。

这里有个细节:远程主机如果是全新的,环境变量不会自动带过去。所以要么在远程的 shell 配置文件(如~/.bashrc或~/.zshrc)里写死,要么用 Codex 自己的配置文件。我倾向后者,因为迁移时配置文件跟着项目走,更可控。

注意:不要把 Key 硬编码进会提交到 Git 的文件里。用.env加.gitignore,或者用 Codex 的本地配置目录。

配置完成后,先在本地验证一次模型调用能通,再去做 Handoff。顺序反了的话,迁移失败你分不清是 SSH 问题还是 Key 问题。验证方法在第四节给。

3. 可复制配置:SSH 通道 + Codex 模型接入的完整片段

这一节给可直接复制的配置。分两块:SSH 免密通道,和 Codex 的模型服务配置。

先配 SSH。编辑本地~/.ssh/config,加入远程主机条目。假设远程 IP 是203.0.113.10,用户名ubuntu,密钥~/.ssh/id_ed25519,别名tokyo:

Host tokyo HostName 203.0.113.10 User ubuntu IdentityFile ~/.ssh/id_ed25519 ServerAliveInterval 60 ServerAliveCountMax 3 TCPKeepAlive yes

ServerAliveInterval 60是关键,它让本地每 60 秒发一次心跳,防止迁移过程中 SSH 超时断开。ServerAliveCountMax 3表示连续 3 次心跳无响应才断开,给网络波动留缓冲。

配完测试连通性:

ssh tokyo 'hostname && uname -a'

能返回远程主机名和内核信息,说明通道通了。如果提示Permission denied (publickey),说明公钥没传到远程,执行:

ssh-copy-id -i ~/.ssh/id_ed25519.pub ubuntu@203.0.113.10

再测一次。

接着配远程主机的 Codex 环境。SSH 登录远程:

ssh tokyo

安装 Codex 和依赖:

npm install -g @openai/codex codex --version

检查 bubblewrap 和 git:

if ! command -v bwrap >/dev/null 2>&1 || ! command -v git >/dev/null 2>&1; then sudo apt-get update && sudo apt-get install -y bubblewrap git else echo "bubblewrap and git are already installed." fi

bubblewrap 是 Codex 构建沙箱隔离环境的核心组件,git 用于同步代码差异,两个都不能少。

然后是模型服务配置。Codex 支持通过配置文件或环境变量接入自定义 API。以配置文件方式为例,在项目根目录或 Codex 配置目录创建config.toml:

model = "按文档填入模型ID" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY" wire_api = "chat"

对应的环境变量在本地和远程都要设置:

export TAOTOKEN_API_KEY="sk-你的Key"

写进~/.bashrc或~/.zshrc让它持久化。远程主机同样操作一遍。这样本地和远程引用的是同一个 Base URL、同一个 Key、同一个 Model ID,Handoff 迁移后模型调用无缝衔接。

如果你用的是 Codex 的 auth.json 方式(部分版本支持),配置结构类似:

{ "auth_mode": "apikey", "providers": { "taotoken": { "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "model": "按文档填入模型ID" } } }

三件套记牢:Base URL 是https://taotoken.net/api,Key 从控制台拿,Model ID 从文档查。任何一处不一致,迁移后都会报错。

4. 验证请求与成功结果:迁移前后各跑一次确认

配置写完不能直接上 Handoff,先做两次验证:本地一次,远程一次。两次都通,才说明迁移后模型调用不会断。

本地验证。在本地终端跑一个最小请求,确认 Key 和 Base URL 有效:

curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "按文档填入模型ID", "messages": [{"role": "user", "content": "reply with ok"}] }'

返回 JSON 里choices[0].message.content有内容,说明本地通道正常。如果返回 401,检查 Key 是否复制完整、有没有多余空格。如果返回 404,检查 Base URL 是不是写成了https://taotoken.net/api而不是带/v1的完整路径——具体以文档为准。

远程验证。SSH 到远程,跑同样的 curl:

ssh tokyo 'curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"model\":\"按文档填入模型ID\",\"messages\":[{\"role\":\"user\",\"content\":\"reply with ok\"}]}"'

远程也能返回内容,说明双端模型通道一致。这一步很多人跳过,结果 Handoff 迁移过去任务卡在模型调用上,回头排查浪费半小时。

两次验证都通过后,做一次 Handoff 触发。在本地 Codex 会话里,确认当前任务正在运行,然后输入迁移指令:

把当前正在执行的任务迁移到 tokyo 主机上继续运行

Codex 会做几件事:打包未提交改动(相当于 stash)、序列化会话历史、通过 SSH 传输到远程、在远程恢复会话。过程中终端会显示迁移进度。完成后给出远程会话的标题和会话 ID。

成功结果长这样:本地终端提示迁移完成,附带远程会话标识;远程主机上codex进程开始接管执行;你本地可以安全合盖。验证远程任务确实在跑:

ssh tokyo 'ps aux | grep codex'

能看到 codex 进程,说明任务已在远程执行。再等几分钟,看远程日志有没有新的模型调用记录,确认任务在持续推进而不是卡住。

如果迁移后远程任务立刻退出,多半是远程工作目录和本地不一致。Handoff 依赖双端存在同一个 Git 仓库路径。本地项目在/Users/you/projects/my-app,远程也要有对应仓库,或者在 Codex 项目设置里显式关联工作区。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth 逐条对照

配置和迁移过程中,几个报错反复出现。逐条给现象、原因、解决。

401 Unauthorized。现象:curl 或 Codex 调用模型返回 401。原因:Key 无效、过期、或环境变量没生效。排查:echo $TAOTOKEN_API_KEY看有没有值,注意前后空格。远程主机如果没设这个变量,echo会是空。解决:在远程~/.bashrc里补上export TAOTOKEN_API_KEY="sk-...",然后source ~/.bashrc。另外确认 Key 绑定的模型分组包含你要用的模型。

local proxy failed。现象:Codex 启动或迁移时报本地代理失败。原因:环境里残留了HTTP_PROXY/HTTPS_PROXY之类的变量,指向一个不存在的本地端口。排查:env | grep -i proxy。解决:unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy,或者把代理配置指向正确地址。远程主机同样检查一遍,很多人本地清了远程忘了清。

reading choices 报错。现象:模型返回的 JSON 解析失败,提示读取choices字段出错。原因:Base URL 路径不对,请求打到了非兼容端点,返回了 HTML 或错误结构。排查:确认 Base URL 是https://taotoken.net/api,且请求路径拼成了/v1/chat/completions。解决:对照接入文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 核对完整端点。另外确认wire_api设成了chat而不是其他模式。

OAuth 相关报错。现象:Codex 提示 OAuth 登录失败或 token 过期。原因:Codex 默认走账号 OAuth,但你配了自定义 API Key,两种认证方式冲突。排查:看配置文件里auth_mode是不是还留着 OAuth。解决:把auth_mode改成apikey,并确保env_key指向正确的环境变量名。如果用的是 auth.json,检查providers结构有没有写错层级。

SSH 迁移中途断开。现象:迁移进度条卡死,提示Connection closed by remote host。原因:网络波动导致 SSH 超时。解决:确认~/.ssh/config里有ServerAliveInterval 60。如果还断,把值降到 30,并加TCPKeepAlive yes。

bwrap 权限错误。现象:远程任务运行时报bwrap: No permissions。原因:部分云服务器内核默认禁用用户命名空间。解决:

sudo sysctl -w kernel.unprivileged_userns_clone=1

永久生效写入/etc/sysctl.conf。改完重启 Codex 会话。

代码冲突。现象:接力后远程代码和本地不一致。原因:本地有未追踪文件没被 Git 管理,Handoff 打包时漏掉。解决:迁移前git status检查,把新文件git add进去,或者让 Codex 自动处理临时暂存。

这些报错里,401 和 reading choices 占了我遇到问题的大半,根因都是配置三件套没对齐。把 Base URL、Key、Model ID 三项在本地和远程各核对一遍,能省掉大量排查时间。

6. 长期编码与 Agent 场景:用 Coding Plan 把接力变成常态

Handoff 单次用起来已经能解决“关机不断任务”,但如果你经常跑长任务、经常换机器,建议把配置固化成常态。TaoToken 的 Coding Plan 页面 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 提供了面向长期编码场景的接入方案,适合把本地和远程的模型通道统一管理。

我的做法是:把 SSH 别名、Codex 配置、环境变量三样东西写成一个初始化脚本,新机器一条命令配好。远程主机扩容或换机时,跑一遍脚本,Handoff 立刻可用。脚本大致长这样:

#!/bin/bash # setup-codex-handoff.sh set -e # 1. 检查依赖 command -v bwrap >/dev/null || sudo apt-get install -y bubblewrap command -v git >/dev/null || sudo apt-get install -y git # 2. 安装 Codex npm install -g @openai/codex # 3. 写入模型配置 mkdir -p ~/.codex cat > ~/.codex/config.toml <<'EOF' model = "按文档填入模型ID" model_provider = "taotoken" [model_providers.taotoken] name = "TaoToken" base_url = "https://taotoken.net/api" env_key = "TAOTOKEN_API_KEY" wire_api = "chat" EOF # 4. 提示设置 Key echo 'export TAOTOKEN_API_KEY="sk-你的Key"' >> ~/.bashrc source ~/.bashrc echo "setup done. run: codex --version"

本地侧同样维护一份 SSH 配置模板,新机器复制~/.ssh/config即可。这样无论本地换机还是远程扩容,Handoff 的迁移链路都能快速重建。

对于 Agent 类长任务,比如让 Codex 持续跑一个多轮重构,Handoff 的价值更明显。你可以白天在本地盯着跑,晚上迁到远程让它自己迭代,第二天早上迁回来继续。整个过程模型调用走同一个 TaoToken 通道,会话历史不断,上下文不丢。

最后给一个实用技巧:迁移前先git stash list确认没有遗留的 stash,避免 Handoff 打包时和已有 stash 冲突。迁移完成后在远程跑一次git status,确认工作区状态符合预期。这两个动作花不了十秒,能避免大部分“迁移后代码不对”的问题。

配置一次,后面就是一句话的事。把 SSH 通道、模型三件套、初始化脚本准备好,关机继续跑任务这件事就真正落地了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询