Serverless AI 架构实践
原创
灵阙教研团队
S 精选 提升 |
约 7 分钟阅读
更新于 2026-02-28 AI 导读
Serverless AI 架构实践 Lambda/Cloud Functions 运行 AI 推理、冷启动优化、GPU Serverless(Modal/Replicate)与成本模型分析 引言 Serverless 计算的核心承诺是"按需付费、零运维"。对于 AI 应用来说,这意味着不需要为 GPU 实例 7x24 待命——只在有推理请求时才消耗计算资源。然而,AI...
Serverless AI 架构实践
Lambda/Cloud Functions 运行 AI 推理、冷启动优化、GPU Serverless(Modal/Replicate)与成本模型分析
引言
Serverless 计算的核心承诺是"按需付费、零运维"。对于 AI 应用来说,这意味着不需要为 GPU 实例 7x24 待命——只在有推理请求时才消耗计算资源。然而,AI 工作负载的特殊性(大模型体积、GPU 依赖、长推理时间)让传统 Serverless 平台面临诸多挑战。
本文探讨如何在 Serverless 架构下高效运行 AI 推理,从传统 CPU Serverless 到 GPU Serverless 的最新实践。
架构模式对比
三种 AI 部署模式
| 模式 | 成本模型 | 延迟 | 扩缩容 | 运维 | 适用场景 |
|---|---|---|---|---|---|
| 常驻服务器 | 固定月费 | 最低 | 手动/慢 | 高 | 高 QPS、延迟敏感 |
| 容器 Auto-scaling | 按实例时间 | 低 | 自动/中 | 中 | 中等 QPS、可预测 |
| Serverless | 按请求+时间 | 冷启动高 | 自动/快 | 低 | 低/突发 QPS、成本敏感 |
Serverless 适用性判断
决策树:我的 AI 应用适合 Serverless 吗?
开始
│
├─ 平均 QPS > 10?
│ └─ YES → 常驻服务器更经济
│
├─ 突发流量(闲时 0 QPS,峰值 100+ QPS)?
│ └─ YES → Serverless 是最佳选择
│
├─ 延迟要求 < 100ms?
│ └─ YES → 需要 Provisioned Concurrency 或常驻
│
├─ 模型 > 10GB?
│ └─ YES → GPU Serverless (Modal/Replicate)
│
└─ 推理时间 > 15 分钟?
└─ YES → 异步队列 + 长时任务服务
CPU Serverless AI
AWS Lambda 部署轻量模型
适用于小型模型(<250MB)的实时推理:
# lambda_function.py
import json
import os
import boto3
from transformers import pipeline
# Global: loaded once, reused across invocations (warm start)
_classifier = None
def get_classifier():
global _classifier
if _classifier is None:
# Load from EFS mount or layer
model_path = os.environ.get("MODEL_PATH", "/mnt/models/distilbert-sentiment")
_classifier = pipeline(
"sentiment-analysis",
model=model_path,
device=-1, # CPU only
)
return _classifier
def handler(event, context):
body = json.loads(event.get("body", "{}"))
text = body.get("text", "")
if not text:
return {
"statusCode": 400,
"body": json.dumps({"error": "Missing 'text' field"}),
}
classifier = get_classifier()
result = classifier(text, truncation=True, max_length=512)
return {
"statusCode": 200,
"headers": {"Content-Type": "application/json"},
"body": json.dumps({
"label": result[0]["label"],
"score": round(result[0]["score"], 4),
}),
}
冷启动优化策略
冷启动分解:
总冷启动时间 = 容器初始化 + 运行时启动 + 依赖加载 + 模型加载
(~500ms) (~200ms) (~2-5s) (~3-30s)
优化手段:
1. 减小包体积
- 使用 Lambda Layer 分离依赖
- 只打包必需的 Python 包
- 用 onnxruntime 替代 pytorch (10x 更小)
2. 模型优化
- ONNX 格式 (启动更快)
- 量化模型 (体积更小)
- 模型存 EFS 而非打包 (避免解压)
3. 预热策略
- Provisioned Concurrency (预热实例)
- CloudWatch 定时 ping (保持 warm)
- SnapStart (JVM, 目前 Python 不支持)
4. 架构优化
- 模型预加载到 /tmp (10GB)
- 使用 Container Image 部署 (10GB 限制)
- ARM (Graviton) 实例 (性价比更高)
Lambda Container Image 部署
# Dockerfile for Lambda container
FROM public.ecr.aws/lambda/python:3.12
# Install ONNX Runtime (CPU optimized, much smaller than PyTorch)
RUN pip install --no-cache-dir \
onnxruntime==1.18.0 \
transformers==4.42.0 \
tokenizers==0.19.0
# Copy model (pre-converted to ONNX)
COPY models/sentiment-onnx/ /opt/models/sentiment/
# Copy handler
COPY lambda_function.py ${LAMBDA_TASK_ROOT}/
CMD ["lambda_function.handler"]
# Build and deploy
docker build -t ai-inference:latest .
docker tag ai-inference:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/ai-inference:latest
docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/ai-inference:latest
aws lambda create-function \
--function-name ai-sentiment \
--package-type Image \
--code ImageUri=123456789.dkr.ecr.us-east-1.amazonaws.com/ai-inference:latest \
--role arn:aws:iam::123456789:role/lambda-execution \
--memory-size 3008 \
--timeout 30 \
--ephemeral-storage '{"Size": 10240}'
GPU Serverless
Modal 实践
Modal 是目前最成熟的 GPU Serverless 平台,支持按秒计费的 GPU 实例:
# modal_app.py
import modal
app = modal.App("llm-inference")
# Define container image with dependencies
image = (
modal.Image.debian_slim(python_version="3.11")
.pip_install(
"vllm==0.6.0",
"transformers==4.44.0",
"torch==2.4.0",
)
)
# Pre-download model to Modal's distributed volume
volume = modal.Volume.from_name("model-cache", create_if_missing=True)
@app.function(
image=image,
gpu=modal.gpu.A100(count=1, size="40GB"),
volumes={"/models": volume},
timeout=300,
container_idle_timeout=120, # Keep warm for 2 minutes
allow_concurrent_inputs=16, # Batch processing
retries=2,
)
def generate(prompt: str, max_tokens: int = 512) -> str:
from vllm import LLM, SamplingParams
# Model loaded once per container lifecycle
llm = LLM(
model="meta-llama/Llama-3.1-8B-Instruct",
download_dir="/models",
max_model_len=8192,
gpu_memory_utilization=0.90,
)
params = SamplingParams(
temperature=0.7,
max_tokens=max_tokens,
top_p=0.9,
)
outputs = llm.generate([prompt], params)
return outputs[0].outputs[0].text
# Web endpoint with streaming
@app.function(
image=image,
gpu=modal.gpu.A100(count=1, size="40GB"),
volumes={"/models": volume},
container_idle_timeout=120,
)
@modal.web_endpoint(method="POST")
async def inference_endpoint(request: dict):
result = generate.remote(
prompt=request["prompt"],
max_tokens=request.get("max_tokens", 512),
)
return {"text": result}
# Scheduled model warm-up
@app.function(schedule=modal.Cron("*/5 * * * *"))
def keep_warm():
"""Ping every 5 minutes to keep container warm."""
generate.remote("Hello", max_tokens=1)
Replicate 实践
Replicate 提供了更简单的模型部署方式,适合快速原型:
# Using Replicate API
import replicate
# Run a pre-deployed model
output = replicate.run(
"meta/llama-3.1-405b-instruct",
input={
"prompt": "Explain quantum computing:",
"max_tokens": 512,
"temperature": 0.7,
},
)
# Stream output
for token in output:
print(token, end="", flush=True)
# Deploy custom model on Replicate
# cog.yaml - Replicate's container definition
"""
build:
gpu: true
python_version: "3.11"
python_packages:
- "torch==2.4.0"
- "transformers==4.44.0"
- "accelerate==0.33.0"
predict: "predict.py:Predictor"
"""
# predict.py
from cog import BasePredictor, Input, ConcatenateIterator
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
class Predictor(BasePredictor):
def setup(self):
"""Load model once during container startup."""
self.tokenizer = AutoTokenizer.from_pretrained(
"meta-llama/Llama-3.1-8B-Instruct"
)
self.model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3.1-8B-Instruct",
torch_dtype=torch.float16,
device_map="auto",
)
def predict(
self,
prompt: str = Input(description="Input prompt"),
max_tokens: int = Input(default=512, ge=1, le=4096),
temperature: float = Input(default=0.7, ge=0.0, le=2.0),
) -> ConcatenateIterator[str]:
inputs = self.tokenizer(prompt, return_tensors="pt").to("cuda")
with torch.inference_mode():
outputs = self.model.generate(
**inputs,
max_new_tokens=max_tokens,
temperature=temperature,
do_sample=temperature > 0,
)
result = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
yield result[len(prompt):]
成本模型分析
GPU Serverless 成本对比
场景:每天 1000 次推理,每次平均 5 秒,使用 A100-40GB
方案 A: 常驻 GPU 服务器
AWS p4d.24xlarge (8x A100): ~$32/小时
月成本: $32 x 24 x 30 = $23,040
利用率: 1000 x 5s / 86400s = 5.8% (极低)
方案 B: Modal GPU Serverless
A100-40GB: ~$0.001/秒
计算时间: 1000 x 5s = 5000s/天
月成本: 5000 x 30 x $0.001 = $150
+ 冷启动额外时间: ~$50
月成本: ~$200
方案 C: Replicate
A100-40GB: ~$0.0023/秒
月成本: 5000 x 30 x $0.0023 = $345
节省比例:
Modal vs 常驻: $200 vs $23,040 → 节省 99.1%
Replicate vs 常驻: $345 vs $23,040 → 节省 98.5%
成本交叉点分析
| 日请求量 | 常驻 (p4d) | Modal (A100) | Replicate | 推荐 |
|---|---|---|---|---|
| 100 | $23,040/月 | ~$20/月 | ~$35/月 | Serverless |
| 1,000 | $23,040/月 | ~$200/月 | ~$345/月 | Serverless |
| 10,000 | $23,040/月 | ~$2,000/月 | ~$3,450/月 | Serverless |
| 50,000 | $23,040/月 | ~$10,000/月 | ~$17,250/月 | Serverless |
| 100,000 | $23,040/月 | ~$20,000/月 | ~$34,500/月 | 常驻 |
| 500,000 | $23,040/月 | ~$100,000/月 | - | 常驻 |
交叉点大约在日均 70,000-100,000 次请求(每次 5 秒推理),超过这个量级常驻服务器更经济。
混合架构
实际推荐架构
┌──────────────────────────────────────────────────┐
│ API Gateway │
│ (路由 + 认证 + 限流) │
└───────────────┬───────────────┬───────────────────┘
│ │
┌───────────▼─────┐ ┌─────▼───────────┐
│ 高频推理 (>10QPS) │ │ 低频推理 (<1QPS) │
│ │ │ │
│ 常驻 GPU 服务器 │ │ GPU Serverless │
│ vLLM on K8s │ │ Modal / Replicate│
│ Auto-scaling │ │ 按需启动 │
│ min=1, max=8 │ │ min=0, max=inf │
└───────────────────┘ └──────────────────┘
// Hybrid routing logic
async function routeInference(request: InferenceRequest): Promise<InferenceResponse> {
const currentQps = await getRecentQps(request.model, "5m");
if (currentQps > 10) {
// Route to persistent GPU cluster
return callVllmCluster(request);
}
// Route to serverless for low-traffic models
return callModalEndpoint(request);
}
异步推理模式
对于长时间运行的推理任务(视频生成、大批量处理),采用异步模式:
# Async inference with callback
import modal
@app.function(
gpu=modal.gpu.A100(count=1),
timeout=600,
)
def batch_inference(items: list[dict]) -> list[dict]:
"""Process a batch of inference requests."""
model = load_model()
results = []
for item in items:
result = model.generate(item["prompt"])
results.append({"id": item["id"], "output": result})
return results
# Client side: submit and poll
@app.local_entrypoint()
async def main():
# Submit batch job
call = batch_inference.spawn(items=batch_items)
# Poll for completion
result = call.get(timeout=600)
print(f"Processed {len(result)} items")
总结
- Serverless AI 的最佳场景是低频突发流量:日均请求量低但偶尔有峰值的场景,Serverless 可以节省 95%+ 的成本。
- 冷启动是最大挑战:通过模型压缩、ONNX 转换、预热策略和容器复用来缓解。
- GPU Serverless 正在成熟:Modal 和 Replicate 让 GPU 推理也可以按秒计费,但生态还在快速演进。
- 混合架构是务实选择:高频模型用常驻服务器,低频模型用 Serverless,通过统一网关路由。
- 成本交叉点要持续跟踪:GPU Serverless 定价在快速变化,每季度重新评估成本模型。
Maurice | maurice_wen@proton.me