Skip to content

模型部署实战教程

一篇面向 AI 应用开发者的模型部署完整指南——从本地跑通到线上服务,手把手覆盖每一步。


一、为什么需要这篇教程

你大概率已经用过 OpenAI、Claude 或者通义千问的 API——传一个请求,拿回一段文本,非常方便。但当你开始认真做产品,几个现实问题会接踵而来:

  • 成本:GPT-4 级别的 API 按 token 计费,日调用量上万次之后账单会变得很刺眼
  • 隐私:客户数据不能发到第三方服务器,合规要求你必须自建
  • 延迟:跨境调用 OpenAI API 动辄 2–5 秒,国内用户体验很差
  • 可控性:闭源 API 随时可能涨价、限流、甚至下线模型

这时候,部署一个自己的开源模型就成了刚需。

1.1 教程定位与读者画像

这篇教程和《2.4 模型部署与推理》的区别在于:那篇是"地图",告诉你有哪些技术和方案;这篇是"导航",手把手带你跑通每一步

你会在这篇教程里看到具体的命令、完整的代码、真实的截图,而不只是概念介绍。

适合你的前提

  • 有 Python 基础(能写 FastAPI 接口)
  • 用过至少一个 LLM API(OpenAI / Claude / 通义千问 都算)
  • 想部署开源模型(Qwen、LLaMA、DeepSeek 等),但还没跑通过
  • Mac / Linux / Windows 任一系统都可以

不适合的情况

  • 你只是想调 API,不需要自己部署 → 直接用闭源 API 就好
  • 你需要训练或微调模型 → 请看《2.3 模型微调》

1.2 本地 vs 线上:两条路线概览

本教程围绕两条主线展开,你可以根据自己的场景选择阅读路径:

路线一:本地部署

在你自己的电脑或公司内网服务器上运行模型。

  • 适用场景:个人实验、本地开发调试、数据隐私要求高、内网环境
  • 硬件要求:Mac(Apple Silicon)、Windows / Linux(NVIDIA 显卡最佳,CPU 也能跑)
  • 代表方案:Ollama、LM Studio、llama.cpp、vLLM、Xinference

路线二:线上部署

把模型部署到云端,通过公网 API 对外提供服务。

  • 适用场景:产品上线、多用户并发、没有本地 GPU、需要弹性扩缩容
  • 两种子路线:
    • Serverless 平台(零运维):硅基流动、Replicate、Modal
    • GPU 云服务器自建(完全可控):AutoDL + vLLM、阿里云 PAI

两条路线并不互斥——最常见的工作流是:本地用 Ollama 开发调试,确认效果后切到云端 vLLM 上线。本教程第六章的实战项目就是这个流程。

开发流程推荐路径
═══════════════════════════════════════════════════════
 本地 Ollama       ──▶  确认效果  ──▶  云端 vLLM 上线
(快速迭代、零成本)   (Prompt/参数调优)  (高并发、稳定服务)
═══════════════════════════════════════════════════════

1.3 前置准备(硬件检查、环境依赖)

在动手之前,花 2 分钟检查一下你的环境。

硬件自检

你的设备能跑什么推荐方案
Mac M1/M2/M3/M4(16 GB+)7B 模型流畅,14B 可用Ollama / LM Studio
Windows / Linux + RTX 3060(12 GB)7B 模型流畅Ollama / vLLM
Windows / Linux + RTX 4090(24 GB)14B 流畅,70B 量化后可用vLLM / Ollama
纯 CPU(无独显)7B 量化模型(较慢但能用)llama.cpp / Ollama
云服务器 A100(80 GB)70B+ 模型vLLM

💡 经验法则:模型参数量(十亿)× 0.5 ≈ 4-bit 量化后所需显存(GB)。比如 7B 模型约需 3.5 GB 显存,14B 约需 7 GB。

软件依赖

bash
# 确认 Python 版本(推荐 3.10+)
python3 --version

# 确认 pip 可用
pip3 --version

# 如果有 NVIDIA 显卡,确认 CUDA 环境
nvidia-smi  # 应显示驱动版本和 GPU 信息

如果你用 Mac,不需要额外安装 CUDA——Ollama 和 llama.cpp 会自动使用 Metal 加速。

准备就绪,接下来我们从最简单的本地方案开始。


二、本地部署方案

本地部署的核心价值:零成本、零延迟、完全隐私。从个人实验到团队内网服务,这一章覆盖 6 个主流方案,由简到繁。

2.1 Ollama:最推荐的入门方案

Ollama 的设计哲学和 Docker 很像——一个命令下载模型,一个命令运行模型,自动提供 API 服务。如果你只看一个方案,看这个就够了。

安装

bash
# macOS / Linux:一行命令安装
curl -fsSL https://ollama.com/install.sh | sh

# Windows:从 https://ollama.com 下载安装包

# 验证安装
ollama --version

运行模型

bash
# 下载并运行(首次会自动下载模型,后续直接启动)
ollama run qwen2.5:7b          # Qwen 2.5 7B(推荐,中文能力强)
ollama run llama3.1:8b         # LLaMA 3.1 8B
ollama run deepseek-r1:8b      # DeepSeek-R1 蒸馏版(推理能力强)
ollama run gemma2:9b           # Google Gemma 2 9B

# 查看已下载的模型
ollama list

# 删除不需要的模型
ollama rm llama3.1:8b

运行后会进入交互式对话,直接在终端里和模型聊天。按 Ctrl+D 退出。

API 服务

Ollama 启动后自动在 localhost:11434 提供 OpenAI 兼容的 API,无需额外配置:

bash
# 确认服务正在运行
curl http://localhost:11434/api/tags

# 用 curl 测试对话接口
curl http://localhost:11434/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen2.5:7b",
    "messages": [{"role": "user", "content": "用一句话解释什么是 Docker"}]
  }'
python
# Python 调用(使用 openai 库,和调 OpenAI API 完全一样)
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:11434/v1",
    api_key="ollama"  # Ollama 不验证 key,随便填
)

response = client.chat.completions.create(
    model="qwen2.5:7b",
    messages=[{"role": "user", "content": "用 Python 实现快速排序"}]
)
print(response.choices[0].message.content)

💡 因为 Ollama 兼容 OpenAI API 格式,你的应用代码几乎零改动就能在闭源 API 和本地模型之间切换——只需要改 base_url

Modelfile:自定义模型

Modelfile 类似 Dockerfile,用来创建预配置的模型:

dockerfile
# 文件名:Modelfile-reviewer
FROM qwen2.5:7b
SYSTEM "你是一个资深的 Python 代码审查专家。你只关注:1. 安全漏洞 2. 性能问题 3. 代码可维护性。对每个问题给出修复建议和代码示例。"
PARAMETER temperature 0.3
PARAMETER num_ctx 8192
bash
# 创建自定义模型
ollama create code-reviewer -f Modelfile-reviewer

# 运行自定义模型
ollama run code-reviewer

这在 RAG 应用、Agent 开发中非常实用——你可以为不同任务创建不同的预配置模型,而不需要每次都塞一大段 System Prompt。

2.2 LM Studio:图形界面方案

如果你不想碰命令行,或者需要给非技术同事演示,LM Studio 是最好的选择。它提供了一个类似 ChatGPT 的桌面客户端,内置模型搜索、下载、对话、API 服务全部功能。

安装:从 lmstudio.ai 下载对应系统的安装包(支持 macOS / Windows / Linux),双击安装即可。

核心功能

  1. 模型发现与下载:内置 Hugging Face 搜索,支持按模型大小、量化级别筛选。推荐搜索 GGUF 格式的模型(如 Qwen2.5-7B-Instruct-GGUF),下载速度比命令行快
  2. 聊天界面:和 ChatGPT 体验一致,支持多轮对话、System Prompt 配置、参数调节(温度、Top-P 等)
  3. 本地 API 服务器:一键开启 OpenAI 兼容的本地 API,默认端口 1234

