← [ BACK_TO_NOTES ]

AI 服务可观测性设计

AI 服务特有的可观测性需求:LLM 调用的结构化日志、token 用量追踪、延迟指标、SSE 管道的 trace ID 串联、告警规则设计。

#synthesis #growing #ai #ops

[!info] related notes

AI 服务可观测性设计

这篇解决什么问题

传统服务的可观测性关注”请求是否成功、延迟多少”。AI 服务在此基础上还需要回答:

  1. LLM 花了多少钱 — 每次调用消耗了多少 token?
  2. LLM 回答得好不好 — faithfulness 检查通过了吗?red flag 触发了吗?
  3. 流式管道断在哪 — SSE 事件流在哪个环节中断了?
  4. RAG 检索质量如何 — 检索到的知识和用户问题相关吗?

本篇补充模型调用、检索与生成质量信号;通用可观测性也覆盖性能、业务行为与正确性。以下是设计示例,不表示 BodySense 当前已采集这些字段。

LLM 调用的结构化日志

以下为结构化事件字段示意,使用支持关键字字段的 logger(如 structlog),不是 Python 标准 logging 的直接调用方式。按产品需要和数据策略采集;检查未执行、usage 未返回时记录 unknown / null,不伪造成功或零用量:

logger.info("llm_call_completed",
    # 请求标识
    request_id=req_id,
    session_id=session_id,
    turn_index=turn_index,

    # 模型信息
    model=model_name,
    provider=provider_name,

    # Token 用量
    prompt_tokens=usage.prompt_tokens,
    completion_tokens=usage.completion_tokens,
    total_tokens=usage.total_tokens,

    # 延迟
    latency_ms=latency_ms,
    time_to_first_token_ms=ttft_ms,

    # 质量指标
    faithfulness_passed=faithfulness_result.faithful,
    red_flag_triggered=len(red_flags) > 0,
    red_flag_categories=[f.category for f in red_flags],

    # 工具调用
    tool_calls=[tc.name for tc in tool_calls],
    tool_call_count=len(tool_calls),
)

关键设计:

  • request_id 贯穿整个请求链路(前端 → Go → Python),用于跨服务关联
  • session_id + turn_index 用于定位会话位置,不足以重建完整上下文;还需获准保留的输入、配置与证据版本
  • 质量判定另关联 evaluator / policy 版本,未检查不等于通过;red flag 触发本身不说明模型出错
  • token 用量是计费输入之一,费用还取决于模型、价格版本、缓存类别与其他计费项;缺失 usage 标为未知
  • 日志按需脱敏、控制访问和保留期,不默认保存完整对话或健康信息

Token 用量追踪

# 按维度聚合 token 用量
class TokenTracker:
    def record(self, session_id: str, model: str, usage: TokenUsage):
        # TOKEN_COUNTER 为预先注册的 counter;按实际消费增量计数
        TOKEN_COUNTER.labels(
            model=model,
            direction="prompt"
        ).inc(usage.prompt_tokens)
        TOKEN_COUNTER.labels(
            model=model,
            direction="completion"
        ).inc(usage.completion_tokens)

示例按调用累计 prompt / completion token;如果流事件提供累计 usage,只计最终值或差值,不能逐事件重复累加。session / request ID 放日志或 trace,避免作为 Prometheus 高基数 label。

以下阈值只是演示,必须按工作负载、预算与基线设置:

维度用途告警阈值示例
每次调用 token 数发现异常大请求> 8000 tokens
每会话总 token 数成本控制> 50k tokens/session
每日总 token 数预算告警> 1M tokens/day
prompt vs completion 比例观察输入输出构成,结合任务判断completion > 3x prompt(并非普遍异常)

LLM 延迟指标

# 两个关键延迟
LLM_LATENCY.labels(model=model).observe(latency_ms)           # 总延迟
LLM_TTFT.labels(model=model).observe(time_to_first_token_ms)  # 首 token 延迟
指标含义用户感知
模型调用 TTFT应用发出模型请求到首个有效输出 token不等于前端可见首字时间
总调用延迟应用发出模型请求到约定结束前端还可能等待传输、校验和渲染
流式吞吐每秒 token 数”打字速度”

