星辰AI头像
关注

AI 工作流的可观测性架构:Trace、Metric 与 Log 的三维性能诊断体系

AI 工作流的可观测性架构:Trace、Metric 与 Log 的三维性能诊断体系

一、可观测性在 AI 工作流中的必要性

AI 工作流的复杂性与传统微服务有本质区别。一个典型的 Agent 调用链可能涉及:用户意图解析 → RAG 检索 → 多轮 LLM 推理 → 工具调用 → 结果聚合 → 流式输出。这条链路上,延迟的累积不是线性的——一个工具调用的超时可能引发后续节点的重试风暴,一个 Prompt 的长度膨胀可能让 Token 成本翻倍。

传统监控的痛点在于:Metrics 能告诉你 P99 延迟变高了,但不知道是哪个环节在拖后腿;Log 记录了每个节点的输出,却无法关联到具体的用户请求;Trace 有父子 Span 关系,但 LLM 调用的耗时不等于"网络延迟 + 推理时间",中间还有 Tokenization、KV Cache 查找等不可观测的步骤。

三维可观测性体系的核心思路是:Metrics 发现问题,Trace 定位环节,Log 还原现场

graph TD
    A[告警触发: P99 延迟 > 5s] --> B{Metrics 面板}
    B --> C[推理耗时占比 80%]
    B --> D[工具调用耗时占比 50%]
    C --> E[Trace 下钻到具体 Span]
    D --> E
    E --> F[定位到特定 Prompt 模板]
    E --> G[定位到特定 Tool API]
    F --> H[Log 查看完整 Prompt 内容]
    G --> I[Log 查看 API 返回]
    H --> J[优化 Prompt 长度 / 切换模型]
    I --> K[增加缓存 / 切换供应商]

二、Trace 设计:从链路追踪到语义追踪

标准 OpenTelemetry Span 的属性是针对 HTTP/RPC 调用设计的,对于 LLM 调用需要扩展自定义属性。建议按以下维度设计 Span:

// LLM 调用的自定义 Span 属性
type LLMSpanAttributes struct {
    Model           string  // gpt-4o-mini
    Provider        string  // openai
    PromptTokens    int
    CompletionTokens int
    TotalTokens     int
    Temperature     float64
    StopReason      string  // stop | length | tool_calls
    FirstTokenLatency time.Duration  // TTFT
    StreamMode      bool
    ToolCallsCount  int
    CacheHit        bool    // 是否命中 Prompt Cache
}

关键设计原则:

  1. Span 的父子关系要反映语义依赖,而非物理调用时序。如果一个 Agent 先做查询改写再检索,两个 LLM 调用应该是串行的父子 Span;但如果做并行工具调用(同时查天气、查日历),它们应该是同一个父 Span 下的兄弟 Span。

  2. 区分"排队延迟"和"执行延迟"。LLM API 调用中,从发起请求到收到第一个 Token 的时间(TTFT)包含排队时间,这往往是供应商侧的瓶颈。通过记录 ttfttokens_per_second 可以判断:

P99 延迟高 + TTFT 高 → 供应商排队拥塞,考虑切换供应商或增加并发限制
P99 延迟高 + tokens_per_second 低 → 模型推理慢,考虑切换更快的模型
P99 延迟高 + 两者都正常 → 业务逻辑耗时多,优化 Prompt 或减少 Tool 调用轮次

三、Metrics 设计:从基础设施指标到业务指标

基础设施层面的 Metrics(CPU、内存、GC 暂停)是必要但不充分的。AI 工作流需要额外的业务视角:

// 业务 Metrics 的设计维度
const businessMetrics = {
  // 质量指标
  task_success_rate: { type: 'gauge', labels: ['agent_type', 'workflow_id'] },
  tool_call_success_rate: { type: 'gauge', labels: ['tool_name'] },
  
  // 成本指标
  token_cost_per_task: { type: 'histogram', labels: ['model', 'agent_type'], buckets: [0.001, 0.01, 0.05, 0.1, 0.5] },
  daily_token_cost: { type: 'counter', labels: ['model'] },
  
  // 延迟指标
  end_to_end_latency: { type: 'histogram', labels: ['agent_type'], buckets: [1, 5, 10, 30, 60, 120] },
  ttft_latency: { type: 'histogram', labels: ['model', 'provider'] },
  tool_execution_latency: { type: 'histogram', labels: ['tool_name'] },
  
  // 缓存指标
  semantic_cache_hit_rate: { type: 'gauge', labels: ['cache_layer'] },
  cache_memory_mb: { type: 'gauge' },
  
  // 限流指标
  rate_limit_hits: { type: 'counter', labels: ['model', 'provider'] }
};

PromQL 查询示例:

# 过去 1 小时 Token 成本突增
(sum(rate(token_cost_per_task_sum[5m])) / sum(rate(token_cost_per_task_count[5m]))) 
  > 2 * (sum(rate(token_cost_per_task_sum[1h])) / sum(rate(token_cost_per_task_count[1h])))

# 特定 Tool 调用的成功率下降
tool_call_success_rate{tool_name="search_database"} < 0.95

四、Log 设计:结构化日志与采样策略

AI 工作流的日志量可能远超传统服务:一次 Agent 对话可能产生 20+ 轮 LLM 调用,每轮都有完整的 Prompt 和 Response。全量记录所有 Prompt 内容极不经济。

分层采样策略:

Level 1(始终记录):任务 ID、Agent 类型、总耗时、Token 总消耗、成功/失败
Level 2(采样 10%):每个 LLM 调用的 Prompt 前 500 字符 + Response 前 500 字符
Level 3(按错误采样 100%,正常采样 1%):完整 Prompt + 完整 Response
Level 4(单条 Trace 按需开启):所有中间状态、向量检索结果、RAG 召回内容

实现示例:

type AIWorkflowLogger struct {
    base      *slog.Logger
    sampler   Sampler
}

func (l *AIWorkflowLogger) LogLLMCall(ctx context.Context, call LLMCallRecord) {
    // Level 1: 始终记录
    l.base.InfoContext(ctx, "llm_call",
        "task_id", call.TaskID,
        "model", call.Model,
        "prompt_tokens", call.PromptTokens,
        "completion_tokens", call.CompletionTokens,
        "latency_ms", call.Latency.Milliseconds(),
    )
    
    // Level 2: 采样记录摘要
    if l.sampler.ShouldSample(call.TaskID, 0.1) {
        l.base.DebugContext(ctx, "llm_call_detail",
            "prompt_preview", truncate(call.Prompt, 500),
            "response_preview", truncate(call.Response, 500),
        )
    }
    
    // Level 3: 错误全量 + 正常采样
    if call.Error != nil || l.sampler.ShouldSample(call.TaskID, 0.01) {
        l.base.DebugContext(ctx, "llm_call_full",
            "prompt", call.Prompt,
            "response", call.Response,
            "error", call.Error,
        )
    }
}

五、总结

AI 工作流的可观测性不是监控工具的简单叠加,需要针对 LLM 调用、Token 消费、语义缓存等新维度设计指标体系。核心原则:Metrics 用于发现异常并触发告警,Trace 用于定位到具体的 Span 节点,Log 用于还原完整的上下文。Trace 设计要反映语义依赖而非物理时序,Metrics 要覆盖业务指标(成本、成功率、缓存命中率),Log 要用分层采样避免存储爆炸。三者协同,才能在 AI 工作流的性能迷宫中快速找到出口。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_34803115/article/details/163001197

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--