启动 API 服务

在 LM Studio 左侧栏点击「Local Server」→ 选择已下载的模型 → 点击「Start Server」。

python
# Python 调用 LM Studio 的 API
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:1234/v1",
    api_key="lm-studio"
)

response = client.chat.completions.create(
    model="qwen2.5-7b-instruct",  # 模型名在 LM Studio 界面可以看到
    messages=[{"role": "user", "content": "解释一下什么是向量数据库"}]
)
print(response.choices[0].message.content)

LM Studio vs Ollama

  • LM Studio 胜在可视化体验——模型搜索、参数调节、对话测试都在 GUI 里完成
  • Ollama 胜在自动化和集成——命令行操作更适合脚本化、CI/CD、Docker 容器
  • 两者都提供 OpenAI 兼容 API,客户端代码可以无缝切换

2.3 llama.cpp + llama-cpp-python:CPU / Apple Silicon 极致方案

llama.cpp 是所有本地推理方案的"底层引擎"——Ollama 和 LM Studio 底层都在用它。直接使用 llama.cpp 的好处是:最大程度的控制权最广泛的硬件支持

它是唯一能让大模型在纯 CPU 环境下流畅运行的方案,同时也支持 CUDA(N 卡)、Metal(Mac)、Vulkan 等 GPU 加速后端。

安装方式一:用 Python 绑定(推荐)

如果你主要用 Python 开发,llama-cpp-python 是最方便的选择:

bash
# 基础安装(CPU 推理)
pip install llama-cpp-python

# Mac 用户(启用 Metal GPU 加速)
CMAKE_ARGS="-DGGML_METAL=on" pip install llama-cpp-python

# NVIDIA 显卡用户(启用 CUDA 加速)
CMAKE_ARGS="-DGGML_CUDA=on" pip install llama-cpp-python

下载 GGUF 模型

llama.cpp 使用 GGUF 格式的模型文件。去 Hugging Face 搜索带 GGUF 标签的模型:

bash
# 推荐用 huggingface-cli 下载
pip install huggingface_hub
huggingface-cli download Qwen/Qwen2.5-7B-Instruct-GGUF \
    qwen2.5-7b-instruct-q4_k_m.gguf \
    --local-dir ./models

💡 量化等级选择:Q4_K_M 是最常用的平衡点——模型大小约为原始的 30%,质量损失几乎感知不到。Q8_0 质量更高但更大,Q2_K 最小但质量明显下降。

Python 调用

python
from llama_cpp import Llama

# 加载模型
llm = Llama(
    model_path="./models/qwen2.5-7b-instruct-q4_k_m.gguf",
    n_ctx=8192,      # 上下文长度
    n_gpu_layers=-1,  # -1 表示全部层都加载到 GPU(Mac Metal / CUDA)
    verbose=False
)

# 对话
response = llm.create_chat_completion(
    messages=[
        {"role": "system", "content": "你是一个有帮助的助手。"},
        {"role": "user", "content": "解释一下 GGUF 格式是什么"}
    ],
    temperature=0.7,
    max_tokens=512
)
print(response["choices"][0]["message"]["content"])

也可以启动 OpenAI 兼容的 API 服务

bash
python -m llama_cpp.server \
    --model ./models/qwen2.5-7b-instruct-q4_k_m.gguf \
    --n_gpu_layers -1 \
    --host 0.0.0.0 \
    --port 8000

启动后就可以用 openai 库调用 http://localhost:8000/v1,和 Ollama、LM Studio 的客户端代码完全通用。

什么时候选 llama.cpp 而不是 Ollama

  • 需要精确控制 GPU 层数分配(部分 GPU + 部分 CPU 的混合推理)
  • 需要使用最新的 GGUF 模型(Ollama 的模型库更新有延迟)
  • 需要嵌入到 C/C++ 项目中
  • 需要在树莓派、嵌入式设备等极端环境运行

2.4 vLLM 本地部署:有 N 卡就上生产级

如果你的电脑或工作站有 NVIDIA 显卡(最好 12 GB 以上显存),vLLM 能给你本地最强的推理性能。它的核心技术 PagedAttention 让显存利用率远超其他方案,同样的硬件能跑更大的模型、服务更多的并发。

⚠️ vLLM 目前只支持 NVIDIA GPU(CUDA),Mac 和 AMD 显卡用户请用 Ollama 或 llama.cpp。

安装

bash
# 推荐在虚拟环境中安装
python -m venv vllm-env
source vllm-env/bin/activate

# 安装 vLLM(会自动安装 PyTorch + CUDA 依赖)
pip install vllm

启动推理服务

bash
# 启动 OpenAI 兼容的 API 服务(模型会自动从 Hugging Face 下载)
vllm serve qwen/Qwen2.5-7B-Instruct \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 8192

# 如果有多张显卡,可以用张量并行
vllm serve qwen/Qwen2.5-7B-Instruct \
    --tensor-parallel-size 2 \
    --host 0.0.0.0 \
    --port 8000

客户端调用

python
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="unused")

# 普通调用
response = client.chat.completions.create(
    model="qwen/Qwen2.5-7B-Instruct",
    messages=[{"role": "user", "content": "解释 PagedAttention 的原理"}]
)
print(response.choices[0].message.content)

# 流式调用
stream = client.chat.completions.create(
    model="qwen/Qwen2.5-7B-Instruct",
    messages=[{"role": "user", "content": "写一个 FastAPI 的 hello world"}],
    stream=True
)
for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

加载量化模型(节省显存):

bash
# 加载 AWQ 量化模型(显存占用减半)
vllm serve Qwen/Qwen2.5-7B-Instruct-AWQ \
    --quantization awq \
    --max-model-len 8192

# 加载 GPTQ 量化模型
vllm serve Qwen/Qwen2.5-7B-Instruct-GPTQ-Int4 \
    --quantization gptq \
    --max-model-len 8192

vLLM vs Ollama 本地对比

维度vLLMOllama
推理速度更快(PagedAttention)够用
并发能力强(Continuous Batching)默认单并发
显卡要求必须 NVIDIA支持任意硬件
安装复杂度较高(CUDA 依赖)极低
适用场景本地高性能服务个人实验、快速开发

2.5 Xinference:多模型统一管理平台

Xinference(Xorbits Inference)的独特价值在于:一个平台同时管理 LLM、Embedding 模型、Rerank 模型、图像模型。如果你在做 RAG 应用,需要同时跑对话模型 + 向量模型 + 重排模型,Xinference 比分别用三个工具方便得多。

安装与启动

bash
pip install "xinference[all]"

# 启动 Xinference 服务(默认端口 9997)
xinference-local --host 0.0.0.0 --port 9997

启动后打开 http://localhost:9997,会看到一个 Web 管理界面——可以在浏览器里搜索、下载、启动模型。

通过 Web UI 部署模型

  1. 打开 http://localhost:9997 → 点击「Launch Model」
  2. 选择模型类型(LLM / Embedding / Rerank)
  3. 选择具体模型(如 qwen2.5-instruct)和量化级别
  4. 点击部署,等待模型下载和加载

通过命令行部署

bash
# 部署 LLM
xinference launch \
    --model-name qwen2.5-instruct \
    --size-in-billions 7 \
    --model-format ggufv2 \
    --quantization q4_k_m

# 部署 Embedding 模型(RAG 用)
xinference launch \
    --model-name bge-m3 \
    --model-type embedding

# 部署 Rerank 模型(RAG 用)
xinference launch \
    --model-name bge-reranker-v2-m3 \
    --model-type rerank

API 调用(兼容 OpenAI 格式):

python
from openai import OpenAI

client = OpenAI(base_url="http://localhost:9997/v1", api_key="xinference")

# 调用 LLM
response = client.chat.completions.create(
    model="qwen2.5-instruct",
    messages=[{"role": "user", "content": "什么是 RAG?"}]
)

