AI Infra 全栈知识体系学习指南

一份面向AI 基础设施全栈知识体系学习指南,涵盖从算力、数据、训练、推理到 MLOps/LLMOps、RAG 与可观测性的完整技术栈,并融入当前主流实践与最新技术趋势。


一、指南定位与适用对象

  • 目标:系统掌握「AI 基础设施」全栈能力,能设计、搭建与运维从数据到模型上线的完整链路。
  • 适用:算法工程师转 infra、SRE/DevOps 做 AI 平台、以及希望做 AI 全栈的开发者。
  • 前置:具备编程(Python 必备)、Linux、网络与基础系统知识;对机器学习/深度学习有概念即可,不必先精通算法。

实操环境说明:下文所有 Step-by-step 与脚本均在「个人高端办公电脑」上可执行:MacBook Pro(M1/M2/M3)带 RTX 4090 的 PC(Linux/Windows)。涉及 NVIDIA 专用命令(如 nvidia-smi、vLLM/TensorRT-LLM)的步骤会标明「需 4090/ NVIDIA GPU」;Mac 上可用 CPU/MPS 或 Ollama 等替代方案完成对应概念验证。

依赖环境与安装

建议使用 Python 3.10+(推荐 3.11),在虚拟环境中按需安装以下依赖。按「章节/层次」区分:做某章实践时安装对应包即可;若希望一次性具备全文脚本的运行环境,可使用「全量安装」清单。

1. 基础运行环境

  • Python:3.10 或 3.11(python.org 或 pyenv/conda)。
  • 系统与工具(按需):
    • Docker:用于 Qdrant、Prometheus、Grafana、Kubecost 等(Get Docker)。
    • Kubernetes 本地集群:minikube 或 kind(minikubekind),用于 L0/L1/L4/L6/安全相关案例。
    • Ollama(Mac 或 4090 本地 LLM):Ollama 安装
    • NVIDIA 驱动与 CUDA(仅 4090/带 NVIDIA GPU 的机器):CUDA Toolkitnvidia-container-toolkit(若在容器/K8s 中用 GPU)。

2. 按章节的 Python 依赖(pip 安装)

章节 用途 依赖包(示例版本可随最新版调整)
三、三大支柱 DataLoader/编译/训推对比 torchtorchvisiontransformerssentence-transformers(可选)
四、L0 数学/ML/系统 numpyscikit-learnsentence-transformerstorchtorchvisiontransformersdatasets、Flask、gunicorn
五、L1 GPU/ Ray torchray[default]torchvision
六、L2 数据/向量/Feature Store pysparkdvcqdrant-clientsentence-transformers;Feast(feast)按需
七、L3 分布式训练 torchtorchvisionacceleratedeepspeedtransformers
八、L4 推理 serving vllm(需 NVIDIA GPU)、requests;TensorRT-LLM 见其官方文档
九、L5 MLOps/可观测 mlflowscikit-learnprometheus_clientflask;RAGAS(ragas)、datasetspandas
十、L6 RAG/Agent/路由 langchainlangchain-communitylangchain-coresentence-transformersqdrant-clientfastapihttpx;CrossEncoder 含在 sentence-transformers
十一、安全与成本 审计/网关 标准库 jsonlogging;K8s 用 kubectl 与 YAML,无额外 Python 包

3. 一键安装示例

最小环境(仅跑 L0 + 三大支柱 + L2 向量/L5 MLflow/L6 RAG 部分脚本)

1
2
3
4
pip install torch torchvision numpy scikit-learn sentence-transformers transformers datasets
pip install qdrant-client langchain langchain-community langchain-core
pip install mlflow pandas requests flask gunicorn prometheus_client
pip install langchain-text-splitters

含 L1 Ray、L2 Spark/DVC、L3 分布式、L5 RAGAS

1
pip install "ray[default]" pyspark dvc accelerate deepspeed ragas

含 L4 vLLM(仅 4090/NVIDIA GPU 环境)

1
2
pip install vllm
# 或按 vLLM 官方文档:pip install vllm 并确保 CUDA 可用

L6 Agent 与 L4 压测

1
2
pip install fastapi httpx
# Ollama 需单独安装:https://ollama.com

4. requirements.txt 示例(全量,便于复现)

可将以下内容保存为 requirements-ai-infra.txt,按需注释掉不需要的包后执行 pip install -r requirements-ai-infra.txt

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
# 核心
torch>=2.0
torchvision
numpy
scikit-learn
pandas

# 模型与 NLP
transformers
datasets
sentence-transformers
accelerate

# 向量与 RAG
qdrant-client
langchain
langchain-community
langchain-core
langchain-text-splitters

# MLOps 与可观测
mlflow
prometheus_client
ragas

# 服务与工具
flask
gunicorn
requests
fastapi
httpx

# 分布式与数据(按需)
ray[default]
pyspark
dvc
deepspeed

# vLLM(仅 NVIDIA GPU 环境,通常单独安装)
# vllm

5. 使用说明

  • 文中脚本均假设已激活上述依赖对应的环境;若某脚本报缺包,根据报错补装上表或全量清单中的包即可。
  • 使用 GPU 时:PyTorch 请从 pytorch.org 选择与 CUDA 版本匹配的安装命令;vLLM/TensorRT-LLM 需在带 NVIDIA 驱动的机器上使用。
  • 涉及 Docker 的案例(Qdrant、Prometheus、Grafana、Kubecost)需先安装并启动 Docker,再执行文档中的 docker run 或 K8s 配置。

二、知识体系总览(按层次)

层次 主题 核心内容
L0 基础 数学与 ML 基础、系统与网络 线性代数/概率、ML 基本概念、Linux/容器/网络
L1 算力与编排 GPU/TPU、调度与编排 CUDA 概念、K8s、Slurm/Ray、资源隔离与成本
L2 数据 数据管道、特征与向量存储 ETL、Feature Store、Vector DB、数据治理
L3 训练 分布式训练与框架 DP/TP/PP/CP/EP、DeepSpeed/Megatron/FSDP
L4 推理与 serving 模型服务与优化 vLLM、TensorRT-LLM、batching、量化
L5 工程与运维 MLOps / LLMOps 实验管理、Model Registry、CI/CD、可观测性
L6 应用架构 RAG、Agent、多模型 RAG 链路、Agent 编排、混合部署策略

贯穿全栈的三大关键:基础硬件架构、编程与编译、训推框架是 AI Infra 的支柱,下文单独成节说明后再进入各层。


三、AI Infra 三大关键支柱

以下三项贯穿 L1–L6,建议在进入算力与训推细节前建立整体认知,并在后续每层学习中反复对照。

3.1 基础硬件架构

  • CPU 与内存:多核、NUMA、内存带宽与容量对数据加载与预处理的影响;与 GPU 的 PCIe 通信瓶颈。
  • GPU 架构:SM(Streaming Multiprocessor)、CUDA Core、Tensor Core;显存(HBM/GDDR)带宽与容量;多卡拓扑(NVLink、NVSwitch、PCIe 树)。
  • 多机与网络:节点间 RDMA(InfiniBand/RoCE)、GPUDirect RDMA;存储(NVMe、分布式文件系统)与训练 checkpoint/数据 I/O。
  • TPU:Systolic 阵列、HBM 与高速互连;与 GPU 在编程模型与适用场景上的差异。

实践意义:理解硬件才能正确做资源申请、亲和性绑定、通信与 I/O 优化,以及成本估算。

3.2 编程与编译

  • GPU 编程模型:CUDA kernel、grid/block/thread、共享内存与全局内存;cuDNN/cuBLAS 等库的抽象层次。
  • 编译链:nvcc、LLVM、PTX 与 cubin;不同 GPU 架构的 JIT 与 AOT。
  • 图编译与优化:PyTorch 的 torch.compile、TorchDynamo、Inductor;JAX/XLA;算子融合、kernel 选择与内存规划。
  • 自定义 kernel:Triton 写 GPU kernel;cuBLASLt、CUTLASS 做矩阵运算;与框架的集成方式。

实践意义:区分「写模型代码」与「跑在什么设备、经什么编译」;能排查训练/推理性能问题与选择合适后端。

3.3 训推框架

  • 训练侧:PyTorch / TensorFlow / JAX 为前端;DeepSpeed、Megatron、FSDP、Horovod 等负责分布式与显存优化;从单机单卡到多机多卡的统一视图。
  • 推理侧:vLLM、TensorRT-LLM、TGI、ONNX Runtime、Triton Inference Server;图优化、量化与 batching 在框架中的位置。
  • 统一视角:从模型定义 → 训练(含编译与并行)→ 导出(ONNX/TorchScript)→ 推理部署的完整链路;各阶段可替换组件与厂商生态。

实践意义:选型与排障时知道「问题在框架层还是硬件层、在训练还是推理」;能设计可复用的训推一体流水线。

3.4 三大支柱:学习资料(含链接)

3.5 三大支柱:关键学习点实践案例

学习点 实践案例
CPU/内存与 PCIe 瓶颈 在固定 GPU 下,逐步增大 DataLoader 的 num_workersprefetch_factor,观察训练吞吐变化,体会 CPU 预处理与 PCIe 传数对迭代速度的影响。
GPU 架构与显存带宽 nvidia-smi dmon 或 DCGM 在训练时监控显存带宽占用;对比同一模型在 HBM(A100)与 GDDR(消费卡)上的吞吐差异。
多卡拓扑(NVLink/PCIe) 在同一机器上跑 2 卡 DDP:先查 nvidia-smi topo -m 确认拓扑,再对比「NVLink 直连的两卡」与「仅 PCIe 的两卡」的 AllReduce 耗时或训练速度。
图编译(torch.compile) 对同一 Transformer 小模型分别用 model()torch.compile(model)() 训练若干 step,对比首步延迟与后续 step 的吞吐,理解 JIT 编译与 kernel 融合的效果。
训推框架选型 用同一 checkpoint 分别经 PyTorch 原生、ONNX、vLLM 做推理,记录延迟与显存;写一份一页纸对比表(格式、优化、适用场景),作为日后选型依据。

3.6 三大支柱:Step-by-step 细化流程与脚本

案例 1:CPU/内存与 PCIe 瓶颈

  • 选型:PyTorch 2.x + 小模型(如 ResNet18),CIFAR-10;Mac/4090 均可。
  • Step 1:创建虚拟环境并安装 torch torchvision
  • Step 2:运行下面脚本,依次将 num_workers 设为 0、2、4、8,记录每个配置下 100 个 batch 的耗时(秒)。
  • Step 3:在同一脚本中把 prefetch_factor 从 2 改为 4 再测一轮,观察「CPU 预处理 + 传数」对迭代速度的影响。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# scripts/l0_dataloader_bench.py
