mcpField
M
model-serving

model-serving

github.com/ancoleman云与 DevOps52561 次安装46 周前更新
代码仓库

关于 model-serving

面向部署 LLM 与机器学习推理服务的工程人员,介绍自托管推理引擎、GPU 优化、流式 API 和服务编排。内容覆盖 RAG、性能基准测试及生产部署模式。

主要功能

  1. 01比较 LLM 推理引擎与选择方案
  2. 02配置 GPU 推理与量化
  3. 03构建流式响应 API
  4. 04编排 RAG 与向量数据库流程
  5. 05提供吞吐量和延迟基准测试
  6. 06介绍 Kubernetes 生产部署

适用场景

  1. 01部署自托管 LLM 推理端点
  2. 02为聊天应用提供流式生成
  3. 03构建结合向量检索的 RAG 流程
  4. 04测量推理服务的延迟与吞吐量

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ancoleman/ai-design-components --skill model-serving

安装后在 Claude Code 中输入/model-serving确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

outputs.yaml
examples/k8s-vllm-deployment/
README.md
examples/langchain-agents/
main.py
README.md
requirements.txt
examples/langchain-rag-qdrant/
README.md
examples/ollama-local/
main.py
README.md
requirements.txt
examples/vllm-serving/
main.py
README.md
requirements.txt
references/
bentoml.md
inference-optimization.md
langchain-orchestration.md
streaming-sse.md
tgi.md
vllm.md
scripts/
benchmark_inference.py
validate_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 和 Agent
  • references/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 进行性能分析

后续步骤

  1. 本地开发:从 examples/ollama-local/ 开始,无需 GPU 即可测试
  2. 生产环境设置:使用 examples/vllm-serving/ 部署 vLLM
  3. RAG 集成:使用 examples/langchain-rag-qdrant/ 添加向量数据库
  4. Kubernetes:使用 examples/k8s-vllm-deployment/ 扩展
  5. 监控:使用 Prometheus 和 Grafana 添加指标

评论

支持 Markdown