# 调用 Embedding
embedding = client.embeddings.create(
    model="bge-m3",
    input="这是一段需要向量化的文本"
)

适用场景:本地 RAG 全流程开发(LLM + Embedding + Rerank 一站式)、需要同时管理多个不同类型模型的团队。

2.6 LocalAI:OpenAI API 的本地替代

LocalAI 的目标很明确:做一个 OpenAI API 的完整本地替代品。它不仅支持对话补全,还支持 Embedding、TTS(语音合成)、STT(语音识别)、图像生成等 OpenAI API 的全部端点。

Docker 一键启动(推荐):

bash
# 基础版(CPU)
docker run -p 8080:8080 --name local-ai \
    -v ./models:/models \
    localai/localai:latest

# GPU 版(NVIDIA)
docker run -p 8080:8080 --gpus all --name local-ai \
    -v ./models:/models \
    localai/localai:latest-gpu-nvidia-cuda-12

启动后打开 http://localhost:8080,会看到一个模型管理界面。可以从内置的模型库一键安装模型,也可以手动放入 GGUF 文件。

API 调用(完全兼容 OpenAI 格式):

python
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8080/v1", api_key="local-ai")

# 对话
response = client.chat.completions.create(
    model="qwen2.5-7b-instruct",
    messages=[{"role": "user", "content": "你好"}]
)

# Embedding(如果安装了 Embedding 模型)
embedding = client.embeddings.create(
    model="text-embedding-ada-002",  # LocalAI 可以用兼容的模型名
    input="需要向量化的文本"
)

什么时候选 LocalAI

  • 你的项目大量使用 OpenAI SDK,想要一个 drop-in 的本地替代(连模型名都可以保持一致)
  • 需要一个 Docker 容器内集成多种 AI 能力(对话 + Embedding + TTS)
  • 偏好容器化部署,不想在宿主机安装依赖

2.7 本地方案横向对比与选型建议

六个方案各有侧重,一张表帮你快速决策:

方案上手难度硬件要求推理性能多模型管理API 兼容最佳场景
Ollama⭐ 极低任意★★★基础OpenAI个人开发、快速实验
LM Studio⭐ 极低任意★★★GUI 管理OpenAI非技术人员、演示
llama.cpp⭐⭐⭐ 中任意(CPU 友好)★★★★OpenAI极致控制、嵌入式
vLLM⭐⭐⭐ 中NVIDIA GPU★★★★★OpenAI高并发本地服务
Xinference⭐⭐ 低任意★★★强(多类型)OpenAIRAG 全流程、多模型
LocalAI⭐⭐ 低任意★★★Docker 内置OpenAI(全端点)OpenAI 完整替代

快速选型指南

你的场景是什么?

├── 个人实验 / 学习 ──────────────▶ Ollama(最省心)

├── 给非技术人员演示 ────────────▶ LM Studio(有 GUI)

├── Mac 开发 / CPU 服务器 ──────▶ Ollama 或 llama.cpp

├── 有 N 卡,要高并发 ──────────▶ vLLM

├── RAG 应用(LLM + Embedding)──▶ Xinference

└── Docker 部署,要完整 API ────▶ LocalAI

💡 务实建议:如果你不确定选哪个,从 Ollama 开始。它能覆盖 80% 的本地使用场景,等你遇到了它解决不了的问题(比如需要更高并发、需要多模型管理),再切换到对应的方案。

2.8 本地模型接入应用(Python / JS 客户端调用示例)

因为上面所有方案都兼容 OpenAI API 格式,你可以写一个通用的客户端封装,通过配置切换不同的后端:

Python 通用封装

python
from openai import OpenAI

# 只需要改这两行,就能切换不同的本地后端
CONFIGS = {
    "ollama":      {"base_url": "http://localhost:11434/v1", "model": "qwen2.5:7b"},
    "lm_studio":   {"base_url": "http://localhost:1234/v1",  "model": "qwen2.5-7b-instruct"},
    "vllm":        {"base_url": "http://localhost:8000/v1",  "model": "qwen/Qwen2.5-7B-Instruct"},
    "xinference":  {"base_url": "http://localhost:9997/v1",  "model": "qwen2.5-instruct"},
    "localai":     {"base_url": "http://localhost:8080/v1",  "model": "qwen2.5-7b-instruct"},
}

def get_client(backend: str = "ollama"):
    config = CONFIGS[backend]
    client = OpenAI(base_url=config["base_url"], api_key="local")
    return client, config["model"]

# 使用
client, model = get_client("ollama")  # 切换后端只需改这里
response = client.chat.completions.create(
    model=model,
    messages=[{"role": "user", "content": "你好"}]
)
print(response.choices[0].message.content)

JavaScript(前端 fetch 调用)

javascript
// 前端直接调用本地 API(开发环境)
async function chat(message, baseUrl = "http://localhost:11434") {
  const response = await fetch(`${baseUrl}/v1/chat/completions`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      model: "qwen2.5:7b",
      messages: [{ role: "user", content: message }],
      stream: true,
    }),
  });

  // 处理流式输出
  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    const chunk = decoder.decode(value);
    const lines = chunk.split("\n").filter((line) => line.startsWith("data: "));

    for (const line of lines) {
      const data = line.slice(6); // 去掉 "data: " 前缀
      if (data === "[DONE]") return;
      const parsed = JSON.parse(data);
      const content = parsed.choices[0]?.delta?.content;
      if (content) process.stdout.write(content); // 或更新 DOM
    }
  }
}

💡 这就是 OpenAI 兼容 API 的最大好处:你的应用代码和底层推理引擎完全解耦。开发时用 Ollama,上线时切 vLLM,甚至回退到 OpenAI API——只需要改一个 URL。


三、线上部署方案(一):Serverless 推理平台

线上部署的第一条路线:把推理交给平台,你只管调 API。不需要选机器、装驱动、管容器,按调用量付费,适合快速上线和流量不稳定的场景。

3.1 什么时候选 Serverless

Serverless 推理平台的本质是:别人帮你把 vLLM / TGI 搭好了,你直接用

适合选 Serverless 的情况:

  • 快速验证:产品还在 MVP 阶段,不确定有没有人用,不值得花时间搭基础设施
  • 流量波动大:白天高峰、晚上没人,Serverless 自动扩缩容,不用为闲置 GPU 付费
  • 没有运维能力:团队没有 GPU 服务器管理经验,不想踩 CUDA 驱动的坑
  • 合规要求:国内业务选国内平台(硅基流动、火山引擎),避免数据出境问题

不适合的情况:

  • 持续高并发:如果 GPU 需要 7×24 跑满,自建比 Serverless 便宜得多
  • 极致延迟要求:Serverless 平台可能有冷启动延迟(首次请求慢 5–30 秒)
  • 自定义模型:大多数平台只支持热门开源模型,微调过的私有模型需要自建
成本粗算
═══════════════════════════════════════════════════
场景:7B 模型,日均 1 万次请求,每次 ~500 token

Serverless(硅基流动):约 ¥50–100/天
自建(AutoDL A10):约 ¥30–50/天(含闲置时间)
自建(自有 4090):约 ¥5/天(电费)

结论:日请求 < 5000 次时 Serverless 更划算
       日请求 > 10000 次时自建开始有优势
═══════════════════════════════════════════════════

3.2 硅基流动:国内首选(注册→部署→调用全流程)

硅基流动(SiliconFlow)是目前国内最受开发者欢迎的 Serverless 推理平台,模型丰富、价格低、兼容 OpenAI API 格式。新用户还有免费额度可以体验。

Step 1:注册与获取 API Key

  1. 打开 siliconflow.cn,注册账号
  2. 进入控制台 → 「API 密钥」→ 创建新密钥
  3. 复制 API Key,保存好(只显示一次)

Step 2:查看可用模型