import time
import torch
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR10
from torchvision.transforms import ToTensor
from torchvision.models import resnet18

device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
dataset = CIFAR10(root="./data", download=True, transform=ToTensor())
loader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=4, prefetch_factor=2, pin_memory=(device!="cpu"))
model = resnet18().to(device)
model.train()
t0 = time.perf_counter()
for i, (x, _) in enumerate(loader):
x = x.to(device, non_blocking=True)
_ = model(x)
if i >= 99:
break
print(f"100 batches elapsed: {time.perf_counter()-t0:.2f}s")

案例 2:GPU 架构与显存带宽(需 4090/NVIDIA GPU)

  • Step 1:在 4090 上运行上面同一训练循环,另开终端执行 watch -n 1 nvidia-smi,观察显存占用与 GPU 利用率。
  • Step 2:用 nvidia-smi dmon -s u -d 1 采样 10 秒,记录平均 GPU 利用率与显存带宽(若已装 DCGM 可用 dcgmi)。Mac 可跳过或仅用 MPS 观察显存占用(Activity Monitor / 代码内 torch.mps.current_allocated_memory())。

案例 3:多卡拓扑(NVLink/PCIe)(需 2 张 NVIDIA GPU)

  • Step 1:执行 nvidia-smi topo -m 查看拓扑,确认两卡是否 NVLink 直连。
  • Step 2:用 PyTorch DDP 在 2 卡上跑同一小模型 50 step,记录总时间;若仅 1 卡可跳过或使用单机模拟多进程(torch.multiprocessing)理解通信。

案例 4:图编译(torch.compile)(Mac/4090 均可)

  • 选型:Hugging Face transformersgoogle/flan-t5-small(小参数量,适合办公本)。
  • Step 1:安装 transformers torch,加载 AutoModelForSeq2SeqLM 与 tokenizer。
  • Step 2:不编译:对同一输入连续 forward 10 次,记录第 1 次与第 2–10 次平均耗时。
  • Step 3:用 model = torch.compile(model, mode="reduce-overhead") 再测,对比首步冷启动与后续 step 吞吐。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# scripts/l0_torch_compile_bench.py
import time
import torch
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer

model_name = "google/flan-t5-small"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
model = model.to(device)
inputs = tokenizer("translate to German: Hello world.", return_tensors="pt").to(device)

# 不编译
t0 = time.perf_counter()
for _ in range(10):
_ = model.generate(**inputs, max_new_tokens=5)
print("no compile, first 10 runs:", time.perf_counter() - t0)

# 编译
model_compile = torch.compile(model, mode="reduce-overhead")
t1 = time.perf_counter()
for _ in range(10):
_ = model_compile.generate(**inputs, max_new_tokens=5)
print("with compile, 10 runs:", time.perf_counter() - t1)

案例 5:训推框架选型(Mac 用 PyTorch+ONNX;4090 可加 vLLM)

  • 选型:小模型 Qwen/Qwen2.5-0.5B-Instruct(Mac/4090 均可加载)。
  • Step 1:PyTorch 原生:加载模型,对固定 prompt 生成 50 token,记录延迟与(4090 上)显存。
  • Step 2:导出 ONNX(或使用 optimum 导出)并在 ONNX Runtime 中推理,同样测延迟;Mac 上可用 CPU 执行。
  • Step 3:(仅 4090)用 vLLM 部署同一模型,curl/v1/completions 测延迟与显存,填表对比「格式、优化、适用场景」。

四、L0:基础层

4.1 数学与机器学习基础

  • 线性代数:矩阵运算、特征值、SVD(与嵌入、降维相关)。
  • 概率与统计:分布、估计、假设检验(理解评估指标与 A/B 实验)。
  • 机器学习概念:监督/无监督、过拟合、损失函数、优化器、评估指标(准确率、F1、AUC 等)。
  • 深度学习入门:前向/反向传播、常见结构(CNN/RNN/Transformer)、预训练与微调的概念。

不必推导所有公式,但要能读懂论文/文档中的符号与流程。

4.2 系统与网络基础

  • Linux:进程、内存、I/O、常用命令与脚本。
  • 容器:Docker 镜像与容器、多阶段构建、资源限制。
  • 编排:Kubernetes 基本概念(Pod、Deployment、Service、资源 request/limit)。
  • 网络:TCP/HTTP、负载均衡、内网/外网、防火墙与安全组。

4.3 L0 学习资料(含链接)

4.4 L0 实践方法

  • ML 实践:在本地或 Colab 用 PyTorch 跑通一个图像分类(如 ResNet)或简单 NLP 任务;改超参、看 loss/准确率曲线,建立「实验」直觉。
  • 系统实践:在单机用 Docker 跑一个 Web 服务并限制 CPU/内存;用 minikube 或 kind 部署一个 Deployment + Service,用 kubectl 观察 Pod 与访问。
  • 打通一次:在 K8s 里跑一个简单 Python 推理脚本(例如用 FastAPI 包装一个 ONNX 模型),从镜像构建到 kubectl port-forward 访问,形成「代码 → 镜像 → 编排 → 访问」的闭环。

4.5 L0 关键学习点实践案例

学习点 实践案例
线性代数与嵌入 用 NumPy 对一组句子做 SVD 降维(或 sklearn PCA),再与 sentence-transformers 的嵌入做一次「相似句」检索对比,理解向量表示与矩阵运算的关系。
损失与评估指标 在 PyTorch 中训练二分类模型:分别用 BCE 与 CrossEntropy,在验证集上记录准确率、F1、AUC(sklearn.metrics),并画 loss/曲线,建立「损失 ↔ 指标」的直觉。
Transformer 与预训练 用 Hugging Face transformers 加载预训练 BERT 或小 LLM,在 1 个下游任务(如文本分类)上做 fine-tune,观察「只训练 head」与「全参数微调」的收敛与效果差异。
Docker 资源限制 docker run --cpus=0.5 --memory=256m 跑一个 Web 服务,用压测工具(如 wrk)逐步提高并发,观察 OOM 或 CPU throttling,理解 limit 对稳定性的影响。
K8s Pod 与 Service 在 minikube/kind 中部署 2 个 replica 的 Deployment 和一个 ClusterIP Service,用 kubectl exec 在集群内 curl Service 的 ClusterIP:port,确认负载均衡与 DNS。

4.6 L0:Step-by-step 细化流程与脚本

案例 1:线性代数与嵌入

  • 选型:NumPy + sklearn PCA;sentence-transformers all-MiniLM-L6-v2(Mac/4090 均可,CPU 即可)。
  • Step 1:准备 5–10 条短句,用 all-MiniLM-L6-v2 得到嵌入矩阵 X(shape 如 10×384)。
  • Step 2:对 X 做 SVD 或 PCA 降到 32 维,再用降维后的向量做「查询句 vs 其余句」的余弦相似度排序。
  • Step 3:对比「原始 384 维相似度排序」与「32 维降维后排序」是否一致,理解向量表示与矩阵运算的关系。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# scripts/l0_svd_embedding.py
import numpy as np
from sklearn.decomposition import PCA
from sentence_transformers import SentenceTransformer

sentences = ["The cat sits on the mat.", "A dog runs in the park.", "Cats like to sleep.", "Dogs need exercise."]
model = SentenceTransformer("all-MiniLM-L6-v2")
X = model.encode(sentences)
print("Original dim", X.shape)
# 降维
pca = PCA(n_components=2)
X_low = pca.fit_transform(X)
# 查询第0句与其余句的相似度(原始 vs 降维)
q = X[0:1]
sim_full = (X @ q.T).flatten()
sim_low = (X_low @ X_low[0:1].T).flatten()
print("Sim (full):", sim_full)
print("Sim (PCA):", sim_low)

案例 2:损失与评估指标

  • 选型:PyTorch + 二分类(如 IMDB 或自建 0/1 数据),BCE 与 CrossEntropy 各训 1 次;Mac/4090 均可。
  • Step 1:构造 500 条 (text/label) 或 (feature, 0/1),DataLoader。
  • Step 2:用单层线性 + BCEWithLogitsLoss 训练 20 epoch,记录每 epoch 的 loss、accuracy、F1、AUC(sklearn.metrics)。
  • Step 3:改用 CrossEntropy(2 类)再训一轮,画两条 loss/accuracy 曲线对比。
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
# scripts/l0_bce_ce_metrics.py
import torch
import torch.nn as nn
from sklearn.metrics import f1_score, roc_auc_score

torch.manual_seed(42)
N = 500
X = torch.randn(N, 32)
y = (X[:, 0] + 0.3 * torch.randn(N) > 0).float()
loader = torch.utils.data.DataLoader(torch.utils.data.TensorDataset(X, y), batch_size=32, shuffle=True)

def train_with(loss_name, epochs=20):
model = nn.Sequential(nn.Linear(32, 1))
opt = torch.optim.Adam(model.parameters(), lr=1e-2)
if loss_name == "bce":
loss_fn = nn.BCEWithLogitsLoss()
else:
model = nn.Sequential(nn.Linear(32, 2))
opt = torch.optim.Adam(model.parameters(), lr=1e-2)
loss_fn = nn.CrossEntropyLoss()
for ep in range(epochs):
for a, b in loader:
opt.zero_grad()
out = model(a).squeeze(-1) if loss_name == "bce" else model(a)
loss = loss_fn(out, b) if loss_name == "bce" else loss_fn(out, b.long())
loss.backward()
opt.step()
with torch.no_grad():
pred = (model(X).squeeze(-1).sigmoid() > 0.5).float() if loss_name == "bce" else model(X).argmax(1).float()
acc = (pred == y).float().mean().item()
f1 = f1_score(y.numpy(), pred.numpy(), zero_division=0)
print(f"{loss_name} ep{ep} loss acc={acc:.3f} f1={f1:.3f}")

train_with("bce")
train_with("ce")

案例 3:Transformer 与预训练

  • 选型bert-base-uncaseddistilbert-base-uncased + 文本分类(如 2 类);Mac/4090 均可。
  • Step 1:加载 AutoModelForSequenceClassification,冻结 backbone、只训练 classifier head,在 200 条样本上训 3 epoch,记验证准确率。
  • Step 2:解冻全部参数再训 3 epoch,对比收敛速度与最终准确率。
1
2
# 安装
pip install transformers datasets torch
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
# scripts/l0_bert_finetune.py
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
from datasets import load_dataset

model_name = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
ds = load_dataset("imdb", split="train[:200]").train_test_split(test_size=0.2, seed=42)

def tokenize(e):
return tokenizer(e["text"], truncation=True, max_length=128)

