大模型部署教程:生产化与评测

48次阅读
没有评论

共计 5783 个字符,预计需要花费 15 分钟才能阅读完成。

0⃣ 目标与 SLO 建议(先定规矩)

  • 可用性:> 99.9%(月不可用 ≤ 43 分钟)
  • 延迟(P95):
    • 检索 + 重排:≤ 200 ms(TopK≤40,CPU 可跑)
    • 生成:≤ 2.5 s(8B 级模型,≤ 300 生成 token)
  • 答案质量(离线集):Faithfulness ≥ 0.8;Recall@k ≥ 0.85
    (Faithfulness 指答案与检索上下文的一致性,用于约束幻觉倾向。度量定义与实现见 Ragas 文档。(docs.ragas.io))

1⃣ 可观测:指标、日志、链路追踪

1.1 指标采集(Prometheus + Grafana)

  • vLLM:自带 Prometheus /metrics,直接抓取即可,官方页面给了指标清单与示例面板。(VLLM Docs)
  • TEI(嵌入服务):提供生产特性(动态批处理),并支持导出指标与分布式追踪。(Hugging Face)
  • RAG API:用 prometheus_client 自行埋点(如检索耗时、命中率、提示词长度等)。

最小 prometheus.yml(新增一个文件并挂载入 Prometheus 容器)

global:
  scrape_interval: 10s
scrape_configs:
  - job_name: vllm
    static_configs: [{targets: ["vllm-main:8000"] }]
  - job_name: tei
    static_configs: [{targets: ["tei-embeddings:80"] }]
  - job_name: rag_api
    static_configs: [{targets: ["rag-api:8001"] }]

Compose 里新增 Prometheus/Grafana(节选)

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
    ports: ["9090:9090"]

  grafana:
    image: grafana/grafana:latest
    ports: ["3000:3000"]
    depends_on: [prometheus]

访问 vLLM 的 /metrics 验证是否有采样数据;文档说明该端点即为生产指标暴露点。(docs.vllm.com.cn)

1.2 分布式追踪(OpenTelemetry + Jaeger/Tempo)

RAG API 里最小追踪初始化(示例)

# app.py 顶部新增
from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor

# 启动时:provider = TracerProvider(resource=Resource.create({SERVICE_NAME: "rag-api"}))
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint="http://jaeger:4318/v1/traces")))
trace.set_tracer_provider(provider)
FastAPIInstrumentor.instrument_app(app)
HTTPXClientInstrumentor().instrument()

2⃣ 可伸缩:扩、缩、回滚与数据新鲜度

2.1 生成服务(vLLM)横向扩展与就绪探针

  • vLLM 多副本挂在网关后面(Nginx/Traefik/ 服务网格);同一 GPU 不建议跑多个实例,按 CLI 里 --gpu-memory-utilization 做硬性上限控制。(docs.vllm.com.cn)
  • vLLM 暴露 /health;生产上还应配置“就绪 存活”探针区分启动期与退化期(社区讨论过增加 /ready 的必要性,实际部署时可用“首批权重加载 + 推理小样例”作为 readiness)。(GitHub)

2.2 嵌入服务(TEI)并发与批处理

  • TEI 具备 动态批处理 与优化内核,天然适合水平扩展;按流量做副本扩容,前置负载均衡。(Hugging Face)

2.3 向量库(Qdrant)容量与高可用

  • 单机够用时先不分片;上规模后走 分布式部署 + 分片副本(shard replication),副本能提高节点故障下的数据可用性。(qdrant.org.cn)
  • HNSW 参数(m, ef_construct, 搜索时 ef)直接影响召回与延迟,Qdrant 文档对其作用机制有明确说明,用离线集调参最稳。(qdrant.tech)

2.4 新鲜度与“热更新”(不打断服务)

做法:影子重建 + 别名原子切换

  1. 新建集合 rag_chunks_v2,把增量 / 全量数据重新切块并嵌入入库;
  2. Collection Alias 将逻辑名 rag_chunks 指过去(零停机回切)。
    Qdrant 提供 Update Aliases API,可一次性原子更新别名映射。(Qdrant)

备份 / 迁移 :用 快照(snapshots) 完整打包向量与索引结构,恢复快且一致性好。(qdrant.org.cn)

示例(Python 客户端,影子切换)

from qdrant_client import QdrantClient
from qdrant_client.http.models import AliasOperations, CreateAlias, DeleteAlias

qc = QdrantClient(url="http://qdrant:6333")

ops = AliasOperations(
  operations=[
    DeleteAlias(alias_name="rag_chunks"),               # 先删旧别名映射
    CreateAlias(collection_name="rag_chunks_v2", alias_name="rag_chunks")  # 指向新集合
  ]
)
qc.update_aliases(ops)  # 原子切换

3⃣ 可验证:离线评测、在线实验、回归守门

3.1 构建评测数据(最重要的一次“标注投入”)

数据格式建议 CSV/JSONL:

question | gold_context_ids (逗号分隔) | reference_answer
  • gold_context_ids:人工确定应命中的 chunk(可从文档标题 / 小节抽取);
  • reference_answer:2–3 句标准答案,确保可从 gold context 推出;
  • 规模:先 300–500 条,覆盖真实业务分布。

3.2 度量与工具

  • 检索:Recall@k、MRR、nDCG(从 gold_context_ids 计算)。
  • 答案:基于规则 / 字符串的 Exact / F1 + Faithfulness(答案与检索上下文的一致性)。Ragas 对 Faithfulness 有清晰定义与开箱实现。(docs.ragas.io)

