mcpField
O
offload-to-sandbox

offload-to-sandbox

github.com/vercel云与 DevOps33463 次安装今天更新
代码仓库

关于 offload-to-sandbox

offload-to-sandbox 是一项技能,可将繁重构建和长时间测试从本机转移到 Vercel Sandbox Linux 微型虚拟机。它指导开发者和 Agent 准备快照、运行隔离任务环境、传输文件并管理任务生命周期。

主要功能

  1. 01创建可复用的基础快照
  2. 02为每项任务启动独立沙箱
  3. 03传输源文件与结果文件
  4. 04执行并监控远程命令
  5. 05管理超时与资源清理

适用场景

  1. 01在远程 Linux 环境运行大型构建
  2. 02将长测试套件拆分到多个沙箱
  3. 03为并行 Agent 提供隔离环境
  4. 04避免反复安装依赖

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/vercel/vercel-plugin --skill offload-to-sandbox

安装后在 Claude Code 中输入/offload-to-sandbox确认已加载。

详细介绍

将工作卸载到 Vercel Sandbox

Vercel Sandbox 是一种 Linux 微型虚拟机(x86_64),可在几秒内创建,并在完成后删除。因此,它很适合充当远程工作节点:让繁重的构建和耗时的测试套件不占用你的笔记本电脑,并为每个 Agent 或任务提供一台干净的机器。本技能介绍如何使用 vercel sandbox CLI 高效完成这些工作。有关 @vercel/sandbox SDK 和运行不可信代码,请参阅 vercel-sandbox 技能。

何时卸载,哪些工作留在本地

卸载:

  • 完整的测试套件,尤其是可拆分并行运行的套件。
  • 耗时数分钟或需要 Linux 的构建。
  • 同时执行多个任务:每个任务或每个 Agent 使用一个 Sandbox。
  • 任何会占满本地磁盘的工作(大型构建目录、多个 worktree)。

留在本地:

  • 编辑、git、小型定向测试、类型检查、lint 和任务编排。
  • 任何需要 Sandbox 不具备的本地凭据或硬件的工作。

多个 Agent 共用一台机器时,一个不错的默认做法是:Agent 在本地编辑并运行快速的定向检查,把所有繁重工作交给各自的 Sandbox。

计划限制

HobbyProEnterprise
最大 vCPU 数(每个 vCPU 配备 2 GB 内存)4(8 GB)8(16 GB)32(64 GB)
最长会话时长45 分钟24 小时24 小时
并发 Sandbox 数1010,00010,000

--vcpus 可设为 1,或不超过计划上限的偶数;默认值为 2。以下示例使用 Pro 规格(--vcpus 8、--timeout 3h)。在 Hobby 计划下,请使用 --vcpus 4,并将超时设为 45m 或更短。Hobby 计划每月还仅包含 5 小时的活跃 CPU 时间,因此,实际上要进行繁重的工作卸载需要 Pro 计划。

运行中的 Sandbox 按活跃 CPU 时间和已配置内存计费。快照则按每 GB 每月收取快照存储费用,且只要快照存在就会持续计费。

只需准备一次基础快照

在每个新 Sandbox 中安装工具链和依赖会浪费时间和金钱。只需准备一次并创建快照,之后从该快照启动其他所有 Sandbox:

# 1. Create a builder sandbox from the default image (Ubuntu, Node.js, Python, common tools).
vercel sandbox create --name base-builder --non-persistent --vcpus 8 --timeout 2h --image vercel/sandbox/universal

# 2. Install the pinned toolchain and build the baseline tree once.
vercel sandbox copy ./setup-base.sh base-builder:/vercel/sandbox/setup-base.sh
vercel sandbox exec base-builder -- sh -c 'cd /vercel/sandbox && sh setup-base.sh; echo "exit=$?"'

# 3. Snapshot it (this stops the sandbox). The ID is printed on stderr, not stdout.
vercel sandbox snapshot base-builder --stop --expiration 0 2>&1 | grep -o 'snap_[A-Za-z0-9_-]*' | head -n 1 > BASE_SNAPSHOT
test -s BASE_SNAPSHOT

# 4. The builder is no longer needed. Removing it keeps the snapshot.
vercel sandbox remove base-builder

创建快照前,请确认第 2 步输出了 exit=0(有关原因,请参阅运行命令)。