tokenized = ds.map(tokenize, batched=True)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)
# 冻结 backbone(仅训练 head)
for p in model.distilbert.parameters():
p.requires_grad = False
args = TrainingArguments("out", per_device_train_batch_size=8, num_train_epochs=3, logging_steps=10)
trainer = Trainer(model=model, args=args, train_dataset=tokenized["train"], eval_dataset=tokenized["test"])
trainer.train()
print("Frozen eval:", trainer.evaluate())
# 解冻再训
for p in model.distilbert.parameters():
p.requires_grad = True
trainer.train()
print("Full finetune eval:", trainer.evaluate())

案例 4:Docker 资源限制

  • Step 1:写一个最小 Flask 应用(返回 “ok”),打成镜像。
  • Step 2docker run --cpus=0.5 --memory=256m -p 8000:8000 your-image
  • Step 3:用 wrk -t2 -c10 -d5s http://localhost:8000/ab -n 1000 -c 10 http://localhost:8000/ 压测,观察是否 OOM 或 CPU 被限(docker stats)。
1
2
3
4
5
# scripts/l0_docker_limit/Dockerfile
FROM python:3.11-slim
RUN pip install flask gunicorn
COPY app.py .
CMD ["gunicorn", "-b", "0.0.0.0:8000", "-w", "1", "app:app"]
1
2
3
4
5
6
# scripts/l0_docker_limit/app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def ok():
return "ok"

案例 5:K8s Pod 与 Service

  • Step 1:安装 minikubekind,启动集群。
  • Step 2:部署 2 replica 的 nginx Deployment 和 ClusterIP Service;kubectl get pods -o wide 确认 2 个 Pod。
  • Step 3kubectl run curl --rm -it --image=curlimages/curl --restart=Never -- curl -s http://<service-name>.<namespace>.svc.cluster.local(将 service-name 替换为你的 Service 名),多次执行看是否轮询到不同 Pod(若 nginx 有 hostname 可在响应中看到)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# scripts/l0_k8s_svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata: name: nginx
spec:
replicas: 2
selector: matchLabels: app: nginx
template:
metadata: labels: app: nginx
spec:
containers: - name: nginx
image: nginx:alpine
ports: - containerPort: 80
---
apiVersion: v1
kind: Service
metadata: name: nginx-svc
spec:
selector: app: nginx
ports: - port: 80
1
2
3
kubectl apply -f scripts/l0_k8s_svc.yaml
kubectl get svc nginx-svc
kubectl run curl --rm -it --image=curlimages/curl --restart=Never -- curl -s http://nginx-svc.default.svc.cluster.local

五、L1:算力与编排

5.1 硬件与加速器

  • GPU:CUDA 编程模型(kernel、grid/block、memory hierarchy)、cuDNN/cuBLAS 的角色;多卡、NVLink/NVSwitch。
  • TPU:Google TPU 架构与 XLA 编译;何时选 GPU 与何时选 TPU。
  • 成本与选型:按需/预留/spot、不同云厂商与专业 GPU 云(如 CoreWeave、Lambda、RunPod)的取舍。

5.2 资源调度与编排

  • Kubernetes:GPU/TPU 设备插件、nvidia-device-plugin、ResourceClass;多租户与配额。
  • 训练作业调度:Slurm、Ray(Ray Train/Cluster)、KubeFlow Training Operator、Volcano。
  • Serverless GPU:AWS SageMaker、Google Vertex AI、Azure ML 的托管训练/推理;与自建集群的对比。

当前趋势:K8s 成为 AI 工作负载的统一编排层(训练、推理、Agent 等),GKE 等提供托管 GPU/TPU 与生命周期管理。

5.3 L1 学习资料(含链接)

5.4 L1 实践方法

  • 本地/云单卡:在带 GPU 的机器或云实例上跑 nvidia-smi、简单 CUDA 程序或 PyTorch GPU 训练,观察显存与利用率。
  • K8s + GPU:在带 GPU 节点的集群(或云托管的 GKE/EKS 等)上部署一个请求 1 张 GPU 的 Job/Pod,确认设备挂载与驱动;用 Ray Operator 或 KubeFlow 提交一次多卡训练作业。
  • 对比一次:同一小模型在单卡、双卡 DP、以及 Ray 多节点上各跑一遍,记录耗时与显存,理解「调度 + 通信」对实际训练时间的影响。

5.5 L1 关键学习点实践案例

学习点 实践案例
CUDA 与显存 写一个最小 CUDA kernel(或用 PyTorch 在 GPU 上做大矩阵运算),用 nvidia-smi 观察显存占用;调整 tensor 大小直至 OOM,记录「显存 ≈ 模型+激活+优化器」的粗算关系。
nvidia-device-plugin 在带 GPU 的 K8s 集群中部署 nvidia-device-plugin DaemonSet,创建 limits: nvidia.com/gpu: 1 的 Pod,exec 进容器跑 nvidia-smi 确认设备可见。
Ray 多卡训练 Ray Train 示例 在单机多卡或两节点上跑一次 PyTorch 训练,查看 Ray Dashboard 的 GPU 使用与任务分布,并对比与单机 DDP 的耗时。
Spot 与成本 在某一云厂商创建 Spot GPU 实例,跑同一训练任务并记录是否被中断与单价;与 On-Demand 对比,算一笔「可中断场景下的成本节省」账。

5.6 L1:Step-by-step 细化流程与脚本

案例 1:CUDA 与显存(4090:完整;Mac:用 MPS 观察显存或 CPU 跑通逻辑)

  • 选型:PyTorch 在 GPU 上做大批量矩阵运算;4090 可用 nvidia-smi 看显存。
  • Step 1(4090):写脚本在 GPU 上创建多个大 tensor(如每个 1GB),每次分配后 nvidia-smi 记录显存,直至 OOM。
  • Step 2(Mac):用 MPS 做同样逻辑,用 torch.mps.current_allocated_memory()/torch.mps.driver_allocated_memory() 或任务管理器观察;或仅在 CPU 上跑通「显存≈模型+激活」的估算公式。
1
2
3
4
5
6
7
8
9
10
11
# scripts/l1_gpu_mem.py(4090 上运行;Mac 将 device 改为 "mps" 或 "cpu")
import torch
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
# 单 tensor 约 1GB (float32)
try:
for i in range(24):
a = torch.randn(256, 1024, 1024, device=device)
if device == "cuda":
print(i+1, "GB approx, alloc:", torch.cuda.memory_allocated()/2**30, "GB")
except RuntimeError as e:
print("OOM at step", i+1, e)

案例 2:nvidia-device-plugin(需带 NVIDIA GPU 的 K8s 集群,如 4090 单机 + kind/minikube 或云 GKE)

  • Step 1:在节点上安装 NVIDIA 驱动与 nvidia-container-toolkit;部署 k8s-device-plugin DaemonSet。
  • Step 2:创建 Pod,resources.limits["nvidia.com/gpu"]: 1,镜像用 nvidia/cuda:12.0-basekubectl exec 进 Pod 执行 nvidia-smi 确认可见 1 张卡。
1
2
3
4
5
6
7
8
9
10
11
# scripts/l1_gpu_pod.yaml
apiVersion: v1
kind: Pod
metadata: name: gpu-test
spec:
containers:
- name: cuda
image: nvidia/cuda:12.0-base
command: ["sleep", "3600"]
resources:
limits: nvidia.com/gpu: 1

案例 3:Ray 多卡训练(4090:单机 1 卡或 2 卡;Mac:单机 CPU 或 MPS 单卡,理解流程)

  • 选型:Ray Train + PyTorch,小模型(如 ResNet18)在 CIFAR-10 上;模型与数据量保证 5 分钟内可跑完。
  • Step 1:安装 ray[default] torch torchvision,写一个 train_epoch 函数(接收 config 与 data iterator)。
  • Step 2:用 ray.train.torch.TorchTrainer 配置 num_workers=1(或 2,若 2 卡),resources_per_worker={"GPU": 1},启动训练。
  • Step 3:打开 Ray Dashboard(默认 8265 端口),查看 GPU 使用;对比「单卡直接 PyTorch」与「Ray 1 worker 1 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
25
26
27
28
29
30
31
32
# scripts/l1_ray_train.py(单机 1 卡或 2 卡;Mac 可设 num_workers=1, use_gpu=False 或 MPS)
import ray
from ray.train.torch import TorchTrainer
from ray.train import ScalingConfig
import torch
from torch.utils.data import DataLoader
from torchvision.datasets import CIFAR10
from torchvision.transforms import ToTensor
from torchvision.models import resnet18

def train_epoch(config):
model = resnet18(num_classes=10)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
ds = CIFAR10(root="/tmp/data", download=True, transform=ToTensor())
loader = DataLoader(ds, batch_size=64, shuffle=True)
opt = torch.optim.Adam(model.parameters(), lr=1e-3)
for epoch in range(2):
for x, y in loader:
x, y = x.to(device), y.to(device)
opt.zero_grad()
loss = torch.nn.functional.cross_entropy(model(x), y)
loss.backward()
opt.step()

ray.init()
trainer = TorchTrainer(
train_epoch,
scaling_config=ScalingConfig(num_workers=1, use_gpu=torch.cuda.is_available(), resources_per_worker={"GPU": 1} if torch.cuda.is_available() else {}),
)
result = trainer.fit()
print(result)

案例 4:Spot 与成本(需云账号)

  • Step 1:在 AWS/GCP/Azure 控制台创建 Spot(或 Preemptible)GPU 实例,记录单价与区域。
  • Step 2:在同一区域创建 On-Demand 同规格实例,用同一训练脚本各跑 30 分钟,记录是否被中断与账单/预估费用。
  • Step 3:算「Spot 节省比例」并写进笔记(通常 60–80% 节省,但有中断风险)。

六、L2:数据层

6.1 数据管道与存储

  • ETL/ELT:批处理与流式(Spark、Flink、dbt);数据湖(Delta Lake、Iceberg)与数据仓库(Snowflake、BigQuery、Redshift)。
  • 数据版本与可复现:DVC、Delta Lake 时间旅行、数据血缘。

6.2 特征与向量存储

  • Feature Store:离线/在线特征、Feast、Tecton、云厂商 Feature Store;与训练/推理的数据一致性。
  • 向量数据库:Milvus、Pinecone、Weaviate、pgvector、Qdrant 等;索引(IVF、HNSW)、混合检索、过滤。
  • 数据治理:敏感数据、合规、访问控制与审计(与 2025 强调的隐私与安全一致)。

6.3 L2 学习资料(含链接)

