AI 应用的成本、延迟和可观测性
💰 AI 系统优化是一个三角:质量、延迟、成本。只压低 token 费用可能降低任务成功率,导致重试和人工接管,最终反而更贵。最实用的单位是“每个成功任务的总成本”。
端到端成本模型
每成功任务成本 =
(模型 + Embedding + Rerank + 工具 + 基础设施 + 重试 + 人工接管成本)
÷ 成功完成的任务数
模型成本
成本归因要跟随 trace:一次用户任务可能包含多次模型调用、检索、重排和工具执行,按单次 API 请求统计会低估真实成本。
def model_cost(input_tokens, output_tokens, cached_tokens, rate):
return (
input_tokens * rate.input
+ output_tokens * rate.output
+ cached_tokens * rate.cached
) / 1_000_000
价格与模型经常变化,应把费率放在配置中并记录生效日期,不要写死在业务代码或知识页结论中。
延迟拆解
总延迟 = 排队 + 网络 + 检索/工具 + Prefill + Decode + 后处理
生成时长 ≈ 输出 token 数 × TPOT
- TTFT:首 token 到达时间,影响“是否立即有反馈”。
- TPOT:相邻输出 token 的平均时间,影响流式速度。
- E2E:从请求到最终可用结果,工具型 Agent 最重要。
- P50/P95/P99:平均值会隐藏排队、重试与冷启动。
优化顺序
- 先测任务成功率:避免用更便宜但需要多次重试的模型。
- 删除无效上下文:检索后只保留相关证据,避免重复系统提示。
- 模型路由:分类、抽取用小模型;复杂推理按置信度升级。
- 控制输出:Schema、长度上限和停止条件能同时降低延迟与成本。
- 缓存:区分精确缓存、语义缓存、Prompt 前缀缓存和工具结果缓存。
- 并行化独立步骤:多个检索或只读工具并发,但注意供应商限流。
- 批处理离线任务:提高吞吐,接受更高单请求等待时间。
缓存设计
| 缓存 | 适用 | 主要风险 |
|---|---|---|
| 精确缓存 | 相同请求 | 版本与权限失效 |
| 语义缓存 | 近似问答 | 错误复用、个性化泄漏 |
| 前缀缓存 | 长且稳定的共同前缀 | 前缀变化导致失效 |
| 工具缓存 | 天气、配置、检索等有 TTL 的结果 | 陈旧数据 |
缓存 key 应包含租户、权限、模型、Prompt、Schema、知识库版本和必要参数。
Trace 数据模型
@dataclass
class Span:
trace_id: str
span_id: str
parent_span_id: str | None
kind: str # llm / retrieval / tool / rerank
model_or_tool: str
started_at: datetime
latency_ms: float
input_tokens: int | None
output_tokens: int | None
cost_usd: float
status: str
prompt_version: str | None
error_type: str | None
敏感输入输出不一定要全文记录;可以采用脱敏、采样、哈希或仅保存引用。可观测性不能成为新的数据泄漏渠道。
推荐看板
用户体验
- 任务成功率、用户采纳率、人工接管率
- TTFT、E2E 的 P50/P95/P99
- 错误率、取消率、重试率
质量
- 回归集通过率、RAG 忠实性、工具成功率
- 按功能/语言/难度切片
成本
- 每请求与每成功任务成本
- 按功能、模型、租户拆分
- 输入/输出/缓存 token 占比
告警与 SLO 示例
- 10 分钟窗口错误率 > 2%
- P95 TTFT 超过目标 20%
- 单任务成本相对 7 日基线增长 30%
- 工具循环步数或重试率突增
- 某 Prompt/模型版本的任务成功率显著下降
常见反模式
- 只看供应商 API 延迟,忽略排队、检索和工具。
- 记录全部 Prompt,却没有版本号和 trace 关系。
- 只统计 token 单价,不统计失败、重试和人工成本。
- 用流式输出掩盖最终任务完成时间。
- 缓存未纳入权限和知识版本,导致跨用户或陈旧回答。
上线检查清单
- 每个请求有 trace ID 和版本信息
- 同时看质量、延迟、成本
- 指标可按功能/模型/租户切片
- Prompt 与工具日志已脱敏
- 有预算、超时、取消和重试策略
- 优化效果以“每成功任务成本”验证