Skip to content

2.17 部署上线

一句话总结:上线不是终点,而是起点——关注成本控制和可观测性。

📊 学习进度

  • 状态:⬜ 未开始
  • 上次实时更新:2026-07-03
  • 预计时长:2-3 小时
  • 已完成:0/3 个模块
  • 在整体流程中的位置:AI 应用开发·第 5 阶段

📍 本章定位

  • 服务方案:方案 1(重要 60%)/ 方案 2(重要 60%)
  • 学习方式:🔥 推荐
  • 在流程中的作用:把开发完成的应用部署到生产环境
  • 核心知识点:推理服务、成本控制、架构设计
  • 预计时长:2-3 小时
  • 完成后能做什么:能将 AI 应用部署上线并控制成本

人机分工

环节谁做重要度说明
架构设计🧑 人⭐⭐⭐⭐⭐决定部署架构
成本策略🧑 人⭐⭐⭐⭐⭐决定预算和模型选择
部署执行🤖 AI⭐⭐⭐CI/CD 自动化
监控配置🤖 AI⭐⭐⭐工具自动配置

两种部署模式

模式适用场景复杂度成本结构启动成本
调用 API大多数场景、快速验证按 Token 付费¥0
自部署模型数据隐私、高吞吐、定制化GPU 固定成本¥5,000+/月
混合方案成本敏感、质量要求高API + GPU¥2,000+/月

部署平台对比(2025-2026)

平台类型特点适用场景月成本
VercelServerless自动扩缩、零运维前端 + API免费-¥200
RailwayPaaS简单部署、按用量计费后端服务¥50-500
Fly.io边缘计算全球部署、低延迟全球化应用¥100-1000
AWS LambdaServerless极致扩缩、按调用计费事件驱动按量计费
ModalGPU Serverless按秒计费 GPUAI 推理服务按量计费
Replicate模型托管一键部署开源模型模型即服务按量计费

数据来源:各平台官网定价,2025-2026。据 Vercel 2025 报告,AI 应用部署量同比增长 300%。


调用 API 型部署

架构

用户 → CDN → 前端(Vercel) → API Gateway → 后端服务(Railway)

                                          AI API(Claude/OpenAI)

                                          缓存(Redis)/ 消息队列

关键配置

配置说明推荐方案代码示例
重试API 调用失败重试指数退避 + 抖动见下方代码
限流控制调用频率令牌桶算法见下方代码
降级API 不可用时的兜底缓存/规则引擎见下方代码
超时单次调用超时30-60 秒见下方代码

重试与降级代码实现

python
"""
生产级 API 调用封装 - 包含重试、限流、降级
"""
import time
import asyncio
import anthropic
from functools import wraps
from typing import Optional, Callable
from collections import defaultdict
import hashlib
import json

class AIAPIClient:
    """生产级 AI API 客户端"""
    
    def __init__(self, api_key: str, max_retries: int = 3):
        self.client = anthropic.Anthropic(api_key=api_key)
        self.max_retries = max_retries
        self.cache = {}  # 简化版缓存,生产环境用 Redis
        self.rate_limiter = defaultdict(lambda: {"count": 0, "reset_time": 0})
    
    def _get_cache_key(self, messages: list, model: str) -> str:
        """生成缓存键"""
        content = json.dumps(messages, sort_keys=True) + model
        return hashlib.md5(content.encode()).hexdigest()
    
    def _check_cache(self, cache_key: str) -> Optional[str]:
        """检查缓存"""
        if cache_key in self.cache:
            entry = self.cache[cache_key]
            if time.time() < entry["expire_at"]:
                return entry["response"]
            del self.cache[cache_key]
        return None
    
    def _set_cache(self, cache_key: str, response: str, ttl: int = 3600):
        """设置缓存"""
        self.cache[cache_key] = {
            "response": response,
            "expire_at": time.time() + ttl,
        }
    
    def call_with_retry(
        self,
        messages: list,
        model: str = "claude-sonnet-4-20250514",
        max_tokens: int = 1024,
        use_cache: bool = True,
        fallback_response: str = "抱歉,服务暂时不可用,请稍后再试。",
    ) -> str:
        """
        带重试和降级的 API 调用
        
        重试策略:指数退避 + 抖动
        降级策略:返回缓存或默认响应
        """
        # 检查缓存
        if use_cache:
            cache_key = self._get_cache_key(messages, model)
            cached = self._check_cache(cache_key)
            if cached:
                return cached
        
        last_error = None
        for attempt in range(self.max_retries):
            try:
                response = self.client.messages.create(
                    model=model,
                    max_tokens=max_tokens,
                    messages=messages,
                    timeout=60,  # 60 秒超时
                )
                result = response.content[0].text
                
                # 缓存成功响应
                if use_cache:
                    self._set_cache(cache_key, result)
                
                return result
            
            except anthropic.RateLimitError as e:
                # 限流错误:等待后重试
                wait_time = (2 ** attempt) + (time.time() % 1)  # 指数退避 + 抖动
                print(f"限流,等待 {wait_time:.1f} 秒后重试...")
                time.sleep(wait_time)
                last_error = e
            
            except anthropic.APITimeoutError as e:
                # 超时错误:立即重试
                print(f"超时,第 {attempt + 1} 次重试...")
                last_error = e
            
            except anthropic.APIError as e:
                # 其他 API 错误:降级处理
                print(f"API 错误: {e}")
                return fallback_response
        
        # 所有重试都失败
        print(f"重试 {self.max_retries} 次后仍然失败: {last_error}")
        return fallback_response

