核心目标

本模块是课程的收官之作,旨在将我们在前序阶段训练好的模型,真正地从一个本地的、实验性的项目,转变为一个可供外部用户访问的、稳定运行的在线服务。你将学习到模型服务化、容器化部署以及持续集成/持续部署(CI/CD)等关键的工程实践,完成从算法工程师到AI应用开发工程师的最后一块拼图。

你将收获的核心能力:

  1. 模型服务化能力:学会如何将一个PyTorch模型(包括合并后的LoRA模型)封装成一个标准的、可扩展的RESTful API服务。
  2. 容器化核心技术:熟练掌握使用Docker将你的AI应用(代码、依赖、模型)打包成一个独立、可移植的镜像,彻底解决“在我电脑上能跑”的问题。
  3. 云平台实战部署:掌握如何将Docker镜像部署到对开发者最友好的平台——Hugging Face Spaces上,实现公网访问和持续部署。
  4. CI/CD工程化思维:深刻理解CI/CD是保障软件开发质量和效率的核心理念,并能亲手利用GitHub Actions实现代码提交后自动测试和部署的完整流程。
部署流程架构图
云端部署与服务
CI/CD 自动化流程
代码与版本控制
本地开发环境
7. Hugging Face Spaces自动拉取新镜像
8. 启动容器并提供API服务
9. 全球用户通过公网访问
6. GitHub Actions被触发
自动构建Docker镜像
自动推送镜像到Hugging Face Hub
5. 推送代码到GitHub仓库
2. 编写FastAPI服务代码
1. 合并LoRA权重
3. 编写Dockerfile
4. 本地构建与测试Docker镜像

4.1 模型准备与优化

在部署之前,模型本身需要经过一系列“工程化”处理,使其更适合在生产环境中运行。

4.1.1 合并LoRA权重

在微调阶段,我们得到的是一个轻量的LoRA适配器。为了方便部署,我们通常会将其与基础模型合并,生成一个完整的、独立的模型权重文件。这样做的好处是:部署时只需要加载一个模型,简化了推理代码,并且在某些情况下能略微提升推理性能。

代码示例 (merge_lora.py)

import torch
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer

# --- 配置 ---
base_model_name = "Qwen/Qwen1.5-7B-Chat" # 你的基础模型
lora_adapter_path = "./soulmate-ai-v1-adapter" # 你训练好的LoRA适配器路径
merged_model_path = "./soulmate-ai-v1-merged" # 合并后模型的保存路径

# --- 加载基础模型和分词器 ---
print(f"正在加载基础模型: {base_model_name}")
base_model = AutoModelForCausalLM.from_pretrained(
    base_model_name,
    torch_dtype=torch.float16,
    device_map="cpu", # 合并时先加载到CPU,避免显存不足
)
tokenizer = AutoTokenizer.from_pretrained(base_model_name)

# --- 加载LoRA适配器并与基础模型合并 ---
print(f"正在加载LoRA适配器: {lora_adapter_path}")
# PeftModel会自动处理加载和合并的逻辑
merged_model = PeftModel.from_pretrained(base_model, lora_adapter_path)

# 调用merge_and_unload来完成合并,并卸载PeftModel,返回一个标准的Transformer模型
merged_model = merged_model.merge_and_unload()
print("模型合并完成!")

# --- 保存合并后的模型和分词器 ---
print(f"正在保存合并后的模型至: {merged_model_path}")
merged_model.save_pretrained(merged_model_path, safe_serialization=True)
tokenizer.save_pretrained(merged_model_path)
print("模型和分词器已成功保存!")

4.1.2 (选学) 模型量化

对于资源敏感的部署环境(如免费的云平台或边缘设备),模型量化是必不可少的一步。它可以在牺牲少量精度的前提下,大幅降低模型的显存占用和(或)提升推理速度。

  • 常用量化库:
    • bitsandbytes:支持在加载模型时进行4-bit/8-bit量化(如QLoRA中使用的NF4),非常方便。
    • AutoGPTQ:一种训练后量化(Post-Training Quantization, PTQ)方法,可以实现更低的精度(如4-bit, 3-bit),通常需要一个小的校准数据集。
    • AWQ (Activation-aware Weight Quantization):一种先进的PTQ方法,声称能在极低比特下保持更好的性能。

注意:量化是一个复杂的权衡过程,需要在性能、速度和资源占用之间找到平衡点。对于初学者,可以先从bitsandbytes的4-bit加载开始。

本阶段总结

  • 模型部署的第一步是模型自身的准备。
  • 合并LoRA权重是简化部署流程的标准操作。
  • 模型量化是控制成本、提升效率的关键技术,是生产环境中常用的优化手段。