基础环境中应包含:

  • 项目固定使用的确切工具链版本(编译器、运行时、包管理器)。
  • 主分支在已知提交上的已安装并构建版本,作为只读基线(例如 /vercel/sandbox/base)。
  • 任务会重复使用的小型辅助脚本(例如 prepare.sh,用于将刚推送的代码树转换为可运行的检出目录)。

将快照 ID 保存在工具所在目录中的文件里。--expiration 0 表示快照永不过期,因此会一直计费,直到你将其删除。工具链变更时,请创建新快照,并使用 vercel sandbox snapshots delete <old-id> 删除旧快照。大型运行开始前,请检查 vercel sandbox snapshots get "$(cat BASE_SNAPSHOT)" 是否仍显示状态为 created;已删除或已过期的快照会显示 deleted。

每个任务创建一个 Sandbox

vercel sandbox create --name exp-parser --non-persistent --snapshot "$(cat BASE_SNAPSHOT)" \
  --vcpus 8 --timeout 3h --tag app=my-project --tag owner=agent-parser --silent
  • 按所有者和用途命名(exp-parser、exp-parser-2),避免并行工作的 Agent 发生冲突。名称在每个项目中都是唯一的,且在 Sandbox 被移除前会一直占用。绝不要使用其他 Agent 的 Sandbox。
  • **规格:**每个 vCPU 配备 2 GB 内存,这是增加内存的唯一方式。占用内存较多的步骤(大型编译、大型链接任务)可能会被 Linux OOM killer 终止。若未达到计划的 vCPU 上限,请提高规格;达到上限时,请降低步骤的并行度(例如减少构建任务数),或单独运行该步骤。
  • 标签(每个 Sandbox 最多 5 个)有助于清理:结束时,按所有者标签列出并移除所有 Sandbox。

生命周期和清理

沙盒默认会持久保留:会话停止时,文件系统会生成快照,以便之后恢复沙盒,而该快照会按快照存储计费。任务沙盒不需要这样做,因此这里每次调用 create 都会传入 --non-persistent。

  • --timeout 设置的是会话时长,而不是沙盒的生命周期。默认值为 5 分钟。超时后,会话会停止,其中运行的所有进程都会被终止,包括已分离的作业。此时,非持久化沙盒会丢失整个文件系统。请根据整个任务设置超时时长。之后可以用 vercel sandbox config timeout <name> <duration> 修改;提高超时时长也会延长当前运行的会话。
  • 任务完成后,运行 vercel sandbox remove <name>。 vercel sandbox stop 只会结束当前会话:沙盒仍会保留其名称,持久化沙盒的快照也会继续计费。Vercel 会在 14 天不活动后移除无法恢复的沙盒,因此除非手动移除,否则已停止的非持久化沙盒会一直占用其名称。
  • 移除沙盒不会删除快照,因此基础快照会在任务清理后保留。对 remove 使用 --delete-orphan-snapshots,还会删除该沙盒独有、未被其他沙盒使用的快照。移除创建基础快照的构建沙盒时,不要传入此参数。
  • 清理崩溃的 Agent 遗留的孤立沙盒,使用 vercel sandbox list --all --tag owner=<agent>。--all 会包含已停止的沙盒(默认只显示运行中的沙盒),而 list 一次只能按一个标签筛选。使用 vercel sandbox remove <name>... 移除列出的所有沙盒。只有在没有 Agent 仍在工作时,才使用 --tag app=my-project 清理整个项目。

移入代码而不重新安装依赖项

发送源代码,而不是构建产物。将 Git 已知的文件(已跟踪文件,以及未忽略的未跟踪文件)打包为一个 tarball,复制并解压到旧目录旁边。然后将旧目录中的大型目录(node_modules)移到新目录中,无需重新安装,最后交换这两个目录。包装脚本中的 sbx push 正是这样做的:

sbx push exp-parser . /vercel/sandbox/cand
  • 每次更改后都推送;这只需几秒钟。然后运行幂等的准备步骤,只安装或重建发生变化的内容(例如,仅在锁文件发生变化时安装依赖项)。
  • 在沙盒内构建特定于平台的产物。不要将 macOS 二进制文件复制到 Linux 虚拟机中。
  • 不要推送 .git 或依赖目录。如果需要在远程环境中保留 Git 历史记录,请推送 bundle,或在沙盒内运行 git clone。
  • 删除已跟踪文件但未暂存,会导致 tar 失败。请先暂存删除操作(git rm)。

