想象一下,你刚刚使用 vLLM 部署了一个全新的大型语言模型(LLM),它的响应速度比你想象的还要快。然而,在高峰期,突然出现了一些问题:响应速度急剧下降,成本失控,你不得不手忙脚乱地去查找原因。这听起来是不是很熟悉?你不是一个人。成功的 LLM 部署和代价高昂的失败之间的区别,往往在于 可观测性。
可观测性 就像是 LLM 的私人健康监护仪。就像你不会在不监测心率的情况下跑马拉松一样,你不应该在生产环境中运行 LLM 而不监控其关键指标。本文将深入探讨如何利用 OpenTelemetry、Prometheus、Grafana 和 Jaeger 构建生产级 LLM 可观测性,并以 vLLM 为例,阐述其具体应用。
LLM可观测性的重要性
传统的软件监控方法在面对 LLM 时常常显得力不从心。LLM 的复杂性带来了独特的 可观测性 挑战,主要体现在以下几个方面:
- Token 使用与成本: 每个生成的 token 都会产生费用。监控 token 使用情况有助于成本优化和容量规划。
- 延迟与吞吐量: 快速的响应时间对于用户体验至关重要。观察每次 token/请求的延迟和吞吐量(token/秒)等指标可以确保流畅的操作。
- GPU 利用率: LLM 是资源密集型应用。高效的 GPU 利用率是最大化硬件投资的关键。
- 模型性能: 运营指标可以暗示 token 生成错误或其他问题,从而指导改进。
- 分布式追踪: 像检索增强生成 (RAG) 或多代理管道这样的复杂架构需要端到端跟踪,以快速识别瓶颈和故障点。
构建 LLM 任务控制中心
构建一个强大的 LLM 可观测性 平台需要选择合适的工具。本文选择了一套强大的开源工具栈,它们可以协同工作,提供全面的监控能力。
- RAG 应用: 一个 FastAPI 应用程序,模拟 RAG 管道,并进行检测以进行跟踪和指标收集。
- vLLM: 你的快速推理引擎,也是本文的主角。最新版本的 vLLM 现在支持 OpenTelemetry,并公开了一个 Prometheus 可以抓取的指标端点。
- OpenTelemetry: 遥测数据的通用翻译器。OpenTelemetry (OTel) 是一个开源 可观测性 框架,它提供了一种标准化的方法来收集、生成和导出来自云原生应用程序和基础设施的遥测数据(指标、日志和跟踪)。
- Jaeger: 你的请求侦探(跟踪每一步)。使用 OTel 显示跟踪。
- Prometheus: 永不休眠的数据收集器。
- Grafana: 你那美观、可定制的仪表板。
这些组件之间的交互方式如下:
- vLLM 处理 LLM 推理请求,并通过 OpenTelemetry 生成指标和跟踪数据。
- RAG 应用 执行检索增强生成流程,同样通过 OpenTelemetry 生成指标和跟踪数据。
- Jaeger 收集来自 vLLM 和 RAG 应用 的跟踪数据,用于可视化请求的端到端流程。
- Prometheus 定期从 vLLM 和 RAG 应用 的指标端点抓取指标数据。
- Grafana 连接到 Prometheus 并使用抓取的指标数据创建可定制的仪表板,用于实时监控 LLM 的性能和资源使用情况。
设置监控堆栈 (简单方法)
无需手动设置所有内容。本文选择 Docker Compose 来处理繁重的工作,并使你可以轻松试用该堆栈。
先决条件
在开始之前,请确保你拥有:
- 已安装并运行 Docker 或 Podman
- 一台具有 GPU 的 VM
- 基本熟悉 vLLM、Prometheus 和 Grafana 概念
项目结构
首先,让我们组织我们的文件:完整的代码可以在 GitHub 仓库中找到。
├── docker-compose.yml
├── prometheus.yml
├── rag-app/
│ ├── Dockerfile
│ └── app.py
├── vllm-server/
│ └── Dockerfile
└── grafana/
├── provisioning/
│ ├── datasources/
│ │ └── prometheus.yml
│ └── dashboards/
│ └── dashboard.yml
└── dashboards/
├── vllm-dashboard.json
└── rag-dashboard.json
步骤 1:Docker Compose 配置
以下是完整的 docker-compose.yml,用于协调整个监控交响曲:
services:
## Mocked RAG application (embedding + vector search mocked)
rag-app:
build:
context: rag-app # Builds the image using Dockerfile from the rag-app directory
container_name: rag-app
ports:
- "8002:8002" # FastAPI main API endpoint
- "8001:8001" # Prometheus metrics endpoint
environment:
- OTEL_EXPORTER_OTLP_ENDPOINT=grpc://jaeger:4317 # Send traces to Jaeger
depends_on:
- jaeger
- prometheus
## vLLM server for LLM inference
vllm-server:
build: vllm-server # Builds the image from the vllm-server directory
container_name: vllm-server
ports:
- "8000:8000" # vLLM inference API port
environment:
- MODEL_NAME=facebook/opt-125m # Name of the model to serve
- OTEL_SERVICE_NAME=vllm-server # Service name used in tracing
- NVIDIA_VISIBLE_DEVICES=all # Make all GPUs visible to the container
- NVIDIA_DRIVER_CAPABILITIES=compute,utility # Required for GPU compute workloads
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=grpc://jaeger:4317 # Send traces to Jaeger
- OTEL_EXPORTER_OTLP_TRACES_INSECURE=true # Allow insecure (non-TLS) trace export
- VLLM_LOGGING_LEVEL=DEBUG # Set logging level
command: vllm serve facebook/opt-125m --otlp-traces-endpoint=grpc://jaeger:4317 # Start vLLM server
depends_on:
- jaeger
deploy:
resources:
reservations:
devices:
- driver: nvidia # Use the NVIDIA runtime
count: all # Use all available GPUs
capabilities: [gpu] # Request GPU capability
## Jaeger: distributed tracing backend
jaeger:
image: jaegertracing/all-in-one:1.57 # Jaeger all-in-one image
container_name: jaeger
ports:
- "16686:16686" # Jaeger UI
- "4317:4317" # OTLP gRPC endpoint
- "4318:4318" # OTLP HTTP endpoint
- "6831:6831/udp" # Jaeger agent UDP port
- "6832:6832/udp"
- "14250:14250"
- "14268:14268"
- "14269:14269"
- "5778:5778"
- "9411:9411" # Zipkin compatible port
## Prometheus: metrics collector
prometheus:
image: prom/prometheus
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml # Mount custom config
ports:
- "9090:9090" # Prometheus UI and API
## Grafana: metrics dashboard and visualization
grafana:
image: grafana/grafana
container_name: grafana
ports:
- "3000:3000" # Grafana dashboard UI
environment:
- GF_SECURITY_ADMIN_USER=admin # Default admin username
- GF_SECURITY_ADMIN_PASSWORD=admin # Default admin password
volumes:
- grafana-storage:/var/lib/grafana # Persist Grafana data
- ./grafana/dashboards:/var/lib/grafana/dashboards # Mount custom dashboards
- ./grafana/provisioning/dashboards:/etc/grafana/provisioning/dashboards # Auto-provision dashboards
- ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources # Auto-provision data sources
depends_on:
- prometheus
- jaeger
volumes:
grafana-storage: # Named volume for persistent Grafana data
此设置不仅仅是监控,它还是一个具有内置 可观测性 的 RAG 应用程序:
- RAG 应用程序功能:
- 公开 API 端点 (端口 8002) 和指标 (端口 8001)
- 将跟踪发送到 Jaeger 以实现端到端可见性
- 模拟真实的 RAG 管道
- vLLM 配置亮点:
- 使用轻量级 facebook/opt-125m 模型(非常适合测试)
- 具有 NVIDIA 运行时的 GPU 支持
- 启用调试日志以进行故障排除
- 直接 OTLP 跟踪到 Jaeger
- 监控集成:
- Jaeger 通过 OTLP 收集来自 RAG 应用程序和 vLLM 的跟踪
- Prometheus 使用 RAG 应用程序和 vLLM 公开的 /metrics 端点从多个端点抓取指标。
- Grafana 提供具有持久性存储的统一仪表板
- Jaeger UI 可视化端到端跟踪。
步骤 3:配置 Prometheus 抓取
你的 prometheus.yml 应该定位到两个服务:
global:
scrape_interval: 5s
scrape_configs:
- job_name: 'rag-app'
static_configs:
- targets: ['rag-app:8001']
- job_name: 'vllm-server'
static_configs:
- targets: ['vllm-server:8000']
Prometheus 将每 5 秒从这些端点收集指标:http://vllm-server:8000/metrics 和 http://rag-app:8001/metrics
步骤 4:Grafana Provisioning
Grafana 可以预配置为自动连接到 Prometheus 并加载仪表板。 这涉及:
- datasources/datasource.yml:将 Prometheus 定义为数据源,指向 Docker 网络内的 http://prometheus:9090。
# Save this as ./grafana/provisioning/datasources/prometheus.yml
apiVersion: 1
datasources:
- name: prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: true
- dashboards/dashboard.yml:指示 Grafana 从已挂载仪表板目录中的 .json 文件加载仪表板定义。 在 GitHub 仓库中,本文提供了两个预定义的仪表板,一个用于 vLLM 服务器,另一个用于 RAG 应用程序。
步骤 4:启动你的监控帝国
使用以下命令运行整个堆栈:
docker compose up -d
几分钟之内,你将拥有:
- RAG 应用程序:http://localhost:8002(你的应用程序)
- vLLM 服务器:http://localhost:8000(模型服务)
- Jaeger UI:http://localhost:16686(跟踪可视化)
- Prometheus:http://localhost:9090(指标存储)
- Grafana:http://localhost:3000(仪表板 — admin/admin)
预期结果
- 成功的 vLLM 启动日志:
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
grafana grafana/grafana "/run.sh" grafana 25 seconds ago Up 24 seconds 0.0.0.0:3000->3000/tcp, :::3000->3000/tcp
jaeger jaegertracing/all-in-one:1.57 "/go/bin/all-in-one-…" jaeger 25 seconds ago Up 24 seconds 0.0.0.0:4317-4318->4317-4318/tcp, :::4317-4318->4317-4318/tcp, 0.0.0.0:5778->5778/tcp, :::5778->5778/tcp, 0.0.0.0:9411->9411/tcp, :::9411->9411/tcp, 0.0.0.0:14250->14250/tcp, :::14250->14250/tcp, 0.0.0.0:14268-14269->14268-14269/tcp, :::14268-14269->14268-14269/tcp, 0.0.0.0:16686->16686/tcp, :::16686->16686/tcp, 5775/udp, 0.0.0.0:6831-6832->6831-6832/udp, :::6831-6832->6831-6832/udp
prometheus prom/prometheus "/bin/prometheus --c…" prometheus 25 seconds ago Up 24 seconds 0.0.0.0:9090->9090/tcp, :::9090->9090/tcp
rag-app vllm_opentelemetry-rag-app "uvicorn rag_app:app…" rag-app 25 seconds ago Up 24 seconds 0.0.0.0:8001-8002->8001-8002/tcp, :::8001-8002->8001-8002/tcp
vllm-server vllm_opentelemetry-vllm-server "vllm serve facebook…" vllm-server 25 seconds ago Up 24 seconds 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp
- Prometheus targets 应该显示:
rag-app:8001 - UP
vllm-server:8000 - UP
- Jaeger 跟踪显示:
此示例跟踪显示了从 RAG 应用程序到嵌入、向量数据库、LLM 生成以及最终到 vLLM 服务器的端到端流程。 每个服务及其组件都清楚地显示为跨度。
- Grafana 应该显示:
- vLLM 和 RAG 指标的预配置仪表板
- 实时指标更新。 vLLM 仪表板应显示以下所有指标。 你可以配置你的自定义面板。
- 请求延迟
- Token 吞吐量
- 每个输出 Token 的时间延迟
- 首个 Token 的时间延迟
- 请求提示长度
- 请求生成长度
- 请求预填充和解码时间
- 序列组中的最大生成 Token
生产环境最佳实践
- 持久存储: 为 Prometheus 和 Grafana 挂载卷,以在重启时保留指标和仪表板配置。
- 安全性: 更改默认密码,保护网络访问,并考虑对所有 UI 使用 HTTPS。
- 可扩展性: 对于大型部署,请探索分布式 Prometheus (Thanos, Mimir) 和可扩展的 Jaeger 后端 (Elasticsearch, Cassandra)。 使用 OpenTelemetry Collector 进行可靠的摄取。
- 警报: 在 Grafana 中设置警报以检测高延迟、错误峰值或低吞吐量,并主动通知你的团队。
- 集中式日志记录: 使用 ELK 或 Loki 等日志记录解决方案补充指标和跟踪,以进行更深入的调试。
- 高级可观测性: 集成现代的、以 LLM 为中心的工具,例如 Langsmith、Helicone、Instana 或 traceloop,以增强你的 AI 可观测性。
vLLM可观测性的实践案例
假设你正在使用 vLLM 服务一个在线问答系统。通过 Grafana 仪表板,你观察到在用户提问高峰期,vLLM 的请求延迟显著增加,而 GPU 利用率并未达到峰值。这表明瓶颈可能在于 CPU 资源或网络带宽。通过 Jaeger 的分布式追踪,你可以进一步追踪请求的整个生命周期,发现预处理步骤(例如分词)占用了大量时间。最终,你通过优化预处理代码,显著降低了延迟,提高了系统的整体吞吐量。
另一个例子是,通过监控 vLLM 的 token 吞吐量,你可以发现某些模型在特定类型的查询上表现不佳,导致 token 生成速度下降。这可能意味着模型需要针对这些特定查询进行微调或调整参数。
总结
可观测性 改变了我们管理和优化 LLM 部署的方式。通过将 vLLM 与 OpenTelemetry、Jaeger、Prometheus 和 Grafana 集成,你将获得可操作的见解,这些见解有助于诊断问题并确保大规模平稳、经济高效且可靠的运营。
这个 可观测性 堆栈无法检测模型偏差、幻觉、有害内容或个人身份信息 (PII) 等挑战。 对于这些,请考虑 IBM 的 watsonx.governance 等治理工具。
无论你是 MLOps 工程师还是 AI 爱好者,构建强大的 可观测性 基础都是你掌握 LLM 运营的第一步。 深入研究、实验,释放 vLLM 的全部潜力!