AI 应用可观测性架构

LLM 应用的日志、指标、追踪与成本管控全栈实践

Maurice | 灵阙学院


一、为什么 AI 应用需要专属可观测性

传统后端服务的可观测性关注请求延迟、错误率、资源利用率。但 LLM 应用有三个独特挑战:

  1. 非确定性输出:相同输入可能产生不同输出,需要质量评估而非简单的 pass/fail
  2. 成本敏感:每次调用消耗 Token,且不同模型价格差异巨大(GPT-4o 与 GPT-4o-mini 差 15 倍)
  3. 链式调用:一次用户请求可能触发多次 LLM 调用、工具调用、检索操作,调用图谱复杂
┌─────────────────────────────────────────────────────────────┐
│                 AI 可观测性三支柱                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   Logging              Metrics              Tracing         │
│   ┌──────────┐        ┌──────────┐        ┌──────────┐     │
│   │ 请求/响应  │        │ 延迟分布  │        │ 调用链路  │    │
│   │ Prompt    │        │ Token用量 │        │ 依赖关系  │    │
│   │ Completion│        │ 质量评分  │        │ 瀑布图   │     │
│   │ 错误堆栈  │        │ 成本统计  │        │ 时间分布  │    │
│   └──────────┘        └──────────┘        └──────────┘     │
│        │                   │                   │            │
│        └───────────────────┼───────────────────┘            │
│                            ▼                                │
│                    统一仪表盘 + 告警                          │
└─────────────────────────────────────────────────────────────┘

二、核心指标体系

2.1 延迟指标

指标 定义 告警阈值 (参考)
TTFT (Time to First Token) 首 Token 延迟 P95 > 3s
E2E Latency 端到端响应时间 P95 > 15s
Retrieval Latency 检索耗时 P95 > 500ms
Tool Execution Time 工具调用耗时 P95 > 5s
Inter-Token Latency Token 间隔 P95 > 100ms (流式)

2.2 Token 与成本指标

# 核心成本公式
cost = (input_tokens * input_price + output_tokens * output_price)
       * request_count

# 实际需要追踪的维度
metrics = {
    "token_usage": {
        "input_tokens": 1250,
        "output_tokens": 380,
        "cached_tokens": 800,       # 缓存命中省钱
        "total_tokens": 1630,
    },
    "cost_usd": 0.0034,
    "model": "gpt-4o-mini",
    "cache_hit_rate": 0.64,         # 语义缓存命中率
    "cost_per_query_avg": 0.005,    # 每查询平均成本
}

2.3 质量指标

指标 采集方式 说明
Faithfulness 自动评估 (LLM-as-Judge) 生成内容与检索上下文的一致性
Relevance 自动评估 回答与问题的相关性
Hallucination Rate 自动评估 + 人工抽检 幻觉比例
User Feedback 显式 (thumbs up/down) 用户主观满意度
Retrieval Precision 自动评估 检索结果的准确率

三、平台对比

3.1 LangSmith vs LangFuse vs Phoenix

维度 LangSmith LangFuse Phoenix (Arize)
部署方式 SaaS / 自托管 开源自托管 / Cloud 开源自托管 / Cloud
框架绑定 LangChain 深度集成 框架无关 框架无关
追踪能力 强 (嵌套 Span) 强 (OpenTelemetry) 强 (OTEL 原生)
Prompt 管理 内置版本化 内置版本化
评估框架 内置 LLM-as-Judge 内置多种评估器 内置 + Evals 库
数据集管理 内置 内置 内置
成本追踪 内置 内置 需配置
开源协议 部分开源 MIT Apache 2.0
适合团队 LangChain 用户 自托管优先 OTEL 生态优先

3.2 选型建议

你的技术栈是什么?
│
├─ 深度使用 LangChain/LangGraph
│  └─ LangSmith (最佳集成体验)
│
├─ 自托管要求 + 多框架
│  └─ LangFuse (MIT 开源,Docker 一键部署)
│
├─ 已有 OpenTelemetry 基础设施
│  └─ Phoenix (原生 OTEL,与已有可观测体系融合)
│
└─ 预算有限 / 快速验证
   └─ LangFuse Self-hosted (免费,功能完整)

四、分布式追踪设计

4.1 多 Agent 系统追踪架构

[用户请求] trace_id=abc123
    │
    ├── [Orchestrator Agent] span_id=s1
    │       │
    │       ├── [Planning] span_id=s2
    │       │     └── LLM Call (gpt-4o, 1200 tokens, 2.3s)
    │       │
    │       ├── [Research Agent] span_id=s3
    │       │     ├── Web Search (google, 0.8s)
    │       │     ├── LLM Call (gpt-4o-mini, 800 tokens, 1.1s)
    │       │     └── RAG Retrieval (vectordb, 0.3s)
    │       │
    │       ├── [Analysis Agent] span_id=s4
    │       │     ├── Tool: SQL Query (0.5s)
    │       │     └── LLM Call (claude-sonnet, 2000 tokens, 3.2s)
    │       │
    │       └── [Synthesis] span_id=s5
    │             └── LLM Call (gpt-4o, 1500 tokens, 2.8s)
    │
    └── Total: 5500 tokens, $0.018, 10.8s

4.2 OpenTelemetry 集成

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
    OTLPSpanExporter,
)

# 初始化
provider = TracerProvider()
exporter = OTLPSpanExporter(endpoint="http://collector:4317")
provider.add_span_processor(BatchSpanProcessor(exporter))
trace.set_tracer_provider(provider)

tracer = trace.get_tracer("ai-service")