直接读取、写入和复制文件

独立的 sandbox CLI 在包含 vercel/sandbox#380 的版本中支持文件命令。使用 npm i -g sandbox 安装或更新,然后在使用以下示例前检查已安装的命令:

sandbox --version
sandbox read --help
sandbox write --help
sandbox copy --help

确认存在 read 和 write,并且 copy --help 列出了 --recursive。如果这些命令不可用,请继续使用 vercel sandbox copy 和下方的 sbx 封装命令。Vercel CLI 自带的 Sandbox CLI 版本独立于此,因此 sandbox 支持这些功能并不代表 vercel sandbox 也支持。

使用与现有任务沙箱相同的团队和项目。按照身份验证与作用域中的说明设置 SBX_SCOPE 和 SBX_PROJECT;独立 CLI 也必须完成身份验证。

name=exp-parser
: "${SBX_SCOPE:?set SBX_SCOPE to your team slug}"
: "${SBX_PROJECT:?set SBX_PROJECT to your project name}"

# Read a sandbox file to stdout without changing its bytes.
sandbox read --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "${name}:/vercel/sandbox/cand/package.json"

# Write a script from stdin and make it executable.
sandbox write --scope "$SBX_SCOPE" --project "$SBX_PROJECT" --mode 755 "${name}:/vercel/sandbox/check.sh" <<'SCRIPT'
#!/bin/sh
cd /vercel/sandbox/cand
npm test
SCRIPT

# Copy a prepared local directory into the sandbox.
sandbox copy -r --scope "$SBX_SCOPE" --project "$SBX_PROJECT" ./task-input "${name}:/vercel/sandbox/task-input"

# Download the result directory after the task has produced it.
sandbox copy -r --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "${name}:/vercel/sandbox/results" ./results

read(也可用 cat)会将文件内容输出到 stdout。write 会用 stdin 替换目标文件;如果本地已有文件,可使用 < ./script.sh 重定向。两者在失败时都会返回非零状态。

递归复制会将源目录的内容放入目标目录,并保留空目录、符号链接和权限。Windows 下载会拒绝文件名中含有反斜杠或冒号的文件。复制操作会复制所有条目,包括被忽略的文件,并保留目标目录中无关的文件。可将其用于准备好的输入目录和结果。对于需要基于 Git 进行筛选、删除过期文件并复用远程 node_modules 的项目更新,请继续使用 sbx push。

运行命令

vercel sandbox exec --timeout 2h exp-parser -- sh -c 'cd /vercel/sandbox/cand && npm test -- --shard 1/4; echo "exit=$?"'
  • 将整条命令作为一个单引号字符串传给 sh -c。否则,本地 shell 会在沙箱看到命令前展开 $VARS 和 glob。尤其是 zsh 会对未匹配的 glob 报错,并将 $var:r、$var:h 等视为修饰符;请使用 ${var}。
  • 检查自带 CLI 的退出行为。 在 vercel 64.5.0(Sandbox CLI 4.4.0)中,即使远程命令失败,vercel sandbox exec 也会以 0 退出。在该版本中,请以 echo "exit=$?" 结束远程命令并读取输出,或者使用会返回远程状态的 sbx exec。独立的 Sandbox CLI(先运行 npm i -g sandbox,再运行 sandbox exec ...)会传递远程退出代码。
  • 对于超过一行的命令,请在本地编写脚本,通过 vercel sandbox copy 将其复制进去,然后运行。这样更容易处理引号、检查和重新运行。
  • exec --timeout 是可选参数,没有默认值。超时后,命令会收到 SIGKILL 并被终止,CLI 会输出 Command was killed (SIGKILL, exit code 137)。不设置该参数时,命令会一直运行,直到完成或会话超时。
  • 如果要比较耗时,请在同一个沙箱中运行两个版本,因为同等规格的主机速度也可能不同。
使用独立 CLI 运行长时间任务

如果已安装的 CLI 支持原生命令管理,请使用该功能。安装独立 CLI 并按照上述说明完成身份验证后,检查:

sandbox --version
sandbox exec --help
sandbox commands --help

确认 exec 列出了 --detach 和 --stdin,并且 commands 列出了 get、logs、wait 和 kill。请将这些检查与上面的文件命令检查分开进行:CLI 版本可能先支持命令管理,之后才支持 read、write 和递归复制。Vercel CLI 自带的 Sandbox CLI 版本独立于此。

