- 后端
- API网关
- 模型推理服务
- AI Agent
【免费下载链接】semantic-router
An open, programmable decision layer for models and compute.
本篇技术指南聚焦 Semantic Router(vllm-project/semantic-router)的可观测性体系,围绕其官方教程文档 website/versioned_docs/version-v0.1/tutorials/observability/metrics.md 展开。全文以 Router 原生 Prometheus 指标为核心,覆盖本地宿主机模式、Docker Compose 模式、Kubernetes 模式三种部署形态的采集链路搭建,并深入讲解窗口化模型指标(Windowed Model Metrics)的配置、指标语义与查询方法,同时结合 src/semantic-router/pkg/observability/metrics/metrics.go 等源码级实现,帮助读者掌握从「采集端点配置 → 指标查询 → 告警规则」的完整实战能力。
1. 指标端点总览:Router 可观测性的三个入口
Semantic Router 在进程内原生暴露 Prometheus 格式指标,同时提供 HTTP 健康检查端点,若部署了 Envoy 还可采集其自身统计信息。三个端点的关系如下表:
| 组件 | 端点 | 说明 |
|---|---|---|
| Router metrics | :9190/metrics | Prometheus 文本格式,端口由命令行 flag--metrics-port控制 |
| Router health | :8080/health | HTTP readiness / liveness 探针 |
| Envoy metrics(可选) | :19000/stats/prometheus | 仅在启用 Envoy 时存在 |
其中 Router 的 metrics 端点并不依赖配置文件,而是由运行时启动参数直接决定。源码层面,runtime_bootstrap.go 中定义了--metrics-portflag,默认值即为9190;metricsServerEnabled()在cfg.Observability.Metrics.Enabled未显式设置时默认开启指标服务(runtime_bootstrap.go)。启动逻辑通过net.Listen("tcp", ":"+port)绑定端口,并以 metrics.NewServeMux() 作为 HTTP Handler,因此只要 Router 进程存活,curl localhost:9190/metrics即可直接拿到全部指标。
文档约定观测相关配置统一放置在tools/observability/目录(本地/Docker 模式),Kubernetes 模式则对应deploy/kubernetes/observability/,两者共享同一套 Grafana 面板定义llm-router-dashboard.json。在 v0.1 教程所处的仓库基线中,完整目录包括:
prometheus.yaml—— Prometheus 采集配置grafana-datasource.yaml—— Grafana 数据源配置grafana-dashboard.yaml—— 面板 provision 配置llm-router-dashboard.json—— 面板定义(JSON)
提示:当前仓库版本已将 Kubernetes 观测栈独立成 Kustomize 包(见第 4 节),面板与告警规则也随版本演进有所扩充,但端点与核心指标语义保持一致。
2. 本地模式(Router 运行在宿主机)
本地模式适合开发调试:Router 以原生进程运行,Prometheus 与 Grafana 以 Docker 容器提供观测能力。
2.1 快速启动
# 启动 Router(宿主机进程) make run-router # 启动观测栈(Prometheus + Grafana 容器) make o11y-local启动后的访问入口:
- Prometheus:http://localhost:9090
- Grafana:http://localhost:3000(默认账号
admin/admin)
验证采集目标是否生效:
# 确认 Prometheus 正在抓取 localhost:9190 open http://localhost:9090/targets停止观测栈:
make stop-observability2.2 配置文件说明
所有配置均位于tools/observability/:
prometheus.yaml—— 通过环境变量ROUTER_TARGET指定抓取目标,默认值为localhost:9190grafana-datasource.yaml—— Grafana 数据源指向localhost:9090grafana-dashboard.yaml—— 面板自动 provisioning 配置llm-router-dashboard.json—— 面板定义本身
2.3 常见故障排查
| 问题 | 解决方式 |
|---|---|
| Target 显示 DOWN | 先启动 Router:make run-router |
| 无指标数据 | 主动产生流量(通过 Router 发请求),并检查:9190/metrics是否有输出 |
| 端口冲突 | 更换端口或停止占用端口的进程 |
值得注意:Router 的 health 端点与 metrics 端点相互独立。
startMetricsServerIfEnabled()中如果端口已被占用,指标服务会记录metrics_server_failed事件并跳过启动而不会中止 Router 主流程(runtime_bootstrap.go),因此「端口冲突」通常表现为 metrics 端点不可达而非进程崩溃。
3. Docker Compose 模式:全容器化观测栈
当 Router 本身也容器化部署时,观测组件与 Router 共享同一容器网络,抓取目标从localhost变为服务名。
3.1 快速启动
# 启动完整栈(包含观测组件) docker compose -f deploy/docker-compose/docker-compose.yml up --build # 或者启用 testing profile docker compose -f deploy/docker-compose/docker-compose.yml --profile testing up --build访问入口与本地模式一致:
- Prometheus:http://localhost:9090
- Grafana:http://localhost:3000(默认账号
admin/admin)
预期的采集目标:
semantic-router:9190—— Router 指标envoy-proxy:19000—— Envoy 统计信息(可选)
3.2 与本地模式的差异
配置仍复用tools/observability/下的文件,但环境变量需要指向容器服务名:
ROUTER_TARGET=semantic-router:9190PROMETHEUS_URL=prometheus:9090- 使用
semantic-networkbridge 网络互通
4. Kubernetes 模式:生产级观测栈
Kubernetes 模式提供面向生产环境的 Prometheus + Grafana 部署,运行在命名空间vllm-semantic-router-system中。仓库中的完整实现位于 deploy/kubernetes/observability/,由 Kustomize 组织,包含四类组件:
| 组件 | 用途 | 位置 |
|---|---|---|
| Prometheus | 抓取 Router 指标,15 天保留期 | deploy/kubernetes/observability/prometheus/ |
| Grafana | 面板可视化 | deploy/kubernetes/observability/grafana/ |
| Ingress | 可选的外部访问入口 | deploy/kubernetes/observability/ingress.yaml |
| Dashboard | Router 配置与工具数据展示 | deploy/kubernetes/observability/dashboard/ |
4.1 部署
# 渲染并应用全部 manifest kubectl apply -k deploy/kubernetes/observability/ # 验证 Pod 状态 kubectl get pods -n vllm-semantic-router-system官方文档提醒,仓库内自带的值是「便于检查」的开发示例而非安全默认值:grafana/secret.yaml中写死admin/admin、ingress.yaml包含示例域名与 TLS Secret 名称。正式部署前应先执行kubectl kustomize deploy/kubernetes/observability/渲染检查,再通过 overlay 替换凭据、存储类与资源配额。
一个关键前提是:Router 的 metrics Service 必须存在于同一命名空间且暴露名为metrics的端口:
kubectl get service semantic-router-metrics \ --namespace vllm-semantic-router-system4.2 访问方式
端口转发(无 Ingress 时):
kubectl port-forward svc/prometheus 9090:9090 -n vllm-semantic-router-system kubectl port-forward svc/grafana 3000:3000 -n vllm-semantic-router-systemIngress:按需修改ingress.yaml中的域名与 TLS 配置。若通过外部代理转发内部 Host 访问 Grafana Live(WebSocket),还需在 Grafana 容器上设置GF_LIVE_ALLOWED_ORIGINS为浏览器面向 Dashboard 的真实 Origin(不要写成*),详见 deploy/kubernetes/observability/README.md。
4.3 关键配置
Prometheus 使用 Kubernetes 服务发现(Kubernetes SD):仓库中 prometheus/configmap.yaml 的实际实现比文档示例更完整——通过relabel_configs只保留服务名为semantic-router-metrics、端口名为metrics的 endpoint:
scrape_configs: - job_name: semantic-router kubernetes_sd_configs: - role: endpoints namespaces: names: [vllm-semantic-router-system] relabel_configs: - source_labels: [__meta_kubernetes_service_name] regex: semantic-router-metrics action: keep - source_labels: [__meta_kubernetes_endpoint_port_name] regex: metrics<|begin▁of▁sentence|> r action: keep该 ConfigMap 同时设置了全局scrape_interval: 15s、evaluation_interval: 15s,并加载rule_files中的告警规则。
Grafana 数据源与面板 provisioning:grafana/configmap-provisioning.yaml 以datasources.yaml声明默认数据源http://prometheus:9090(timeInterval: 15s),以dashboards.yaml声明文件型 provider,从/var/lib/grafana-dashboards自动加载面板,面板文件由configmap-dashboard.yaml注入。
Grafana 凭据(生产环境务必替换):
kubectl create secret generic grafana-admin \ --namespace vllm-semantic-router-system \ --from-literal=admin-user=admin \ --from-literal=admin-password='your-password'更推荐的做法是先用--dry-run=client -o yaml生成 Secret 再 apply,避免把密码写进提交的 overlay:
kubectl create secret generic grafana-admin \ --namespace vllm-semantic-router-system \ --from-literal=admin-user=monitor \ --from-literal=admin-password="$GRAFANA_ADMIN_PASSWORD" \ --dry-run=client -o yaml | kubectl apply -f - kubectl rollout restart deployment/grafana \ --namespace vllm-semantic-router-system4.4 验证数据链路
官方 K8s 部署文档(deploy/kubernetes/observability/README.md)给出了端到端验证顺序:
- 打开 PrometheusStatus > Targets,确认
semantic-routerjob 为 UP; - 通过 Envoy 发送推理流量;
- 查询 Router 实际输出的指标,如
llm_request_outcomes_total{traffic_kind="inference"}; - 打开 Grafana 已 provisioning 的 Router 面板,确认时间范围覆盖流量时段。
若 target 缺失,先检查服务发现而非面板:
kubectl get endpoints semantic-router-metrics \ --namespace vllm-semantic-router-system kubectl logs deployment/prometheus \ --namespace vllm-semantic-router-system5. 核心指标:Router 原生导出的 Prometheus 指标
Semantic Router 的核心指标全部在 src/semantic-router/pkg/observability/metrics/metrics.go 中通过promauto.NewCounterVec/NewHistogramVec注册。教程文档列出四个基础指标:
| 指标 | 类型 | 描述 |
|---|---|---|
llm_category_classifications_count | counter | 分类(category classification)次数 |
llm_model_completion_tokens_total | counter | 各模型的输出 token 数 |
llm_model_routing_modifications_total | counter | 模型路由变更次数 |
llm_model_completion_latency_seconds | histogram | 模型完成响应耗时 |
示例查询:
# 输出 token 速率(每 5 分钟) rate(llm_model_completion_tokens_total[5m]) # 完成耗时的 P95 分位数 histogram_quantile(0.95, rate(llm_model_completion_latency_seconds_bucket[5m]))5.1 指标背后的源码实现
这组指标在源码中均有对应注册与记录函数,可作为排障时「指标为何缺失」的定位依据:
llm_model_completion_tokens_total:注册于 metrics.go,由RecordModelTokensDetailed(model, promptTokens, completionTokens)在累加llm_model_tokens_total与llm_model_prompt_tokens_total的同时记录(metrics.go);llm_model_routing_modifications_total:注册于 metrics.go,带source_model与target_model两个 label,由RecordModelRouting(sourceModel, targetModel)在源模型与目标模型不同时才Inc()(metrics.go),因此它精确刻画了「路由决策真正改写目标模型」的次数;llm_model_completion_latency_seconds:注册于 metrics.go,bucket 区间为0.005s ~ 1800s的有限序列。源码注释特别说明:由于 completion 可能包含长流式 / reasoning 响应,有限桶上界必须超出维护的 30 秒 P95 告警阈值;llm_category_classifications_count:对应分类管线的计数指标。同文件还注册了llm_classification_confidence(分类置信度分布)与llm_entropy_values(Shannon 熵分布)等分类质量指标,说明分类观测并不止于次数,还包括置信度与不确定性维度(metrics.go)。
5.2 值得关注的扩展指标
除教程列出的四个基础指标外,同文件还导出了模型成本、请求错误、会话级 token 等指标,这些对生产运维同样关键:
| 指标 | 类型 | 说明 |
|---|---|---|
llm_model_requests_total | counter | 每个模型的请求总数(label:model) |
llm_request_errors_total | counter | 按model与reason分类的错误计数(reason 会归一化为timeout、upstream_5xx、upstream_4xx等) |
llm_model_cost_total | counter | 按model与currency统计的成本 |
llm_model_prompt_tokens_total | counter | 各模型输入 token 数 |
llm_prompt_tokens_per_request/llm_completion_tokens_per_request | histogram | 单请求 token 数分布 |
llm_session_turn_prompt_tokens/llm_session_turn_completion_tokens | histogram | 会话级每轮 token 数(label:model、domain) |
llm_model_first_response_observation_seconds | histogram | 首个流式 chunk / 非流式响应头到达耗时 |
llm_model_response_duration_per_output_token_seconds | histogram | 完整响应耗时 ÷ 输出 token 数 |
llm_model_routing_latency_seconds | histogram | 路由决策本身耗时 |
llm_unverified_factual_responses_total | counter | 缺少工具上下文无法核验的事实性响应计数 |
记录错误时RecordRequestError()还会把deadline_exceeded、upstream_500/502/503/504等原始值归一化为timeout、upstream_5xx,便于告警规则聚合(metrics.go)。
5.3 预置告警规则:30 秒 P95 的真实出处
教程中的histogram_quantile(0.95, ...)查询在 K8s 观测栈中被固化为告警规则。仓库 prometheus/rules.yaml 定义了HighCompletionLatencyP95等 7 条规则,其中 completion 延迟告警正是:
histogram_quantile(0.95, sum(rate(llm_model_completion_latency_seconds_bucket[5m])) by (le)) > 30 for: 10m其余规则覆盖:请求错误率 > 5%(HighRequestErrorRate)、首响应 P95 > 5s、每输出 token 时长 P95 > 250ms、路由耗时 P95 > 100ms、单模型 in-flight 请求 > 50、缓存命中率 < 20%。这些规则均带for持续条件与dashboard_panel注解,可直接作为生产基线并路由到 Alertmanager。与之对应的契约测试位于 completion_latency_contract_test.go,用正则校验告警表达式形态,防止查询被误改。
6. 窗口化模型指标(Windowed Model Metrics)与负载均衡
窗口化指标是面向模型性能追踪的增强能力,尤其适合 Kubernetes 环境——该环境下「模型选择」与「下游 endpoint 负载均衡」是分离的职责,Router 需要输出足够细粒度的窗口指标供下游决策使用。
6.1 配置开启
在config.yaml的observability.metrics.windowed_metrics节点开启:
observability: metrics: windowed_metrics: enabled: true time_windows: ["1m", "5m", "15m", "1h", "24h"] update_interval: "10s" model_metrics: true queue_depth_estimation: true max_models: 100字段说明:
enabled:总开关,关闭时RecordRequest直接忽略(windowed_metrics.go);time_windows:时间窗口列表,缺省使用DefaultTimeWindows = ["1m","5m","15m","1h","24h"],每个窗口独立计算统计量;update_interval:后台计算周期,默认10s;WindowedMetricsManager.Start()以该间隔驱动 ticker 调用computeWindowedMetrics()(windowed_metrics.go);max_models:最多追踪的模型数,默认100;达到上限后新模型请求不再入缓冲区(windowed_metrics.go);model_metrics/queue_depth_estimation:教程文档列出的配置开关。需要说明的是,当前源码的指标导出以「已观测完成的响应」为统计对象——源码注释明确WindowedMetricsManager只汇总每个模型最多 10,000 条已完成的响应,并非尝试次数、provider 失败、利用率或队列深度的完整普查(windowed_metrics.go)。
启动时InitializeWindowedMetrics()会注册全部窗口化 Gauge 并创建后台管理 goroutine;若初始化失败,Router 仅记录windowed_metrics_init_failed警告而不崩溃(runtime_bootstrap.go)。
6.2 模型级指标清单
| 指标 | 类型 | 标签 | 描述 |
|---|---|---|---|
llm_model_latency_windowed_seconds | gauge | model, time_window | 窗口内平均延迟 |
llm_model_requests_windowed_total | gauge | model, time_window | 窗口内请求数(实际为保留在窗口内的已完成响应数) |
llm_model_tokens_windowed_total | gauge | model, token_type, time_window | 窗口内 token 吞吐(token_type 取值prompt/completion) |
llm_model_utilization_percentage | gauge | model, time_window | 预估利用率百分比 |
llm_model_queue_depth_estimated | gauge | model | 当前预估队列深度 |
llm_model_error_rate_windowed | gauge | model, time_window | 窗口内错误率 |
llm_model_latency_p50_windowed_seconds | gauge | model, time_window | 窗口内 P50 延迟 |
llm_model_latency_p95_windowed_seconds | gauge | model, time_window | 窗口内 P95 延迟 |
llm_model_latency_p99_windowed_seconds | gauge | model, time_window | 窗口内 P99 延迟 |
注意版本差异:
llm_model_utilization_percentage、llm_model_queue_depth_estimated、llm_model_error_rate_windowed三个指标出现在教程文档中,但当前仓库源码对应的 windowed_metrics_test.go 已将其标记为「退役且不再导出的指标族」(测试断言这些 family 不应存在)。若你在较新版本中查询不到这三个指标,请以llm_model_latency_*、llm_model_requests_windowed_total、llm_model_tokens_windowed_total作为负载均衡与容量规划的主要依据。
6.3 示例查询
# 某模型最近 5 分钟的平均延迟 llm_model_latency_windowed_seconds{model="gpt-4", time_window="5m"} # 跨模型对比 15 分钟窗口 P95 延迟 llm_model_latency_p95_windowed_seconds{time_window="15m"} # 各模型 1 小时窗口内的 completion token 吞吐 llm_model_tokens_windowed_total{token_type="completion", time_window="1h"} # 负载均衡决策所需的当前队列深度 llm_model_queue_depth_estimated{model="gpt-4"} # 错误率监控(5 分钟窗口错误率超过 5%) llm_model_error_rate_windowed{time_window="5m"} > 0.056.4 实现原理:时间窗口与百分位计算
窗口化指标的核心数据结构是每个模型一个的时间型环形缓冲区(RequestRingBuffer):
NewRequestRingBuffer(capacity)创建容量固定的环形数组,Add()在满时覆盖最旧数据(windowed_metrics.go);- 每个
RequestData记录时间戳、模型、延迟、prompt/completion token 数(windowed_metrics.go); - 计算周期到达时,
computeWindowedMetrics()对每个模型 × 每个时间窗口调用GetDataSince(now-window)过滤出窗口内数据,汇总平均延迟、token 总量,并通过computePercentile()线性插值计算 P50/P95/P99(windowed_metrics.go); - 空窗口会把请求数置 0、删除延迟类指标,避免把过期样本当作有效测量(这一点在 TestWindowedCompletedSamplesExpireWithoutStaleLatency 中有专门测试验证)。
这一设计意味着窗口化指标以「gauge + 前台后台周期计算」替代「counter/histogram + Prometheus 端 rate 聚合」,从而允许外部负载均衡器在不依赖 PromQL 时间范围参数的前提下,直接读取 Router 已算好的窗口统计值。
6.5 典型使用场景
- 负载均衡:结合队列深度与延迟指标,把请求路由到负载较轻的模型;
- 性能监控:跟踪各时间窗口下的 P95/P99 延迟趋势;
- 容量规划:观察利用率百分比,判断何时扩容模型;
- 告警:针对窗口内错误率或延迟尖峰设置阈值告警。
7. 汇总排查清单
| 问题 | 检查项 | 修复方式 |
|---|---|---|
| Target DOWN | Prometheus /targets 页面 | 确认 Router 在运行且暴露:9190/metrics;K8s 下另查semantic-router-metricsService 的 endpoints 与端口名metrics |
| 无指标 | 流量是否经过 Router | 通过 Router 发送请求(分类/推理流量)后再查询 |
| 面板为空 | Grafana 数据源配置 | 检查 Prometheus URL 是否可达、指标名是否拼写正确、时间范围是否覆盖流量 |
| PVC Pending(K8s) | kubectl describe pvc | 检查存储类是否可用 |
| Ingress 404 / TLS 报错 | Ingress class、hostname、DNS | 按需 patch hostname 与 TLS Secret |
| Grafana Live 面板加载失败 | GF_LIVE_ALLOWED_ORIGINS | 在 Grafana 容器环境变量中配置浏览器面向 Dashboard 的真实 Origin |
移除整个 K8s 观测示例:
kubectl delete -k deploy/kubernetes/observability/注意:PVC 的删除与保留行为取决于集群与存储类,移除前先确认是否需要保留数据。
8. 小结
Semantic Router 的观测体系是一套「Router 原生指标 + 三种部署形态 + 窗口化模型指标」的组合:--metrics-port控制的:9190/metrics是数据源头;本地与 Docker Compose 模式通过tools/observability/下的配置快速拉起 Prometheus/Grafana;Kubernetes 模式以deploy/kubernetes/observability/Kustomize 包提供生产级服务发现、15 天保留期与 7 条预置告警规则;窗口化指标则在 Router 进程内按时间窗口预先计算平均/分位延迟与 token 吞吐,供外部负载均衡与容量规划直接消费。配合 metrics.go 与 windowed_metrics.go 的源码实现,读者可以精确掌握每条指标的触发条件、标签语义与统计口径,进而搭建出贴合自身业务的可观测与告警体系。
- 后端
- API网关
- 模型推理服务
- AI Agent
【免费下载链接】semantic-router
An open, programmable decision layer for models and compute.
相关推荐
Ray 集群指标采集与监控:基于 Prometheus 与 Grafana 的完整实践指南
Ray 集群指标采集与监控:基于 Prometheus 与 Grafana 的完整实践指南 导读 :本文以 Ray 官方文档 doc/source/cluste
人工智能分布式训练强化学习任务调度模型推理服务后端Semantic Router 指标与监控实战:Prometheus + Grafana 可观测性全指南
Semantic Router 指标与监控实战:Prometheus + Grafana 可观测性全指南 Semantic Router(vLLM Projec
后端API网关模型推理服务AI AgentCortex 集群监控指南:基于 Prometheus 与 Grafana 的指标采集、可视化与导出实践
Cortex 集群监控指南:基于 Prometheus 与 Grafana 的指标采集、可视化与导出实践 Cortex 在生产集群内默认部署了 Promethe
人工智能模型推理服务后端云原生MLOps
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考