# 追踪 LLM 调用
def traced_llm_call(prompt: str, model: str) -> str:
    with tracer.start_as_current_span("llm_call") as span:
        span.set_attribute("llm.model", model)
        span.set_attribute("llm.prompt_tokens", count_tokens(prompt))

        response = llm.invoke(prompt)

        span.set_attribute("llm.completion_tokens", response.usage.output)
        span.set_attribute("llm.total_tokens", response.usage.total)
        span.set_attribute("llm.cost_usd", calculate_cost(response.usage))
        return response.content

五、告警策略

5.1 分层告警

┌──────────────────────────────────────────────────┐
│                    告警金字塔                      │
├──────────────────────────────────────────────────┤
│                                                  │
│  P0 (立即响应, < 5min)                            │
│    - LLM Provider 全部不可用                      │
│    - 错误率 > 10% (5min 窗口)                     │
│    - 成本异常飙升 (> 日均 3x)                      │
│                                                  │
│  P1 (30min 内响应)                                │
│    - 主力模型不可用,已切 Fallback                  │
│    - E2E 延迟 P95 > 30s                           │
│    - 语义缓存命中率骤降 (< 20%)                    │
│                                                  │
│  P2 (工作时间内处理)                               │
│    - 质量评分下降趋势 (7日滑动均值)                 │
│    - Token 用量超预算 80%                          │
│    - 某个 Agent 失败率上升                         │
│                                                  │
│  P3 (周报跟进)                                    │
│    - 模型版本更新导致输出风格变化                    │
│    - 长尾查询延迟偏高                              │
└──────────────────────────────────────────────────┘

5.2 成本异常检测

# 基于滑动窗口的成本异常检测
def detect_cost_anomaly(
    current_cost: float,
    historical_costs: list[float],
    threshold_multiplier: float = 3.0,
) -> bool:
    mean = sum(historical_costs) / len(historical_costs)
    std = (
        sum((x - mean) ** 2 for x in historical_costs) / len(historical_costs)
    ) ** 0.5
    return current_cost > mean + threshold_multiplier * std

六、成本监控仪表盘设计

6.1 核心看板

┌──────────────────────────────────────────────────────────┐
│  AI Cost Dashboard                     Period: Last 7d   │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  Total Cost     Avg/Query     Queries      Cache Hit     │
│  $127.45        $0.0068       18,742       62.3%         │
│  (+12% WoW)     (-3% WoW)    (+8% WoW)    (+5% WoW)    │
│                                                          │
├──────────────────────────────────────────────────────────┤
│  Cost by Model            │  Cost by Feature             │
│  ─────────────            │  ──────────────              │
│  gpt-4o       $78.20 61%  │  Chat        $45.30  36%    │
│  claude-sonnet $32.10 25% │  RAG         $38.20  30%    │
│  gpt-4o-mini  $12.40 10%  │  Agent       $28.70  22%    │
│  embedding     $4.75   4% │  Summary     $15.25  12%    │
│                            │                             │
├──────────────────────────────────────────────────────────┤
│  Daily Trend (bar chart)                                 │
│  Mon: $16.2 | Tue: $18.5 | Wed: $19.1 | ...            │
└──────────────────────────────────────────────────────────┘

6.2 成本优化杠杆

优化手段 预期节省 实施复杂度 质量影响
语义缓存 30-60% 无 (完全命中)
Prompt 压缩 10-20% 轻微
小模型路由 (简单查询用 mini) 40-60% 需评估
批量推理 (非实时场景) 50%
输出长度控制 10-30% 需评估

七、生产部署架构

┌───────────────────────────────────────────────────────────┐
│                                                           │
│  Application Layer                                        │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐                  │
│  │ Chat API │  │ RAG API │  │Agent API│                   │
│  └────┬─────┘  └────┬────┘  └────┬────┘                  │
│       │              │            │                        │
│       └──────────────┼────────────┘                        │
│                      ▼                                     │
│  Instrumentation Layer (SDK / Decorator)                   │
│  ┌──────────────────────────────────┐                     │
│  │ Auto-trace LLM calls + Tools     │                     │
│  │ Capture tokens, latency, errors  │                     │
│  │ Attach trace_id / user_id        │                     │
│  └──────────────┬───────────────────┘                     │
│                 │                                          │
│                 ▼                                          │
│  Collection Layer                                         │
│  ┌─────────────────────────────────┐                      │
│  │ OpenTelemetry Collector          │                     │
│  │ (batch, filter, route)           │                     │
│  └──────┬──────────┬───────────────┘                      │
│         │          │                                       │
│    ┌────▼────┐ ┌───▼────────┐                             │
│    │Langfuse │ │ Prometheus │                              │
│    │(traces) │ │ (metrics)  │                              │
│    └────┬────┘ └───┬────────┘                             │
│         │          │                                       │
│    ┌────▼──────────▼────┐                                 │
│    │   Grafana Dashboard │                                │
│    │   + AlertManager    │                                │
│    └─────────────────────┘                                │
└───────────────────────────────────────────────────────────┘

八、实施路线图

阶段 目标 工具 周期
Phase 1 基础追踪 + 成本可见 LangFuse + 基础 Dashboard 1 周
Phase 2 质量评估 + 告警 LLM-as-Judge + AlertManager 2 周
Phase 3 全链路追踪 + OTEL OpenTelemetry + Grafana 2 周
Phase 4 成本优化闭环 语义缓存 + 模型路由 + A/B 测试 持续

核心原则:先让成本可见(Phase 1),再谈优化(Phase 4)。看不到的东西无法管理。


Maurice | maurice_wen@proton.me