OpenResearch orx 的 SSH 计算后端实战:在自有服务器上以快照方式运行实验的完整指南
2026/9/20 3:10:06 网站建设 项目流程

OpenResearch orx 的 SSH 计算后端实战:在自有服务器上以快照方式运行实验的完整指南

【免费下载链接】OpenResearchTurn your coding agents into research agents项目地址: https://gitcode.com/GitHub_Trending/op/OpenResearch

导读

在 OpenResearch(orx)的计算体系中,SSH 后端(--backend ssh)是把你自己的机器或服务器变成实验运行节点的标准方式:它不依赖任何调度器或云平台,只需一个~/.ssh/config别名,就能把已提交的实验快照流式传输到远程主机并以脱离终端的方式后台运行。读完本文,你将掌握 SSH 后端的适用场景、一条命令的启动方式、远程运行目录的结构、快照上传与进程监督的底层原理,以及取消、等待与资源选择等配套操作,可以直接在自己的 GPU 服务器上跑通完整的 orx 实验流程。

一、SSH 后端是什么、什么时候该用它

根据 SSH 后端参考文档 的定义,这个后端只应该在两种情况下被启用:

  1. 用户明确要求在自己的机器或服务器上运行;
  2. SSH 被配置为 orx 的默认后端(session playbook 中声明的 configured default)。

它做的事情是:在一个来自~/.ssh/config的主机上,以该主机的环境运行一个脱离终端(detached)的进程。典型命令如下:

orx exp run <expId> --backend ssh --host my-gpu-box

在 orx 的计算抽象中,后端(backend)是提交实验运行的位置;计算技能说明 列出了全部九个后端:Hugging Face Jobs、Modal、Kubernetes、SSH、Slurm、Ray Jobs、OpenResearch、Tinker 以及本机(local)。SSH 是其中唯一"没有硬件调度器"的后端——目标就是一台你能ssh进去的普通服务器,见 src/jobs/ssh.rs 的文件头注释。

判断原则:只有在用户点名要用某个后端时才切换,已连接的凭据本身不是切换的信号。默认情况下一律使用orx exp run <expId>裸命令。

二、快速开始:一条命令启动远端实验

启动一次 SSH 后端运行的完整命令格式为:

orx exp run <expId> --backend ssh --host my-gpu-box

其中:

  • <expId>是要运行实验的 ID;
  • --host my-gpu-box每次启动都必须提供,且必须是一个 SSH config 别名(不是 IP、不是user@host字符串,必须是~/.ssh/config中定义的 Host 名称);
  • SSH 后端没有 flavor(无机型规格概念),因为"机器是地址,不是形状"。

如果漏传--host,提交会在校验阶段直接报错。从源码 src/local/ssh.rs 的submit_local_ssh_with_source可以看到完整的校验逻辑:

if args.flavor.is_some() { return Err(anyhow!( "--backend ssh has no flavors — a machine is an address, not a shape. \ Pass --host <alias> (an ~/.ssh/config alias)." )); } if args.image.is_some() { return Err(anyhow!( "--image doesn't apply to --backend ssh — the run uses the host's own environment." )); }

这段代码还揭示了一个重要的使用边界:SSH 后端没有镜像(image)概念,远程直接使用主机的原生环境,因此你需要在目标主机上自行准备好 Python、依赖和运行脚本所需的一切。同样,没有 timeout 标志——超时控制由orx supervise在本地侧以轮询方式体现,而不是在远端强杀。

启动成功后,orx exp run会输出类似下面的摘要(来自 launch_local_ssh 的打印逻辑):

✓ SSH job started. host my-gpu-box (.orx/runs/<runId>) run <runId>

注意orx exp run只是入队并立即返回(queues the run and returns immediately),真正的监督由后台进程完成。提交后应紧跟orx runsorx logsorx exp waitorx exp wake来跟踪状态。

三、前提条件:认证、主机工具与网络要求

