欢迎光临
我们一直在努力

AI 服务可观测性:从黑盒调用到全链路监控的体系建设

AI 服务可观测性:从黑盒调用到全链路监控的体系建设

一、AI 服务的"盲飞"困境:当延迟飙升却无从定位

某智能写作平台上线后,用户反馈"AI 生成内容越来越慢"。运维团队查看传统 APM 指标,CPU、内存、网络均正常。问题在于,传统监控只覆盖了应用层,而 AI 服务的瓶颈在模型推理层。一次完整的 AI 调用链路包括:请求接收、Prompt 组装、缓存查询、模型路由、API 调用、响应解析、结果缓存,任一环节都可能成为延迟热点。

更关键的是成本盲区。大模型按 Token 计费,但传统监控无法追踪 Token 消耗。月底账单比预算高出 200%,却无法定位是哪个业务、哪个用户、哪类请求导致了超额消耗。

AI 服务的可观测性建设,需要从传统的"应用层监控"升级为"AI 调用链路监控",覆盖延迟、成本、质量三个维度。

二、AI 服务可观测性的三层指标体系

AI 服务的可观测性需要建立三层指标:基础设施指标、应用层指标、AI 业务指标。传统监控只覆盖前两层,AI 业务指标是缺失的关键环节。

graph TB
subgraph "第一层:基础设施指标"
CPU["CPU / 内存 / 网络"]
GPU["GPU 利用率 / 显存<br/>(本地推理场景)"]
end

subgraph "第二层:应用层指标"
QPS["请求 QPS / 错误率"]
Latency["P50 / P95 / P99 延迟"]
Thread["线程池 / 连接池状态"]
end

subgraph "第三层:AI 业务指标"
TokenIO["Token 用量<br/>input_tokens / output_tokens<br/>按模型 / 租户 / 接口维度"]
ModelRoute["模型路由分布<br/>各模型调用占比"]
CacheHit["语义缓存命中率"]
Quality["回答质量评估<br/>用户反馈 / 幻觉检测"]
Cost["成本追踪<br/>Token 单价 × 用量<br/>按租户汇总"]
end

CPU –> QPS
GPU –> QPS
QPS –> TokenIO
Latency –> ModelRoute
Thread –> CacheHit
TokenIO –> Cost
ModelRoute –> Quality

Token 用量追踪:成本控制的核心

Token 用量是 AI 服务独有的核心指标。每次模型调用后,响应中包含 usage.prompt_tokens 和 usage.completion_tokens。将这些数据按模型、租户、接口维度聚合,就能实现精细化的成本追踪。

语义缓存命中率:效率的晴雨表

语义缓存命中率直接反映缓存策略的有效性。命中率低于 30% 时,需要检查:相似度阈值是否过高、缓存 TTL 是否过短、业务场景是否适合缓存。

回答质量评估:效果的可量化

大模型的回答质量难以用传统指标衡量。实践中可采用以下方式:用户反馈(点赞/点踩)、自动幻觉检测(对比回答与参考资料的一致性)、LLM-as-Judge(用另一个模型评估回答质量)。

三、基于 Micrometer + OpenTelemetry 的全链路监控实现

Token 用量指标采集

@Component
public class LlmMetricsInterceptor implements ClientHttpRequestInterceptor {

private final MeterRegistry meterRegistry;
private final Tracer tracer;

public LlmMetricsInterceptor(MeterRegistry meterRegistry, Tracer tracer) {
this.meterRegistry = meterRegistry;
this.tracer = tracer;
}

/**
* 拦截所有大模型 API 调用,采集 Token 用量和延迟指标
*/
@Override
public ClientHttpResponse intercept(
HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {

String model = extractModel(request);
String tenant = extractTenant(request);
String operation = extractOperation(request);

Span span = tracer.nextSpan()
.name("llm.call")
.tag("model", model)
.tag("tenant", tenant)
.tag("operation", operation)
.start();

long startTime = System.nanoTime();

try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
ClientHttpResponse response = execution.execute(request, body);

// 从响应体中提取 Token 用量
TokenUsage usage = extractTokenUsage(response);
if (usage != null) {
// 记录 Token 用量指标
meterRegistry.counter("llm.tokens.input",
"model", model, "tenant", tenant).increment(usage.getInputTokens());
meterRegistry.counter("llm.tokens.output",
"model", model, "tenant", tenant).increment(usage.getOutputTokens());

// 计算并记录成本
double cost = calculateCost(model, usage);
meterRegistry.counter("llm.cost",
"model", model, "tenant", tenant).increment(cost);

span.tag("input_tokens", String.valueOf(usage.getInputTokens()));
span.tag("output_tokens", String.valueOf(usage.getOutputTokens()));
}

// 记录延迟
long durationMs = (System.nanoTime() – startTime) / 1_000_000;
meterRegistry.timer("llm.call.duration",
"model", model, "tenant", tenant)
.record(durationMs, TimeUnit.MILLISECONDS);

return response;

} catch (IOException e) {
meterRegistry.counter("llm.call.error",
"model", model, "tenant", tenant).increment();
span.error(e);
throw e;
} finally {
span.end();
}
}

/**
* 根据模型和 Token 用量计算成本
*/
private double calculateCost(String model, TokenUsage usage) {
// 价格表:每千 Token 的美元价格
Map<String, Double> inputPricePerK = Map.of(
"gpt-4", 0.03,
"gpt-4o", 0.005,
"gpt-4o-mini", 0.00015
);
Map<String, Double> outputPricePerK = Map.of(
"gpt-4", 0.06,
"gpt-4o", 0.015,
"gpt-4o-mini", 0.0006
);

double inputCost = usage.getInputTokens() / 1000.0
* inputPricePerK.getOrDefault(model, 0.01);
double outputCost = usage.getOutputTokens() / 1000.0
* outputPricePerK.getOrDefault(model, 0.01);
return inputCost + outputCost;
}
}

