共计 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)
- 给 FastAPI 编排层 接入 OpenTelemetry 自动仪表化(HTTP 入 / 出、Qdrant/TEI 调用、vLLM 调用),官方 FastAPI 插件文档如下。(opentelemetry-python-contrib.readthedocs.io)
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 新鲜度与“热更新”(不打断服务)
做法:影子重建 + 别名原子切换
- 新建集合
rag_chunks_v2,把增量 / 全量数据重新切块并嵌入入库; - 用 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 的这些能力与监控 / 集群文档都在上面的参考里。)
正文完