# 使用示例
client = AIAPIClient(api_key="your-api-key")

# 正常调用
response = client.call_with_retry(
    messages=[{"role": "user", "content": "什么是 RAG?"}],
    model="claude-sonnet-4-20250514",
)

# 带降级的调用
response = client.call_with_retry(
    messages=[{"role": "user", "content": "紧急问题"}],
    fallback_response="客服忙,请拨打热线 400-xxx-xxxx",
)

Docker 容器化配置

dockerfile
# Dockerfile - FastAPI + Claude API 应用
FROM python:3.11-slim

WORKDIR /app

# 安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制代码
COPY . .

# 暴露端口
EXPOSE 8000

# 启动命令
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
yaml
# docker-compose.yml - 完整服务栈
version: '3.8'

services:
  # 后端 API 服务
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
      - REDIS_URL=redis://redis:6379
    depends_on:
      - redis
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 1G
  
  # Redis 缓存
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    restart: unless-stopped
  
  # Nginx 反向代理
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/nginx/ssl
    depends_on:
      - api
    restart: unless-stopped

volumes:
  redis_data:

自部署模型型部署

推理框架对比(2025-2026)

框架特点吞吐量适用场景学习曲线
vLLMPagedAttention、连续批处理最高生产环境
Ollama一键安装、简单易用中等本地开发、原型验证
TensorRT-LLMNVIDIA 深度优化极高极致性能需求
llama.cppCPU 推理、GGUF 格式无 GPU 环境
SGLang结构化生成优化结构化输出场景

数据来源:vLLM 官方基准测试,2025。据测试,vLLM 的吞吐量比 HuggingFace Transformers 高 10-20 倍。

vLLM 部署示例

bash
# 安装 vLLM
pip install vllm

# 启动 API 服务(兼容 OpenAI 格式)
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-7B-Instruct \
    --host 0.0.0.0 \
    --port 8000 \
    --gpu-memory-utilization 0.9 \
    --max-model-len 8192 \
    --dtype auto \
    --quantization awq  # 使用 AWQ 量化
python
# 调用 vLLM API(兼容 OpenAI 格式)
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:8000/v1",
    api_key="not-needed",  # vLLM 不需要 API Key
)

response = client.chat.completions.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    messages=[{"role": "user", "content": "你好!"}],
    max_tokens=512,
    temperature=0.7,
)
print(response.choices[0].message.content)

量化方法对比

方法显存节省质量损失推理速度适用场景
GPTQ4x小(1-2%)GPU 推理
AWQ4x小(1-2%)最快GPU 推理(推荐)
GGUF2-4x中(2-5%)CPU 推理
bitsandbytes2-4x训练+推理
FP82x极小最快H100/H200 GPU

数据来源:HuggingFace 量化基准测试,2025。AWQ 在保持 98% 精度的同时,推理速度比 GPTQ 快 10-20%。

Ollama 本地部署示例

