- 人工智能
- AI Agent
- 深度研究
- 自主智能体
- Agent 编排
【免费下载链接】OpenResearch
Turn your coding agents into research agents
OpenResearch(orx)把编码 Agent 变成研究 Agent,而实验的算力可以按需落到 Modal 的临时 Sandbox 上:--backend modal会在你的 Modal 账户里拉起一个按秒计费的临时沙箱,跑完即释放、缩到零。本文以 agent-skills/orx-compute/references/modal.md 为骨架,结合仓库中的 Rust 后端实现(src/jobs/modal.rs、src/local/modal.rs),完整讲清楚 flavor 选型、鉴权配置、超时与镜像控制、快照传输,以及提交后由orx supervise守护的完整生命周期。
一、Modal 后端是什么:临时沙箱 + 按秒计费
Modal 后端是orx九种计算后端(hf / modal / k8s / ssh / slurm / ray / openresearch / tinker / local,见 agent-skills/orx-compute/SKILL.md)中的一种。它的本质是:
- 临时 Sandbox:
orx在用户的 Modal 账户中创建一次性沙箱执行实验,任务结束即销毁,无需维护常驻节点; - 按秒计费:费用记在发起实验的 Modal 账户上,从提交到结束按秒累积;
- 无需仓库访问权:
orx把记录的 commit 打成不可变快照传进 Sandbox,Modal 侧不需要访问你的 Git 仓库。
从 src/local/modal.rs 可以看到,所有orx沙箱统一归组在一个名为openresearch的 Modal App 下,提交后可在 Modal 控制台按 App 查看;同时代码会给沙箱打上or_run、or_experiment、or_project三类标签(src/local/modal.rs),方便事后按实验维度检索。
使用边界:只有当用户明确要求 Modal、或 Modal 已是配置默认后端时才使用它。已连接凭据本身不构成切换到 Modal 的信号。
二、快速上手:四行命令覆盖主流场景
原文档给出的核心用法如下,覆盖单卡 GPU、大显存、多卡与纯 CPU 四种典型场景:
orx exp run <expId> --backend modal --flavor a10g orx exp run <expId> --backend modal --flavor a100-80gb --timeout 8h orx exp run <expId> --backend modal --flavor h100:2 orx exp run <expId> --backend modal --flavor cpu --image python:3.12对照仓库实现(src/local/modal.rs),--backend modal强制要求--flavor:
--backend modal requires --flavor: a Modal GPU (t4, l4, a10g, a100, a100-80gb, l40s, h100, h200, or e.g. h100:2 for a count) — or cpu / cpu-large for CPU-only. Priced per second on your Modal account.提交成功后,命令行会输出 Modal 沙箱 id(同时是后续重挂载的句柄)、run id 与跟进提示(src/local/modal.rs):
✓ Modal sandbox submitted. sandbox sb-xxxxxxxx (a10g) run <runId>参数速查表
| 参数 | 取值/含义 | 说明 |
|---|---|---|
--backend modal | 后端标识 | 固定值,orx exp run的通用启动入口(见 src/compute.rs 中ModalCompute适配器) |
--flavor | GPU:t4、l4、a10g、a100、a100-80gb、l40s、h100、h200;多卡追加:N(如h100:2);CPU:cpu、cpu-large | 必填,除非配置默认已含 flavor |
--timeout | 整个 Sandbox 的墙钟上限 | 默认4 小时,覆盖整个 Sandbox 而非单条命令 |
--image | 自定义容器镜像 | 覆盖默认的 CUDA PyTorch 或 CPU Python 镜像 |
三、flavor 到资源的映射:多卡与 CPU 规格的底层实现
--flavor的解析逻辑在 src/jobs/modal.rs 的resolve_flavor中,规则如下:
- 以
cpu开头(含cpu本身)→不分配 GPU;cpu-large映射为8 vCPU + 32 GiB 内存;cpu-xlarge映射为16 vCPU + 64 GiB 内存(源码中同样被strip_prefix("cpu-")/cpu_分支覆盖);- 其他
cpu-*走 Modal 默认资源配置;
- 其余任意名称一律按Modal GPU 规格透传并转大写,因此
a100-80gb、h100:2均可直接工作;h100:2中的:N即多卡数量,最终会以gpu参数传给modal.Sandbox.create。
// src/jobs/modal.rs — flavor 解析核心 if n.eq_ignore_ascii_case("cpu") { /* 无 GPU */ } if let Some(rest) = n.strip_prefix("cpu-").or_else(|| n.strip_prefix("cpu_")) { match rest.to_ascii_lowercase().as_str() { "large" => (Some(8.0), Some(32768)), // cpu-large: 8 vCPU / 32 GiB "xlarge" => (Some(16.0), Some(65536)), // cpu-xlarge: 16 vCPU / 64 GiB _ => (None, None), } } ModalResources { gpu: Some(n.to_ascii_uppercase()), .. }默认镜像:GPU 与 CPU 分开
default_image(src/jobs/modal.rs)按是否分配 GPU 选择默认容器:
| 场景 | 默认镜像 |
|---|---|
| GPU | pytorch/pytorch:2.6.0-cuda12.4-cudnn9-runtime |
| CPU | python:3.12 |
--image可覆盖默认值;选择镜像时注意与--flavor的 GPU 型号匹配(CUDA 驱动、PyTorch 构建版本)。这个默认策略与 HF、k8s 后端同源(src/commands/exp.rs),保证了多后端行为一致。
超时:--timeout的解析与默认值
原文档明确timeout 默认 4 小时,且覆盖整个 Sandbox。仓库实现(src/local/modal.rs)确认默认值4 * 3600秒;若显式传入--timeout,则复用与 HF 后端一致的parse_timeout(src/jobs/huggingface.rs),支持s/m/h/d后缀及裸秒数:
--timeout 90s # 90 秒 --timeout 30m # 30 分钟 --timeout 4h # 4 小时(默认值) --timeout 1d # 1 天超时以秒为单位写入ModalJobSpec.timeout_seconds,最终成为modal.Sandbox.create(..., timeout=...)的参数(src/jobs/modal.rs)。为长任务设置合理超时是防止沙箱无限占用的关键护栏——无超时任务在 orx 的 HF/k8s 路径同样被视为隐患。
四、鉴权与运行环境:orx如何免配置使用 Modal
凭据来源(三选一,按优先级)
Modal 鉴权使用MODAL_TOKEN_ID/MODAL_TOKEN_SECRET,或由modal token new生成的凭据。resolve_token(src/jobs/modal.rs)给出完整解析链:
- 进程环境变量
MODAL_TOKEN_ID/MODAL_TOKEN_SECRET(优先级最高); - 同步环境文件(
~/.openresearch/env,即orx upSettings → Environment 中配置的变量); ~/.modal.toml配置文件:读取当前激活 profile 的token_id/token_secret字段;多 profile 且未激活时会要求先执行modal profile activate(对应测试见 src/jobs/modal.rs),也支持MODAL_PROFILE环境变量指定 profile。
modal_auth_env(src/jobs/modal.rs)只在进程环境缺失时才注入同步环境文件中的 token,避免覆盖外部传入的凭据。
托管 Python 环境:首次启动自动就绪
Modal 通过 Python SDK 驱动(没有通用 REST 提交接口),因此orx在首次启动时自动在配置目录的envs/modal下创建 venv 并安装modalSDK(ensure_env,src/jobs/modal.rs),整个过程幂等:
- 已设置
$ORX_MODAL_PYTHON时信任用户解释器,不做任何初始化; - 否则检查托管 venv 是否已存在且能
import modal; - 都没有时,用系统
python3建 venv →pip install modal→ 校验导入; - 缺失 Python 3 或导入失败时给出可操作报错,并提示删除托管环境强制重建。
因此你不需要手动pip install modal;解释器解析顺序为$ORX_MODAL_PYTHON→ orx 托管 venv → 系统python3(src/jobs/modal.rs)。启动前的preflight(src/jobs/modal.rs)会做三重检查:环境可用性、SDK 可导入、token 已配置,任一不满足即提前失败,避免提交阶段才报错。
沙箱环境变量:密钥走临时 Secret
提交时,orx会把用户在 Settings → Environment 中同步的全部环境变量带入沙箱,并自动补入HF_TOKEN(若本地可解析);但这些密钥不会通过明文的env参数传递,而是封装成modal.Secret.from_dict(env)的临时 Secret(src/jobs/modal.rs),避免密钥明文暴露在 Modal 控制台。同时default_python_env(src/jobs/mod.rs)会注入PYTHONUNBUFFERED=1与PYTHONIOENCODING=utf-8,保证日志实时流出、编码稳定。
五、快照传输:Modal 永远不需要访问你的仓库
所有后端的通用契约是:orx exp run只运行记录的 commit 的不可变源码快照(agent-skills/orx-compute/SKILL.md)。Modal 路径的具体实现:
- 提交前用
git archive把实验分支的HEAD打成 tar 包; - 以 SHA-256 摘要内容寻址存放于
source-snapshots/目录(SourceSnapshot::create,src/compute.rs); - 提交后由 launcher 通过
sb.filesystem.copy_from_local(spec["sourceArchive"], "/tmp/orx-source.tar")拷入沙箱,并用.ready哨兵文件通知脚本解包(src/jobs/modal.rs); - 沙箱内的执行脚本
gated_script(src/compute.rs)等待.ready后解包、进入repo/目录执行 run command,stderr 合并进 stdout 一并流回(src/jobs/modal.rs)。
这意味着:未提交的文件不会被运行;任何后端都不依赖 GitHub push。快照的 digest、路径、大小会写入 run 的BackendDescriptor(src/jobs/mod.rs),即使orx supervise重启也能从本地恢复句柄(recover_submission_handle,src/compute.rs),与工作区状态解耦。
六、启动前的三件事:run command、commit 与通用契约
即使使用 Modal 后端,也必须遵守 orx-compute 通用启动契约:
- 一律用
orx exp run启动:不要直接调用 Modal CLI、训练命令或裸 Python。直接任务不受追踪,可能运行非记录 commit 的代码; - 保持 run command 固定:在基线实验上一次性设置,后续通过子分支改代码/配置;未设置时先执行
orx project edit <projectId> --run-command '<cmd>'; - 先 commit 再启动:快照只包含已记录 commit 的内容。
orx exp run会把 run 排入队列并立即返回,随后用orx runs、orx logs、orx exp wait或orx exp wake跟进。同一实验已有在飞 run 时会拒绝重复启动,需--force才能刻意并发(src/compute.rs 的reserve_run锁)。
七、提交之后:orx supervise的守护生命周期
提交后请勿杀掉orx supervise进程——它是整个运行期的守护者。orx exp run --backend modal会通过spawn_detached_supervise(src/commands/exp.rs)拉起一个完全脱离终端(独立进程组、无 stdio)的orx supervise <runId>。
orx supervise的 Modal 分支(run_modal,src/commands/supervise.rs)依赖 Modal Sandbox 的可重挂载特性:modal.Sandbox.from_id(sandboxId)允许从全新进程重新连回同一沙箱(src/jobs/modal.rs),这与 HF 的 SSE、k8s 的kubectl logs -f是同一套"重放 + 去重"模型:
- 状态轮询:每 5 秒调用
status <sandboxId>,把RUNNING / COMPLETED / ERROR映射到本地 run 状态(src/jobs/modal.rs); - 日志流:
logs <sandboxId>每次连接都从起点重放合并 stdout,supervise按已消费行数skip去重后写入本地日志文件;日志静默 30 秒即重新检查状态(src/commands/supervise.rs); - 取消:
orx exp cancel <expId>先在本地登记取消意图,supervisor 观察到后调用terminate()终止沙箱(src/jobs/modal.rs); - 重启幂等:supervisor 带锁运行,重启后从本地 store + 提交句柄恢复,不会重复提交或重复记账(src/commands/supervise.rs)。
等待与休眠:wait 与 wake
orx exp wait <expId>:阻塞直到 run 进入终态;--interval默认 5 秒、--timeout默认 1800 秒,超时以非零码退出(表示"尚无变化"而非失败,src/commands/exp.rs)。--project模式是预算循环原语:任一 run 完成即返回,适合饱和调度;orx exp wake <expId>:结束当前轮次、在 run 成功或失败后恢复,仅在本地orx upAgent 会话中可用;wait 与 wake 二选一。
八、Sizing 建议:怎么选 flavor
结合 SKILL.md 的 Sizing 指南 与 Modal 按秒计费的特点:
- 先定 GPU 还是 CPU:API 驱动评测、数据准备类任务在
cpu/cpu-large上更便宜,完全不需要 GPU; - 选能装下模型 + 最小 batch 的最小规格:从
t4/l4/a10g这类入门卡起步,而不是一上来就h100; - 遇到真实 OOM 或慢到无法忍受再升级:先看
orx logs <runId>确认真实瓶颈,再考虑a100-80gb或h100:2多卡; - 只为真正长跑的任务加
--timeout:默认 4 小时已覆盖大多数实验,超时越大潜在计费风险越高。
多卡场景注意:h100:2这种:N语法透传的是 Modal GPU 数量规格,适用分布式训练或显存聚合场景;单机多卡与单卡的选择取决于你的训练脚本设计。
九、常见问题速查
| 现象 | 原因与处理 |
|---|---|
报错--backend modal requires --flavor | 未传 flavor 且配置默认不含 flavor;按上表补--flavor |
报错The modal Python package isn't importable | 解释器里没有modalSDK;设置ORX_MODAL_PYTHON指向已装 SDK 的解释器,或删除托管 venv 目录让其重建(launcher 退出码 3 专门标识此场景,src/jobs/modal.rs) |
报错No Modal token configured | 执行modal token new,或在进程环境 / Settings → Environment 设置MODAL_TOKEN_ID与MODAL_TOKEN_SECRET |
| 提示存在在飞 run,拒绝启动 | 同实验已有非终态 run;orx exp cancel <expId>或显式--force |
orx exp wait超时退出 | 非零退出只表示"这段时间内状态没变",用orx runs <projectId>核对真实状态 |
| 沙箱跑完即消失 | 正常现象:Modal Sandbox 用完即释放、缩到零,账单按秒累计 |
| 想找历史沙箱 | 在 Modal 控制台按openresearchApp 或or_experiment标签检索 |
十、源码地图:进一步阅读
- 后端实现:src/jobs/modal.rs(launcher、flavor 解析、默认镜像、preflight、token 解析)
- 本地提交入口:src/local/modal.rs(
--flavor强校验、4h 默认超时、快照与标签装配) - 后端注册与预检:src/compute.rs(
ModalCompute适配器:requires-flavor + preflight) - 守护进程:src/commands/supervise.rs(Modal 分支
run_modal、轮询/日志/取消) - 等待与取消:src/commands/exp.rs(
exp wait、spawn_detached_supervise、cancel 锁) - 技能入口与通用契约:agent-skills/orx-compute/SKILL.md
至此,你已经掌握了 Modal 后端从选型、鉴权、提交到守护的完整链路:一条orx exp run --backend modal --flavor <规格>命令,就能把你的研究实验按秒计费地跑在 Modal 临时沙箱上,跑完自动释放,全程由不可变快照保证可复现性。
- 人工智能
- AI Agent
- 深度研究
- 自主智能体
- Agent 编排
【免费下载链接】OpenResearch
Turn your coding agents into research agents
相关推荐
OpenResearch 后端实战:用 `orx exp run --backend openresearch` 按次计费拉起临时 GPU/CPU 沙箱
OpenResearch 后端实战:用 orx exp run backend openresearch 按次计费拉起临时 GPU/CPU 沙箱 本指南讲解 O
人工智能AI Agent深度研究自主智能体Agent 编排在 Modal 无服务器 GPU 上按需部署 Tabby:完整实操指南
在 Modal 无服务器 GPU 上按需部署 Tabby:完整实操指南 Modal 是一个 serverless GPU 平台,通过它运行 Tabby 可以实现
人工智能大模型AI 应用本地部署模型推理服务RAG后端OpenResearch `orx-create` 实战指南:从 `orx up` 建项目到 `orx create-experiment` 构建实验树
OpenResearch orx create 实战指南:从 orx up 建项目到 orx create experiment 构建实验树 导读 orx cr
人工智能AI Agent深度研究自主智能体Agent 编排
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考