SSH 后端对认证的处理原则是:orx 调用 ssh 客户端,但永远不会读取你的私钥

  • 认证完全交给你的 SSH 密钥或 ssh-agent,以及~/.ssh/config中为别名配置的 HostName / User / IdentityFile / Port 等;
  • 远程主机必须装有bashtar,因为快照上传与运行都依赖这两个工具;
  • orx 在设置界面提供了preflight检查:通过command -v bashcommand -v tar探测这两个工具是否就绪,缺失时会提示"This host needs bash and tar installed before orx can copy and run experiments",实现见 src/jobs/ssh.rs 的preflight函数。

关键 SSH 选项:BatchMode 与 ConnectTimeout

每次调用 ssh 时,orx 都会附加一组共享选项(见ssh_opts):

-o BatchMode=yes # 后台批处理:绝不交互式提示密码/确认 -o ConnectTimeout=10 # 连接超时 10 秒

其中BatchMode=yes意味着后台轮询时不会弹出任何交互提示,因此目标主机必须能通过密钥或 agent 无密码登录;而交互式登录(如设置面板里的"连接"测试)则使用BatchMode=no,允许正常提示。

四、远程运行目录:~/.orx/runs/<runId>/

每次运行在远端都有自己私有的、权限为700的运行目录,路径为:

~/.orx/runs/<runId>/

目录内由run_jobinspect_job共同维护四个关键文件(见 src/jobs/ssh.rs 文件头):

文件作用
run.sh启动器脚本:导出环境变量 + 快照解压 + 运行命令(snapshot-and-run payload)
log合并的 stdout/stderr 输出,日志轮询读取的对象
pid脱离终端进程组 leader 的 PID
exit_codepayload 结束时写入的退出码

这套目录设计是整个监督模型的"句柄":重启后的orx supervise仅凭这个目录就能重新挂接(reattach)到运行上,与客户端进程生死无关。

run.sh的实际内容由run_job拼装(src/jobs/ssh.rs):

#!/usr/bin/env bash export VAR1='...' # 已同步环境变量 + HF_TOKEN 等 cd "$HOME/<dir>" || exit 97 ( # snapshot-and-run payload:set -eo pipefail; cd repo; <run command> ) > log 2>&1 echo $? > exit_code

注意 payload 被放在子 shell( … )中执行,而不是{ … }分组——这样即使内部exitset -e失败,也只终止子 shell,外层仍能执行echo $? > exit_code,从而保证退出码总被记录。

五、快照如何传输:一次上传、内容寻址缓存

orx 的实验遵循**不可变快照(immutable snapshot)**原则:每次运行执行的是实验分支已记录 commit 的源码快照,未提交文件被排除,且所有后端都不需要 GitHub push。SSH 后端使用stage_source完成快照传输(src/jobs/ssh.rs):

  1. 本地将记录 commit 的源码打成一个 tar 归档,digest 作为内容寻址标识;
  2. 远端先检查缓存~/.orx/source/<digest>.tar是否存在(test -f);
  3. 若不存在,通过 ssh 的 stdin 管道以umask 077上传到临时文件再mv原子落盘;
  4. 随后mkdir -p ~/.orx/runs/<runId>/repo并将 tar 解压到该目录,作为运行的工作区。

内容寻址的好处是:同一 commit 的多次运行(如同一实验的重跑)只上传一次,后续直接复用远端缓存;而且上传和解压都是可重复操作,客户端或 supervisor 重启后重试不会破坏状态。

stage_source中上传的命令值得注意——它全程通过 ssh stdin 流式写入,而不经过 scp/sftp

umask 077; mkdir -p "$HOME/.orx/source"; \ tmp="$HOME/<cache>.tmp.$$"; cat > "$tmp" && mv "$tmp" "$HOME/<cache>"

而远端运行的真实命令由staged_script生成(src/compute.rs):

set -eo pipefail; cd repo; <run command>

它保证:解压失败立即中止;随后cd repo进入快照工作区;最后执行你在实验基线(baseline)上固定的运行命令。

六、进程如何启动:setsid 脱离终端、进程组可取消

run_job的启动逻辑(src/jobs/ssh.rs)保证了"脱离 ssh 通道关闭而存活":