6.4 L2 实践方法

  • 数据管道:用 Spark 或 Pandas 对一份公开数据集做一次清洗与分区写入(如 S3/本地 + Delta 或 Parquet);用 DVC 做一次数据版本追踪并与 Git 关联。
  • 向量检索:选一个开源向量库(如 Qdrant/Milvus),用 sentence-transformers 生成嵌入并建索引;写一个简单「查询 → 检索 TopK → 返回」的 API,测量延迟与吞吐。
  • 与训练挂钩:为一个小模型训练任务准备「特征表」或「向量检索结果」作为输入,体验训练/推理与数据层的一致性需求。

6.5 L2 关键学习点实践案例

学习点 实践案例
Spark 批处理与分区 用 PySpark 读一份 CSV/Parquet,做过滤与聚合,按日期或 key 分区写回 Delta/Parquet;观察分区数对后续「按分区读」的扫描量影响。
DVC 数据版本 DVC 入门 将一份数据集用 dvc add 追踪,推送到远程(本地目录/S3/GCS),在另一台机器或分支 dvc pull 复现,并与 Git commit 关联。
向量索引(IVF/HNSW) 在 Qdrant 或 Milvus 中对同一批向量分别建 IVF 与 HNSW 索引,用相同查询对比召回率与延迟;调整 ef/nlist 等参数观察 recall-latency 曲线。
Feature Store 离线/在线 用 Feast 定义一份 feature view 与 entity,写离线 historical retrieval 生成训练表,再部署 online store(如 Redis),写推理侧「按 entity 取特征」的代码,对比离线与在线特征一致性。
混合检索 在向量库中存文档的 embedding + 元数据(如 category、date),先按 metadata 过滤再做向量检索(或先向量 TopK 再按 metadata 过滤),对比纯向量与混合的召回与业务效果。

6.6 L2:Step-by-step 细化流程与脚本

案例 1:Spark 批处理与分区(Mac/4090 均可;无 Spark 集群时用 Pandas 模拟「分区写」)

  • 选型:本地 PySpark(pyspark 包)读 CSV/Parquet,按列分区写回;或 Pandas 做同逻辑。
  • Step 1:下载或生成一份带 datekey 列的小数据集(如 sample CSV)。
  • Step 2:用 PySpark 读入,过滤若干行,按 date(或 key)分区写入目录 out/date=xxx/;用 Spark 或 Pandas 再按分区读,对比「全表扫描」与「指定分区」的文件数/行数。
1
2
3
4
5
6
7
8
9
# scripts/l2_spark_partition.py(需 pip install pyspark)
from pyspark.sql import SparkSession
spark = SparkSession.builder.master("local[2]").getOrCreate()
# 生成带 date 的示例数据
df = spark.range(100).selectExpr("id", "id % 3 as key", "current_date() as dt")
df.write.mode("overwrite").partitionBy("key").parquet("/tmp/out_part")
# 按分区读
df2 = spark.read.parquet("/tmp/out_part").filter("key = 1")
print("partition key=1 count:", df2.count())

案例 2:DVC 数据版本

  • 选型:本地目录 + Git;Mac/4090 均可。
  • Step 1mkdir mydata && echo "id,label\n1,0\n2,1" > mydata/train.csvgit init && dvc init
  • Step 2dvc add mydatagit add mydata.csv.dvc .gitignoregit commit -m "add data"
  • Step 3:改 mydata/train.csv 后再次 dvc add、commit;在另一目录或分支 git clone + dvc pull 复现指定版本。
1
2
3
4
5
6
7
8
9
pip install dvc
mkdir -p mydata && echo "id,label\n1,0\n2,1" > mydata/train.csv
git init && dvc init
dvc add mydata
git add mydata.dvc .gitignore
git commit -m "track data v1"
# 改数据后
echo "id,label\n1,0\n2,1\n3,0" > mydata/train.csv
dvc add mydata && git add mydata.dvc && git commit -m "track data v2"

案例 3:向量索引(IVF/HNSW)(Mac/4090 均可;Qdrant 用 Docker 或 pip 内存模式)

  • 选型:Qdrant 本地(Docker:docker run -p 6333:6333 qdrant/qdrant)或 qdrant-client 内存模式;sentence-transformers all-MiniLM-L6-v2
  • Step 1:用 100 条文本生成 embedding,写入 Qdrant 两个 collection:一个用 HNSW、一个用 IVF(或默认),相同 ef/m 等可调参数。
  • Step 2:对 5 个查询做 search,记录两边的延迟与召回 Top5 的 id 列表;微调 ef 再测,画 recall@5 与延迟的取舍。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# scripts/l2_qdrant_hnsw_ivf.py(先启动 Qdrant: docker run -p 6333:6333 qdrant/qdrant)
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance
from sentence_transformers import SentenceTransformer

client = QdrantClient(host="localhost", port=6333)
model = SentenceTransformer("all-MiniLM-L6-v2")
texts = [f"document number {i} about some topic" for i in range(100)]
vectors = model.encode(texts).tolist()
payloads = [{"id": i} for i in range(100)]

client.recreate_collection("hnsw_coll", vectors_config=VectorParams(size=384, distance=Distance.COSINE), hnsw_config={"m": 16, "ef_construct": 100})
client.upsert("hnsw_coll", points=[{"id": i, "vector": v, "payload": p} for i, v, p in zip(range(100), vectors, payloads)])

client.recreate_collection("ivf_coll", vectors_config=VectorParams(size=384, distance=Distance.COSINE))
client.upsert("ivf_coll", points=[{"id": i, "vector": v, "payload": p} for i, v, p in zip(range(100), vectors, payloads)])

q = model.encode("document about topic").tolist()
for name in ["hnsw_coll", "ivf_coll"]:
res = client.search(name, q, limit=5)
print(name, [r.id for r in res])

案例 4:Feature Store 离线/在线(Mac/4090 均可;Feast 本地 + SQLite/Redis)

  • 选型:Feast 本地配置,offline store 用 file 或 SQLite,online store 用 SQLite(生产可换 Redis)。
  • Step 1:按 Feast 快速开始 定义 feature view 与 entity,生成一批 historical 特征并 get_historical_features 得到训练表。
  • Step 2materialize_incremental 或 push 到 online store,写一段推理侧代码用 get_online_features 按 entity 取特征,与离线表同一 entity 行对比数值一致。

案例 5:混合检索(Mac/4090 均可;Qdrant)

  • Step 1:在 Qdrant 中 upsert 时带 payload,如 categoryyear;插入 50 条不同 category。
  • Step 2:纯向量检索:query embedding 搜 Top10;混合:先 filter=(Field("category") == "A") 再向量搜 Top10。
  • Step 3:对同一 query 对比两种方式的 Top5 结果与延迟,记录「过滤后候选少」时的延迟差异。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# scripts/l2_hybrid_search.py
from qdrant_client import QdrantClient
from qdrant_client.models import Filter, FieldCondition, MatchValue, VectorParams, Distance
from sentence_transformers import SentenceTransformer

client = QdrantClient(host="localhost", port=6333)
model = SentenceTransformer("all-MiniLM-L6-v2")
categories = ["A", "B"] * 25
texts = [f"doc {i} cat {c}" for i, c in enumerate(categories)]
vectors = model.encode(texts).tolist()
client.recreate_collection("hybrid", vectors_config=VectorParams(size=384, distance=Distance.COSINE))
client.upsert("hybrid", points=[{"id": i, "vector": v, "payload": {"category": c}} for i, v, c in zip(range(50), vectors, categories)])
q = model.encode("doc about A").tolist()
pure = client.search("hybrid", q, limit=5)
filtered = client.search("hybrid", q, query_filter=Filter(must=[FieldCondition(key="category", match=MatchValue(value="A"))]), limit=5)
print("pure", [p.id for p in pure])
print("filtered A", [p.id for p in filtered])

七、L3:训练层

7.1 分布式训练范式

  • 数据并行(DP):多卡同模型、梯度 AllReduce。
  • 张量并行(TP):单层切分到多卡,解决单卡显存不足。
  • 流水线并行(PP):按层切分,多级流水。
  • 上下文并行(CP):长序列(如 8K+ token)切分。
  • 专家并行(EP):MoE 模型中专家分布到多卡。

7.2 主流框架与工具

  • DeepSpeed:ZeRO(1/2/3)、激活检查点、与 Megatron 集成;单卡/多卡显存优化。
  • Megatron-LM / Megatron Core:TP/PP/DP/CP/EP 组合;大规模预训练标配。
  • FSDP(PyTorch):原生全分片数据并行、混合精度、CPU offload;与 Megatron FSDP 的对比。
  • JAX/Flax:在 TPU 与部分 GPU 场景下的替代方案。

趋势:MegatronApp 等工具链开始覆盖训练期的性能诊断与可解释性;FSDP2 与框架原生支持持续增强。

7.3 L3 学习资料(含链接)

7.4 L3 实践方法

  • 单机多卡:用 PyTorch DDP 或 accelerate 在 2–4 张卡上训练同一小模型,对比单卡与多卡耗时与显存;开启 torch.compile 再测一次。
  • ZeRO/FSDP:用 DeepSpeed ZeRO-2 或 PyTorch FSDP 训练一个 7B 级别模型(或能占满显存的中等模型),观察 OOM 是否消除、吞吐与通信开销。
  • 多机(可选):在 Ray Cluster 或 KubeFlow 上跑一次 2 节点、每节点多卡的训练,记录通信占比与扩展效率,理解 DP/TP/PP 的取舍场景。

7.5 L3 关键学习点实践案例

学习点 实践案例
DDP 与 AllReduce 用 PyTorch DDP 在 2 卡上训练同一模型,用 torch.distributed 的 barrier 与打印,确认两卡梯度一致;对比单卡与 2 卡的总 step 时间与吞吐(应接近 2x)。
ZeRO-2 显存节省 DeepSpeed ZeRO-2 配置 训练一个 7B 模型(或能 OOM 的较小模型),对比 ZeRO 关闭与 ZeRO-2 开启时的显存占用与训练速度。
FSDP 与 CPU offload PyTorch FSDP 教程 在有限显存下开启 cpu_offload,观察显存下降与步时增加,理解「显存-算力」权衡。
TP/PP 概念验证 用 Megatron 或 transformers 的 TP 示例 在 2 卡上跑一个小模型的张量并行,对比 2 卡 DP 与 2 卡 TP 的显存与通信量差异。
torch.compile 对同一训练脚本开启 model = torch.compile(model),对比首 step 冷启动时间与后续 step 吞吐,在不同模型规模下记录「编译收益」与「首步代价」。

7.6 L3:Step-by-step 细化流程与脚本