在现有沙箱中启动任务并保存其命令 ID:

name=exp-parser
: "${SBX_SCOPE:?set SBX_SCOPE to your team slug}"
: "${SBX_PROJECT:?set SBX_PROJECT to your project name}"

command_id=$(sandbox exec --scope "$SBX_SCOPE" --project "$SBX_PROJECT" --detach "$name" -- sh -c 'cd /vercel/sandbox/cand && npm run test:all')
printf '%s\n' "$command_id"

sandbox commands get --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id"
sandbox commands logs --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id"
sandbox commands wait --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id"

get 会检查状态,但不会等待。logs 会持续输出 stdout 和 stderr,直到命令退出;如果想查看任务运行情况,请使用它。wait 会返回远程退出状态,可据此判断任务是否成功。从另一个终端返回该任务时,请保留沙箱名称和命令 ID。

若要取消仍在运行的任务,请使用保存的命令 ID:

sandbox commands kill --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id" --signal SIGTERM
sandbox commands wait --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$name" "$command_id"

取消操作通常会产生非零退出状态。终止命令不会停止沙箱。命令 ID 仅在当前会话中有效;请在会话停止前收集结果。分离运行的命令仍会在命令超时或沙箱会话超时时结束。

在没有交互式终端的情况下通过管道传入输入

对于读取输入后便结束的命令,请使用 --stdin:

printf 'hello\n' | sandbox exec --scope "$SBX_SCOPE" --project "$SBX_PROJECT" --stdin "$name" -- cat

这会打印 hello。CLI 会转发输入,并在本地输入结束时关闭远程 stdin。管道和脚本请使用 --stdin;它不能与 --interactive 一起使用。对于分离式输入,exec --detach --stdin 会保持 stdin 打开,供后续的 commands write 调用使用;在等待需要输入结束信号的程序之前,请使用 commands close-stdin 结束输入。每次写入完成后,再开始下一次写入。请将命令日志视为文本;二进制文件请使用文件传输。

回退到较旧版本的 CLI

如果无法使用原生命令管理功能,请使用现有的 sbx exec 包装器处理退出状态。对于长时间运行的任务,请使用下方的状态文件方案。沙箱会话超时时间必须覆盖整个任务:

vercel sandbox exec exp-parser -- sh -c 'cd /vercel/sandbox/cand && rm -f /tmp/test.status && nohup sh -c "npm run test:all > /tmp/test.log 2>&1; echo \$? > /tmp/test.status" > /dev/null 2>&1 &'
# later, cheap polls:
vercel sandbox exec --timeout 30s exp-parser -- sh -c 'cat /tmp/test.status 2>/dev/null || tail -3 /tmp/test.log'

获取结果

  • 让远程端写入精简的结果文件(失败测试名称摘要、退出代码、JSON 报告),然后只复制这些文件回来:vercel sandbox copy exp-parser:/tmp/results.json ./results/results.json。此处介绍的捆绑 CLI 每次 copy 调用只能移动一个文件,且需要指定完整的目标文件路径。若要复制整个结果目录,请在可用时使用独立的递归复制功能。
  • 在那个较旧的捆绑 CLI 中,源文件不存在时,copy 会打印错误但不会失败,因此请在之后检查本地文件是否存在(sbx get 会进行检查)。
  • 在远程端压缩大型日志,仅在需要时再获取。通过 exec 流式传输数兆字节的输出速度很慢,而且 Agent 读取时会浪费上下文。

分片并行

  • 使用测试运行器的分片功能或一个编排脚本,按分片索引将耗时的测试套件拆分到 N 个沙箱中,并同时运行这些分片。
  • 为每项任务分配独立的沙箱。十个 Agent 各自在自己的沙箱中工作,胜过十项任务排队等待一台机器。
  • 根据预算限制并发,而不是根据 API 允许的上限。每个运行中的沙箱都会产生费用。
  • 大规模扇出受 vCPU 分配速度限制。空闲的 Pro 团队每分钟起始可分配 150 个 vCPU(18 个各配备 8 个 vCPU 的沙箱),并会随着持续使用而提升;Hobby 每分钟允许 20 到 40 个。

区分既有故障与新故障