bash
# 安装 Ollama(macOS/Linux)
curl -fsSL https://ollama.ai/install.sh | sh

# 拉取模型
ollama pull qwen2.5:7b

# 运行模型
ollama run qwen2.5:7b

# 启动 API 服务
ollama serve
# API 默认在 http://localhost:11434
python
# 调用 Ollama API
import requests

response = requests.post(
    "http://localhost:11434/api/generate",
    json={
        "model": "qwen2.5:7b",
        "prompt": "什么是 RAG?",
        "stream": False,
    },
)
print(response.json()["response"])

成本控制策略

人机分工:🧑 人制定策略 / 🤖 AI 执行优化

成本优化四层架构

语义缓存实现

python
"""
语义缓存 - 相似问题不重复调用 API
节省比例:30-50%(据 LangChain 2025 测试)
"""
import hashlib
import numpy as np
from typing import Optional, List, Dict
from sentence_transformers import SentenceTransformer
import chromadb

class SemanticCache:
    """语义缓存:相似问题命中缓存"""
    
    def __init__(self, similarity_threshold: float = 0.92):
        self.model = SentenceTransformer("all-MiniLM-L6-v2")
        self.client = chromadb.Client()
        self.collection = self.client.create_collection("cache")
        self.threshold = similarity_threshold
        self.cache_data = {}
    
    def get(self, question: str) -> Optional[str]:
        """查询缓存"""
        embedding = self.model.encode(question).tolist()
        
        results = self.collection.query(
            query_embeddings=[embedding],
            n_results=1,
        )
        
        if results["distances"][0] and results["distances"][0][0] < (1 - self.threshold):
            cache_key = results["ids"][0][0]
            return self.cache_data.get(cache_key)
        
        return None
    
    def set(self, question: str, answer: str, ttl: int = 3600):
        """设置缓存"""
        cache_key = hashlib.md5(question.encode()).hexdigest()
        embedding = self.model.encode(question).tolist()
        
        self.collection.add(
            ids=[cache_key],
            embeddings=[embedding],
            metadatas=[{"question": question, "ttl": ttl}],
        )
        self.cache_data[cache_key] = answer

# 使用示例
cache = SemanticCache(similarity_threshold=0.92)

# 查询缓存
cached = cache.get("什么是 RAG?")
if cached:
    print(f"缓存命中: {cached}")
else:
    # 调用 API
    answer = call_api("什么是 RAG?")
    cache.set("什么是 RAG?", answer)
    print(f"API 调用: {answer}")

成本控制策略详解

策略说明节省比例实现复杂度
语义缓存相似问题不重复调用30-50%
模型路由简单问题用小模型40-60%
Prompt 精简减少不必要的 Token10-20%
批处理非实时请求批量处理20-40%
Token 预算限制输入长度15-25%
异步调用并发处理提升吞吐间接节省

成本对比(月调用 100 万次):

策略组合月成本节省幅度
无优化¥30,000基准
仅缓存¥18,00040%
缓存 + 路由¥10,00067%
缓存 + 路由 + Prompt 精简¥7,00077%

CI/CD 自动化部署

GitHub Actions 部署流程

yaml
# .github/workflows/deploy.yml - CI/CD 配置
name: Deploy AI App

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install -r requirements.txt
      - run: pytest tests/ -v
  
  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      # 构建 Docker 镜像
      - name: Build Docker image
        run: docker build -t myapp:${{ github.sha }} .
      
      # 推送到 Docker Hub
      - name: Push to Docker Hub
        run: |
          docker tag myapp:${{ github.sha }} myuser/myapp:latest
          docker push myuser/myapp:latest
      
      # 部署到 Railway
      - name: Deploy to Railway
        uses: bervProject/railway-deploy@main
        with:
          railway_token: ${{ secrets.RAILWAY_TOKEN }}
          service: myapp
      
      # 健康检查
      - name: Health Check
        run: |
          for i in $(seq 1 10); do
            if curl -s https://myapp.railway.app/health | grep -q "ok"; then
              echo "部署成功!"
              exit 0
            fi
            sleep 10
          done
          echo "健康检查失败,触发回滚"
          exit 1

健康检查与优雅关闭

生产环境必须实现健康检查和优雅关闭,防止请求丢失和服务中断。

