问答题3/1784如何实现 Agent 的 Token 实时统计?

难度:
2026-06-08 创建

参考答案:

实现 Agent 的 Token 实时统计,核心是把它设计成“实时估算 + 最终校准”的体系,而不是只在前端按字符数粗略计算。

Agent 的一次响应通常不是一次模型调用,可能包含规划、工具调用、工具结果回填、再次推理、多轮循环等过程。因此统计维度应该以 runId 为主线,再细分到每一次 model_call

1type TokenUsageEvent = { 2 runId: string; 3 stepId: string; 4 model: string; 5 phase: 'prompt' | 'completion' | 'tool' | 'final'; 6 promptTokens?: number; 7 completionTokens?: number; 8 totalTokens?: number; 9 estimated?: boolean; 10};

服务端是统计的主位置。原因是服务端最清楚真正发送给模型的上下文内容,包括 system prompt、历史消息、工具定义、工具调用参数、RAG 检索结果、工具返回内容以及压缩后的上下文。前端如果只根据输入框内容统计,会漏掉大量 Agent 内部消耗。

实时过程中可以这样处理:在发起模型请求前,服务端先用对应模型的 tokenizer 计算 prompt token,并通过 SSE 或 WebSocket 推给前端;模型流式输出时,根据增量文本持续估算 completion token;当模型 API 返回最终 usage 后,再用权威数据覆盖估算值。

1// 伪代码 2emit({ 3 runId, 4 stepId, 5 phase: 'prompt', 6 promptTokens: countPromptTokens(messages, tools, model), 7 estimated: false, 8}); 9 10for await (const chunk of stream) { 11 const delta = chunk.text ?? ''; 12 13 emit({ 14 runId, 15 stepId, 16 phase: 'completion', 17 completionTokens: estimateTokenDelta(delta, model), 18 estimated: true, 19 }); 20} 21 22emit({ 23 runId, 24 stepId, 25 phase: 'final', 26 promptTokens: usage.prompt_tokens, 27 completionTokens: usage.completion_tokens, 28 totalTokens: usage.total_tokens, 29 estimated: false, 30});

这里有一个关键点:流式 token 很难做到完全准确。因为不同模型的 tokenizer 不同,中文、代码、JSON、函数调用参数的 token 分布也不一样。实时阶段更适合展示“接近真实的估算值”,最终以模型返回的 usage 为准。如果使用支持流式 usage 的模型接口,可以在最后一个 chunk 拿到官方 usage;如果不支持,就需要服务端用同款 tokenizer 进行兜底统计。

前端的职责主要是展示和交互,不应该承担权威统计逻辑。它需要按 runId + stepId 合并事件,区分 estimated 和 final 状态,展示当前请求、当前 Agent Run、当前会话的 token 累计值。为了避免频繁刷新带来性能问题,可以对 completion token 的更新做节流,比如 200ms 合并一次。

还要特别注意 Agent 场景里的边界情况。比如工具调用失败后重试,token 需要按实际调用累计;用户取消请求时,已经产生的 completion token 仍然要保留;多个 Agent 并发执行时,事件必须通过 runId 隔离;如果有上下文压缩、RAG 检索、工具结果回填,也要作为下一次 prompt token 的组成部分统计进去。

如果系统还要展示成本,就不能只统计 token 数,还要结合模型价格表计算 input、output、cached input 等不同类型的费用。这个价格表也应该放在服务端,避免前端硬编码后过期。

最后,Token 实时统计不只是 UI 展示能力,也应该服务于控制逻辑。当接近上下文上限时,可以提前提示、压缩历史、裁剪工具结果,或者阻止继续执行,避免 Agent 在中途因为上下文超限失败。

最近更新时间:2026-06-08

赞赏支持

题库维护不易,您的支持就是我们最大的动力!