LLM Token 预算告警:让对话机器人在崩溃前悬崖勒马的完整方案

Token预算告警机制

背景:上线3个月后开始答非所问

我们的客服机器人跑了3个月后,开始出现"答非所问"的问题。用户说"查一下我的订单",AI 回的是"工单编号格式如下"。日志里单会话 token 已经突破 18 万,上下文窗口直接爆了。

事后复盘发现:不是模型变差了,是上下文累积没有控制。从 Round 25(约 46000 tokens)开始,模型就开始受影响,但没有告警机制,等到发现问题已经是 Round 50 了。

实测数据:

用户类型 开始告警阈值 崩溃临界点
普通用户(3个月) ~46000 tokens(Round 25) ~80000 tokens
重度用户 ~46000 tokens(Round 15) ~180000 tokens(Round 50)

解决方案:三层 Token 预算告警机制

核心思路:不等模型崩溃,先于用户感知告警。我们实现了一套三层告警:

  1. 信息池 — 关键字段(用户ID、订单号、工单号)永远置顶,不参与滑动窗口
  2. 预算控制 — Token 计数器 + 双阈值(warn 70%、critical 90%)
  3. 自动压缩 — 超过阈值时触发摘要压缩,保留关键信息

核心代码实现

第一步:Token 计数器

import tiktoken
from dataclasses import dataclass, field
from typing import Optional

@dataclass
class TokenBudget:
    model: str = "gpt-4o-mini"
    warn_pct: float = 0.70
    crit_pct: float = 0.90
    max_tokens: int = 128000

    # 关键信息池(永远不参与滑动窗口)
    priority_pool: dict = field(default_factory=dict)

    _history_tokens: int = 0

    def count_messages(self, messages: list[dict]) -> int:
        enc = tiktoken.encoding_for_model(self.model)
        total = 0
        for msg in messages:
            total += len(enc.encode(msg.get("content", "")))
            total += len(enc.encode(msg.get("role", ""))) + 4
        return total

    def check(self, messages: list[dict]) -> dict:
        current = self.count_messages(messages)
        pct = current / self.max_tokens

        level = "normal"
        if pct >= self.crit_pct:
            level = "critical"
        elif pct >= self.warn_pct:
            level = "warning"

        return {
            "level": level,
            "current_tokens": current,
            "max_tokens": self.max_tokens,
            "pct": round(pct * 100, 1),
            "should_compress": pct >= self.warn_pct,
        }

第二步:关键信息自动提取

import re

PRIORITY_PATTERNS = [
    r"工单[号#]?\s*[::]?\s*([A-Z0-9]{8,})",
    r"订单[号#]?\s*[::]?\s*([A-Z0-9]{8,})",
    r"用户ID\s*[::]?\s*([a-zA-Z0-9]{6,})",
]

def extract_priority_fields(messages: list[dict]) -> dict:
    pool = {}
    for msg in messages:
        text = msg.get("content", "")
        for pattern in PRIORITY_PATTERNS:
            if match := re.search(pattern, text):
                field_name = pattern.split(r"(")[1].rstrip(")")
                pool[field_name] = match.group(1)
    return pool

第三步:接入 Prometheus 告警

from prometheus_client import Counter, Gauge

token_warn_total = Counter("llm_token_warn_total", "Warning level triggered")
token_crit_total = Counter("llm_token_crit_total", "Critical level triggered")
token_pct_gauge = Gauge("llm_token_pct", "Current token usage pct", ["user_id"])

def on_token_check(budget: TokenBudget, messages: list[dict], user_id: str):
    result = budget.check(messages)
    token_pct_gauge.labels(user_id=user_id).set(result["pct"] / 100)

    if result["level"] == "critical":
        token_crit_total.inc()
        compress_conversation(messages, budget)
    elif result["level"] == "warning":
        token_warn_total.inc()
        log.warning(f"Token usage high for {user_id}: {result['pct']}%")

阈值怎么定:别猜,用数据

网上说"Token 超过 70% 就该压缩",这是废话——不同用户、不同场景阈值完全不一样。

正确做法:先跑一个季度,用真实数据定阈值。我们的方法:

  1. 上线后记录每个会话的 Round 数和对应 Token 数
  2. 找到"模型开始答非所问"的 Round 作为 ground truth
  3. 往前取 20% 的 Round 数作为 warn 阈值
  4. 往前取 10% 的 Round 数作为 critical 阈值

Grafana 告警配置

groups:
  - name: llm_token_alerts
    rules:
      - alert: LLMTokensWarning
        expr: llm_token_pct > 0.70
        for: 1m
        labels:
          severity: warning
        annotations:
          summary: "LLM Token 使用率超过 70%"
          description: "用户 {{ $labels.user_id }} 的 Token 使用率已达 {{ $value | humanizePercentage }}"

      - alert: LLMTokensCritical
        expr: llm_token_pct > 0.85
        for: 30s
        labels:
          severity: critical
        annotations:
          summary: "LLM Token 即将崩溃"
          description: "用户 {{ $labels.user_id }} 的 Token 使用率已达 {{ $value | humanizePercentage }},建议立即压缩"

推荐配两档:70% 预警发飞书通知客服85% 自动触发上下文压缩

现在你可以做什么

第一步:装依赖

pip install tiktoken prometheus_client --break-system-packages

第二步:把 TokenBudget 类复制到你的对话机器人代码里

第三步:在每轮对话结束后调用 budget.check(messages),根据返回值决定是否压缩

第四步:Prometheus 上报后,在 Grafana 配两条告警规则:70% 预警 + 85% 严重

第五步:跑一个季度,用真实 Round 数据校准你的 warn/critical 阈值

不要抄网上的"80%就该压缩"——用你自己产品的真实数据,阈值差 5% 可能就是用户满意和不满意的分水岭。

相关踩坑记录:

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享