SSE 场景特殊处理:流式响应的延迟不是”请求-响应”的单点,而是一个流。需要记录:

  • 连接建立、首事件和首个有效回答 token 分别记录
  • 流结束时间
  • 流是否被中断

SSE 管道的追踪与关联

React → Go → Python 可采用 W3C Trace Context / OpenTelemetry 传播:入口提取合法 traceparent,各服务创建自己的 span,调用下游时注入当前 context。X-Request-ID 只是应用关联标识;仅透传一个 ID 或设置 span attribute 不会自动建立父子 span。

SSE 连接的 trace 与业务 run / event identity 也应分开:重连可能产生新的 trace,但仍恢复同一个 run。前端可从响应头或连接上下文关联 trace;只有需要跨连接独立关联时,才按事件合同附带相应 ID,不要求每个 token 事件重复携带。

代理应保留 SSE 的 event、id、多行 data 和空行边界;不能逐行读取 data: 后就插入空行并丢掉其他字段。若需要改写事件,必须先完整解析并遵循事件 schema,否则直接透传。结束、取消和断流分别记录,并在资源释放时结束对应 span。

跨服务传播原则见 distributed-tracing-multi-service;用户可见延迟见 ai-assistant-first-token-latency-optimization;恢复游标见 durable-sse-recovery-with-after-seq。

AI 特有的告警规则

以下为候选阈值,需指定统计窗口、最小样本数、分母和服务 SLO。告警是调查线索,不是根因证明。

告警条件严重程度含义
LLM 延迟飙升p95 > 10s 持续 5minwarning可能排队、网络或推理变慢,需 trace 定位
LLM 错误率> 5% 持续 3mincritical调用失败增加,核实错误类型与实际可用率
Faithfulness 失败率> 20% 持续 10minwarning检索、生成、样本分布或 evaluator 都可能变化
Red Flag 触发率突增> 2x 基线info可能是输入分布、规则版本或检测行为变化
Token 用量异常> 2x 日均warning可能有循环调用或滥用
SSE 流中断率> 10% 持续 5mincritical先区分主动停止、网络断开与服务端失败

与通用可观测性的关系

维度通用可观测性AI 特有
日志请求级需要 LLM 调用级(token、model、工具调用)
指标QPS、延迟、错误率+ token 用量、faithfulness 率、red flag 率
追踪服务间调用链+ LLM 内部的 tool call 链、RAG 检索链
告警服务健康+ 质量退化、成本异常

通用可观测性是基础,AI 可观测性是在此之上增加 AI 特有的信号。两者共用同一套 trace ID 体系。

设计要点

  1. 将 request / run / trace / span 的关联规则写清楚,不能用一个 ID 混代所有身份。
  2. 明确 usage 来源、单位、价格版本与缺失值;成本控制还需预算和配额。
  3. 质量判定携带版本与依据,模型自评或单个 checker 通过不代表答案已证实正确。
  4. 流建立、首输出、正常完成、取消与异常断开分别记录;采样与日志保留决定事后能重建多少信息。
  5. 结构化事件便于关联和聚合,但默认只收必要字段。

常见错误

只记录成功调用

# ❌ 只在成功时记录
logger.info("llm_call", tokens=usage.total_tokens)

# ✅ 成功和失败都记录,失败时带上错误信息
logger.info("llm_call",
    success=True,
    tokens=usage.total_tokens,
    error=None,
)
logger.error("llm_call",
    success=False,
    error_code=error_code,  # 从异常映射的安全分类,避免输出原始敏感信息
    tokens=None,
)

误把每个 SSE 事件都带 trace_id 当作完整追踪

事件上的 ID 只能帮助关联。完整追踪还依赖 context 提取 / 注入、span 生命周期、采样与导出;SSE 业务恢复则依赖稳定 run ID 和事件游标。

Token 用量只记总数不分维度

# ❌ 只记总数,无法分析哪个模型/哪个功能消耗最多
TOKEN.inc(usage.total_tokens)

# ✅ 使用有界的模型和功能 label;会话 ID 放日志 / trace
TOKEN.labels(model=model, feature="diagnosis").inc(usage.total_tokens)

来源

创建于 2026/6/26 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本