案例 1:DDP 与 AllReduce(4090 单卡或双卡;Mac 单机单卡/MPS 或 CPU 理解流程)

  • 选型:PyTorch DDP,小模型(如 ResNet18)+ CIFAR-10;双卡时用 torchrun 启动。
  • Step 1:写单卡训练脚本,记录 50 step 耗时;再写 DDP 版,用 torchrun --nproc_per_node=2 script.py 启动(4090 双卡)。
  • Step 2:在 DDP 脚本里加 torch.distributed.barrier() 与一次打印每 rank 的梯度范数,确认两卡同步后数值一致。
  • Step 3:对比单卡 50 step 时间与双卡 DDP 50 step 时间(应接近 2x 加速)。
1
2
3
# 4090 双卡启动
pip install torch torchvision
torchrun --nproc_per_node=2 scripts/l3_ddp_train.py
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
# scripts/l3_ddp_train.py
import os
import torch
import torchvision
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
from torchvision.models import resnet18
from torchvision.datasets import CIFAR10
from torch.utils.data import DataLoader, DistributedSampler

def main():
dist.init_process_group("nccl")
rank = int(os.environ["RANK"])
device = torch.device(f"cuda:{rank}")
model = resnet18(num_classes=10).to(device)
model = DDP(model, device_ids=[rank])
sampler = DistributedSampler(CIFAR10(root="/tmp/data", download=True, transform=torchvision.transforms.ToTensor()), num_replicas=dist.get_world_size(), rank=rank)
loader = DataLoader(CIFAR10(root="/tmp/data", download=True, transform=torchvision.transforms.ToTensor()), batch_size=64, sampler=sampler)
opt = torch.optim.Adam(model.parameters(), lr=1e-3)
t0 = torch.cuda.Event(enable_timing=True)
t0.record()
for i, (x, y) in enumerate(loader):
if i >= 50: break
x, y = x.to(device), y.to(device)
opt.zero_grad()
loss = torch.nn.functional.cross_entropy(model(x), y)
loss.backward()
dist.barrier()
opt.step()
t1 = torch.cuda.Event(enable_timing=True)
t1.record()
torch.cuda.synchronize()
if rank == 0:
print("50 steps time (s):", t0.elapsed_time(t1) / 1000)

if __name__ == "__main__":
main()

案例 2:ZeRO-2 显存节省(需 4090 或大显存 GPU;Mac 可用小模型 + CPU 跑通配置)

  • 选型:Hugging Face accelerate + DeepSpeed ZeRO-2,模型 Qwen2.5-0.5B-Instructgoogle/flan-t5-small
  • Step 1accelerate config 选 DeepSpeed ZeRO-2,单卡。
  • Step 2:写一训练脚本(2 个 batch 即可),先关 ZeRO 跑一次看显存;再开 ZeRO-2 跑,对比显存占用(nvidia-smi)。
1
2
pip install accelerate deepspeed transformers
accelerate config # 选 DeepSpeed, ZeRO stage 2

案例 3:FSDP 与 CPU offload(4090 或 Mac;大模型可开 cpu_offload)

  • 选型:PyTorch FSDP,torch.distributed.fsdp;模型可用 meta-llama/Llama-2-7b-hf 或更小的 HuggingFaceM4/tiny-random-LlamaForCausalLM 做测试。
  • Step 1:用官方 FSDP 教程 脚本,先不 offload 跑 5 step 记显存。
  • Step 2:开启 CPUOffload(offload_params=True) 再跑 5 step,观察显存下降、步时增加。

案例 4:TP/PP 概念验证(需 2 卡 4090;或单卡理解文档)

  • 选型transformerstensor parallelism 或 Megatron 小模型示例。
  • Step 1:在两卡上跑 2-way TP 的 forward 一次,记录显存(每卡约为单卡一半量级);对比同模型 2 卡 DDP 的每卡显存。

案例 5:torch.compile(Mac/4090 均可)

  • 选型:同 3.6 案例 4 的 flan-t5-smalldistilbert;测量首 step 与后续 step。
  • Step 1:不编译训练 10 step,记录第 1 step 与第 2–10 平均 step 时间。
  • Step 2model = torch.compile(model, mode="reduce-overhead") 再训 10 step,对比首步冷启动与后续加速比。

八、L4:推理与 Serving

8.1 推理服务器与优化

  • vLLM:PagedAttention、Continuous Batching、CUDA kernel 优化;高吞吐、低显存占用。
  • TensorRT-LLM:NVIDIA 官方、FP4/FP8 量化、多 GPU/多节点、Speculative Decoding。
  • TGI(Text Generation Inference):Hugging Face 的 serving 方案;与 vLLM 的选型场景。
  • 通用推理框架:Triton Inference Server、ONNX Runtime、OpenVINO。

8.2 性能与成本

  • Batching:静态 vs 动态/连续 batching;延迟与吞吐的权衡。
  • 量化:INT8/INT4、GPTQ、AWQ、FP8;精度与显存/速度的平衡。
  • 多模型与混合部署:同一集群内多模型共存、资源分区(如 VectorLiteRAG 风格的细粒度分配)。

趋势:开源与自托管模型增多;推理与向量检索共置(RAG 场景)的联合优化(如 RAGO、VectorLiteRAG)成为热点。

8.3 L4 学习资料(含链接)

8.4 L4 实践方法

  • 本地 serving:用 vLLM 或 TGI 在单卡上部署一个 7B 级开源模型,用 curl/Postman 调 OpenAI 兼容 API;压测不同 batch 与并发下的 QPS、P99 延迟。
  • 量化对比:同一模型分别用 FP16、INT8/INT4 部署,对比显存占用、首 token 与生成延迟、简单任务准确率。
  • 上 K8s:将上述推理服务容器化并在 K8s 中部署(HPA、GPU 资源限制);配合 Ingress 或 LoadBalancer 做一次从外网到模型的完整请求链路。

8.5 L4 关键学习点实践案例

学习点 实践案例
vLLM 部署与 API vLLM Quickstart 在单卡上启动一个 7B 模型,用 curl/v1/completions/v1/chat/completions,改 max_tokensn 观察延迟与吞吐变化。
Continuous Batching 用同一 vLLM 服务,用脚本并发发送 10 个不同长度的请求,对比「串行 10 次」与「并发 10 个」的总耗时与 P99,理解连续批对吞吐的提升。
量化对比(FP16 vs INT4) 同一模型用 vLLM 分别以 FP16 与 AWQ/GPTQ INT4 启动,在相同 prompt 下对比:显存占用(nvidia-smi)、首 token 延迟、生成 100 token 的耗时与简单问答正确率。
TensorRT-LLM 多 GPU TensorRT-LLM Multi-GPU 在 2 卡上部署一个模型,用 mpirun 或脚本调用,观察 2 卡下的吞吐与单卡对比。
推理服务上 K8s 将 vLLM/TGI 打成 Docker 镜像,写 Deployment(request/limit 各 1 GPU)和 Service,用 HPA 或手动 scale 到 2 replica,用 LoadBalancer/Ingress 从集群外压测,记录多副本下的 QPS 与延迟分布。

8.6 L4:Step-by-step 细化流程与脚本

案例 1:vLLM 部署与 API(4090:vLLM;Mac:Ollama 替代,同样 OpenAI 兼容 API)

  • 选型(4090):vLLM + Qwen2.5-1.5B-Instructmistralai/Mistral-7B-Instruct-v0.2;Mac:Ollama 拉取 qwen2.5:1.5b
  • Step 1(4090)pip install vllmpython -m vllm.entrypoints.openai.api_server --model Qwen/Qwen2.5-1.5B-Instruct --port 8000,等待加载完成。
  • Step 2curl http://localhost:8000/v1/completions -d '{"model":"Qwen/Qwen2.5-1.5B-Instruct","prompt":"Hello","max_tokens":50}"' -H "Content-Type: application/json",记录返回与耗时。
  • Step 3:改 max_tokens 为 100、n 为 2 各请求一次,观察延迟与吞吐变化。Mac 用 Ollama 时:ollama run qwen2.5:1.5b,用 OpenAI 兼容端口或 curl http://localhost:11434/api/generate
1
2
3
4
5
# 4090
pip install vllm
python -m vllm.entrypoints.openai.api_server --model Qwen/Qwen2.5-1.5B-Instruct --port 8000
# 另终端
curl http://localhost:8000/v1/completions -H "Content-Type: application/json" -d '{"model":"Qwen/Qwen2.5-1.5B-Instruct","prompt":"Say hi","max_tokens":20}'

案例 2:Continuous Batching(4090:对 vLLM 并发请求;Mac:对 Ollama 并发)

  • Step 1:保持 vLLM/Ollama 服务运行,用 Python 并发发 10 个不同长度 prompt 的请求(如 1 字、5 字、10 字…),记录总耗时与各请求 P99。
  • Step 2:串行发同样 10 个请求,记录总耗时;对比「并发总时」远小于「串行总时」理解连续批效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# scripts/l4_continuous_batch.py(改 URL 为你的 vLLM/Ollama 端点)
import concurrent.futures
import time
import requests

def one_request(prompt):
t0 = time.perf_counter()
r = requests.post("http://localhost:8000/v1/completions", json={"model": "Qwen/Qwen2.5-1.5B-Instruct", "prompt": prompt, "max_tokens": 30}, timeout=60)
return time.perf_counter() - t0

prompts = ["Hi"] * 2 + ["Tell me a short story"] * 2 + ["Explain ML in one sentence"] * 2
# 并发
t0 = time.perf_counter()
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as ex:
latencies = list(ex.map(one_request, prompts))
print("concurrent total:", time.perf_counter() - t0, "latencies", latencies)
# 串行
t0 = time.perf_counter()
for p in prompts:
one_request(p)
print("serial total:", time.perf_counter() - t0)

案例 3:量化对比(FP16 vs INT4)(需 4090;vLLM 支持 AWQ/GPTQ)

  • 选型:同一模型如 Qwen2.5-1.5B-Instruct,先 FP16 再 AWQ 量化版(若有无现成 AWQ 则用 GPTQ 或 vLLM 文档中支持的量化模型)。
  • Step 1:vLLM 启动 FP16 版,记显存(nvidia-smi)与同一 prompt 首 token、生成 100 token 耗时。
  • Step 2:vLLM 启动 AWQ/INT4 版(如 Qwen/Qwen2.5-1.5B-Instruct-AWQ 或文档中对应名),同样测显存与延迟;对比表格。
1
2
3
4
5
# 4090
nvidia-smi # 记录空闲显存后
python -m vllm.entrypoints.openai.api_server --model Qwen/Qwen2.5-1.5B-Instruct --port 8000
# 测完关掉,再起量化版(示例名,以 vLLM 文档为准)
python -m vllm.entrypoints.openai.api_server --model Qwen/Qwen2.5-1.5B-Instruct-AWQ --port 8000 --quantization awq