4.2 构建API服务 (使用FastAPI)

我们将使用现代、高性能的Web框架FastAPI来将模型封装成一个API服务。

4.2.1 为什么选择FastAPI?

  • 高性能:基于Starlette和Pydantic,性能与NodeJS和Go相当,是Python Web框架中的佼佼者。
  • 开发效率高:利用Python的类型提示,可以减少大量代码,并获得极佳的编辑器支持(自动补全、类型检查)。
  • 自动交互式文档:自动生成Swagger UI和ReDoc,让前端或其他服务的调用者可以非常方便地在线测试你的API,无需额外编写API文档。

4.2.2 API代码实现 (main.py)

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
import os

# --- 1. 初始化FastAPI应用 ---
app = FastAPI(
    title="SoulMate AI API",
    description="API for the SoulMate AI, a mental health assistant.",
    version="1.0.0",
)

# --- 2. 加载模型和分词器 ---
# 在生产环境中,模型应该在应用启动时加载一次,而不是在每次请求时都加载
MODEL_PATH = os.environ.get("MODEL_PATH", "./soulmate-ai-v1-merged") # 从环境变量读取模型路径,提供默认值

# 全局变量,用于存储加载的模型
text_generator = None

@app.on_event("startup")
def load_model():
    """应用启动时执行,加载模型到全局变量"""
    global text_generator
    print(f"正在从 {MODEL_PATH} 加载模型...")
    try:
        # 检查是否有可用的GPU
        device = "cuda" if torch.cuda.is_available() else "cpu"
        print(f"使用设备: {device}")
        
        model = AutoModelForCausalLM.from_pretrained(MODEL_PATH, torch_dtype=torch.float16, device_map="auto")
        tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)
        
        # 使用Hugging Face Pipeline简化推理调用
        text_generator = pipeline(
            "text-generation", 
            model=model, 
            tokenizer=tokenizer, 
            max_new_tokens=512
        )
        print("模型加载完成!")
    except Exception as e:
        print(f"模型加载失败: {e}")
        # 如果模型加载失败,text_generator将保持为None

# --- 3. 定义请求和响应的数据模型 ---
# 使用Pydantic模型可以进行数据验证和自动生成API文档
class ChatRequest(BaseModel):
    user_input: str
    system_prompt: str = "你是一个温暖、有同理心的心理健康助手。你的回答应该基于科学知识,同时充满关怀。请记住,你不能提供专业诊断。"

class ChatResponse(BaseModel):
    response: str

# --- 4. 创建API端点 ---
@app.post("/chat", response_model=ChatResponse)
def chat_with_ai(request: ChatRequest):
    """
    接收用户输入并返回模型的响应。
    """
    if text_generator is None:
        raise HTTPException(status_code=503, detail="模型正在加载或加载失败,请稍后再试。")

    prompt = f"### Instruction:\n{request.system_prompt} 现在,请回答用户的问题:{request.user_input}\n\n### Response:\n"
    
    try:
        generated_outputs = text_generator(prompt)
        if generated_outputs and len(generated_outputs) > 0:
            generated_text = generated_outputs[0]['generated_text']
            # 提取模型真正的输出部分
            response_text = generated_text.split("### Response:\n")[1].strip()
            return ChatResponse(response=response_text)
        else:
            raise HTTPException(status_code=500, detail="模型生成了空的响应。")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"模型推理时发生错误: {e}")

# --- 5. 添加一个根路径用于健康检查 ---
@app.get("/")
def read_root():
    if text_generator is None:
        return {"status": "API is running, but model is not loaded yet."}
    return {"status": "API is running and model is loaded."}

# --- 运行 (使用uvicorn) ---
# 在命令行中运行: uvicorn main:app --host 0.0.0.0 --port 8000

本阶段总结

  • FastAPI是构建AI服务API的理想选择。
  • 通过Pydantic模型定义请求和响应体,可以实现数据校验和文档自动生成。
  • 模型应该在应用启动时加载,而不是在每次API请求时重复加载,这是生产服务的基本原则。使用@app.on_event("startup")是实现这一点的标准方式。

4.3 应用容器化 (使用Docker)

Docker可以将我们的应用及其所有依赖(Python库、系统工具、甚至模型文件)打包到一个标准的、可移植的容器中。

4.3.1 编写Dockerfile

Dockerfile是一个蓝图,定义了如何一步步构建我们的应用镜像。

# 1. 使用一个包含CUDA和Python的基础镜像
# 为了在Hugging Face Spaces上使用GPU,推荐使用官方提供的镜像
FROM huggingface/transformers-pytorch-gpu:latest

# 2. 设置工作目录
WORKDIR /app