硅基流动支持主流开源模型,常用的包括:

模型模型 ID适用场景
Qwen2.5-7BQwen/Qwen2.5-7B-Instruct通用对话、中文任务
Qwen2.5-72BQwen/Qwen2.5-72B-Instruct复杂推理、高质量生成
DeepSeek-R1deepseek-ai/DeepSeek-R1强推理、数学、代码
GLM-4-9BTHUDM/glm-4-9b-chat通用对话

💡 平台会持续更新模型列表,最新支持的模型以官网为准。部分小模型(如 Qwen2.5-7B)有永久免费额度。

Step 3:Python 调用

python
from openai import OpenAI

client = OpenAI(
    base_url="https://api.siliconflow.cn/v1",
    api_key="sk-xxxxxxxxxxxxx"  # 替换为你的 API Key
)

# 普通调用
response = client.chat.completions.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    messages=[
        {"role": "system", "content": "你是一个专业的技术文档写手。"},
        {"role": "user", "content": "用 200 字解释什么是 RAG"}
    ],
    temperature=0.7,
    max_tokens=1024
)
print(response.choices[0].message.content)

# 流式调用
stream = client.chat.completions.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    messages=[{"role": "user", "content": "写一个 Python 装饰器教程"}],
    stream=True
)
for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

Step 4:调用 Embedding 模型(RAG 场景)

python
# 硅基流动也支持 Embedding 模型
embedding = client.embeddings.create(
    model="BAAI/bge-m3",
    input="这段文本需要转成向量"
)
print(f"向量维度:{len(embedding.data[0].embedding)}")

计费说明:按 token 计费,不同模型价格不同。7B 模型约 ¥0.5/百万 token,72B 模型约 ¥4/百万 token。新用户有免费额度,小模型部分请求永久免费。

💡 从本地切到硅基流动只需要改两行:把 base_urlhttp://localhost:11434/v1 改成 https://api.siliconflow.cn/v1,把 api_key 填上真实的 Key。其他代码完全不用动。

3.3 Replicate / Modal:海外方案

如果你的用户主要在海外,或者需要用一些国内平台还没上架的模型,两个海外平台值得了解。

Replicate

Replicate 的特色是"一行代码跑模型",模型生态非常丰富(不只是 LLM,还有图像、音频、视频模型)。

python
import replicate

# 安装:pip install replicate
# 设置环境变量:export REPLICATE_API_TOKEN=r8_xxxxx

output = replicate.run(
    "meta/llama-2-70b-chat",
    input={
        "prompt": "Explain quantum computing in simple terms",
        "max_tokens": 500,
        "temperature": 0.7
    }
)
# output 是一个生成器,逐 token 返回
for token in output:
    print(token, end="", flush=True)
  • 按秒计费,冷启动优化较好(通常 2–5 秒)
  • 支持自定义 Docker 镜像部署私有模型
  • 官网:replicate.com

Modal

Modal 更偏向"Serverless GPU 计算平台"——你可以把任意 Python 函数部署成 GPU 服务,不限于 LLM 推理。

python
import modal

# 定义一个 GPU 函数
app = modal.App("my-llm-service")

@app.function(gpu="A10G", image=modal.Image.debian_slim().pip_install("vllm"))
def generate(prompt: str):
    from vllm import LLM, SamplingParams
    llm = LLM(model="Qwen/Qwen2.5-7B-Instruct")
    outputs = llm.generate([prompt], SamplingParams(temperature=0.7, max_tokens=512))
    return outputs[0].outputs[0].text

# 本地调用远程 GPU 函数
with app.run():
    result = generate.remote("What is RAG?")
    print(result)
  • 按 GPU 秒计费,支持 A10G / A100 / H100
  • 可以将 vLLM 直接部署为 Serverless 端点
  • 冷启动可配置预热策略(keep-warm)
  • 官网:modal.com

海外平台 vs 国内平台

维度硅基流动ReplicateModal
国内访问速度慢(需代理)慢(需代理)
中文模型支持丰富较少自己部署
计费方式按 token按秒按 GPU 秒
灵活性只能用平台模型可自定义完全自定义
适用场景国内业务海外业务、多模态自定义推理逻辑

3.4 Hugging Face Inference Endpoints

Hugging Face 的 Inference Endpoints 是一个"独占实例"方案——你选一个模型,HF 帮你在云端启一台 GPU 机器跑起来,按小时计费。

和前面的 Serverless 平台不同,它不是按请求计费,而是按运行时间计费。适合需要稳定在线服务、但不想自己管服务器的场景。

创建步骤

  1. 打开 huggingface.co/inference-endpoints
  2. 点击「Create Endpoint」
  3. 选择模型(可以是 HF Hub 上任意公开模型,也可以是你的私有模型)
  4. 选择 GPU 类型和区域(如 AWS us-east-1 / A10G)
  5. 点击创建,等待部署(通常 2–5 分钟)

API 调用

python
from openai import OpenAI

# Endpoint URL 在 HF 控制台可以看到
client = OpenAI(
    base_url="https://xxxxx.endpoints.huggingface.cloud/v1",
    api_key="hf_xxxxxxxxxxxxx"  # Hugging Face Token
)

response = client.chat.completions.create(
    model="tgi",  # HF Endpoints 默认模型名
    messages=[{"role": "user", "content": "What is transfer learning?"}],
    max_tokens=512
)
print(response.choices[0].message.content)

优缺点

  • ✅ 支持 HF Hub 上任意模型(包括你微调后上传的私有模型)
  • ✅ 底层用 TGI,性能有保障
  • ✅ 支持自动扩缩容(Scale-to-zero:没请求时自动关机,省钱)
  • ❌ 价格较贵(A10G 约 $1.3/小时,A100 约 $6.5/小时)
  • ❌ 服务器在海外,国内访问延迟高

适用场景:你有微调过的私有模型上传在 HF Hub,需要快速部署一个稳定的推理端点,且用户主要在海外。


四、线上部署方案(二):GPU 云服务器自建

线上部署的第二条路线:租一台有 GPU 的云服务器,自己搭推理服务。完全可控,适合有稳定流量且需要定制化的场景。

4.1 什么时候选自建

自建意味着你要自己处理环境安装、服务启动、监控告警、扩缩容等运维工作。这些事并不轻松,所以先确认你是否真的需要自建:

值得自建的情况

  • 持续高并发:GPU 需要 7×24 跑满,此时自建比 Serverless 平台便宜 50%+
  • 私有模型:微调过的模型不想上传到第三方平台,需要完全掌控
  • 定制化需求:需要特殊的推理参数、自定义的前后处理逻辑、LoRA 动态加载等
  • 内网部署:企业安全要求服务不能暴露在公网,需要部署在公司内网或 VPC

不值得自建的情况

  • 日请求量 < 5000 次 → Serverless 更省钱省心
  • 团队没人懂 Linux / Docker / CUDA → 运维成本远超你的预期
  • 产品还在验证阶段 → 先用 API 跑通,确认有需求再自建

💡 经验之谈:很多团队在产品上线前就花了两周搭 GPU 服务,结果上线后发现没人用。先用闭源 API / Serverless 验证需求,再自建,能避免大量资源浪费。

4.2 GPU 云平台选型(AutoDL / 阿里云 / RunPod)

主流 GPU 云平台对比:

平台定位GPU 选择价格参考优势劣势
AutoDL国内个人/中小团队RTX 4090 / A100 / A8004090: ~¥2/时, A100: ~¥6/时性价比极高、镜像丰富、社区活跃企业级功能偏弱
阿里云 PAI国内企业级A10 / A100 / GU系列A10: ~¥15/时完整 MLOps 工具链、SLA 保障贵、配置复杂
RunPod海外开发者A100 / H100A100: ~$1.5/时H100 货源充足、按秒计费国内访问需代理
Lambda Cloud海外团队A100 / H100H100: ~$2.5/时开发者友好、预装 ML 环境库存紧张