远程测试套件通常会有一些与代码更改无关的故障:环境差异、易出错的测试,以及主分支上已有的故障。

  • 在同一沙箱中,对未修改的基线代码树重新运行失败的测试。基线中没有的故障才是由你的更改引起的。
  • 在工具旁维护一份简短的已知环境故障清单,避免其他人重复排查。
  • 迭代时运行针对性检查。在最终候选版本上运行完整测试套件,不要在每个中间步骤都运行。

身份验证与作用域

  • 令牌: vercel sandbox 依次使用 --token、VERCEL_AUTH_TOKEN、VERCEL_TOKEN,然后使用你的 vercel login 会话。仅当这些都不可用时,才会回退使用 VERCEL_OIDC_TOKEN 环境变量。对于 CI 或长时间运行的自动化,请设置 VERCEL_TOKEN。
  • 独立的 sandbox CLI 会读取 VERCEL_AUTH_TOKEN,但不会读取 VERCEL_TOKEN;它还会从当前目录加载 .env 文件。因此,从 .env.local 读取的 VERCEL_OIDC_TOKEN 会优先于你在该目录中的登录会话,其项目也会成为默认作用域。
  • 团队和项目: 沙箱及其名称均属于一个项目。--scope(或 --team)和 --project 用于设置项目。未指定时,如果令牌是 OIDC 令牌,CLI 会先使用令牌中的项目;然后使用当前目录中的 .vercel/project.json(由 vercel link 创建);最后使用你的默认团队和名为 vercel-sandbox-default-project 的项目(如有需要会创建该项目)。
  • 在脚本中明确传入 --scope 和 --project。否则,脚本从其他目录运行时会使用不同的项目,无法查看、复用或清理你的沙箱。

用一个小脚本封装

轻量封装可避免大多数错误,并让 Agent 指令保持简短。将以下内容保存为 sbx,赋予其可执行权限,并设置 SBX_SCOPE、SBX_PROJECT 和 SBX_OWNER(在 Hobby 上还要设置 SBX_VCPUS=4 SBX_TIMEOUT=45m):

#!/bin/sh
# sbx: offload work to Vercel Sandboxes through `vercel sandbox`.
#   sbx create <name>                         new task sandbox from the base snapshot
#   sbx push <name> <local-dir> <remote-dir>  sync git-tracked and untracked files, keep node_modules
#   sbx exec <name> <script>                  run a shell script remotely, exit with its status
#   sbx get <name> <remote-file> <local-file>
#   sbx put <name> <local-file> <remote-file>
#   sbx rm <name>...                          permanently remove sandboxes
#   sbx clean                                 remove every sandbox tagged with your owner tag
# shellcheck disable=SC2016 # single-quoted scripts are expanded by the remote shell
set -eu

: "${SBX_SCOPE:?set SBX_SCOPE to your team slug}"
: "${SBX_PROJECT:?set SBX_PROJECT to your project name}"
owner=${SBX_OWNER:-${USER:-agent}}
vcpus=${SBX_VCPUS:-8}              # Pro maximum; Hobby allows 4
timeout=${SBX_TIMEOUT:-3h}         # session length; Hobby allows 45m
exec_timeout=${SBX_EXEC_TIMEOUT:-2h}

sb() { # sb <subcommand> [args...]
  sub=$1
  shift
  vercel sandbox "$sub" --scope "$SBX_SCOPE" --project "$SBX_PROJECT" "$@"
}

# `vercel sandbox exec` exits 0 even when the remote command fails, so the
# remote shell prints the script's exit status and remote() returns it.
remote() { # remote <name> <script> [args...]
  name=$1
  script=$2
  shift 2
  log=$(mktemp)
  sb exec --timeout "$exec_timeout" "$name" -- \
    sh -c 'sh -c "$0" sh "$@"; echo "__sbx_exit=$?"' "$script" "$@" | tee "$log"
  code=$(sed -n 's/^__sbx_exit=//p' "$log" | tail -n 1)
  rm -f "$log"
  return "${code:-1}"
}

