AI 生产环境可观测性全景图:指标维度收敛与全链路日志联动排障
在企业级 AI 系统的可观测性体系建设中,很多团队常常陷入一个极端:为了“大而全”,把所有的用户 Prompt、微小参数以及高基数(High Cardinality)标签一股脑塞进 Prometheus 指标和日志系统。结果不到一周,Prometheus 就因为高基数维度爆炸(Metric Explosion)发生 OOM 崩溃,日志存储集群每天被打入几十 TB 的非结构化文本,真正需要排查一次故障时,却由于噪音过多根本无法有效检索。
为了构建一套高效、轻量且具备实战排障能力的可观测性体系,我们梳理了“指标维度精准收敛 + OpenTelemetry 分布式链路追踪 + 结构化日志联动”的全局落地全景图。
flowchart LR UserReq[用户交互请求] --> APIGW[AI 接入网关 (注入 W3C TraceID)] subgraph 指标层: 维度精准收敛 APIGW --> PromMetrics[Prometheus: 仅采集低基数黄金指标] PromMetrics --> PromDB[(Prometheus TSDB: 内存稳定 / 拒绝高基数)] end subgraph 链路与日志层: 结构化联动 APIGW --> OTelTracer[OpenTelemetry Tracer] OTelTracer --> VectorSearch[向量数据库检索 Span] OTelTracer --> LLMInfer[大模型生成 Span (记录 TTFT / TPOT)] LLMInfer --> StructuredLog[结构化 JSON 日志 (绑定 TraceID / SpanID)] end StructuredLog --> LokiLog[(Loki / ES 日志中心)] OTelTracer --> JaegerUI[(Tempo / Jaeger 链路追踪)]1. 指标维度收敛法则:消灭高基数灾难
在 Prometheus 中,指标标签(Labels)的组合数称为基数。绝对严禁将user_id、session_id、prompt_hash或完整的error_message作为 Prometheus Label 写入指标!否则每一个不同的用户都会在时序数据库中创建一条全新的时间序列,导致内存呈指数级暴涨。
我们制定的指标收敛规范如下:
- 允许的 Label 集合(固定低基数枚举):
model_name(模型名)、tenant_dept(业务部门)、status_code(HTTP 状态码)、error_type(收敛后的错误大类,如Timeout/RateLimit/OOM); - 动态高基数信息必须下沉至 Trace 与日志:具体的 Prompt 文本、详细堆栈、租户用户 ID 全部存入 OpenTelemetry Trace 的 Span Attributes 或结构化日志中。
# 规范化的 Prometheus 指标采集配置 apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: ai-gateway-monitor namespace: monitoring spec: endpoints: - port: metrics interval: 10s metricRelabelings: # 强制剔除开发误打的高基数标签 - action: labeldrop regex: "(user_id|session_id|prompt_content)"2. 跨阶段 Span 链路追踪与关键时间点埋点
大模型应用通常经历多个执行阶段。通过 OpenTelemetry 将各阶段耗时清晰分块,可以一眼看清性能瓶颈到底是在向量检索、Prompt 预处理、还是在模型生成环节:
package tracing import ( "context" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) var tracer = otel.Tracer("ai-pipeline") func TraceRAGWorkflow(ctx context.Context, query string) { ctx, span := tracer.Start(ctx, "RAG_Overall_Execution") defer span.End() // 阶段 1: 向量召回 Span func() { _, embedSpan := tracer.Start(ctx, "Vector_Search") defer embedSpan.End() embedSpan.SetAttributes(attribute.Int("rag.top_k", 5)) // 执行检索... }() // 阶段 2: 模型流式生成 Span func() { _, llmSpan := tracer.Start(ctx, "LLM_Generation") defer llmSpan.End() llmSpan.SetAttributes(attribute.String("llm.model", "qwen-72b")) // 记录 TTFT 和 TPOT... }() }3. 日志、指标与链路的三位一体联动排障
在生产实际排障中,工程师标准的 3 步排查闭环如下:
- 指标看板定位大盘异常:在大屏上看到某个部门的
llm_ttft_p95突然从 1.2s 飙升到 6s; - 从 Prometheus 图表一键跳转至 Tempo/Jaeger 链路:在 Grafana 中点击异常时间点的 Trace,直接展示具体的慢请求调用拓扑,清晰看到耗时卡在
Vector_Search(向量数据库索引重建导致超时); - 基于 TraceID 检索结构化日志:在 Loki 中输入
trace_id="4bf92f3577b34da6a3ce929d0e0e4736",秒级检索出该请求完整的上下文与错误原因。
通过这套规范化收敛的可观测体系,我们不仅将监控系统的资源占用压缩了 70%,更将线上 AI 故障的平均定位时间(MTTD)从 40 分钟降低至 3 分钟以内。