案例 4:TensorRT-LLM 多 GPU(需 2 张 4090 或 2 卡环境)

  • Step 1:按 TensorRT-LLM Multi-GPU 构建并运行 2 卡示例,用 mpirun -n 2 启动。
  • Step 2:记录 2 卡总吞吐与单卡同模型吞吐,理解多卡扩展。

案例 5:推理服务上 K8s(需带 GPU 的 K8s 集群,如 4090 + kind 或云)

  • Step 1:将 vLLM 或 TGI 打成镜像(Dockerfile 内安装 vllm 并 CMD 启动 openai.api_server),推送到可被集群拉取的仓库。
  • Step 2:写 Deployment(replicas: 1,limits: nvidia.com/gpu: 1)、Service(ClusterIP 或 LoadBalancer),kubectl apply
  • Step 3kubectl scale deployment vllm-deploy --replicas=2,用 port-forward 或 LoadBalancer 从本机压测两个 endpoint,记录 QPS 与 P99。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# scripts/l4_k8s_vllm.yaml(镜像名替换为你的)
apiVersion: apps/v1
kind: Deployment
metadata: name: vllm
spec:
replicas: 1
selector: matchLabels: app: vllm
template:
metadata: labels: app: vllm
spec:
containers:
- name: vllm
image: vllm/vllm-openai:latest
args: ["--model", "Qwen/Qwen2.5-1.5B-Instruct", "--port", "8000"]
ports: - containerPort: 8000
resources: limits: nvidia.com/gpu: 1
---
apiVersion: v1
kind: Service
metadata: name: vllm-svc
spec:
selector: app: vllm
ports: - port: 8000

九、L5:MLOps / LLMOps 与工程化

9.1 实验与模型管理

  • 实验追踪:MLflow、Weights & Biases、Neptune;指标、参数、artifact 与复现。
  • Model Registry:版本、别名(如 champion)、审批与发布流程;MLflow Model Registry、云厂商 Registry。
  • 特征与模型血缘:从数据到模型到部署的追溯与审计。

9.2 流水线与发布

  • CI/CD for ML:代码 + 数据 + 模型 的流水线;KubeFlow Pipelines、Airflow、Dagster、GitHub Actions 与 ML 步骤。
  • 发布策略:蓝绿、金丝雀、影子流量;回滚与流量切换。

9.3 LLMOps 特有

  • Prompt 管理与版本:Prompt 模板版本化、A/B 测试。
  • 评估:困惑度、人工偏好、特定任务指标;RAG 的检索质量与答案相关性。
  • 幻觉与安全:监控与缓解;人类反馈(RLHF)在流水线中的位置。
  • RAG 流水线:检索 → 重排 → 生成 的编排、评估与迭代。

趋势:端到端 MLOps 强调自动化、合规与可持续;LLMOps 与 RAG 管线成为 2025 实践重点。

9.4 可观测性

  • 指标:QPS、延迟(P50/P99)、错误率、GPU 利用率。
  • 追踪:请求级 trace(从网关到模型、到向量库);OpenTelemetry。
  • 日志与告警:结构化日志、敏感信息脱敏、基于 SLO 的告警。

9.5 L5 学习资料(含链接)

9.6 L5 实践方法

  • 实验闭环:用 MLflow 或 W&B 记录多次训练(不同超参/数据),在 UI 中对比并选出一个「champion」注册到 Model Registry;写一个简单脚本从 Registry 拉取模型并触发部署或导出。
  • 流水线一次:用 Airflow/Dagster 或 GitHub Actions 串起「拉数据 → 训练 → 评估 → 若通过则写 Registry」的流水线,至少跑通一次端到端。
  • 可观测性:为已部署的推理服务加上 Prometheus metrics(请求数、延迟分位、错误率);用 Grafana 做一张 dashboard;可选:用 OpenTelemetry 把一次请求从网关到模型、到向量库的 trace 打出来。

9.7 L5 关键学习点实践案例

学习点 实践案例
MLflow 实验与 Registry MLflow 快速入门 跑 3 次不同超参的训练并 mlflow.log_*,在 UI 中对比曲线并选一个 run 用 register_model 注册;写脚本用 mlflow.pyfunc.load_model("models:/my_model/1") 加载。
流水线「训练→评估→注册」 用 GitHub Actions 或 Dagster 定义一个 pipeline:拉取数据 → 训练脚本 → 若验证准确率 > 阈值则 mlflow register 并打 tag;手动触发一次并确认端到端跑通。
Prompt 版本与 A/B 在 LangSmith 或自建表中记录「prompt 模板版本 + 请求 + 响应 + 人工打分」;对同一任务跑 2 个 prompt 版本各 50 条请求,对比平均分与稳定性,做出选用决策。
RAG 评估(RAGAS/自定义) RAGAS 或自写脚本:对 20 个问题跑 RAG 得到答案,计算 faithfulness、answer_relevancy 等;改 chunk 策略或模型后再测,形成「指标-迭代」闭环。
Prometheus + Grafana 推理监控 在推理服务中暴露 /metrics(请求数、延迟直方图、错误数),用 Prometheus scrape;在 Grafana 建 dashboard 看 QPS、P99、错误率;可选:为 GPU 使用率加 DCGM exporter。

9.8 L5:Step-by-step 细化流程与脚本

案例 1:MLflow 实验与 Registry(Mac/4090 均可)

  • 选型:MLflow 本地 backend/store(mlruns),sklearn 或 PyTorch 小模型。
  • Step 1pip install mlflow,在脚本里 mlflow.set_tracking_uri("file:./mlruns"),跑 3 次训练(不同 lr:0.01、0.001、0.0001),每次 mlflow.log_parammlflow.log_metricmlflow.sklearn.log_model(或 pyfunc)。
  • Step 2mlflow ui 打开 UI,在 Runs 里对比 3 次曲线,选最优 run 点击 Register Model,命名为 my_model,版本 1。
  • Step 3:写加载脚本 model = mlflow.pyfunc.load_model("models:/my_model/1"),对一条样本做 model.predict(...) 验证。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# scripts/l5_mlflow_register.py
import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

mlflow.set_tracking_uri("file:./mlruns")
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
for lr in [0.01, 0.001, 0.0001]: # 用 lr 模拟不同超参
with mlflow.start_run():
mlflow.log_param("lr", lr)
model = RandomForestClassifier(n_estimators=10)
model.fit(X_train, y_train)
acc = model.score(X_test, y_test)
mlflow.log_metric("accuracy", acc)
mlflow.sklearn.log_model(model, "model")
# 注册:在 UI 中选最优 run 点 Register Model,或 CLI:
# mlflow register-model -r <run_id> -n my_model
# 加载
# model = mlflow.pyfunc.load_model("models:/my_model/1")
# print(model.predict(X_test[:1]))

案例 2:流水线「训练→评估→注册」(Mac/4090 均可)

  • 选型:GitHub Actions 或本地 shell 脚本;MLflow 做存储。
  • Step 1:写 train.py:拉数据(如 sklearn 内置)、训练、评估、若 accuracy > 阈值则 mlflow.register_model(run_id, "champion")
  • Step 2:写 .github/workflows/train.ymlbash run_pipeline.shpython train.py;手动触发一次,确认 MLflow UI 中出现新 run 且达标时模型被注册。
1
2
3
4
5
6
7
8
9
10
11
12
# .github/workflows/train.yml(示例)
name: train-and-register
on: workflow_dispatch
jobs:
train:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: python-version: "3.11"
- run: pip install mlflow scikit-learn
- run: python scripts/l5_train_register.py

案例 3:Prompt 版本与 A/B(Mac/4090 均可)

  • 选型:本地 CSV 或 SQLite 记录 (prompt_version, request, response, score);两个 prompt 模板。
  • Step 1:定义 prompt_v1、prompt_v2(如「用一句话回答:{q}」vs「请简洁回答:{q}」),各调用 10 次本地 LLM(Ollama/vLLM)或 API,将 request/response 写入表。
  • Step 2:人工或规则对每条打 0/1 分,算两版本的均分与方差,做出选用决策。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# scripts/l5_prompt_ab.py
import csv
# 模拟:真实场景下替换为调用 Ollama/vLLM/API
def call_llm(prompt_template, q):
return prompt_template.format(q=q) + " [simulated answer]"

