目标

不开浏览器、不用 Jupyter 网页,直接在终端里申请 Colab 的 GPU 实例、跑本地脚本、传文件、用完释放。附带一个给 AI agent 用的 skill,可以让编码助手直接调度云端算力。

工具由 Google 官方发布:PyPI 包名 google-colab-cli,仓库 googlecolab/google-colab-cli。

前置条件

  • 操作系统必须是 Linux 或 macOS。Windows 不支持,本机走 WSL。
  • Python >= 3.12(uv 会自动管理)。
  • 能访问 accounts.google.com 和 colab.research.google.com。

步骤

1. 安装(WSL Ubuntu 内)

curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
uv tool install google-colab-cli

可执行文件落在 ~/.local/bin/colab。每次新开 shell 都要 export PATH="$HOME/.local/bin:$PATH",否则 colab: command not found。

2. 打依赖补丁(必做,见下方踩坑)

uv pip install --python ~/.local/share/uv/tools/google-colab-cli/bin/python \
  "jupyter-kernel-client @ git+https://github.com/googlecolab/jupyter-kernel-client.git@f18e982c3265df5e923aa9def101ab3fd737e139"

3. 登录

colab 故意不用 localhost 回调,而是用 gcloud 那套远程流程,因为 localhost 回调在 headless / 容器 / 远端主机上会失败:

  1. 命令打印一个 accounts.google.com 授权链接;
  2. 在任意浏览器打开、同意;
  3. 谷歌的落页 sdk.cloud.google.com/applicationdefaultauthcode.html 显示一串授权码;
  4. 把码粘回终端。

所以没有浏览器的机器也能登。token 缓存到 ~/.config/colab-cli/token.json,之后不用重复登录。

脚本里要喂 stdin 给它的 input(),用 tail -f 文件 | colab ...,再往文件里 append 授权码。

验证身份和权限:

colab whoami    # 隐藏调试命令:邮箱、scopes、有效期
colab sessions  # 只读,列出服务端现有的实例

4. 开卡、跑代码、释放

# 开一台 GPU 实例;-s 一定要给,不给会生成随机 6 位十六进制名字,后面没法引用
colab new -s myjob --gpu T4

# 跑本地脚本(脚本内容本地读取后传到内核,不用先 upload)
colab exec -s myjob -f train.py

# 或直接管道喂代码
echo 'import torch; print(torch.cuda.get_device_name(0))' | colab exec -s myjob

# 传文件
colab upload -s myjob ./data.zip /content/data.zip
colab download -s myjob /content/out.png ./out.png

# 用完必须释放
colab stop -s myjob

一次性任务用 colab run,等价于 new + exec + stop 三连:

colab run --gpu T4 job.py --arg1

验证方法

echo 'import subprocess, sys; import torch
print(sys.version.split()[0], torch.__version__, torch.cuda.is_available())' | colab exec -s myjob

实测输出(2026-09-24,免费档 T4):Python 3.13.15、torch 2.11.0+cu128、cuda.is_available()=True。

踩坑

PyPI 打包 bug:装完必崩 AttributeError: module 'jupyter_kernel_client' has no attribute 'JupyterSubprotocol'

发生条件:2026-09 从 PyPI 装 google-colab-cli==0.7.2,第一次执行任何需要连内核的命令(colab exec)就崩。

症状:

AttributeError: module 'jupyter_kernel_client' has no attribute 'JupyterSubprotocol'
  File ".../colab_cli/runtime.py", line 99, in kernel_client

尝试过的方案:一开始怀疑是 Python 3.14 太新或环境损坏,实际都不是。

根因:PyPI 打包 bug,不是用户环境问题。
仓库的 uv.lock 里这条依赖指向的是谷歌自己 fork 的 github.com/googlecolab/jupyter-kernel-client(commit f18e982),但发布到 PyPI 的 wheel 元数据把它写成了 jupyter-kernel-client==0.8。于是解析到 PyPI 上同版本号的 0.8.0——而 PyPI 的 0.8.0 没有 JupyterSubprotocol 这个类,谷歌 fork 的 0.8.0 才有。同名同版本号,内容不同。

