关于 model-serving
面向部署 LLM 与机器学习推理服务的工程人员,介绍自托管推理引擎、GPU 优化、流式 API 和服务编排。内容覆盖 RAG、性能基准测试及生产部署模式。
主要功能
- 01比较 LLM 推理引擎与选择方案
- 02配置 GPU 推理与量化
- 03构建流式响应 API
- 04编排 RAG 与向量数据库流程
- 05提供吞吐量和延迟基准测试
- 06介绍 Kubernetes 生产部署
适用场景
- 01部署自托管 LLM 推理端点
- 02为聊天应用提供流式生成
- 03构建结合向量检索的 RAG 流程
- 04测量推理服务的延迟与吞吐量
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ancoleman/ ai-design-components --skill model-serving安装后在 Claude Code 中输入/model-serving确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
outputs.yamlexamples/k8s-vllm-deployment/README.mdexamples/langchain-agents/main.pyREADME.mdrequirements.txtexamples/langchain-rag-qdrant/README.mdexamples/ollama-local/main.pyREADME.mdrequirements.txtexamples/vllm-serving/main.pyREADME.mdrequirements.txtreferences/bentoml.mdinference-optimization.mdlangchain-orchestration.mdstreaming-sse.mdtgi.mdvllm.mdscripts/benchmark_inference.pyvalidate_model_config.py详细介绍
模型服务
用途
使用经过优化的服务引擎、流式响应模式和编排框架,为生产环境部署 LLM 和 ML 模型。重点关注可自托管的模型服务、GPU 优化,以及与前端应用的集成。
适用场景
- 为生产环境部署 LLM(自托管 Llama、Mistral、Qwen)
- 构建支持流式响应的 AI API
- 提供传统 ML 模型服务(scikit-learn、XGBoost、PyTorch)
- 使用向量数据库实现 RAG 流水线
- 优化推理吞吐量和延迟
- 将 LLM 服务集成到前端聊天界面
模型服务选型
LLM 服务引擎
vLLM(首选)
- 使用 PagedAttention 管理内存(吞吐量提升 20-30 倍)
- 使用连续批处理动态处理请求
- 提供兼容 OpenAI 的 API 端点
- 适用场景:大多数自托管 LLM 部署
TensorRT-LLM
- GPU 效率最高(比 vLLM 快 2-8 倍)
- 需要转换和优化模型
- 适用场景:需要绝对最高吞吐量的生产工作负载
Ollama
- 无需 GPU 即可进行本地开发
- 简洁的命令行界面
- 适用场景:原型开发、笔记本电脑开发、教育用途
决策框架:
Self-hosted LLM deployment needed?
├─ Yes, need maximum throughput → vLLM
├─ Yes, need absolute max GPU efficiency → TensorRT-LLM
├─ Yes, local development only → Ollama
└─ No, use managed API (OpenAI, Anthropic) → No serving layer needed
ML 模型服务(非 LLM)
BentoML(推荐)
- 原生支持 Python,易于部署
- 使用自适应批处理提升吞吐量
- 支持多种框架(scikit-learn、PyTorch、XGBoost)
- 适用场景:大多数传统 ML 模型部署
Triton Inference Server
- 在同一 GPU 上提供多模型服务
- 支持模型集成(串联多个模型)
- 适用场景:NVIDIA GPU 优化、为 10 个以上模型提供服务
LLM 编排
LangChain
- 通用工作流、Agent 和 RAG
- 100 多种集成(LLM、向量数据库、工具)
- 适用场景:大多数 RAG 和 Agent 应用
LlamaIndex
- 专注于 RAG,提供高级检索策略
- 100 多种数据连接器(PDF、Notion、网页)
- 适用场景:RAG 是主要用例
快速入门示例
vLLM 服务设置
# Install
pip install vllm
# Serve a model (OpenAI-compatible API)
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--dtype auto \
--max-model-len 4096 \
--gpu-memory-utilization 0.9 \
--port 8000
关键参数:
--dtype:模型精度(auto、float16、bfloat16)--max-model-len:上下文窗口大小--gpu-memory-utilization:GPU 内存占比(0.8-0.95)--tensor-parallel-size:用于模型并行的 GPU 数量
流式响应(SSE 模式)
后端(FastAPI):
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from openai import OpenAI
import json
app = FastAPI()
client = OpenAI(base_url="http://localhost:8000/v1", api_key="not-needed")
@app.post("/chat/stream")
async def chat_stream(message: str):
async def generate():
stream = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{"role": "user", "content": message}],
stream=True,
max_tokens=512
)
for chunk in stream:
if chunk.choices[0].delta.content:
token = chunk.choices[0].delta.content
yield f"data: {json.dumps({'token': token})}\n\n"
yield f"data: {json.dumps({'done': True})}\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream",
headers={"Cache-Control": "no-cache"}
)
前端(React):
// Integration with ai-chat skill
const sendMessage = async (message: string) => {
const response = await fetch('/chat/stream', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message })
})
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\n')
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = JSON.parse(line.slice(6))
if (data.token) {
setResponse(prev => prev + data.token)
}
}
}
}
}
BentoML 服务
import bentoml
from bentoml.io import JSON
import numpy as np
@bentoml.service(
resources={"cpu": "2", "memory": "4Gi"},
traffic={"timeout": 10}
)
class IrisClassifier:
model_ref = bentoml.models.get("iris_classifier:latest")
def __init__(self):
self.model = bentoml.sklearn.load_model(self.model_ref)
@bentoml.api(batchable=True, max_batch_size=32)
def classify(self, features: list[dict]) -> list[str]:
X = np.array([[f['sepal_length'], f['sepal_width'],
f['petal_length'], f['petal_width']] for f in features])
predictions = self.model.predict(X)
return ['setosa', 'versicolor', 'virginica'][predictions]
LangChain RAG 流水线
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Qdrant
from langchain.chains import RetrievalQA
from langchain.text_splitter import RecursiveCharacterTextSplitter
# Load and chunk documents
text_splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=50)
chunks = text_splitter.split_documents(documents)
# Create vector store
embeddings = OpenAIEmbeddings()
vectorstore = Qdrant.from_documents(
chunks,
embeddings,
url="http://localhost:6333",
collection_name="docs"
)
# Create retrieval chain
llm = ChatOpenAI(model="gpt-4o")
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),
return_source_documents=True
)
# Query
result = qa_chain({"query": "What is PagedAttention?"})
性能优化
GPU 内存估算
LLM 经验法则:
GPU Memory (GB) = Model Parameters (B) × Precision (bytes) × 1.2
示例:
- Llama-3.1-8B(FP16):8B × 2 字节 × 1.2 = 19.2 GB
- Llama-3.1-70B(FP16):70B × 2 字节 × 1.2 = 168 GB(需要 2-4 张 A100)
量化可减少内存占用:
- FP16:每个参数 2 字节
- INT8:每个参数 1 字节(内存占用减少 2 倍)
- INT4:每个参数 0.5 字节(内存占用减少 4 倍)
vLLM 优化
# Enable quantization (AWQ for 4-bit)
vllm serve TheBloke/Llama-3.1-8B-AWQ \
--quantization awq \
--gpu-memory-utilization 0.9
# Multi-GPU deployment (tensor parallelism)
vllm serve meta-llama/Llama-3.1-70B-Instruct \
--tensor-parallel-size 4 \
--gpu-memory-utilization 0.9
批处理策略
连续批处理(vLLM 默认):
- 动态向批次中添加或移除请求
- 吞吐量高于静态批处理
- 无需配置
自适应批处理(BentoML):
@bentoml.api(
batchable=True,
max_batch_size=32,
max_latency_ms=1000 # Wait max 1s to fill batch
)
def predict(self, inputs: list[np.ndarray]) -> list[float]:
# BentoML automatically batches requests
return self.model.predict(np.array(inputs))
生产部署
Kubernetes 部署
完整的 YAML 清单请参阅 examples/k8s-vllm-deployment/。
关键注意事项:
- GPU 资源请求:
nvidia.com/gpu: 1 - 健康检查:
/health端点 - 根据队列深度进行水平 Pod 自动扩缩容
- 用于模型缓存的持久卷
API 网关模式
在生产环境中,添加速率限制、身份验证和监控:
Kong 配置:
services:
- name: vllm-service
url: http://vllm-llama-8b:8000
plugins:
- name: rate-limiting
config:
minute: 60 # 60 requests per minute per API key
- name: key-auth
- name: prometheus
监控指标
关键 LLM 指标:
- 每秒 Token 数(吞吐量)
- 首 Token 时间(TTFT)
- Token 间延迟
- GPU 利用率和内存
- 队列深度
Prometheus 埋点:
from prometheus_client import Counter, Histogram
requests_total = Counter('llm_requests_total', 'Total requests')
tokens_generated = Counter('llm_tokens_generated', 'Total tokens')
request_duration = Histogram('llm_request_duration_seconds', 'Request duration')
@app.post("/chat")
async def chat(request):
requests_total.inc()
start = time.time()
response = await generate(request)
tokens_generated.inc(len(response.tokens))
request_duration.observe(time.time() - start)
return response
集成模式
前端(ai-chat)集成
此技能为 ai-chat 技能提供后端服务层。
流程:
Frontend (React) → API Gateway → vLLM Server → GPU Inference
↑ ↓
└─────────── SSE Stream (tokens) ─────────────────┘
完整实现模式请参阅 references/streaming-sse.md。
使用向量数据库实现 RAG
架构:
User Query → LangChain
├─> Vector DB (Qdrant) for retrieval
├─> Combine context + query
└─> LLM (vLLM) for generation
完整模式请参阅 references/langchain-orchestration.md 和 examples/langchain-rag-qdrant/。
异步推理队列
用于批处理或非实时推理:
Client → API → Message Queue (Celery) → Workers (vLLM) → Results DB
适用于:
- 批量处理文档
- 后台摘要生成
- 非交互式工作流
基准测试
使用 scripts/benchmark_inference.py 测量部署情况:
python scripts/benchmark_inference.py \
--endpoint http://localhost:8000/v1/chat/completions \
--model meta-llama/Llama-3.1-8B-Instruct \
--concurrency 32 \
--requests 1000
输出:
- 每秒请求数
- P50/P95/P99 延迟
- 每秒令牌数
- GPU 内存用量
捆绑资源
详细指南:
references/vllm.md- vLLM 设置、PagedAttention、优化references/tgi.md- Text Generation Inference 模式references/bentoml.md- BentoML 部署模式references/langchain-orchestration.md- LangChain RAG 和 Agentreferences/inference-optimization.md- 量化、批处理、GPU 调优
可运行示例:
examples/vllm-serving/- 完整的 vLLM + FastAPI 流式设置examples/ollama-local/- 使用 Ollama 进行本地开发examples/langchain-agents/- LangChain Agent 模式
实用脚本:
scripts/benchmark_inference.py- 吞吐量和延迟基准测试scripts/validate_model_config.py- 验证部署配置
常见模式
从 OpenAI API 迁移
vLLM 提供兼容 OpenAI 的端点,便于迁移:
# Before (OpenAI)
from openai import OpenAI
client = OpenAI(api_key="sk-...")
# After (vLLM)
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="not-needed"
)
# Same API calls work!
response = client.chat.completions.create(
model="meta-llama/Llama-3.1-8B-Instruct",
messages=[{"role": "user", "content": "Hello"}]
)
多模型服务
根据任务将请求路由到不同模型:
MODEL_ROUTING = {
"small": "meta-llama/Llama-3.1-8B-Instruct", # Fast, cheap
"large": "meta-llama/Llama-3.1-70B-Instruct", # Accurate, expensive
"code": "codellama/CodeLlama-34b-Instruct" # Code-specific
}
@app.post("/chat")
async def chat(message: str, task: str = "small"):
model = MODEL_ROUTING[task]
# Route to appropriate vLLM instance
成本优化
跟踪令牌用量:
import tiktoken
def estimate_cost(text: str, model: str, price_per_1k: float):
encoding = tiktoken.encoding_for_model(model)
tokens = len(encoding.encode(text))
return (tokens / 1000) * price_per_1k
# Compare costs
openai_cost = estimate_cost(text, "gpt-4o", 0.005) # $5 per 1M tokens
self_hosted_cost = 0 # Fixed GPU cost, unlimited tokens
故障排查
GPU 内存不足:
- 降低
--max-model-len - 调低
--gpu-memory-utilization(尝试 0.8) - 启用量化(
--quantization awq) - 使用更小的模型变体
吞吐量低:
- 提高
--gpu-memory-utilization(尝试 0.95) - 启用连续批处理(vLLM 默认启用)
- 检查 GPU 利用率(应高于 80%)
- 多 GPU 场景下可考虑张量并行
延迟高:
- 使用静态批处理时,减小批次大小
- 检查到 GPU 服务的网络延迟
- 使用
scripts/benchmark_inference.py进行性能分析
后续步骤
- 本地开发:从
examples/ollama-local/开始,无需 GPU 即可测试 - 生产环境设置:使用
examples/vllm-serving/部署 vLLM - RAG 集成:使用
examples/langchain-rag-qdrant/添加向量数据库 - Kubernetes:使用
examples/k8s-vllm-deployment/扩展 - 监控:使用 Prometheus 和 Grafana 添加指标