推荐策略

  • 个人开发者 / 学习:AutoDL(国内性价比最高,最低几毛钱一小时)
  • 国内企业生产:阿里云 PAI / 腾讯云 TI(有 SLA,合规可控)
  • 海外业务:RunPod / Lambda(H100 资源好找)

以下实操以 AutoDL 为例,因为它最适合从零开始学习部署。

4.3 vLLM 部署全流程(AutoDL 实操)

以下是在 AutoDL 上从零部署 vLLM 推理服务的完整步骤。

Step 1:创建 GPU 实例

  1. 注册并登录 autodl.com
  2. 点击「容器实例」→「创建实例」
  3. 选择配置:
    • GPU:RTX 4090(24 GB)够跑 7B 模型,A100(80 GB)可跑 70B
    • 镜像:选择 PyTorch 2.1 + CUDA 12.1 + Python 3.10 的官方镜像
    • 系统盘:30 GB(默认够用)
    • 数据盘:50 GB+(存模型用,7B 模型约占 15 GB)
  4. 点击创建,等待实例启动(通常 1–3 分钟)

Step 2:SSH 登录与环境配置

bash
# 在 AutoDL 控制台复制 SSH 登录命令
ssh -p <port> root@<host>

# 确认 GPU 可用
nvidia-smi

# 创建虚拟环境并安装 vLLM
python -m venv /root/vllm-env
source /root/vllm-env/bin/activate
pip install vllm

Step 3:下载模型

AutoDL 有 Hugging Face 镜像加速,下载速度很快:

bash
# 方法一:vLLM 启动时自动下载(推荐)
# 设置 HF 镜像(AutoDL 通常已配置)
export HF_ENDPOINT=https://hf-mirror.com

# 方法二:手动提前下载
pip install huggingface_hub
huggingface-cli download Qwen/Qwen2.5-7B-Instruct \
    --local-dir /root/models/Qwen2.5-7B-Instruct

Step 4:启动 vLLM 服务

bash
# 基础启动
vllm serve Qwen/Qwen2.5-7B-Instruct \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.9

# 如果用了本地下载的模型
vllm serve /root/models/Qwen2.5-7B-Instruct \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 8192

# 后台运行(推荐,断开 SSH 后服务不中断)
nohup vllm serve Qwen/Qwen2.5-7B-Instruct \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.9 \
    > /root/vllm.log 2>&1 &

# 查看日志
tail -f /root/vllm.log

Step 5:验证服务

bash
# 在服务器上测试
curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen2.5-7B-Instruct",
    "messages": [{"role": "user", "content": "你好,自我介绍一下"}],
    "max_tokens": 100
  }'

Step 6:开放外网访问

AutoDL 支持自定义服务端口映射:

  1. 在 AutoDL 控制台 → 实例详情 → 「自定义服务」
  2. 开放 8000 端口,获得一个公网 URL(如 https://u-xxxxx-8000.westc.gpuhub.com
  3. 在本地用这个 URL 调用:
python
from openai import OpenAI

client = OpenAI(
    base_url="https://u-xxxxx-8000.westc.gpuhub.com/v1",  # AutoDL 公网 URL
    api_key="unused"
)

response = client.chat.completions.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    messages=[{"role": "user", "content": "AutoDL 部署成功了吗?"}]
)
print(response.choices[0].message.content)

⚠️ AutoDL 的自定义服务 URL 是临时的,每次重启实例可能会变。生产环境建议用固定 IP + 域名。

4.4 TGI Docker 部署(备选方案)

如果你更熟悉 Docker 部署,或者对 Hugging Face 生态有偏好,TGI(Text Generation Inference)是一个稳定的选择。它是 Hugging Face 官方维护的推理服务,很多云厂商的推理服务底层就是 TGI。

Docker 一键启动

bash
# 拉取并启动 TGI 容器(NVIDIA GPU)
docker run --gpus all -d \
    --name tgi \
    -p 8000:80 \
    -v /root/models:/data \
    -e HF_TOKEN=hf_xxxxx \
    ghcr.io/huggingface/text-generation-inference:latest \
    --model-id Qwen/Qwen2.5-7B-Instruct \
    --max-input-tokens 4096 \
    --max-total-tokens 8192

# 查看启动日志(等待模型加载完成)
docker logs -f tgi

API 调用(兼容 OpenAI 格式):

python
from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="unused")

response = client.chat.completions.create(
    model="Qwen/Qwen2.5-7B-Instruct",
    messages=[{"role": "user", "content": "TGI 和 vLLM 有什么区别?"}],
    max_tokens=512
)
print(response.choices[0].message.content)

TGI vs vLLM 怎么选

维度TGIvLLM
部署方式Docker 一键启动pip install + 命令行
极端吞吐略低更高(PagedAttention)
HF 生态集成原生支持需手动配置
社区活跃度中等非常活跃
推荐场景Docker 运维、HF 生态追求极致性能

简单总结:追求性能选 vLLM,追求简单选 TGI

4.5 生产化配套(Nginx 反代、HTTPS、监控)

vLLM / TGI 跑起来只是第一步。要给真实用户提供稳定服务,还需要几个工程化配套。

Nginx 反向代理

vLLM 直接暴露在公网不安全也不专业。用 Nginx 反代可以实现:域名绑定、SSL 证书、请求限流、负载均衡。

nginx
# /etc/nginx/sites-available/llm-api
server {
    listen 80;
    server_name api.yourdomain.com;

    # 限制请求体大小(防止超大 prompt 打崩服务)
    client_max_body_size 10m;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;

        # 流式输出必须关闭缓冲
        proxy_buffering off;
        proxy_cache off;

        # 长连接超时(大模型生成可能需要较长时间)
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}
bash
# 启用配置并重载 Nginx
sudo ln -s /etc/nginx/sites-available/llm-api /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