解决步骤:把 tool 环境里的这个包换成 fork 版本(见上方步骤 2)。装完 hasattr(module, 'JupyterSubprotocol') 返回 True。

下次怎么认出来:CLI 报错指向库内部某个"应该存在"的类或常量不存在时,先怀疑版本号相同但来源不同(PyPI 正式包 vs 厂商 fork)。查仓库 uv.lock 里这条依赖的 source 字段是 registry 还是 git,一眼就能分辨。

副作用:uv tool upgrade google-colab-cli 会把这个补丁冲掉,升级后要重打。

认不出的 --gpu 值会静默退回 A100

写错卡名(比如 --gpu V100)不会报错,会当成 A100 去申请,然后在下一步失败。可用的值只有 T4 / L4 / G4 / H100 / A100(TPU 是 v5e1 / v6e1)。

colab auth 不是登录

colab auth 是往运行中的 VM 内核里注入 GCP 凭证,让 notebook 代码能调 BigQuery/GCS,跟 CLI 自身能不能连上 Colab 后端无关。CLI 报 401/403 时去查 scopes,不要跑这个。而且它需要 TTY,agent 里跑会挂住。

会挂住的命令

colab repl / colab console / colab auth / colab drivemount 都期望 TTY。前两个可以管道喂 stdin、读到 EOF 就退出;后两个必须真人在终端操作,Agent 里不要碰。

适用边界:算力单元与订阅权益

Colab 按算力单元(Compute Units, CU)计费,一种按小时扣的虚拟点数。单价约 $0.10/CU,高档卡扣得更快(A100 大约 12–15 CU/小时)。开着连接就扣,装依赖和空闲也算。未用完的 CU 有有效期,过期失效。

月费订阅的关系(2026-09 查证):

方案CU/月可用卡后台长跑
免费档无(动态配额)T4否
Google AI Pro100 CU优先 T4/L4 档否
Google AI Ultra更多优先 A100/H100 档是

要点:

  • "关掉浏览器还能后台跑"是 AI Ultra 独占,AI Pro 没有。 这一点最容易记错。
  • 独立订阅的 Colab Pro 与 Google AI 订阅,CU 会叠加。
  • 免费档的 T4 是真能用的:15 GB 显存,torch/CUDA 开箱即用,跑 SD1.5/SDXL 推理和小模型 LoRA 微调够用。AI Pro 的加值主要在"优先用更快的卡"和更多 CU。

查余额:colab usage(读后端 GET /tun/m/ccu-info),或在 Colab 网页右下角资源面板看。

注意区分:"订阅了 Google AI Pro" ≠ "Colab 里 CU 到账"。CU 按订阅自身的计费周期发放,新订阅或续费可能有同步延迟;账号地区不在 Colab 支持范围内也可能拿不到。判断方法:colab usage 看余额 + colab new --gpu L4 试能否分配到高档卡,两者都会立刻给出明确答复(被拒时提示 Backend rejected accelerator ... You may not have quota or entitlement)。

会话生命周期:它是"借机器",不是"拥有机器"

这是用之前必须建立的预期,否则会被频繁的会话消失搞崩溃。

colab new 分配的是一台租来的机器。CLI 自带保活守护进程(colab new 自动以脱离进程起一个,每 60 秒向后端发一次心跳),但保活的作用域很窄:

保活能防保活防不了
闲置超时被踢后端资源紧张时的主动抢占
免费档的会话时长上限
24 小时保活上限到期

官方文档的原话是:除了那个 24 小时上限,没有任何东西会自动释放一个 session——反过来也成立:没有任何东西保证它不被收走。