语义缓存命中率监控

@Component
public class SemanticCacheMonitor {

private final MeterRegistry meterRegistry;
private final Counter cacheHitCounter;
private final Counter cacheMissCounter;

public SemanticCacheMonitor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.cacheHitCounter = meterRegistry.counter("llm.cache.hit");
this.cacheMissCounter = meterRegistry.counter("llm.cache.miss");
}

public void recordHit(String tenant, double similarity) {
cacheHitCounter.increment();
meterRegistry.summary("llm.cache.similarity",
"tenant", tenant).record(similarity);
}

public void recordMiss(String tenant) {
cacheMissCounter.increment();
}

/**
* 获取当前缓存命中率
* 用于健康检查接口和告警规则
*/
public double getHitRate() {
double hits = cacheHitCounter.count();
double total = hits + cacheMissCounter.count();
return total == 0 ? 0 : hits / total;
}
}

告警规则配置

# Prometheus 告警规则
groups:
– name: llm_service_alerts
rules:
# Token 消耗速率异常:单租户每分钟消耗超过 100K Token
– alert: HighTokenConsumption
expr: rate(llm_tokens_input_total{tenant!=""}[1m]) * 60 > 100000
for: 5m
labels:
severity: warning
annotations:
summary: "租户 {{ $labels.tenant }} Token 消耗异常"

# 语义缓存命中率过低
– alert: LowCacheHitRate
expr: rate(llm_cache_hit_total[10m]) / (rate(llm_cache_hit_total[10m]) + rate(llm_cache_miss_total[10m])) < 0.2
for: 30m
labels:
severity: info
annotations:
summary: "语义缓存命中率低于 20%"

# 模型调用 P99 延迟超过 10 秒
– alert: HighModelLatency
expr: histogram_quantile(0.99, rate(llm_call_duration_bucket[5m])) > 10
for: 5m
labels:
severity: critical
annotations:
summary: "模型 {{ $labels.model }} P99 延迟超过 10 秒"

四、AI 可观测性建设的边界与取舍

采样率与成本的矛盾

全量采集每次 AI 调用的 Trace 数据,存储成本极高。一次 AI 调用的 Span 包含完整的 Prompt 和 Response,数据量可能达到数 KB。在高 QPS 场景下,Trace 存储成本可能接近模型调用成本。解决方案是:错误请求全量采集,正常请求按 1%-5% 采样,关键业务(如交易、医疗)全量采集。

质量评估的主观性

回答质量的自动化评估仍不成熟。LLM-as-Judge 方法存在"自我偏好"问题——评估模型倾向于给同系列模型更高的分数。用户反馈数据稀疏且有偏差——满意的用户不反馈,不满的用户才反馈。质量指标应作为参考,而非唯一决策依据。

实时性与一致性的取舍

Token 用量和成本数据需要实时展示,但精确的成本计算依赖模型供应商的账单数据,通常有 24-48 小时延迟。实时指标基于本地计算的估算值,与实际账单可能存在 5%-10% 的偏差。需要定期用供应商账单校准本地估算。

隐私与可观测性的冲突

AI 调用的 Trace 数据包含用户输入的 Prompt 和模型返回的 Response,其中可能包含敏感信息(如用户对话内容、企业内部数据)。全量采集 Trace 会带来数据安全风险。解决方案是:对 Trace 中的 Prompt 和 Response 做脱敏处理,或仅采集元数据(Token 数量、延迟、模型名称),不采集内容。

五、总结

AI 服务的可观测性建设,需要从传统的"应用层监控"扩展到"AI 业务指标监控"。Token 用量追踪是成本控制的基础,语义缓存命中率是效率优化的依据,回答质量评估是效果保障的手段。三者结合,才能让 AI 服务从"黑盒调用"变为"透明运营"。

但可观测性本身也有成本。全量 Trace 采集的存储开销、质量评估的计算开销、实时指标的延迟偏差,都是需要权衡的因素。建设路径应该是渐进式的:先建立 Token 用量和延迟的基础监控,再引入缓存命中率和成本追踪,最后在关键业务上试点质量评估。

落地路线建议:第一阶段在 AI 网关层集成 Micrometer 指标采集,覆盖 Token 用量、延迟、错误率;第二阶段接入 OpenTelemetry Trace,实现从用户请求到模型调用的全链路追踪;第三阶段搭建 Grafana 监控面板,配置告警规则,建立成本日报和周报机制;第四阶段在关键业务上试点回答质量评估,形成效果-成本-延迟的三角监控闭环。

赞(0)
未经允许不得转载:171主机测评 » AI 服务可观测性:从黑盒调用到全链路监控的体系建设
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址