Prometheus可观测性体系与LLM翻译质量监控
Prometheus 可观测性实战:为 LLM 翻译系统构建全链路监控
LLM 应用的可观测性远比传统 Web 服务复杂——除了常规的 QPS 和延迟,还需要追踪 Token 消耗、模型降级、翻译质量评分、Chunk 处理成功率等 LLM 特有指标。本文以"欧小译"为例,详解如何用 Prometheus + Grafana 构建一个 LLM 翻译系统的全链路可观测性体系。
一、LLM 应用的监控"三维模型"
传统 Web 服务的监控聚焦于性能(延迟、吞吐、错误率),但 LLM 应用还需要额外关注两个维度:
┌─────────────┐
│ 性能维度 │ 延迟、QPS、错误率
└──────┬──────┘
│
┌────────────┼────────────┐
│ │
┌───▼───────┐ ┌─────▼───────┐
│ 成本维度 │ │ 质量维度 │
│ Token消耗 │ │ 翻译评分 │
│ 模型调用量 │ │ 术语一致性 │
│ 降级/重试 │ │ 人工反馈 │
└───────────┘ └─────────────┘
我们的指标设计围绕这三个维度展开。
二、指标体系设计
2.1 业务指标
# 翻译请求总量(按语言对、领域、状态四维度切分)
translate_requests_total = Counter(
'translate_requests_total',
'翻译请求总数',
['source_lang', 'target_lang', 'domain', 'status']
)
# 端到端翻译耗时(Histogram,预定义桶边界)
translate_duration_seconds = Histogram(
'translate_duration_seconds',
'端到端翻译耗时',
['source_lang', 'target_lang', 'domain'],
buckets=[1, 5, 10, 15, 30, 60, 120, 300]
)
桶边界的设计考量:翻译任务通常在 5~120 秒之间,因此桶边界覆盖了从 1s(极短文本)到 300s(超长文本或模型降级重试)的范围。桶太多浪费存储,太少丢失精度。
可以回答的核心问题:
- 过去 1 小时,
zh→en的tech领域翻译请求量是多少? - P95 延迟是多少?→
histogram_quantile(0.95, rate(translate_duration_seconds_bucket[5m]))
2.2 步骤级指标
# 各步骤耗时(按步骤名和模型名切分)
step_duration_seconds = Histogram(
'step_duration_seconds',
'各步骤耗时',
['step_name', 'model_name'],
buckets=[0.5, 1, 2, 5, 10, 20, 30, 60]
)
# Chunk 处理总量
chunk_processing_total = Counter(
'chunk_processing_total',
'Chunk 处理总数',
['status', 'step_name']
)
这两个指标能精确定位性能瓶颈在哪个步骤:
# 各步骤平均耗时对比
sum(rate(step_duration_seconds_sum[5m])) by (step_name)
/
sum(rate(step_duration_seconds_count[5m])) by (step_name)
如果发现 polish 步骤平均耗时是 terminology 的 3 倍,就知道优化方向在哪里。
2.3 成本指标
# Token 消耗总量
token_usage_total = Counter(
'token_usage_total',
'Token 消耗总量',
['model_name', 'token_type'] # prompt | completion
)
为什么区分 prompt 和 completion? 因为多数 LLM API 的定价中,completion token 的价格是 prompt token 的 2~4 倍。分开统计才能精确计算成本。
Grafana 面板示例:
# 过去 24 小时各模型的 Token 消耗(按美元估算)
sum(increase(token_usage_total{token_type="completion"}[24h])) by (model_name) * 0.000002
+
sum(increase(token_usage_total{token_type="prompt"}[24h])) by (model_name) * 0.0000005
2.4 质量指标
# 翻译质量评分
translate_eval_score = Gauge(
'translate_eval_score',
'翻译质量评分',
['metric_name', 'domain'] # bleu | comet | human
)
支持三种评分来源:
- BLEU:自动计算的机器翻译经典指标
- COMET:基于神经网络的翻译质量评估
- Human:用户在界面上的人工评分反馈
2.5 错误与降级指标
# 翻译错误总量
translation_errors_total = Counter(
'translation_errors_total',
'翻译错误总数',
['error_type', 'step_name', 'model_name']
)
# 模型重试次数
model_retries_total = Counter(
'model_retries_total',
'模型重试次数',
['model_name', 'step_name', 'fallback_model']
)
# 模型降级次数
model_fallbacks_total = Counter(
'model_fallbacks_total',
'模型降级次数',
['original_model', 'fallback_model', 'step_name']
)
这三个 Counter 组合起来可以计算出模型可靠性看板:
# DeepSeek 模型过去 1 小时的故障率
sum(increase(translation_errors_total{model_name="deepseek"}[1h]))
/
sum(increase(step_duration_seconds_count{model_name="deepseek"}[1h]))
2.6 资源指标
# 活跃翻译会话数
active_sessions = Gauge('active_sessions', '当前进行中的翻译会话数')
# SSE 连接数
sse_connections = Gauge('sse_connections', '当前活跃的 SSE 连接数')
# SSE 事件推送量
sse_events_total = Counter(
'sse_events_total',
'SSE 事件推送总数',
['event_type', 'status']
)
active_sessions 是一个 Gauge(可增可减),反映系统实时负载。当它接近系统容量上限时,可以触发限流或扩容。
三、指标埋点位置
指标埋点遵循"在业务逻辑中就近采集"原则:
translate_service.py ──→ translate_requests_total, translate_duration_seconds, active_sessions
llm_router.py ──→ step_duration_seconds, model_retries_total, model_fallbacks_total
terminology.py ──→ chunk_processing_total (terminology)
literal.py ──→ chunk_processing_total (literal)
redis_client.py ──→ sse_events_total
translate_service.py ──→ translation_errors_total (catch block)
关键原则:指标采集不应改变业务逻辑的控制流。所有 .inc() / .observe() 调用都是"旁路"操作,不影响主流程的执行。
四、Prometheus 告警规则设计
基于上述指标,可以设计以下告警规则:
告警1:模型故障率过高
- alert: ModelHighErrorRate
expr: |
sum(rate(translation_errors_total[5m])) by (model_name)
/
sum(rate(step_duration_seconds_count[5m])) by (model_name)
> 0.3
for: 5m
labels:
severity: warning
annotations:
summary: "模型 {{ $labels.model_name }} 过去 5 分钟故障率超过 30%"
告警2:翻译延迟 P95 过高
- alert: TranslationHighLatency
expr: |
histogram_quantile(0.95,
sum(rate(translate_duration_seconds_bucket[5m])) by (le)
) > 120
for: 10m
labels:
severity: warning
annotations:
summary: "翻译 P95 延迟超过 120 秒"
告警3:活跃会话过多(容量告警)
- alert: HighActiveSessions
expr: active_sessions > 50
for: 3m
labels:
severity: critical
annotations:
summary: "活跃翻译会话数超过 50,可能需要扩容"
告警4:降级频率异常
- alert: ExcessiveModelFallbacks
expr: |
sum(rate(model_fallbacks_total[10m])) > 5
for: 10m
labels:
severity: warning
annotations:
summary: "过去 10 分钟模型降级超过 5 次,请检查模型服务状态"
五、Grafana Dashboard 布局建议
┌──────────────────────────────────────────────────────────────┐
│ 📊 翻译系统总览 │
├───────────────┬───────────────┬──────────────┬───────────────┤
│ 活跃会话 (G) │ 请求量/min │ P95 延迟 │ 错误率 │
│ [数字面板] │ [时序图] │ [时序图] │ [时序图] │
├───────────────┴───────────────┴──────────────┴───────────────┤
│ 📈 各步骤耗时对比(Stacked Bar Chart) │
│ terminology | literal | review | polish | aggregate │
├──────────────────────────────────────────────────────────────┤
│ 💰 Token 消耗趋势(按模型分组的 Area Chart) │
│ DeepSeek | Bailian | OpenAI | Claude │
├────────────────────────┬─────────────────────────────────────┤
│ 🔄 模型降级事件 │ 📊 翻译质量评分趋势 │
│ (Event Timeline) │ BLEU / COMET / Human (时序折线) │
├────────────────────────┴─────────────────────────────────────┤
│ 📦 Chunk 处理成功率(按步骤分组) │
│ success / failed 饼图 │
└──────────────────────────────────────────────────────────────┘
六、从指标到决策:三个真实场景
场景1:该不该换模型?
问题:DeepSeek 在 literature 领域的意译评分一直偏低,是否值得切到 Claude?
数据:
translate_eval_score{metric_name="human", domain="literature"}→ DeepSeek: 6.2, Claude: 8.1step_duration_seconds{step_name="polish", model_name="claude"}→ P95 = 15s(可接受)token_usage_total{model_name="claude"}× 单价 → 成本增加约 40%
决策:在 literature 领域的 polish 步骤切换到 Claude,其他步骤保持 DeepSeek。这正是路由表的设计初衷——按步骤粒度选模型。
场景2:Chunk 切分策略是否合理?
问题:用户反馈长文本翻译质量不稳定。
数据:
chunk_processing_total{status="failed", step_name="literal"}→ 失败率 12%- 关联日志发现失败的 Chunk 平均 token 数为 780(接近 800 上限)
决策:将 MAX_CHUNK_TOKENS 从 800 降到 600,留出更多余量给系统 Prompt。
场景3:Redis 连接池是否需要扩容?
问题:高峰期 SSE 推送偶尔延迟。
数据:
active_sessions峰值 45sse_events_total{status="failed"}偶发增长
决策:Redis max_connections=100 对于 45 个并发会话足够(每个会话在轮询时占用 1 个连接),问题可能在 Redis 服务端,进一步排查发现是 EXPIRE 命令堆积。优化方案:将 TTL 设置从每次 LPUSH 后执行改为批量设置。
七、可观测性的"冰山模型"
╱╲
╱ ╲ ← 用户可见:SSE 进度推送
╱────╲
╱ ╲ ← 运维可见:Prometheus + Grafana
╱────────╲
╱ ╲ ← 开发可见:结构化日志 (logger)
╱────────────╲
╱ ╲ ← 调试可见:LLM Prompt/Response 日志
╱────────────────╲
Prometheus 指标是冰山的中层——它比日志更适合做聚合分析,比 SSE 推送更适合做历史回溯。但三层不能互相替代:
- SSE 给用户提供实时反馈(秒级)
- Prometheus 给运维提供告警和趋势分析(分钟级)
- 日志 给开发提供调试信息(请求级)
在"欧小译"中,这三层是并行存在的,同一个事件(如模型降级)会同时触发:
- SSE 推送 → 用户看到"已切换到备用模型"
- Prometheus Counter +1 → 运维看到降级频率
- logger.warning → 开发看到详细堆栈
八、总结
LLM 应用的可观测性需要超越传统的"三大金信号"(延迟、流量、错误),深入到模型行为(降级、重试、Token 消耗)和输出质量(评分、一致性)层面。
本文的指标体系覆盖了五个维度:业务量、性能、成本、质量、可靠性——这五个维度的交叉分析,才能真正驱动 LLM 应用的持续优化。
记住:你无法优化你无法度量的东西。在 LLM 翻译系统中,这句话的分量比任何工程领域都重。
浙公网安备 33010602011771号