推论

  • Colab 没有"部署 / 常驻服务"这个概念。 它天生是爆发式用法:开卡 → 跑完 → 把结果取出来 → 关掉。
  • VM 的硬盘随 VM 一起消失。 下载的模型、装好的依赖,会话一被回收全部重来。实测重下 6.9 GB 的模型要 66–170 秒。
  • 想避免重下,只能把模型缓存到 Google Drive 之类的持久存储(colab drivemount 需要真人在终端授权一次)。

推荐姿势:colab run 而不是 new + exec + stop

colab run --gpu T4 job.py --args

一条命令把"开卡 → 执行 → 传参 → 关卡"打包成一次调用,整个任务的生命周期 == 会话的生命周期,不依赖会话活得久。

长任务:脱离 + 轮询日志(重要手法)

colab exec 的 websocket 会因为等太久而超时断开,但 VM 上的进程还在跑。所以长任务不要指望 exec 直接返回结果,要:

# 1. 脱离终端后台跑,stdout 落盘
echo 'cd /content && setsid nohup python3 -u job.py > /content/job.log 2>&1 < /dev/null &' \
  | colab console -s mysession

# 2. 用 download 轮询日志(不占用内核,内核忙着也能读)
colab download -s mysession /content/job.log /tmp/job.log

结果文件同理:算完立刻落盘,然后轮询 colab ls 发现新文件就 colab download 取回来。这样即使会话随后被收走,产物也已经到手。

一个容易误判的坑:本地那条轮询命令自己超时了(shell 超时 / colab exec 超时),不代表 VM 上的任务失败。先去查日志和产物,再下结论。曾因为这个误判过一次"任务挂了"。

别去动宿主机的 WSL 生命周期

如果 CLI 装在 WSL 里(Windows 上只能这样),wsl --terminate / wsl --shutdown 会把保活守护进程一起杀掉,紧接着会话就被回收。修 WSL 网络问题时尤其容易踩——修网络的动作本身把任务搞死了。

踩坑:Clash 的 TUN 模式会让 WSL 彻底断网

症状:WSL 里所有网络请求失败(SSL EOF / connection reset),连自己的 NAT 网关都 ping 不通;但 Windows 侧完全正常,Google 都能开。

根因:Clash 的 TUN 虚拟网卡(进程名常见 verge-mihomo,网卡别名 Meta)抢占了默认路由,WSL 的流量进了隧道后被丢弃。

无效的修法:wsl --terminate 修不好,wsl --shutdown 也修不好。因为问题在 Windows 侧的路由,不在 WSL 里面。

根治:关掉 TUN 模式,改用系统代理 + 让 WSL 走局域网代理(见下)。

Clash 关掉 TUN 之后:WSL 必须显式挂代理

关掉 TUN 后 WSL 恢复直连,但直连被墙(Google / HuggingFace 全 000,百度 200)。此时必须让 WSL 走 Windows 上的 Clash:

前提:Clash Verge 里打开「允许局域网连接」(Allow LAN)。否则 Clash 只监听 127.0.0.1:7890,而 WSL 够不到 Windows 的 127.0.0.1(NAT 模式下这是两个网络栈,localhostForwarding 只解决 Windows → WSL 方向)。

打开后,WSL 里用网关 IP 访问:

gw=$(ip route | awk '/default/{print $3; exit}')   # 例如 172.25.192.1
export https_proxy=http://$gw:7890 http_proxy=http://$gw:7890 no_proxy=localhost,127.0.0.1

实测 172.25.192.1:7890 对 google / colab.research.google.com / huggingface.co 全部返回 200。

另一条路(不用改 Clash,但要管理员):在 %USERPROFILE%\.wslconfig 里加 networkingMode=mirrored,然后 wsl --shutdown。镜像模式下 WSL 与 Windows 共用网络栈,127.0.0.1:7890 直接可用。

免费档能干什么:算力不是瓶颈,会话窗口才是

T4 本身很快,实测:

算力
普通笔记本 CPU约 0.1–0.5 TFLOPS
Colab 免费 T4约 8 TFLOPS(fp16 走张量核可达 65)