Ragas 计算示例(单轮)

from ragas import evaluate
from ragas.metrics import faithfulness
from datasets import Dataset

ds = Dataset.from_list([{
  "question": "系统如何做数据脱敏?",
  "answer": "……(模型回答)",
  "contexts": ["……(检索片段 1)","……(检索片段 2)"]
}])

report = evaluate(ds, metrics=[faithfulness])
print(report)  # 各指标 0~1

3.3 在线 A/B 与灰度

  • 路由器 分流:A= 当前生产策略,B= 新策略(比如换嵌入模型 / 调检索参数 / 换 LLM);10–20% 灰度流量起步。
  • 线上指标:P50/P95 延迟、失败率、人工申诉率、点赞 / 点踩、“需要人工确认”的占比等。
  • 干预守门:若 P95 或失败率越过阈值,自动熔断回 A;这类指标可直接来自 vLLM/TEI 的 /metrics 和编排层自埋指标。(VLLM Docs)

4⃣ 编排层:把“生产化”写进代码

4.1 指标埋点(检索 / 重排 / 拼接 / 生成)

from prometheus_client import Counter, Histogram, Gauge, start_http_server
start_http_server(8001)  # /metrics 暴露在 rag-api:8001/metrics

q_time = Histogram("rag_retrieval_seconds", "retrieval latency")
gen_time = Histogram("rag_generation_seconds", "generation latency")
ctx_tokens = Gauge("rag_prompt_ctx_tokens", "tokens in context block")
miss_ctr = Counter("rag_no_answer_total", "answer says insufficient context")

@q_time.time()
async def retrieve(...): ...

4.2 A/B 分流(极简示例)

import random
def pick_policy(user_id: str)->str:
    # 10% 走策略 B
    return "B" if (hash(user_id) % 10 == 0) else "A"

4.3 就绪探针与“自测”

  • /healthz:仅返回 200;
  • /readyz:串行做一次 轻量自测(TEI /embed 1 条 + Qdrant ping + vLLM 5 token 生成),失败则 503;
  • 容器编排用 /readyz 做 Readiness,/healthz 做 Liveness。

5⃣ 检索质量的工程化技巧

  • Chunk 策略:600–1500 字符 + 10–20% 重叠;标题 / 小节名前置,增强匹配语义。
  • 重排:召回 40→重排到 8–12;Cross-Encoder 用 CPU 也能跑,成本低而收益大。
  • HNSW 调参
    • 建索引:m 越大越准但内存涨;ef_construct 越大构建越慢但质量更好;
    • 查询时:提高 ef 提升 Recall,注意与延迟 trade-off;这些参数与影响机制见 Qdrant Indexing 文档。(qdrant.tech)
  • 集合规划 :大多场景 单集合 + payload 过滤 即可;多租户 / 隔离再分集合,官方概念页有建议。(qdrant.org.cn)

6⃣ 安全与回滚

  • 影子索引 & 别名切换:上面 2.4 的“影子重建 + Update Aliases”是零停机回滚 / 前滚的关键。(Qdrant)
  • 快照 :定期做 Collection Snapshot;故障时“新集群 -> 恢复 snapshot -> 别名切换”一键回到稳定版本。(qdrant.tech)
  • 输入净化:在切块前做脱敏(PII、密钥);在提示组装处做“非上下文拒答”策略(明确回答“不足以确定”)。

7⃣ 一份可直接加到 Compose 的监控与追踪扩展(精简)

# 追加到原 docker-compose.yml
services:
  jaeger:
    image: jaegertracing/all-in-one:1
    ports: ["16686:16686", "4318:4318"]  # UI + OTLP HTTP
    restart: unless-stopped

  prometheus:
    image: prom/prometheus:latest
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
    ports: ["9090:9090"]
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    ports: ["3000:3000"]
    depends_on: [prometheus]
    restart: unless-stopped

vLLM 与 TEI 的指标端点:/metrics;文档确认它们面向 Prometheus。(VLLM Docs)


8⃣ 运行手册(Runbook)速记

  • QPS 飙高:vLLM 增副本;降 max_tokens 与并发 --max-num-seqs;TEI 增副本;检索 TopK 降低。
  • 延迟飘:先看 vLLM batching/queue 指标与 GPU 利用率;再看 TEI 动态批;最后看重排是否过重。(VLLM Docs)
  • 答非所问 / 幻觉:提高重排强度;减少上下文噪音;强化系统提示的“只用上下文”;上线前跑离线 Faithfulness 回归。(docs.ragas.io)
  • 数据更新:影子集合重建 + 别名切换;大版本前做快照。(Qdrant)

结语:把系统当成“可实验的平台”

把“评测 - 上线 - 观测 - 回滚”做成固定套路:每个改动都在离线集过线、在线灰度监控稳定、指标告警与回滚脚本可一键执行。下一步,你可以:

  • 接入 混合检索(向量 + 关键词 /BM25;Qdrant 支持丰富的索引 / 过滤配置);
  • 自适应路由 / 级联(小模型→大模型);
  • 评测流水线 做成 CI(新数据→自动重建→回放→产出报表),临门一脚就是真正的“平台化”。(TEI、vLLM、Qdrant 的这些能力与监控 / 集群文档都在上面的参考里。)

正文完
 0
一诺
版权声明:本站原创文章,由 一诺 于2025-10-02发表,共计5783字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码