python
"""
生产级 FastAPI 应用 - 健康检查 + 优雅关闭 + 中间件
"""
from fastapi import FastAPI, Request
from contextlib import asynccontextmanager
import signal
import asyncio
import time

# 全局状态:标记服务是否正在关闭
is_shutting_down = False

@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用生命周期管理"""
    # 启动时:初始化资源
    print("服务启动中...")
    yield
    # 关闭时:清理资源
    global is_shutting_down
    is_shutting_down = True
    print("服务正在优雅关闭,等待当前请求完成...")
    await asyncio.sleep(5)  # 等待当前请求完成
    print("服务已关闭")

app = FastAPI(lifespan=lifespan)

@app.middleware("http")
async def check_shutdown(request: Request, call_next):
    """关闭期间拒绝新请求"""
    if is_shutting_down and request.url.path != "/health":
        return {"status": "error", "message": "服务正在关闭"}
    return await call_next(request)

@app.get("/health")
async def health_check():
    """健康检查端点"""
    return {
        "status": "healthy" if not is_shutting_down else "shutting_down",
        "timestamp": time.time(),
        "version": "1.0.0",
    }

@app.get("/ready")
async def readiness_check():
    """就绪检查:验证依赖服务是否可用"""
    checks = {
        "api": True,      # AI API 是否可用
        "cache": True,     # Redis 是否连接
        "database": True,  # 数据库是否连接
    }
    all_healthy = all(checks.values())
    return {"status": "ready" if all_healthy else "not_ready", "checks": checks}

健康检查配置(Docker)

yaml
# docker-compose.yml 中添加健康检查
services:
  api:
    build: .
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s      # 每 30 秒检查一次
      timeout: 10s        # 超时 10 秒
      retries: 3          # 连续 3 次失败标记为不健康
      start_period: 40s   # 启动后 40 秒开始检查

部署检查清单

阶段检查项状态
部署前单元测试通过
部署前集成测试通过
部署前环境变量配置正确
部署中Docker 镜像构建成功
部署中服务启动正常
部署后健康检查通过
部署后API 响应正常
部署后监控告警就绪

常见问题

问题原因解决方案
响应慢模型太大/网络延迟流式响应+CDN+就近部署
成本高Token 消耗过多缓存+模型路由+Prompt 精简
服务不稳定API 限流重试+降级+多 Provider 兜底
部署失败依赖冲突Docker 容器化+固定版本
冷启动慢Serverless 初始化预热机制+保持实例
内存溢出并发过高限流+队列+资源监控
SSL 证书过期未配置自动续期使用 Let's Encrypt + certbot 自动续期
日志丢失未配置日志收集使用 ELK 或 Loki 收集日志
环境变量泄露代码中硬编码使用 .env 文件 + 密钥管理服务

实操案例:AI 写作助手部署

场景

一个 AI 写作助手产品,日活 1000+ 用户,日均 API 调用 5 万次。

部署架构

部署成本对比

组件方案月成本
前端Vercel Pro¥150
后端Railway¥200
数据库Supabase¥150
AI APIClaude(带路由)¥3,000
缓存Redis Cloud¥100
总计¥3,600

前后对比

指标之前(手动部署)之后(自动化)改善
部署时间30 分钟3 分钟90%↓
部署频率每周 1 次每天 3-5 次15-25x
回滚时间15 分钟30 秒97%↓
故障率5%0.5%90%↓

下一步

完成部署后,进入 阶段 6:监控与迭代


参考与延伸

[1] vLLM. "Documentation"(2025)— 高性能推理框架,PagedAttention 技术

[2] Ollama(2025)— 本地模型运行工具,一键部署

[3] Docker. "Best Practices for Python"(2025)— Python 容器化最佳实践

[4] GitHub Actions. "Documentation"(2025)— CI/CD 自动化部署

[5] Railway. "Documentation"(2025)— PaaS 部署平台

[6] Vercel. "AI Applications"(2025)— AI 应用部署平台

[7] HuggingFace. "Quantization Guide"(2025)— 模型量化方法对比

[8] SGLang. "Documentation"(2025)— 结构化生成优化框架,支持 JSON 约束输出

[9] Modal. "GPU Cloud"(2025)— GPU Serverless 平台,按秒计费,适合 AI 推理

OPC 超级个体实战指南