HTTPS 证书(Let's Encrypt 免费证书):

bash
# 安装 Certbot
sudo apt install certbot python3-certbot-nginx

# 自动配置 HTTPS
sudo certbot --nginx -d api.yourdomain.com

# 证书会自动续期,无需手动管理

健康检查脚本

bash
#!/bin/bash
# healthcheck.sh - 定时检查 vLLM 服务状态

ENDPOINT="http://localhost:8000/health"
ALERT_WEBHOOK="https://your-webhook-url"  # 企业微信/钉钉/Slack webhook

if ! curl -sf "$ENDPOINT" > /dev/null 2>&1; then
    echo "[$(date)] vLLM 服务异常,尝试重启..."

    # 重启 vLLM
    pkill -f "vllm serve"
    sleep 5
    nohup vllm serve Qwen/Qwen2.5-7B-Instruct \
        --host 0.0.0.0 --port 8000 \
        --max-model-len 8192 \
        > /root/vllm.log 2>&1 &

    # 发送告警
    curl -s "$ALERT_WEBHOOK" \
        -H "Content-Type: application/json" \
        -d '{"content": "⚠️ vLLM 服务异常已自动重启"}'
fi
bash
# 添加到 crontab,每分钟检查一次
echo "* * * * * /root/healthcheck.sh" | crontab -

基础监控指标

vLLM 内置了 Prometheus 指标端点(/metrics),可以对接 Grafana 监控面板:

  • vllm:num_requests_running — 当前正在处理的请求数
  • vllm:num_requests_waiting — 等待队列长度
  • vllm:gpu_cache_usage_perc — GPU KV Cache 使用率
  • vllm:avg_generation_throughput_toks_per_s — 平均生成吞吐(tokens/秒)

💡 对于中小规模部署,健康检查脚本 + 日志监控就够了。上了多台 GPU 服务器之后,再考虑 Prometheus + Grafana 的完整监控方案。


五、推理性能优化

模型能跑只是及格线。要在有限的硬件上服务更多用户、降低每次请求的成本,需要掌握几个关键的优化技术。这一章不深入数学原理,只讲你需要做什么决策、怎么配置

5.1 量化方案选型指南(GGUF / GPTQ / AWQ)

量化的本质:把模型权重从高精度(FP16,每个参数占 2 字节)压缩到低精度(INT4,每个参数占 0.5 字节),用微小的质量损失换取显存减半、速度翻倍

三大量化格式对比

格式量化方式适用后端精度保持推理速度适用场景
GGUF离线量化,多种量化级别llama.cpp / Ollama / LM Studio★★★★★★★CPU / Mac / 边缘设备
GPTQ离线量化,基于校准数据vLLM / TGI / Transformers★★★★★★★★GPU 推理(生产环境)
AWQ激活感知量化vLLM / TGI★★★★★★★★★★GPU 推理(推荐首选)

GGUF 量化级别详解

GGUF 格式有多种量化级别,名字看起来很晦涩,其实逻辑很简单:

量化级别大小(7B 模型)质量推荐度
Q2_K~2.7 GB明显下降仅内存极有限时
Q3_K_M~3.3 GB可接受内存紧张的折中
Q4_K_M~4.1 GB几乎无损最推荐
Q5_K_M~4.8 GB非常接近原始追求质量
Q6_K~5.5 GB接近 FP16内存充裕时
Q8_0~7.2 GB几乎等于 FP16不差内存的首选

💡 记住一个就行:Q4_K_M。它是社区公认的最佳性价比量化级别——模型大小缩小到原始的 ~30%,质量损失在大多数任务上感知不到。

选型决策

你用什么硬件?

├── Mac / CPU / 边缘设备 ──▶ GGUF(Q4_K_M)

├── NVIDIA GPU(vLLM 部署)
│   ├── 追求质量 ──────────▶ AWQ(推荐)
│   └── 模型只有 GPTQ 版本 ▶ GPTQ

└── 不确定 ────────────────▶ GGUF(通用性最好)

5.2 vLLM 调优参数详解

vLLM 启动时有很多参数可以调,但大多数情况下默认值就够了。这里只列出你最可能需要调整的参数

显存与模型相关

bash
vllm serve Qwen/Qwen2.5-7B-Instruct \
    --max-model-len 8192 \           # 最大上下文长度(越长越耗显存)
    --gpu-memory-utilization 0.9 \   # GPU 显存使用比例(默认 0.9)
    --enforce-eager \                # 禁用 CUDA Graph(调试用,牺牲速度换稳定性)
    --dtype auto                     # 数据类型,auto 会自动选择
参数默认值调优建议
--max-model-len模型最大长度设为你实际需要的长度。8192 够大多数场景。设太大会浪费显存
--gpu-memory-utilization0.9显存紧张时调到 0.95,但可能导致 OOM。留 10% 余量更稳
--dtypeauto一般不用改。A100 用 bfloat16,其他卡用 float16

并发与吞吐相关

bash
vllm serve Qwen/Qwen2.5-7B-Instruct \
    --max-num-seqs 256 \             # 最大并发序列数
    --max-num-batched-tokens 8192 \  # 每个批次最大 token 数
    --swap-space 4                   # CPU 交换空间(GB),显存不够时用
参数默认值调优建议
--max-num-seqs256并发数上限。显存紧张时调小(如 64),能提高稳定性
--swap-space4当并发请求的 KV Cache 超出显存时,交换到 CPU 内存。设为 0 可禁用

多卡与量化

bash
# 双卡张量并行
vllm serve Qwen/Qwen2.5-72B-Instruct \
    --tensor-parallel-size 2

# 加载 AWQ 量化模型
vllm serve Qwen/Qwen2.5-7B-Instruct-AWQ \
    --quantization awq

# 启用 KV Cache 量化(实验性功能,减少显存占用)
vllm serve Qwen/Qwen2.5-7B-Instruct \
    --kv-cache-dtype fp8

一个实用的生产配置模板

bash
# 适用于单卡 RTX 4090(24 GB)跑 7B 模型的推荐配置
vllm serve Qwen/Qwen2.5-7B-Instruct \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.9 \
    --max-num-seqs 64 \
    --swap-space 4 \
    --disable-log-requests   # 生产环境关闭请求日志,减少 I/O 开销

5.3 成本与性能的平衡策略

部署优化不是"越快越好",而是在预算、质量、速度三者之间找到适合你的平衡点。

策略一:模型大小选择

不要盲目追求大模型。在很多任务上,7B 模型 + 好的 Prompt 可以达到 70B 模型 80%+ 的效果,但成本只有 1/10。

模型规模典型显存(FP16)典型显存(4-bit)适用场景
1.5B–3B3–6 GB1–2 GB简单分类、提取、格式化
7B–9B14–18 GB4–5 GB通用对话、代码辅助、客服
14B–32B28–64 GB8–18 GB复杂推理、专业领域
70B+140+ GB35+ GB最高质量要求、多卡部署

💡 务实建议:先用 7B 量化模型跑通,测试质量是否满足需求。不够再升级到 14B 或 70B,而不是一上来就部署最大的。

策略二:请求路由(大小模型搭配)

对不同复杂度的请求用不同模型处理:

用户请求 ──▶ 路由判断

             ├── 简单问题(FAQ、格式化)──▶ 7B 模型(便宜、快)

             └── 复杂问题(推理、创作)──▶ 70B 模型或闭源 API

这种模式可以让 80% 的请求由低成本模型处理,只在真正需要时调用大模型,综合成本降低 60%+。

策略三:缓存常见响应

如果你的应用有很多重复或相似的查询(比如客服场景),可以缓存模型的响应:

  • 精确匹配缓存:相同输入直接返回缓存结果
  • 语义缓存:用 Embedding 计算相似度,相似问题返回缓存结果(GPTCache 等方案)

缓存命中率达到 30% 就能显著降低 GPU 成本。

策略四:按需启停

如果流量有明显的高低峰:

  • AutoDL:使用"无卡模式"——低峰期释放 GPU 只保留数据盘,高峰期恢复(每小时只收几毛钱存储费)
  • 云服务器:结合 Serverless 平台,低峰期用 Serverless(按量付费),高峰期用自建服务器
  • HF Endpoints:启用 Scale-to-zero,没有请求时自动关机

综合成本参考(7B 模型,日均 1 万次请求):

方案对比(月成本估算)
═══════════════════════════════════════════
闭源 API(GPT-4o-mini)    : ¥300–600/月
硅基流动 Serverless         : ¥150–300/月
AutoDL 4090 按需             : ¥500–1000/月(不间断)
AutoDL 4090 按需 + 无卡模式  : ¥200–400/月(白天开机)
自有 4090                   : ¥100–150/月(电费)
═══════════════════════════════════════════

六、端到端实战项目

前面五章讲的都是单个技术点。这一章把它们串起来——从本地开发到线上部署,完成一个可以真正给人用的对话 API 服务

6.1 项目目标与架构设计

我们要做什么

搭建一个基于 Qwen2.5-7B 的智能对话 API,支持:

  • 多轮对话(带上下文记忆)
  • 流式输出(逐 token 返回)
  • System Prompt 自定义
  • 本地和线上两套部署方案

技术栈

  • 模型:Qwen2.5-7B-Instruct
  • 本地推理:Ollama
  • 线上推理:vLLM(AutoDL)
  • API 层:FastAPI
  • 前端:原生 HTML + JavaScript(演示用)

架构图

开发环境(本地)                    生产环境(云端)
════════════════                    ════════════════

┌──────────┐                       ┌──────────┐
│  前端页面  │◀── HTTP/SSE ──▶     │  前端页面  │
└────┬─────┘                       └────┬─────┘
     │                                  │
     ▼                                  ▼
┌──────────┐                       ┌──────────┐
│  FastAPI  │                       │  Nginx   │
│  (API 层) │                       │ (反向代理)│
└────┬─────┘                       └────┬─────┘
     │                                  │
     ▼                                  ▼
┌──────────┐                       ┌──────────┐
│  Ollama   │                       │  vLLM    │
│(localhost)│                       │ (GPU 服务)│
└──────────┘                       └──────────┘

关键设计决策

FastAPI 作为中间层的价值在于:业务逻辑和推理引擎解耦。切换后端(Ollama → vLLM → 闭源 API)只需改一行配置,前端代码和 API 接口完全不变。

6.2 本地开发阶段(Ollama + FastAPI)

Step 1:确保 Ollama 运行

bash
# 下载模型(如果还没下载)
ollama pull qwen2.5:7b

# 确认服务在跑
curl http://localhost:11434/api/tags

Step 2:创建项目结构

bash
mkdir llm-chat-api && cd llm-chat-api
python -m venv .venv
source .venv/bin/activate
pip install fastapi uvicorn openai python-dotenv
llm-chat-api/
├── .env            # 环境配置
├── main.py         # FastAPI 主文件
└── static/
    └── index.html  # 前端页面(6.4 编写)

Step 3:编写环境配置

bash
# .env
LLM_BASE_URL=http://localhost:11434/v1
LLM_API_KEY=ollama
LLM_MODEL=qwen2.5:7b

Step 4:编写 FastAPI 服务

python
# main.py
import os
from dotenv import load_dotenv
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from openai import OpenAI

load_dotenv()

app = FastAPI(title="LLM Chat API")

# 允许前端跨域访问
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

# 初始化 LLM 客户端(通过 .env 切换后端)
client = OpenAI(
    base_url=os.getenv("LLM_BASE_URL"),
    api_key=os.getenv("LLM_API_KEY"),
)
MODEL = os.getenv("LLM_MODEL")


class ChatRequest(BaseModel):
    messages: list[dict]
    system_prompt: str = "你是一个有帮助的 AI 助手。"
    stream: bool = True
    temperature: float = 0.7
    max_tokens: int = 1024


@app.post("/api/chat")
async def chat(request: ChatRequest):
    # 构建消息列表(加入 system prompt)
    messages = [{"role": "system", "content": request.system_prompt}]
    messages.extend(request.messages)

    if request.stream:
        # 流式输出
        def generate():
            stream = client.chat.completions.create(
                model=MODEL,
                messages=messages,
                temperature=request.temperature,
                max_tokens=request.max_tokens,
                stream=True,
            )
            for chunk in stream:
                content = chunk.choices[0].delta.content
                if content:
                    yield f"data: {content}\n\n"
            yield "data: [DONE]\n\n"

        return StreamingResponse(generate(), media_type="text/event-stream")
    else:
        # 非流式输出
        response = client.chat.completions.create(
            model=MODEL,
            messages=messages,
            temperature=request.temperature,
            max_tokens=request.max_tokens,
        )
        return {"content": response.choices[0].message.content}


# 挂载静态文件(前端页面)
app.mount("/", StaticFiles(directory="static", html=True), name="static")

Step 5:启动并测试

bash
# 启动 FastAPI
uvicorn main:app --reload --host 0.0.0.0 --port 3000

# 测试非流式调用
curl -X POST http://localhost:3000/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{"role": "user", "content": "用一句话介绍你自己"}],
    "stream": false
  }'