# 3. 复制依赖文件并安装
# 将requirements.txt复制到镜像中,可以利用Docker的层缓存机制
# 只有当requirements.txt改变时,才会重新执行pip install
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 4. 复制应用代码和模型文件
# 将当前目录下的所有文件(代码、合并后的模型等)复制到镜像的/app目录下
COPY . .

# 5. 暴露端口
# 告诉Docker容器在运行时监听哪个端口
EXPOSE 8000

# 6. 定义启动命令
# 当容器启动时,执行此命令
# 使用--host 0.0.0.0来允许外部访问
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

4.3.2 编写requirements.txt

fastapi
uvicorn[standard]
python-dotenv
transformers
torch
accelerate
bitsandbytes
# 根据你的模型和代码,可能需要添加其他依赖

4.3.3 构建与测试Docker镜像

  1. 构建镜像:在包含Dockerfile的目录下运行:
    docker build -t soulmate-ai-api:latest .
    
  2. 运行容器:
    # --gpus all 表示允许容器使用宿主机的所有GPU
    # -p 8000:8000 将宿主机的8000端口映射到容器的8000端口
    # -v $(pwd)/soulmate-ai-v1-merged:/app/soulmate-ai-v1-merged 将本地模型目录挂载到容器中,便于调试
    docker run --gpus all -p 8000:8000 -v $(pwd)/soulmate-ai-v1-merged:/app/soulmate-ai-v1-merged soulmate-ai-api:latest
    
  3. 测试API:打开浏览器或使用curl访问 http://localhost:8000,你应该能看到健康检查的返回。然后可以测试/chat端点。

本阶段总结

  • Docker是实现“一次构建,到处运行”的关键技术。
  • 一个好的Dockerfile应该结构清晰,并能有效利用层缓存来加速构建。
  • 在本地构建和测试Docker镜像是确保其在云端能正常运行的重要步骤。

4.4 部署到Hugging Face Spaces

Hugging Face Spaces是一个专门为托管AI应用(模型、数据集、应用)而设计的平台,对开发者极其友好。

4.4.1 创建Space

  1. 登录Hugging Face Hub。
  2. 点击右上角头像,选择“New Space”。
  3. 命名你的Space(例如:your-username/soulmate-ai-api)。
  4. 选择SDK:选择Docker。
  5. 选择硬件:可以选择免费的CPU,或者升级到T4等GPU硬件(推荐)。
  6. 点击“Create Space”。

4.4.2 配置Space

创建后,你会得到一个类似于GitHub仓库的页面。你需要将你的main.py, requirements.txt, 和 Dockerfile推送到这个仓库。

关键:你不需要推送庞大的模型文件!Hugging Face Spaces可以让你直接从Hub上的另一个模型仓库动态加载模型。

  1. 上传模型:将你合并后的模型(soulmate-ai-v1-merged文件夹)上传到一个新的模型仓库(Model Repository)中。
  2. 在Space中配置模型路径:在你的Space的Settings页面,找到Secrets部分,添加一个名为MODEL_PATH的Secret,其值就是你刚刚上传的模型仓库ID,例如your-username/soulmate-ai-v1-merged。

4.4.3 部署

将你的代码(main.py, Dockerfile, requirements.txt)推送到Space的Git仓库后,Hugging Face Spaces会自动开始构建Docker镜像并启动你的应用。你可以在“Logs”标签页查看构建和运行日志。

4.4.4 (进阶) 使用GitHub Actions实现CI/CD

为了实现更专业的开发流程,我们可以设置一个GitHub Action,当我们向GitHub主分支推送代码时,自动将代码同步到Hugging Face Space,从而触发自动重新部署。

在你的GitHub仓库中创建.github/workflows/sync-to-hub.yml:

name: Sync to Hugging Face Hub

on:
  push:
    branches:
      - main # 只在main分支有push时触发

jobs:
  sync-to-hub:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Push to Hub
        uses: simonw/push-to-hub@v1
        env:
          HF_TOKEN: ${{ secrets.HF_TOKEN }} # 在GitHub仓库的Secrets中设置你的HF_TOKEN
          HF_USERNAME: your-hf-username
          HF_REPO_ID: soulmate-ai-api # 你的Space仓库ID
          HF_REPO_TYPE: space
          GIT_USER: your-github-username
          GIT_EMAIL: your-email@example.com

本阶段总结

  • Hugging Face Spaces是部署AI应用最简单、最快捷的平台之一。
  • 将模型与代码分离是一个重要的部署实践,可以减小应用镜像的体积,并方便模型的独立管理和更新。
  • CI/CD是现代软件开发的标准实践,能极大地提升开发效率和部署的可靠性。
Logo

聚焦RDK与具身智能,汇集机器人开发教程、开源案例和技术交流

更多推荐