前言:为什么选择 Modal?
在众多免费 AI 算力平台中,Modal 是一个被严重低估的选择。与 Google Colab 需要手动操作笔记本不同,Modal 提供的是真正的 Serverless GPU 计算——你只需编写 Python 代码,Modal 自动管理基础设施、自动扩容、按需计费(免费额度内完全免费)。
Modal 每月提供 $30 免费额度,足以运行数百次推理任务或几十小时的模型训练。它支持 A100、H100、L40S 等顶级 GPU,且无需手动管理任何服务器。本文将从注册到实战,带你完整掌握 Modal 的使用方法。

一、Modal 平台概览与免费额度
1.1 核心优势
- Serverless 架构:无需管理服务器,代码即服务
- 免费额度慷慨:每月 $30 免费额度,无信用卡也可注册
- GPU 种类丰富:T4、L40S、A100(40G/80G)、H100
- 自动休眠:5 分钟内无请求自动缩零,不产生费用
- Python 原生:直接使用 pip 依赖,支持主流深度学习框架
1.2 免费额度详解
| 资源类型 | 免费额度 | 超出后价格 |
|---|---|---|
| CPU 计算 | $30/月(共享) | $0.0001/秒起 |
| GPU(T4) | $30/月覆盖约 30 小时 | $0.0007/秒 |
| GPU(A100-40G) | $30/月覆盖约 10 小时 | $0.0021/秒 |
| GPU(H100) | $30/月覆盖约 3 小时 | $0.0031/秒 |
| 存储 | 免费(按使用计) | $0.1/GB/月 |
| 网络出站 | 每月 100GB 免费 | $0.09/GB |
对于个人开发者,T4 GPU 的性价比最高,$30 额度足够日常实验和推理任务。如果只是跑 CPU 任务,$30 几乎是无限使用。
二、环境配置与项目初始化
2.1 注册与安装 CLI
首先前往 modal.com 注册账号(支持 GitHub/Google 登录,无需信用卡)。然后安装 CLI 工具:
1
2
3
4
5 # 安装 Modal Python 包
pip install modal
# 生成并配置 Token(首次运行会引导登录)
modal setup
安装完成后,运行
1 | modal token set |
创建 API Token。Token 会保存在
1 | ~/.modal.toml |
中:
1
2
3
4 # ~/.modal.toml
[default]
token_id = "tk-xxxxx"
token_secret = "ts-xxxxx"
2.2 基础项目结构
一个典型的 Modal 项目结构如下:
1
2
3
4
5 my-modal-project/
├── app.py # 主应用定义
├── requirements.txt # Python 依赖
├── modal.toml # 项目级配置(可选)
└── data/ # 数据文件(可选)
三、核心技术:编写第一个 Modal 函数
3.1 Hello World 与 GPU 选型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import modal
# 创建应用
app = modal.App("hello-gpu")
# 定义镜像(带 GPU 驱动)
image = modal.Image.debian_slim().pip_install("torch", "transformers")
@app.function(
image=image,
gpu="t4", # 可选: "t4", "l40s", "a100", "a100-80gb", "h100"
timeout=300 # 超时时间(秒)
)
def gpu_hello():
import torch
return {
"device": torch.cuda.get_device_name(0),
"memory": torch.cuda.get_device_properties(0).total_mem / 1e9,
"cuda_version": torch.version.cuda
}
# 本地调用测试
if __name__ == "__main__":
print(gpu_hello.remote())
运行
1 | python app.py |
后,Modal 会自动构建镜像并执行。首次运行会拉取基础镜像,后续调用会复用缓存,速度极快。
3.2 保存函数输出到云端
Modal 提供 Volume 持久化存储,重启后数据不丢失:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import modal
app = modal.App("volume-demo")
volume = modal.Volume("my-data")
image = modal.Image.debian_slim().pip_install("pillow")
@app.function(
image=image,
gpu="t4",
volumes={"/data": volume}, # 挂载 Volume 到 /data
timeout=600
)
def save_model_output():
import torch
from PIL import Image
import os
# 模拟模型输出
outputs = [f"result_{i}.pt" for i in range(10)]
# 保存到 Volume
for name in outputs:
data = torch.randn(256, 256)
torch.save(data, f"/data/{name}")
return os.listdir("/data")
四、实战案例:在 Modal 上跑 LLM 推理
4.1 部署 HuggingFace 模型
以 Meta 的 Llama 3.2 1B 模型为例,展示如何在 Modal 上搭建推理API:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 import modal
app = modal.App("llm-inference")
# 构建镜像,安装依赖
image = (
modal.Image.debian_slim()
.pip_install(
"torch",
"transformers",
"accelerate",
"bitsandbytes",
"huggingface-hub"
)
)
# 模型权重挂载(避免重复下载)
MODEL_DIR = "/model"
model_volume = modal.Volume("llama-model")
@app.function(
image=image,
gpu="a100",
volumes={MODEL_DIR: model_volume},
timeout=120,
allow_concurrent_inputs=8 # 支持并发请求
)
def generate(prompt: str, max_tokens: int = 512):
from transformers import AutoModelForCausalLM, AutoTokenizer
model_name = "meta-llama/Llama-3.2-1B"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype="auto",
device_map="auto"
)
inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
outputs = model.generate(
**inputs,
max_new_tokens=max_tokens,
temperature=0.7,
do_sample=True
)
return tokenizer.decode(outputs[0], skip_special_tokens=True)
@app.function(
image=image,
gpu="a100",
volumes={MODEL_DIR: model_volume},
timeout=120,
allow_concurrent_inputs=8
)
@app.web("/v1/chat", method="POST")
def web_handler(body: dict):
"""提供 HTTP API 接口"""
prompt = body.get("prompt", "Hello!")
max_tokens = body.get("max_tokens", 512)
result = generate.remote(prompt, max_tokens)
return {"response": result}
部署到生产环境仅需一行命令:
1 modal deploy app.py
部署后会得到一个 HTTPS 端点,可以直接用 curl 调用:
1
2
3 curl -X POST https://your-app.modal.run/v1/chat \
-H "Content-Type: application/json" \
-d '{"prompt": "解释什么是 Transformer 架构", "max_tokens": 300}'
4.2 批量推理与并发控制
1
2
3
4
5
6
7
8
9
10
11
12
13
14 @app.function(
image=image,
gpu="t4",
timeout=600,
allow_concurrent_inputs=16
)
def batch_generate(inputs: list):
"""批量处理多个输入(自动并发)"""
results = [generate.remote(inp) for inp in inputs]
return results
# 使用 map 实现真正的并行
inputs = ["问题1", "问题2", "问题3", "问题4"]
results = list(batch_generate.map(inputs))
五、进阶技巧:定时任务与 Webhook
5.1 使用 Cron 定时调度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 import modal
app = modal.App("daily-summary")
image = modal.Image.debian_slim().pip_install(
"openai", "httpx"
)
@app.function(
image=image,
schedule=modal.Cron("0 9 * * *"), # 每天 UTC 9:00 执行
timeout=300
)
def daily_analysis():
"""每天自动运行数据分析任务"""
import httpx
# 获取数据
response = httpx.get("https://api.example.com/daily-data")
data = response.json()
# 处理数据(模拟)
summary = {
"date": data.get("date"),
"total": len(data.get("items", [])),
"status": "completed"
}
return summary
5.2 Webhook 与外部系统集成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 @app.function(
image=image,
allow_concurrent_inputs=32
)
@app.web("/webhook/github", method="POST")
def github_webhook(body: dict):
"""接收 GitHub Webhook,自动触发 CI 或分析"""
event = body.get("action", "unknown")
repo = body.get("repository", {}).get("full_name", "unknown")
# 处理推送事件
if event == "push":
commits = body.get("commits", [])
result = analyze_commits.remote(commits)
return {"status": "analyzed", "commits": len(commits)}
return {"status": "ignored", "event": event}
六、性能优化与成本控制
6.1 容器冷启动优化
Modal 函数的首次调用需要构建和启动容器(冷启动)。以下方法可以大幅减少冷启动时间:
- 使用 Snapshots 预构建:在镜像构建阶段预下载模型权重
- 设置 min_containers:保持最少 1 个热容器
- 分层构建:将不常变的依赖预安装到基础镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 image = (
modal.Image.debian_slim()
.pip_install("torch", cache=True) # 缓存 pip 包
.run_commands([
"python -c 'from transformers import AutoModel; AutoModel.from_pretrained("meta-llama/Llama-3.2-1B")'"
])
)
@app.function(
image=image,
gpu="t4",
container_idle_timeout=300,
keep_warm=1,
timeout=600
)
def warm_function():
pass
6.2 省钱技巧总结
| 技巧 | 效果 | 适用场景 |
|---|---|---|
| 使用 T4 而非 A100 | 节省 ~70% 费用 | 推理、轻量训练 |
| 设置超时时间 | 防止任务卡住浪费额度 | 所有场景 |
| Volume 缓存模型权重 | 减少重复下载 | 多函数共享模型 |
| 适当保持热容器 | 消除冷启动延迟 | 生产环境 API |
| 使用函数并发 | 提高 GPU 利用率 | 批量推理 |
| 按需选择 GPU 显存 | 避免浪费 | 小模型推理 |
七、与同类平台对比
| 特性 | Modal | Google Colab | RunPod | Vast.ai |
|---|---|---|---|---|
| 免费额度 | $30/月 | 免费 T4(有限) | $0.25/小时(无免费) | 无免费 |
| GPU 种类 | T4/A100/H100/L40S | T4/V100/A100 | A100/H100/RTX4090 | 任意 |
| 是否需要管理 | 完全无需管理 | 需要上传笔记本 | 需要选模板 | 需要选机器 |
| API 部署 | 原生支持 | 需 ngrok | 支持 | 需自行搭建 |
| 冷启动 | 约 10-30 秒 | 无(随时切换) | 约 1-3 分钟 | 约 1-5 分钟 |
| 持久化存储 | Volume | Google Drive | 模板卷 | SSH 同步 |
| 适用场景 | 生产级 API/定时任务 | 教学/实验 | 训练/部署 | 租赁特定硬件 |
Modal 的最大优势在于 Serverless 原生体验——你把代码写好,剩下的全交给 Modal。对于需要稳定运行的 API 服务和定时任务,Modal 远胜于 Colab 的手动操作模式。
八、常见问题排错
8.1 GPU 显存不足
1
2
3
4
5
6
7
8
9 # 错误:CUDA out of memory
# 解决方案:
# 1. 升级 GPU(t4 -> a100-40g)
# 2. 使用 4-bit 量化加载模型
model = AutoModelForCausalLM.from_pretrained(
model_name,
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.float16
)
8.2 网络访问受限
1
2
3
4
5
6
7
8 # 某些网络地址被限制?尝试:
@app.function(
image=image,
gpu="t4",
network_file_system="/mnt/nfs"
)
def my_function():
pass
8.3 函数超时
默认超时是 300 秒(5 分钟)。长时间训练任务需要显式设置更高的 timeout:
1
2
3
4
5
6
7
8
9 @app.function(
image=image,
gpu="a100",
timeout=3600, # 最长 1 小时
cpu=4, # 分配更多 CPU
memory=32768 # 32GB 内存
)
def long_training():
# 长时间训练代码...
总结与行动建议
Modal 是目前最被低估的免费 GPU 算力平台之一。每月 $30 的免费额度搭配 Serverless 架构,让开发者可以零成本搭建 AI 推理 API、定时数据处理任务和模型微调流水线。
如果你正在寻找一个比 Colab 更专业、比自建服务器更省心的方案,Modal 是最佳选择。建议从以下路径入门:
- 注册 Modal 账号(无需信用卡)
- 安装 CLI 并运行本文第一个 GPU Hello World 示例
- 尝试部署一个 HuggingFace 模型的推理 API
- 将你的定时分析任务迁移到 Modal Cron
当你习惯了 “写代码即部署” 的工作流后,就再也回不去手动管理服务器的日子了。
汤不热吧