v1 = "用一句话回答:{q}"
v2 = "请简洁回答:{q}"
questions = ["什么是机器学习?"] * 5 + ["什么是深度学习?"] * 5
rows = []
for i, q in enumerate(questions):
for name, t in [("v1", v1), ("v2", v2)]:
resp = call_llm(t, q)
rows.append({"version": name, "question": q, "response": resp, "score": 1 if i % 2 == 0 else 0})
with open("prompt_ab.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["version", "question", "response", "score"])
w.writeheader()
w.writerows(rows)
# 分析
import pandas as pd
df = pd.read_csv("prompt_ab.csv")
print(df.groupby("version")["score"].agg(["mean", "std"]))

案例 4:RAG 评估(RAGAS/自定义)(Mac/4090 均可)

  • 选型:20 条 (question, reference_answer 或 key_facts);RAGAS 或自写 faithfulness/relevancy。
  • Step 1:用现有 RAG 管道对 20 问生成 answer;用 RAGAS 的 evaluate(dataset, answer_key=...) 或自写:用 NLI 模型判「answer 是否蕴含 reference」、用 embedding 相似度判 relevancy。
  • Step 2:改 chunk_size 或 base 模型后重跑 RAG,再算一次指标,记录对比表。
1
pip install ragas datasets
1
2
3
4
5
6
7
8
9
10
11
# scripts/l5_ragas_eval.py(需 OpenAI API key 或 RAGAS 支持的本地模型)
# from ragas import evaluate
# from ragas.metrics import faithfulness, answer_relevancy
# dataset = ... # 含 question, answer, contexts, ground_truth
# r = evaluate(dataset, metrics=[faithfulness, answer_relevancy])
# 自写简化:用 sentence-transformers 算 query 与 answer 相似度作为 relevancy
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-MiniLM-L6-v2")
def relevancy(q, a):
return float(model.encode([q, a]).dot(model.encode([q, a]).T)[0, 1])
print(relevancy("What is ML?", "ML is a subset of AI."))

案例 5:Prometheus + Grafana 推理监控(Mac/4090 均可)

  • 选型:Flask/FastAPI 推理服务内用 prometheus_client 暴露 /metrics;本地 Prometheus + Grafana Docker。
  • Step 1:在推理接口中加 Counter('requests_total', ...)Histogram('request_latency_seconds', ...),每次请求递增与 observe。
  • Step 2docker run -p 9090:9090 prom/prometheus(配置 scrape localhost:8000/metrics)、docker run -p 3000:3000 grafana/grafana,在 Grafana 添加 Prometheus 数据源,建 Panel 看 requests_total 与 request_latency P99。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# scripts/l5_prometheus_metrics.py(在现有 app 中加入)
from prometheus_client import Counter, Histogram, generate_latest
from flask import Flask, Response

REQUEST_COUNT = Counter("inference_requests_total", "Total requests")
LATENCY = Histogram("inference_latency_seconds", "Request latency")

app = Flask(__name__)

@app.route("/metrics")
def metrics():
return Response(generate_latest(), mimetype="text/plain")

@app.route("/infer")
def infer():
REQUEST_COUNT.inc()
with LATENCY.time():
# 模拟推理
pass
return "ok"

十、L6:应用架构(RAG、Agent、多模型)

10.1 RAG(检索增强生成)

  • 组件:文档切分、嵌入模型、向量索引、检索、重排序、LLM 生成。
  • 架构:向量库与 LLM 同机/同集群的资源分配;延迟与吞吐的联合优化(参见 VectorLiteRAG、RAGO 等)。
  • 评估:检索召回、答案准确性、幻觉率、端到端延迟。

10.2 Agent 与多步推理

  • 编排:LangChain、LlamaIndex、CrewAI 等;工具调用、规划与执行。
  • 基础设施:长时间运行、状态管理、与 K8s/Serverless 的配合。

10.3 部署策略(与当前实践一致)

  • 混合部署:Serverless API(如托管 OpenAI 兼容接口)+ 自建关键模型;成本与可控性平衡。
  • 多模型与路由:按业务路由到不同模型/版本;灰度与回滚。
  • 开源与微调:优先使用开源/微调模型以控制成本与数据主权;与托管 API 的混合使用。

10.4 L6 学习资料(含链接)

10.5 L6 实践方法

  • RAG 端到端:选一个垂直领域(如内部文档、产品手册),完成「文档切分 → 嵌入 → 向量库索引 → 检索 + 重排 → 调用本地或 API LLM 生成」;用一批问题做检索质量与答案准确性评估,迭代 chunk 策略与模型。
  • Agent 小应用:用 LangChain/LlamaIndex 做一个带工具调用的 Agent(如查天气、查数据库),在本地或 Docker 跑通;再在 K8s 中部署为常驻服务,观察长会话与资源占用。
  • 混合部署:设计一个「部分请求走自建 vLLM、部分走 OpenAI 兼容 API」的网关或路由逻辑,做一次流量切换与回滚演练。

10.6 L6 关键学习点实践案例

学习点 实践案例
文档切分与嵌入 用 LangChain 的 RecursiveCharacterTextSplitter 对一份 PDF/HTML 做不同 chunk_size 与 overlap 的切分,用 sentence-transformers 嵌入并写入 Qdrant;对比不同 chunk 策略对「同一问题」的 Top3 召回文档差异。
检索→重排→生成 实现一条链路:用户 query → 向量检索 TopK(如 10)→ 用 cross-encoder 或 LLM 做 rerank 取 Top3 → 将 3 段 context 与 query 拼成 prompt 送 LLM 生成;对比「仅 Top1」与「Top3 rerank」的答案质量与延迟。
RAG 评估闭环 准备 20 个「问题 + 标准答案或关键事实」,跑 RAG 得到答案;用 RAGAS 或自写脚本算 faithfulness、relevancy;改 chunk 策略或 base 模型后重跑,记录指标变化。
Agent 工具调用 用 LangChain 定义一个带「搜索」「计算器」等工具的 Agent,在本地跑 5 个多步问题(如「北京今天天气如何,若下雨则推荐带伞」),检查 chain 中 tool 的调用顺序与结果是否正确。
多模型路由 用 Nginx 或简单 Python 网关:按 URL path(如 /v1/small/v1/large)或 header 将请求转发到不同 vLLM 后端(如 7B 与 70B);压测时切换路由权重,观察各后端 QPS 与延迟。

10.7 L6:Step-by-step 细化流程与脚本

案例 1:文档切分与嵌入(Mac/4090 均可)

  • 选型:LangChain RecursiveCharacterTextSplitter,sentence-transformers all-MiniLM-L6-v2,Qdrant(Docker 或内存)。
  • Step 1:准备一份 1–2 页的 Markdown/HTML 或 TXT,用 RecursiveCharacterTextSplitter(chunk_size=200, overlap=20) 切分,打印 chunk 数量与每块前 50 字。
  • Step 2:用 all-MiniLM-L6-v2 对 chunks 编码,写入 Qdrant;再对同一问题用 chunk_size=100、overlap=10 重做一遍,对比「同一 query」的 Top3 召回 chunk 是否不同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# scripts/l6_chunk_embed.py
from langchain.text_splitter import RecursiveCharacterTextSplitter
from sentence_transformers import SentenceTransformer
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance

text = open("sample_doc.txt").read() # 或任意 1 页文本
splitter = RecursiveCharacterTextSplitter(chunk_size=200, overlap=20)
chunks = splitter.split_text(text)
model = SentenceTransformer("all-MiniLM-L6-v2")
vecs = model.encode(chunks).tolist()
client = QdrantClient(host="localhost", port=6333)
client.recreate_collection("docs", vectors_config=VectorParams(size=384, distance=Distance.COSINE))
client.upsert("docs", points=[{"id": i, "vector": v, "payload": {"text": c}} for i, (v, c) in enumerate(zip(vecs, chunks))])
q = model.encode("你的问题").tolist()
res = client.search("docs", q, limit=3)
for r in res:
print(r.payload["text"][:80])

案例 2:检索→重排→生成(Mac/4090 均可;LLM 可用 Ollama 或 vLLM)

  • 选型:Qdrant 检索 Top10;重排用 cross-encoder(如 cross-encoder/ms-marco-MiniLM-L-6-v2)取 Top3;LLM 用本地 Ollama qwen2.5:1.5b 或 vLLM。
  • Step 1:实现 retrieve(query, k=10)rerank(query, docs, top_k=3)generate(context, query) 三段式;记录每段耗时。
  • Step 2:对比「仅用 Top1 检索结果生成」与「Top3 重排后生成」的答案质量(人工或简单 NLI 打分)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# scripts/l6_retrieve_rerank_generate.py
from sentence_transformers import SentenceTransformer, CrossEncoder
from qdrant_client import QdrantClient

embed = SentenceTransformer("all-MiniLM-L6-v2")
reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-6-v2")
client = QdrantClient(host="localhost", port=6333)

def retrieve(query, k=10):
q = embed.encode(query).tolist()
return client.search("docs", q, limit=k)

def rerank(query, hits, top_k=3):
pairs = [(query, h.payload["text"]) for h in hits]
scores = reranker.predict(pairs)
top = sorted(zip(hits, scores), key=lambda x: -x[1])[:top_k]
return [t[0] for t in top]

# generate: 将 Top3 的 payload["text"] 拼成 context,调用 Ollama/vLLM
# 示例:import requests; r = requests.post("http://localhost:11434/api/generate", json={"prompt": f"Context: {context}\nQ: {query}\nA:"})

案例 3:RAG 评估闭环(Mac/4090 均可)

  • Step 1:准备 20 条 (question, reference_or_key_facts) 存 CSV;用案例 2 的 RAG 管道对每问生成 answer。
  • Step 2:用 RAGAS 或自写脚本算 faithfulness(answer 与 reference 的蕴含关系)与 answer_relevancy(query 与 answer 相似度);记录平均分。
  • Step 3:改 chunk_size 或 base 模型,重跑 RAG 与评估,填对比表。

案例 4:Agent 工具调用(Mac/4090 均可)

  • 选型:LangChain + 本地 LLM(Ollama)或 OpenAI API;工具:计算器、当前时间(或 mock 天气)。
  • Step 1:用 @tool 定义 add(a,b)get_time(),用 create_react_agentAgentExecutor 绑定 LLM 与 tools。
  • Step 2:问「3+5 等于多少」和「现在几点」,检查 chain 中是否调用了对应 tool 并返回正确结果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# scripts/l6_agent_tools.py
from langchain.agents import create_react_agent, AgentExecutor
from langchain.tools import tool
from langchain_community.llms import Ollama
from langchain_core.prompts import ChatPromptTemplate

@tool
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b

@tool
def get_time() -> str:
"""Get current time."""
import datetime
return datetime.datetime.now().isoformat()

llm = Ollama(model="qwen2.5:1.5b")
prompt = ChatPromptTemplate.from_messages([("human", "{input}\n\n{agent_scratchpad}")])
agent = create_react_agent(llm, [add, get_time], prompt)
executor = AgentExecutor(agent=agent, tools=[add, get_time], verbose=True)
print(executor.invoke({"input": "What is 3 + 5?"}))

案例 5:多模型路由(4090:两路 vLLM;Mac:两路 Ollama 或一路 Ollama 一路 mock)

  • 选型:Python FastAPI 网关:/v1/small 转发到 1.5B 模型,/v1/large 转发到 7B 或同一模型不同端口(模拟)。
  • Step 1:启动两个后端(如 vLLM 8000/8001 或 Ollama 不同 model);写网关根据 path 选 backend URL,proxy 请求。
  • Step 2:用脚本对 /v1/small/v1/large 各发 10 个请求,记录两路 QPS 与 P99;改网关权重(如 80% small、20% large)再压测。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# scripts/l6_router.py(FastAPI 网关示例)
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
import httpx

app = FastAPI()
SMALL = "http://localhost:8000"
LARGE = "http://localhost:8001"

@app.post("/v1/small/{path:path}")
async def small(request: Request, path: str):
body = await request.json()
async with httpx.AsyncClient() as c:
r = await c.post(f"{SMALL}/v1/completions", json=body)
return r.json()

@app.post("/v1/large/{path:path}")
async def large(request: Request, path: str):
body = await request.json()
async with httpx.AsyncClient() as c:
r = await c.post(f"{LARGE}/v1/completions", json=body)
return r.json()

十一、安全、合规与成本

  • 安全:模型与数据加密(静态/传输)、VPC/私有子网、身份与访问控制(IAM)、密钥管理。
  • 合规:数据属地、审计日志、合规报告(如 SOC2、GDPR)。
  • 成本:GPU 占大头;通过 spot、预留实例、自动伸缩与混合云优化;监控与 FinOps。

行业痛点:隐私与安全、GPU 价格与可用性、部署与维护复杂度;本指南各层均需兼顾这三者。

11.1 安全、合规与成本:学习资料(含链接)

11.2 安全、合规与成本:关键学习点实践案例

学习点 实践案例
推理服务网络隔离 在 K8s 中将推理服务仅暴露给集群内 Service,通过 Ingress 或 API Gateway 做 TLS 终止与认证,确保外网不直接访问推理 Pod;用 kubectl 与 curl 从集群内/外验证访问策略。
密钥与配置管理 用 K8s Secret 或云厂商 Secret Manager 存 API Key/数据库密码,在 Deployment 中通过 env 或 volume 注入;在本地与 CI 中禁止硬编码密钥,用环境变量或 secret 注入验证一次完整发布。
审计日志 为关键操作(如模型注册、流水线触发、推理 API 调用)打结构化日志(含 user、resource、timestamp);接入 ELK 或云日志,做一次「按 user 查询某日操作」的检索。
GPU 成本对比 在同一区域选 On-Demand、Spot、1 年预留三种 GPU 实例,用同一训练脚本跑 1 小时,记录账单或单价 × 时长;算一笔「可中断训练用 Spot 的节省比例」。
简单 FinOps 看板 用云厂商 Cost Explorer 或 Kubecost 拉取「按 namespace/label 的 GPU 或 Pod 成本」,在 Grafana 或表格中做一张「本周各项目/团队 GPU 消耗」视图,并设一条超支告警。

11.3 安全、合规与成本:Step-by-step 细化流程与脚本

案例 1:推理服务网络隔离(Mac/4090 均可;需 K8s 集群)

  • 选型:K8s 内推理 Deployment 不暴露 NodePort/LoadBalancer;仅通过 Ingress 或 ClusterIP + 另一 Gateway Pod 访问。
  • Step 1:部署推理服务(如 Flask 返回 “ok”),Service 类型为 ClusterIP;确认集群外 curl <node_ip>:<nodeport> 无法访问(未建 NodePort)。
  • Step 2:部署一个带 curl 的 Pod,kubectl exec 进该 Pod,curl http://<svc-name>.<namespace>.svc.cluster.local:8000 确认集群内可访问。
  • Step 3:配置 Ingress(或 API Gateway)做 TLS 与路径转发到该 Service;从集群外通过 Ingress 域名访问,验证「仅经网关可达推理服务」。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# scripts/l11_network_isolate.yaml(推理仅 ClusterIP,无对外 NodePort)
apiVersion: v1
kind: Service
metadata: name: infer-svc
spec:
type: ClusterIP
selector: app: infer
ports: - port: 8000
---
apiVersion: apps/v1
kind: Deployment
metadata: name: infer
spec:
replicas: 1
selector: matchLabels: app: infer
template:
metadata: labels: app: infer
spec:
containers: - name: infer
image: your-infer-image:latest
ports: - containerPort: 8000

案例 2:密钥与配置管理(Mac/4090 均可)

  • 选型:K8s Secret + Deployment env 注入;或本地 .env + 禁止提交到 Git。
  • Step 1kubectl create secret generic my-secret --from-literal=API_KEY=xxx;在 Deployment 中 env: - name: API_KEY; valueFrom: secretKeyRef: name: my-secret; key: API_KEY,Pod 内 echo $API_KEY 验证。
  • Step 2:在 CI 或本地脚本中从环境变量读 API_KEY,禁止代码内硬编码;用 python -c "import os; print(os.environ.get('API_KEY',''))" 验证注入。
1
2
3
4
5
6
7
8
9
kubectl create secret generic my-secret --from-literal=API_KEY=demo-key
# Deployment 片段
# env:
# - name: API_KEY
# valueFrom:
# secretKeyRef:
# name: my-secret
# key: API_KEY
kubectl run test --rm -it --image=busybox --restart=Never --env="API_KEY=\$(kubectl get secret my-secret -o jsonpath='{.data.API_KEY}' | base64 -d)" -- printenv API_KEY

案例 3:审计日志(Mac/4090 均可)

  • 选型:Python 结构化日志(JSON),字段含 user、resource、timestamp、action。
  • Step 1:在「模型注册」「推理调用」等关键路径打 log:logging.info(json.dumps({"user": "alice", "resource": "model/my_model", "action": "register", "ts": time.time()}))
  • Step 2:将日志输出到文件或 stdout,用 jq 或 ELK 做一次「按 user 过滤某日」的检索;若无 ELK,可用 grep user *.log | jq . 模拟。
1
2
3
4
5
6
7
8
9
10
11
12
13
# scripts/l11_audit_log.py
import json
import logging
import time

logging.basicConfig(level=logging.INFO, format="%(message)s")

def audit(user: str, resource: str, action: str):
logging.info(json.dumps({"user": user, "resource": resource, "action": action, "ts": time.time()}))

audit("alice", "model/champion", "register")
audit("bob", "infer/v1", "call")
# 检索:cat log | grep alice | jq .

案例 4:GPU 成本对比(需云账号)

  • Step 1:在 AWS/GCP/Azure 控制台查看同一区域 On-Demand 与 Spot GPU 实例单价(如 g5.xlarge 或 A10G)。
  • Step 2:用同一训练脚本在 On-Demand 与 Spot 各跑 30 分钟,记录是否被抢占;用「单价 × 0.5h」算两笔费用,得到 Spot 节省比例(通常 60–80%)。

案例 5:简单 FinOps 看板(需云或 Kubecost)

  • Step 1:若用云:在 Cost Explorer 中按「服务」或「标签」筛选 GPU 相关费用,导出本周数据到 CSV;若用 K8s:部署 Kubecost,打开 Dashboard 看 namespace/label 成本。
  • Step 2:在 Grafana 或 Excel 中做一张「本周各项目 GPU 消耗」表;在 Kubecost 或云控制台设「预算告警」(如某 namespace 超 100 美元/周则告警)。
1
2
3
# Kubecost 快速体验(需 K8s)
kubectl apply -f https://raw.githubusercontent.com/kubecost/cost-analyzer-helm-chart/develop/kubecost.yaml
# 访问 Kubecost UI 查看 namespace 成本

十二、学习路径建议(按角色)

12.1 偏平台 / Infra

  1. L0 系统与 K8s 打牢 → L1 算力与调度(GPU 插件、Ray/KubeFlow)→ L4 推理(vLLM/TensorRT-LLM 部署)→ L5 MLOps(流水线、Registry、可观测性)→ L6 RAG/Agent 部署。
  2. 可选深化:L2 Feature Store/Vector DB、L3 分布式训练(便于做训练平台)。

12.2 偏算法 / 全栈

  1. L0 ML 基础 → L2 数据与特征 → L3 训练(DeepSpeed/FSDP 实践)→ L4 推理与量化 → L5 实验与 Registry → L6 RAG/评估。
  2. 可选深化:L1 调度与 K8s、L5 可观测性与 SLO。

12.3 偏应用 / 产品

  1. L0 基础 + L4 推理(API 与 batching)→ L5 LLMOps(Prompt、评估、发布)→ L6 RAG 与 Agent 端到端。
  2. 可选:L2 向量库与检索、L5 可观测性。

十三、整体实践建议(学习与动手结合)

整体学习过程应与具体实践紧密结合:每学完一个层次或一个子模块,就通过该阶段知识点的实际应用来巩固,避免只看不练。下面给出可落地的实践原则与节奏建议。

13.1 原则

  • 每层必有产出:L0 至少有一个「能跑的 ML 小项目 + 一次 K8s 部署」;L1 至少有一次「GPU 作业在集群上跑通」;L2 有一次「数据/向量管线接入训练或推理」;L3 有一次多卡/多机训练;L4 有一次推理服务上线并压测;L5 有一次「实验 → Registry → 流水线 → 可观测」的闭环;L6 有一次完整 RAG 或 Agent 应用。
  • 用真实问题驱动:优先用你关心的业务场景或开源数据集(如某个垂直领域问答、内部文档检索),从数据准备到模型选型、训推与评估一路做到底,这样各层知识会自然串联。
  • 先跑通再优化:第一遍以「能跑、能测、能观测」为主,第二遍再针对瓶颈做硬件/编译/框架层面的优化(例如换量化、调 batching、改并行策略)。
  • 三大支柱贯穿始终:在 L1 实践时对照「硬件架构」(显存、带宽、多卡拓扑);在 L3/L4 实践时对照「编程与编译」(torch.compile、后端选择);在选型与排障时对照「训推框架」(训练栈与推理栈的对应关系)。每完成一个阶段可简单写一份「本阶段用到的硬件/编译/框架要点」小结。

13.2 节奏建议

  • L0→L1:约 2–4 周打牢基础并完成首次 GPU + K8s 部署;可并行看「三大关键支柱」建立全局图景。
  • L2→L3:约 2–4 周完成数据/向量管线与一次多卡训练;建议用同一数据集做「数据 → 训练」的连贯实践。
  • L4→L5:约 2–3 周完成推理部署、MLOps/LLMOps 流水线与可观测性;建议用 L3 产出的模型做「训练 → Registry → 推理 → 监控」的闭环。
  • L6:约 1–2 周做一个 RAG 或 Agent 小项目,把 L2(向量)、L4(推理)、L5(评估与发布)串起来。

13.3 项目式巩固(推荐)

  • 主线项目:选一个贯穿多层的项目(例如「内部文档 RAG 问答系统」),在推进过程中按需补 L0–L6:先搭最小可用版本(数据→向量→检索→LLM),再加训练/微调、再加 MLOps 与可观测、再优化推理与资源。这样每个阶段的知识都会在真实场景下被反复调用和加深理解。
  • 实验记录:用 MLflow 或笔记记录每次实践的配置、结果与踩坑(例如「ZeRO-2 在此规模下的显存与吞吐」「vLLM 在此 batch 下的 P99」),形成可复现、可复用的经验库,便于日后选型与排障。

十四、推荐资源与延伸阅读(含链接)


十五、小结

AI 基础设施全栈涵盖:算力与编排(L1)→ 数据与特征/向量(L2)→ 分布式训练(L3)→ 推理与 Serving(L4)→ MLOps/LLMOps 与可观测性(L5)→ RAG/Agent 应用架构(L6),并建立在扎实的 L0 基础 之上。基础硬件架构、编程与编译、训推框架 是贯穿全栈的三大关键支柱,建议在进入各层细节前建立整体认知,并在每层学习与实践中反复对照。学习过程应与具体实践紧密结合:每层都有建议的学习资料与实践方法,整体上通过「每层必有产出、用真实问题驱动、先跑通再优化、项目式巩固」来常理与内化知识。2024–2025 的实践更强调:混合与多模型部署、开源与微调优先、K8s 统一编排、RAG 与推理联合优化、以及安全合规与成本控制。按本指南分层推进,结合自身角色选一条主路径、并配合第十三节的整体实践建议逐步深化,即可系统构建 AI Infra 全栈能力。