push() { # push <name> <local-dir> <remote-dir>
  git -C "$2" rev-parse --is-inside-work-tree > /dev/null
  tgz=$(mktemp)
  (cd "$2" && git ls-files -z --cached --others --exclude-standard |
    COPYFILE_DISABLE=1 tar -czf "$tgz" --null -T -)
  sb copy "$tgz" "$1:$3.tgz"
  rm -f "$tgz"
  remote "$1" '
    set -e
    dest=$1
    rm -rf "$dest.new"
    mkdir -p "$dest.new"
    tar -xzf "$dest.tgz" -C "$dest.new"
    rm -f "$dest.tgz"
    if [ -d "$dest" ]; then
      (cd "$dest" && find . -maxdepth 4 -type d -name node_modules -prune -print) > "$dest.keep"
      while IFS= read -r keep; do
        [ -e "$dest.new/$keep" ] && continue
        mkdir -p "$(dirname "$dest.new/$keep")"
        mv "$dest/$keep" "$dest.new/$keep"
      done < "$dest.keep"
      rm -rf "$dest" "$dest.keep"
    fi
    mv "$dest.new" "$dest"' "$3" > /dev/null
}

cmd=${1:?usage: sbx create|push|exec|get|put|rm|clean ...}
shift
case "$cmd" in
  create)
    name=${1:?usage: sbx create <name>}
    snapshot=${SBX_SNAPSHOT:-$(cat BASE_SNAPSHOT)}
    sb create --name "$name" --non-persistent --snapshot "$snapshot" \
      --vcpus "$vcpus" --timeout "$timeout" \
      --tag "app=$SBX_PROJECT" --tag "owner=$owner" --silent
    echo "$name"
    ;;
  push)
    push "${1:?name}" "${2:?local dir}" "${3:?remote dir}"
    ;;
  exec)
    name=${1:?usage: sbx exec <name> <script>}
    shift
    remote "$name" "$*"
    ;;
  get)
    rm -f "${3:?local file}"
    sb copy "${1:?name}:${2:?remote file}" "$3"
    [ -f "$3" ] || { echo "sbx: could not copy $1:$2" >&2; exit 1; }
    ;;
  put)
    [ -f "${2:?local file}" ] || { echo "sbx: no such file: $2" >&2; exit 1; }
    sb copy "$2" "${1:?name}:${3:?remote file}"
    ;;
  rm)
    : "${1:?usage: sbx rm <name>...}"
    sb remove "$@"
    ;;
  clean)
    # `list` shows 50 sandboxes per page; run `sbx clean` again if more remain.
    names=$(sb list --all --tag "owner=$owner" | awk 'NR > 1 && NF && $1 != "More" { print $1 }')
    # shellcheck disable=SC2086 # one word per sandbox name
    if [ -n "$names" ]; then sb remove $names; fi
    ;;
  *)
    echo "usage: sbx create|push|exec|get|put|rm|clean ..." >&2
    exit 2
    ;;
esac

典型的 Agent 会话:

sbx create exp-parser
sbx push exp-parser . /vercel/sandbox/cand
sbx exec exp-parser 'cd /vercel/sandbox/cand && sh /vercel/sandbox/prepare.sh && npm test'
sbx get exp-parser /tmp/results.json ./results.json
sbx rm exp-parser

在封装脚本旁记录工作流(简短的 SANDBOX.md):快照 ID、基础环境包含的内容、准备步骤、运行测试套件的方法,以及已知的仅由环境导致的失败。让每个 Agent 的指令都指向该文件。

常见问题

  • **虚假成功:**远程命令失败时,vercel sandbox exec 仍会以 0 退出。请读取打印出的退出状态,或使用 sbx exec。
  • **内存不足:**大型编译可能会被终止。远程退出状态 137 表示进程收到了 SIGKILL,通常是 OOM killer 导致的。在套餐额度内升级规格,或在达到上限时降低并行度,而不是盲目重试。
  • **会话超时导致工作丢失:**非持久化沙盒会在会话停止时丢弃文件系统。请在超时前复制结果,并将超时时长设置为足以覆盖整个任务。
  • 残留沙盒:stop 不会释放沙盒名称,也不会删除沙盒。请使用 remove,并通过 list --all 清理残留项。
  • **快照过期:**从旧基础环境启动的任务可能遇到工具链版本不匹配。版本变更时,请重建快照,或在任务沙盒中更新工具。
  • **共享沙盒:**两个 Agent 使用同一个沙盒会破坏彼此的目录树。每个沙盒只分配一个负责人。
  • **运行中耗尽配额:**在 Hobby 上,月度额度用尽后会暂停创建沙盒;在 Pro 上,Spend Management 限制可能会暂停项目。分小步提交工作,边做边将结果写入磁盘,并确保脚本具备幂等性,这样替换后的 Agent 就能接续工作,而不必从头开始。

评论

支持 Markdown