cd "$HOME/<dir>" && \ if command -v setsid >/dev/null 2>&1; then setsid bash run.sh </dev/null >/dev/null 2>&1 & \ else nohup bash run.sh </dev/null >/dev/null 2>&1 & fi; \ echo $! > pid
  • 优先使用setsid:它创建新会话,使pid == pgid,这样取消时可以用kill -TERM -<pid>一次终止整个进程组;
  • 目标主机没有setsid(例如 macOS 主机)时回退到nohup,此时只能按单个 PID 终止;
  • PID 记录到pid文件,供状态检查和取消使用。

取消语义(cancel_job)因此是:

p=$(cat "$HOME/<dir>/pid" 2>/dev/null); \ [ -n "$p" ] && { kill -TERM -"$p" 2>/dev/null || kill -TERM "$p" 2>/dev/null; }; true

先尝试向负 PID(整个进程组)发送 TERM,失败则退回单进程 TERM。这与参考文档中"Cancellation terminates the remote process group"的表述一致。

七、监督与状态机:orx supervise如何轮询远端

启动后,orx 会派生一个脱离终端的orx supervise进程在本地持续轮询远端。参考文档特别提醒:不要杀掉它。它的行为在 src/commands/supervise.rs 中实现,核心是两个并发任务:

  1. 状态轮询:每 5 秒调用一次inspect_jobPOLL_INTERVAL = 5s),根据远端文件推断阶段:
    • exit_code存在 → 已结束:0COMPLETED,非零为ERROR(附退出码原因);
    • pid存在且kill -0存活 →RUNNING
    • pid存在但已死且无exit_codeDEAD(被强杀);
    • 尚无pidPENDING(刚刚启动)。
  2. 日志跟踪stream_logs每次用tail -n +<skip+1> ~/.orx/runs/<runId>/log拉取增量日志,按"一行日志 = 一条记录"的契约交给日志 sink 写入本地log_path(run_id)LOG_IDLE = 30s表示日志静默多久后重新检查作业状态。

因为监督状态全部落在本地 store 与远端目录(backend 自身),所以orx supervise重启幂等的:无论客户端、supervisor 重启多少次,重新运行都能从断点继续,日志去重基于已消费的行号。

本地 store 中保存的后端描述符BackendDescriptor将 kind 记录为ssh_jobnamespace存主机别名,job_id存远端运行目录(~/.orx/runs/<runId>),并在重启后由ssh_ref()解出(host, dir)句柄重新挂接,见 src/jobs/mod.rs。

等待运行完成:orx exp wait

orx exp wait <expId> # 等待该实验最近一次运行 orx exp wait --project <projectId> # 任一项目运行完成即返回(预算循环原语) orx exp wait <expId> --interval 10 --timeout 3600
  • 默认轮询间隔 5 秒、默认超时 1800 秒;超时以非零退出码结束,含义是"还没有变化"而非"运行失败"
  • 失败运行会带reason:行;启动后才失败的情况需要orx logs <runId>排查;
  • 不想阻塞当前回合时改用orx exp wake <expId>:它只在donefailed时触发,并排队在用户消息之后;wait 与 wake 二选一。

八、主机密钥策略与连接复用:安全细节

HostKeyPolicy 三种策略

orx 对远端主机密钥的处理有三种策略(src/jobs/ssh.rs 的HostKeyPolicy),由SshTarget::host_port统一生成对应的-o参数:

策略参数适用场景
UserConfig不附加任何 host-key 选项用户自己敲的主机名,可能已在known_hosts固定过,完全交给用户配置
AcceptNewStrictHostKeyChecking=accept-new首次见到的裸 IP:真正的 TOFU(trust-on-first-use),首次连接接受并记录,后续密钥变更会被发现
EphemeralStrictHostKeyChecking=no+UserKnownHostsFile=/dev/null+LogLevel=ERROR仅用于云平台临时供应的机器(如 OpenResearch box):其host:port会被平台回收复用,真正的固定反而会引发虚假的不匹配

alias目标(即本后端场景)不附加任何额外选项,完全由~/.ssh/config和用户自己的known_hosts决定。

ControlMaster 连接复用

在 Unix 上,orx 会为每个目标启用 SSH 连接复用:

-o ControlMaster=auto -o ControlPath=/tmp/orx-ssh-<uid>-<hash>/<16位hex> -o ControlPersist=600

这意味着状态轮询、日志拉取、上传等大量短连接共享同一条已认证的 TCP 会话,而不是每次握手一次。ControlPath 由dest + extra_opts哈希生成,所以同主机不同端口不会共享 socket(有专门测试control_path_differs_per_port验证);路径放在/tmp下并以700权限创建,是为了绕开 macOS 104 字节的 Unix socket 路径上限(见control_path_fits_macos_unix_socket_limit测试)。

在 Windows 上,Win32-OpenSSH 不支持连接复用,因此显式传入ControlMaster=noControlPath=none显式关闭而非省略,防止用户自己的 ssh_config 重新启用一个导致getsockname failed的 ControlPath);这也意味着 Windows 上后台调用需要 agent 密钥或无口令密钥。

九、与其他后端的关联:OpenResearch 与 Slurm 复用同一套 SSH 通道

SSH 后端的实现并不孤单:ssh_runSshTarget等基础设施被另外两个后端复用:

  • Slurm 后端以同样的方式驱动集群登录节点(login node);
  • OpenResearch 后端在云平台临时供应的机器上运行实验,使用HostKeyPolicy::Ephemeral策略接受任意主机密钥,并把ssh_host/ssh_port/ssh_user记录在后端描述符中(见 src/jobs/mod.rs 的openresearch_ssh_target)。

两者的监督循环都走同一个watch_ssh_job("运行目录在某台可 ssh 的机器上"这一通用模型),这也是为什么 SSH 后端自身的实现如此精简。

十、配套实践:计算规模选择与运行纪律

配合 orx-compute 技能说明 的通用规范,使用 SSH 后端时应遵循以下纪律:

  1. 一切运行都通过orx exp run启动:绝不直接调用 ssh、调度器或训练命令本身。工作区只用于编辑、Git 与轻量检查;直接作业不在记录 commit 之内,可能运行与记录快照不一致的代码。
  2. 保持运行命令固定(fixed run command):在基线上用orx project edit <projectId> --run-command '<cmd>'设定一次,之后通过子分支改代码/配置,而不是改命令。
  3. 先 commit 再启动:每个后端都运行记录 commit 的不可变快照,未提交文件不会进入运行。
  4. 计算规模:先决定 GPU 还是 CPU(API 驱动评估与数据准备通常 CPU 更划算);选择能装下模型与最小 batch 的最小规格;遇到真实 OOM 或慢到无望再升级,而不是一开始就用最大的加速器;timeout 只为真正长时间运行而调大。
  5. 并发控制:默认情况下同一节点已有 in-flight 运行时 orx 会拒绝再次启动;确需并发时显式加--force

十一、参考路径速查

  • 后端参考文档:agent-skills/orx-compute/references/ssh.md
  • 计算技能总览(通用启动契约、wait/wake、规模选择):agent-skills/orx-compute/SKILL.md
  • SSH 后端核心实现(目标解析、上传、启动、监督、取消):src/jobs/ssh.rs
  • 本地提交入口与校验(无 flavor、无 image、必须 --host):src/local/ssh.rs
  • 后端描述符与ssh_ref挂接句柄:src/jobs/mod.rs
  • 监督进程与 SSH 轮询循环:src/commands/supervise.rs
  • 快照脚本(snapshot / staged / gated)生成:src/compute.rs

结语

SSH 后端是 orx 计算抽象中最"朴素"却最灵活的一环:没有镜像、没有调度器、没有机型,只有一条指向~/.ssh/config别名的连接、一套~/.orx/runs/<runId>/目录约定,以及orx supervise的远程轮询。理解它的文件级状态机(run.sh/log/pid/exit_code)、内容寻址快照缓存与setsid进程组取消语义,你就能在自有 GPU 服务器上稳定、可复现地跑出与云后端完全一致的实验体验。

【免费下载链接】OpenResearchTurn your coding agents into research agents项目地址: https://gitcode.com/GitHub_Trending/op/OpenResearch

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询