差距 20–100 倍。真正的瓶颈是会话窗口有多长,以及每次开卡要不要重新准备环境。

核心原则:优先挑"零下载、零安装"的活

模型下载要 1–3 分钟,依赖安装更久,而会话可能只有几十分钟。不用下载 = 全部时间都在算,白嫖效率最高。

适合的工作负载

A. 纯算力(零安装,开卡就跑,最划算)

  • 蒙特卡洛仿真:期权定价、Ising 模型、粒子输运
  • 物理仿真:N 体引力、流体、分子动力学
  • 光线追踪 / 分形渲染 → 直接出 MP4
  • 暴力搜索:哈希爆破基准、大素数搜索、小密钥 RSA 分解(安全研究 / CTF)
  • 数值线性代数:超大矩阵求逆、特征值、SVD
  • 组合优化:遗传算法、模拟退火、旅行商

B. 小模型训练(几分钟级,能做完)

  • CIFAR-10 训个卷积网络,几分钟跑几轮
  • 字符级 Transformer 玩文本生成

C. 数据处理(吃 CPU 和内存)

  • 几 GB 的 CSV / 日志清洗、去重、聚合

D. 批量推理

  • 中等模型的批量 embedding / 分类 / OCR(但要先下模型,把下载时间算进预算)

不适合的

  • 长训练(几小时级):会话活不了那么久
  • 常驻服务:Colab 没有这个概念
  • 要上传大量数据:上传带宽有限,且文件通道本身不稳(见下)

实际耗时参考(Anima-2.9B,bf16,含下载和加载)

分辨率画图一张总计
640x8964.5 分钟~6 分钟 ✅ 甜点区
768x1024~6 分钟~8 分钟 ⚠️ 看运气
832x1216~9 分钟~11 分钟 ❌ 基本跑不完

规律:把单次任务压在 10 分钟以内。超了就拆,或者降规模。

会话寿命(未测准,待补)

两次观察:一次会话在约 10 分钟的渲染任务中掉线;一次在 20–40 分钟区间消失。样本不足,也未能排除是保活守护进程被杀导致的(见上面的"会话生命周期"一节)。

想测准:开一个会话,跑一个每分钟写一行时间戳的心跳脚本落盘,隔一段时间回来看日志有多少行。注意心跳脚本本身要用 setsid nohup ... & 脱离,并且先验证它真的在写文件——第一次做这个实验时心跳根本没起来,白等。

踩坑:文件通道会间歇性 SSL EOF

症状:colab download / colab ls / colab upload 报

SSLError(SSLEOFError(8, '[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol'))

目标主机是每台机器专属的 8080-<session>.prod.colab.dev。

关键区分:同一次故障里

通道状态
colab status / colab sessions(控制面,走 colab.research.google.com)正常
colab run / exec 的代码执行正常
ls / download / upload(走 *.prod.colab.dev)间歇性 SSL EOF

排查过的:不是墙(该域名直连确实不通,但走代理通);不是代理配置(同一时刻 curl -x <proxy> 对该主机能拿到响应);不是 CLI 独有(用 requests 直接打同一个 URL,也是一次成功、之后连续失败)。属于代理到该域名这条隧道本身不稳。

怎么应对:

  1. 只重试。同一操作重试几次通常能成。
  2. 绕开 CLI 直接读:会话信息在 ~/.config/colab-cli/sessions.json,里面有 url(运行时主机)和 token。用 requests 打
    {url}/api/contents/{path}?authuser=0&colab-runtime-proxy-token={token}&content=1
    即可取文件。注意 VM 的 /content/x 对应 API 路径 content/x(Jupyter 根是 VM 的 /,别把 content/ 前缀剥掉,剥了就是 404)。
  3. 把结果留在文件名可预期的地方,这样重连后能直接取。

一个教训:colab status 说会话在,不代表文件通道能用——这两个走不同的后端。反过来,文件通道报错也不代表会话死了,先重试再下结论。

相关


本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/AI apps