十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

分布式追踪进 AI 时代:OpenTelemetry 捕获大模型 Step 级 Span 实战

分布式追踪进 AI 时代:OpenTelemetry 捕获大模型 Step 级 Span 实战 分布式追踪进 AI 时代OpenTelemetry 捕获大模型 Step 级 Span 实战在传统微服务架构中分布式链路追踪Distributed Tracing如 Jaeger、Zipkin、SkyWalking已经深入人心。通过在 HTTP/gRPC 调用上下文中透传traceparent请求头我们可以清晰地在调用链图谱上看到一个请求从 API 网关 - 用户微服务 - 订单微服务 - MySQL 数据库的每一个毫秒级耗时节点。然而当我们的业务链路上引入了复杂的大模型应用——例如Agent 自主规划、多轮 Tool Calling、RAG 向量检索召回、Prompt 模板动态装配、流式自回归生成时传统的链路追踪显得力不从心Trace 视图上只能看到一个巨大的、耗时 8 秒的单一 SpanPOST /v1/chat/completions至于这 8 秒钟里到底是 RAG 向量检索花了 500ms还是 Agent 内部的反思循环执行了 3 次或者是大模型 Prefill 首字耗时了 2 秒在现有的 APM 看板中完全是一个无法洞察的黑盒。为了让 AI 应用具备可观测的工业级透明度CNCF 的OpenTelemetryOTel专门推出了针对大模型与生成式 AI 的标准化语义约定Semantic Conventions for Generative AI。本文将带大家使用 Go 与 Python 实战演示如何在 OpenTelemetry 中精确捕获大模型调用的Step 级 Span、Token 消耗元数据与流式耗时分析。flowchart TD ClientSpan[Root Span: POST /api/v1/agent/solve_problem 耗时 4.2s] ClientSpan -- SpanRAG[Child Span 1: RAG_Vector_Search 向量库检索 180ms] SpanRAG -- SpanEmbedding[Sub Span: OpenAI text-embedding-3 50ms] SpanRAG -- SpanMilvus[Sub Span: Milvus Query 120ms] ClientSpan -- SpanPrompt[Child Span 2: Prompt_Template_Render 5ms] ClientSpan -- SpanLLM[Child Span 3: LLM_Inference_Execution 耗时 3.8s] SpanLLM -- SpanPrefill[Event: First Token TTFT 620ms] SpanLLM -- SpanDecode[Event: Decode 128 Tokens 24ms/token] SpanLLM -.- Attributes[Attributes 注入: modelllama3-70b, prompt_tokens1520, completion_tokens128]1. OpenTelemetry GenAI 语义约定核心标准在 OTel 官方规范中针对大模型调用定义了一套标准化的 Span 属性键值杜绝了各团队自定义 Tag 导致的割裂gen_ai.system大模型系统标识如openai,vllm,anthropicgen_ai.request.model请求的目标模型名称如llama-3-70b-instructgen_ai.request.temperature采样温度参数gen_ai.usage.input_tokens本次请求消耗的输入提示词 Token 数量gen_ai.usage.output_tokens模型生成的输出 Token 数量gen_ai.response.finish_reasons生成结束原因stop,length,tool_calls。2. Go 网关层的 OpenTelemetry 细粒度打点实战以下是在 Go 编写的 AI 应用网关中如何使用官方go.opentelemetry.io/otel/trace包构建多级嵌套 Span 的生产代码package main import ( context fmt time go.opentelemetry.io/otel go.opentelemetry.io/otel/attribute go.opentelemetry.io/otel/trace ) var tracer otel.Tracer(ai-gateway-tracer) func HandleAgentRequest(ctx context.Context, query string) error { // 1. 创建顶层根 Span ctx, rootSpan : tracer.Start(ctx, Agent_Execute_Pipeline, trace.WithSpanKind(trace.SpanKindServer)) defer rootSpan.End() rootSpan.SetAttributes(attribute.String(user.query, query)) // 2. 子步骤一: 执行 RAG 向量召回 contextDocs, err : executeRAGSearch(ctx, query) if err ! nil { rootSpan.RecordError(err) return err } // 3. 子步骤二: 调用大模型流式生成 err executeLLMGeneration(ctx, query, contextDocs) if err ! nil { rootSpan.RecordError(err) return err } return nil } func executeRAGSearch(ctx context.Context, query string) (string, error) { ctx, span : tracer.Start(ctx, RAG_Vector_Retrieval, trace.WithSpanKind(trace.SpanKindInternal)) defer span.End() span.SetAttributes( attribute.String(db.system, milvus), attribute.Int(rag.top_k, 5), ) // 模拟检索耗时 time.Sleep(120 * time.Millisecond) span.AddEvent(RAG 检索完成命中 5 条知识切片) return 召回的上下文知识库内容, nil } func executeLLMGeneration(ctx context.Context, query string, docs string) error { ctx, span : tracer.Start(ctx, GenAI_LLM_Inference, trace.WithSpanKind(trace.SpanKindClient)) defer span.End() // 遵循 OTel GenAI 语义约定注入属性 span.SetAttributes( attribute.String(gen_ai.system, vllm), attribute.String(gen_ai.request.model, llama-3-70b-instruct), attribute.Float64(gen_ai.request.temperature, 0.7), ) startPrefill : time.Now() // 模拟首字计算 time.Sleep(450 * time.Millisecond) ttftCost : time.Since(startPrefill) // 记录关键事件: 首字到达时间 (TTFT) span.AddEvent(First_Token_Arrived, trace.WithAttributes( attribute.Int64(gen_ai.latency.ttft_ms, ttftCost.Milliseconds()), )) // 模拟生成后续 150 个 Token time.Sleep(800 * time.Millisecond) // 记录 Token 消耗度量 span.SetAttributes( attribute.Int(gen_ai.usage.input_tokens, 850), attribute.Int(gen_ai.usage.output_tokens, 150), attribute.String(gen_ai.response.finish_reason, stop), ) return nil }3. 在 Jaeger / Grafana Tempo 上的可视化排障体验当全链路接入 OTel 之后运维和开发团队在 Jaeger / Tempo 看板上可以获得无与伦比的排障洞察力一秒定位延迟瓶颈一眼就能看出 4.2 秒的总耗时中RAG 检索仅占 120ms而模型 Prefill 首字耗费了 450ms解码生成耗费了 800ms精准过滤异常 Trace在 Jaeger 搜索栏中输入gen_ai.usage.input_tokens 4000可以瞬间筛选出所有超长 Prompt 的请求链路排查是否有人在恶意打长文档拖慢集群关联 Metrics 与 Logs三位一体点击某个 Span 上的 TraceID可以直接联动跳转到 Loki 查看对应的请求日志并跳转到 Prometheus 查看该请求发生时刻 GPU 节点的显存与温度曲线。4. 生产落地的采样率治理建议对于高 QPS 的大模型 API如果 100% 全量采集 Trace 数据每天产生的 Span 数据量会达到数百 GB造成巨大的存储与网络开销。建议在 OpenTelemetry Collector 中配置尾部采样策略Tail-based Sampling常规正常请求配置 1%5% 的低比例概率采样异常请求HTTP 5xx、包含 Error 的 Span强制100% 全量采样保留慢请求总耗时超过 5 秒或 TTFT 超过 2 秒强制100% 全量采样保留。通过这种“保慢留错”的智能采样策略我们既把 APM 存储成本降低了 90%又确保了每一次线上偶发的慢调用与崩溃都能被 100% 完整捕捉复现。
返回列表