# 测试流式调用
curl -X POST http://localhost:3000/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [{"role": "user", "content": "写一首关于编程的诗"}],
    "stream": true
  }'

💡 切换到线上 vLLM 只需要改 .env 文件中的 LLM_BASE_URLLLM_MODEL,代码完全不用动。

6.3 线上部署阶段(AutoDL + vLLM)

本地开发验证通过后,切到线上只需两步:启动 vLLM + 修改 .env 配置。

Step 1:在 AutoDL 启动 vLLM

按照 4.3 节的流程,在 AutoDL 上启动 vLLM 服务:

bash
# SSH 登录 AutoDL 实例后
source /root/vllm-env/bin/activate

nohup vllm serve Qwen/Qwen2.5-7B-Instruct \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 8192 \
    --gpu-memory-utilization 0.9 \
    > /root/vllm.log 2>&1 &

# 确认启动成功
curl http://localhost:8000/v1/models

开放 8000 端口,获取公网 URL(如 https://u-xxxxx-8000.westc.gpuhub.com)。

Step 2:修改 .env 配置

bash
# .env(线上版本)
LLM_BASE_URL=https://u-xxxxx-8000.westc.gpuhub.com/v1
LLM_API_KEY=unused
LLM_MODEL=Qwen/Qwen2.5-7B-Instruct

Step 3:部署 FastAPI 服务

FastAPI 服务可以部署在任意有公网 IP 的服务器上(不需要 GPU):

bash
# 在云服务器上(普通 CPU 机器即可)
git clone your-repo llm-chat-api
cd llm-chat-api
pip install -r requirements.txt

# 生产启动(使用 gunicorn + uvicorn workers)
pip install gunicorn
gunicorn main:app \
    -w 4 \
    -k uvicorn.workers.UvicornWorker \
    --bind 0.0.0.0:3000

完整的请求链路

用户浏览器


FastAPI 服务器(CPU 云服务器,¥50/月)

    ▼ (HTTP 请求)
vLLM 服务(AutoDL GPU 服务器,按需启停)

    ▼ (GPU 推理)
Qwen2.5-7B 模型

💡 这个架构的好处:FastAPI 服务器很便宜(不需要 GPU),GPU 服务器按需启停。如果临时不用 vLLM,把 .env 切回硅基流动或 OpenAI API,服务不中断。

6.4 前端接入(流式输出聊天界面)

最后一步:做一个简单的聊天页面,接入我们的 FastAPI 服务。以下是一个完整的单文件 HTML,支持流式打字效果。

创建 static/index.html

html
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>LLM Chat</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
            background: #1a1a2e; color: #eee;
            display: flex; justify-content: center;
            min-height: 100vh; padding: 20px;
        }
        .container { max-width: 800px; width: 100%; display: flex; flex-direction: column; }
        h1 { text-align: center; margin-bottom: 20px; color: #8b5cf6; }
        #chat-box {
            flex: 1; overflow-y: auto; padding: 20px;
            background: #16213e; border-radius: 12px;
            margin-bottom: 16px; min-height: 400px;
        }
        .message { margin-bottom: 16px; line-height: 1.6; }
        .user { color: #60a5fa; }
        .user::before { content: "🧑 "; }
        .assistant { color: #d1d5db; }
        .assistant::before { content: "🤖 "; }
        .input-area { display: flex; gap: 8px; }
        input {
            flex: 1; padding: 12px 16px; border: none;
            border-radius: 8px; background: #16213e;
            color: #eee; font-size: 16px; outline: none;
        }
        input:focus { box-shadow: 0 0 0 2px #8b5cf6; }
        button {
            padding: 12px 24px; border: none; border-radius: 8px;
            background: #8b5cf6; color: white; font-size: 16px;
            cursor: pointer; transition: background 0.2s;
        }
        button:hover { background: #7c3aed; }
        button:disabled { background: #4a4a6a; cursor: not-allowed; }
    </style>
</head>
<body>
    <div class="container">
        <h1>💬 LLM Chat</h1>
        <div id="chat-box"></div>
        <div class="input-area">
            <input id="input" placeholder="输入消息..." 
                   onkeydown="if(event.key==='Enter') sendMessage()" />
            <button id="send-btn" onclick="sendMessage()">发送</button>
        </div>
    </div>

    <script>
        const chatBox = document.getElementById('chat-box');
        const input = document.getElementById('input');
        const sendBtn = document.getElementById('send-btn');
        const messages = []; // 对话历史

        async function sendMessage() {
            const text = input.value.trim();
            if (!text) return;

            // 显示用户消息
            messages.push({ role: 'user', content: text });
            appendMessage('user', text);
            input.value = '';
            sendBtn.disabled = true;

            // 创建 AI 回复容器
            const aiDiv = appendMessage('assistant', '');

            try {
                const response = await fetch('/api/chat', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ messages, stream: true }),
                });

                const reader = response.body.getReader();
                const decoder = new TextDecoder();
                let fullContent = '';

                while (true) {
                    const { done, value } = await reader.read();
                    if (done) break;

                    const chunk = decoder.decode(value);
                    const lines = chunk.split('\n')
                        .filter(line => line.startsWith('data: '));

                    for (const line of lines) {
                        const data = line.slice(6);
                        if (data === '[DONE]') break;
                        fullContent += data;
                        aiDiv.textContent = '🤖 ' + fullContent;
                    }
                }

                messages.push({ role: 'assistant', content: fullContent });
            } catch (error) {
                aiDiv.textContent = '🤖 出错了:' + error.message;
            }

            sendBtn.disabled = false;
            chatBox.scrollTop = chatBox.scrollHeight;
        }

        function appendMessage(role, content) {
            const div = document.createElement('div');
            div.className = `message ${role}`;
            div.textContent = (role === 'user' ? '🧑 ' : '🤖 ') + content;
            chatBox.appendChild(div);
            chatBox.scrollTop = chatBox.scrollHeight;
            return div;
        }
    </script>
</body>
</html>

启动并验证

bash
# 确保 Ollama 在跑,然后启动 FastAPI
uvicorn main:app --reload --host 0.0.0.0 --port 3000

# 打开浏览器访问 http://localhost:3000

你应该看到一个暗色主题的聊天界面,输入消息后模型会逐字流式返回。

至此,整个项目完成

✅ 本地 Ollama 跑通模型推理
✅ FastAPI 封装 API(支持流式输出)
✅ 环境变量切换后端(Ollama → vLLM → 闭源 API)
✅ AutoDL + vLLM 线上部署
✅ 前端聊天页面接入(流式打字效果)

七、选型决策与常见问题

如果你跳过前面直接翻到这里——没问题,这一章就是为快速决策设计的。

7.1 场景-方案速查表

按你的身份选

你是谁推荐方案理由
学生 / 个人开发者Ollama 本地零成本,Mac / Windows 通吃
独立开发者做产品硅基流动 Serverless零运维,按量付费,有免费额度
创业团队(< 10 人)硅基流动 + AutoDL vLLM 备用低峰用 Serverless,高峰自建
企业(数据安全要求高)内网 vLLM / Xinference数据不出网,完全可控
海外业务团队Replicate / Modal海外节点延迟低

按你的硬件选

你有什么推荐方案
Mac M 系列(16 GB+)Ollama(开发)→ 硅基流动(上线)
Windows / Linux + RTX 4090Ollama(开发)→ vLLM 本地(内网服务)
没有 GPUOllama CPU 模式(开发)→ Serverless(上线)
多张 A100 服务器vLLM + 张量并行

按你的预算选

月预算推荐方案
¥0Ollama 本地 + 硅基流动免费额度
¥100–500硅基流动 Serverless
¥500–2000AutoDL 4090 按需启停 + vLLM
¥2000+阿里云 PAI / 自建多卡集群

一句话总结

🎯 不确定选什么?从 Ollama 本地 + 硅基流动 API 开始。这个组合覆盖了从开发到上线的全流程,零成本起步,遇到瓶颈再升级。

7.2 常见问题排错

Q1:Ollama 启动后模型下载很慢怎么办?

bash
# 设置 Hugging Face 镜像加速(国内用户)
export OLLAMA_HOST=0.0.0.0
# Ollama 有自己的 CDN,通常不需要配置镜像
# 如果确实很慢,尝试用代理或在 LM Studio 中下载 GGUF 后导入

Q2:vLLM 启动报 CUDA out of memory

三个排查方向:

  1. 减小 --max-model-len(如从 32768 降到 8192)
  2. 用量化模型(AWQ / GPTQ),显存占用减半
  3. 降低 --gpu-memory-utilization(如从 0.9 降到 0.85),让系统有更多余量

Q3:模型输出质量很差 / 答非所问?

通常不是部署问题,而是模型或 Prompt 的问题:

  • 确认用的是 Instruct 版本(如 Qwen2.5-7B-Instruct),而不是 Base 版本
  • 检查 System Prompt 是否合理
  • 7B 模型在复杂推理任务上确实能力有限,考虑换更大的模型

Q4:vLLM 安装失败 / 编译报错?

bash
# 确认 CUDA 版本兼容
nvidia-smi  # 查看驱动支持的最高 CUDA 版本
nvcc --version  # 查看已安装的 CUDA 工具链版本

# vLLM 要求 CUDA 12.1+,如果版本太低需要升级
# 最简单的方案:用 AutoDL 的预配置镜像,自带 CUDA 12.1

Q5:流式输出无效,前端一次性收到全部内容?

检查 Nginx 配置是否关闭了缓冲:

nginx
proxy_buffering off;
proxy_cache off;

如果没有 Nginx,检查 FastAPI 的 StreamingResponse 是否正确设置了 media_type="text/event-stream"

Q6:Ollama 和 vLLM 的模型名不一样,切换后报错?

Ollama 用简短名(qwen2.5:7b),vLLM 用 HF 全名(Qwen/Qwen2.5-7B-Instruct)。解决方案:把模型名放在 .env 里,通过环境变量读取,切换后端时一起改。

Q7:AutoDL 实例重启后 vLLM 服务没了?

vLLM 进程不会自动随系统启动。解决方案:

bash
# 方法一:写一个启动脚本,放到 /root/start.sh
# 方法二:用 supervisor 管理进程
pip install supervisor
# 配置 supervisord 自动拉起 vLLM

Q8:本地 Ollama 跑 7B 模型很慢(< 5 tokens/s)?

  • Mac 用户:确认 Ollama 在用 Metal GPU 加速(Activity Monitor 看 GPU 使用率)
  • Windows / Linux:确认 Ollama 检测到了 GPU(ollama run qwen2.5:7b 启动时会打印使用的设备)
  • 如果是纯 CPU:7B Q4 模型在现代 CPU 上大约 5–15 tokens/s,这是正常速度

7.3 下一步学习路径

模型部署只是 AI 应用开发的一环。跑通部署后,以下方向值得继续深入:

如果你想提升模型质量

  • 学习 Prompt Engineering(→ 参考《3.1 Prompt 设计原则》)——好的 Prompt 比换大模型更有效
  • 学习 RAG(→ 参考《4.1 RAG 核心架构》)——让模型基于你的私有数据回答问题
  • 学习 模型微调(→ 参考《2.3 模型微调》)——让模型掌握你的领域知识和行为模式

如果你想构建更复杂的应用

  • 学习 Agent 开发(→ 参考《5.1 Agent 基础概念》)——让 LLM 使用工具、自主规划
  • 学习 Function Calling(→ 参考《5.3 工具使用》)——让模型调用你的 API
  • 学习 多模态模型(→ 参考《6.1 视觉模型》)——处理图像、音频输入

如果你想优化生产系统

  • 深入 vLLM 的高级特性:LoRA 动态加载、推测解码、前缀缓存
  • 学习 Kubernetes + GPU 调度,实现多模型、多副本的弹性部署
  • 研究 LLM 评测方法,建立质量评估体系

推荐的学习顺序

你现在在这里


模型部署(本教程)✅

      ├──▶ Prompt Engineering(立竿见影提升效果)

      ├──▶ RAG(让模型用上你的数据)

      ├──▶ Agent(让模型自主完成任务)

      └──▶ 模型微调(终极手段,需要数据和算力)

📝 本教程完。从 Ollama 一行命令到 vLLM 生产部署,从本地实验到云端上线——你已经掌握了模型部署的完整武器库。现在,去部署你的第一个模型吧。

坚持是一种品格