AI SaaS上线后用户增多导致延迟飙升,核心解法是制定LLM延迟预算:规定每个工作流的响应速度、token上限、流式启动时机、缓存策略和多模型路由规则。
AI 平台新闻指向同一个方向:开发者们正从聊天演示转向生产级工作流。Agent 工具、Web 上下文 API、语音 Agent、编码助手和 RAG 平台的能力都在不断提升。与此同时,推理成本和可靠性正面临压力。
延迟如今已是一种产品指标。推理效率正在成为一种业务指标。然而许多文章止步于 TTFT、TPOT、量化、批处理或模型服务层面。很少有人展示 SaaS 开发者如何将这些理念转化为包含代码、仪表盘、兜底策略和客户安全限制的产品级预算。
你不需要攻读服务系统的博士才能上手。只需追踪三个数字。
首 Token 延迟(Time to First Token,TTFT) 是用户操作到首个流式 Token 之间的延迟。它包含网络时间、排队时间、提供商开销、工具设置、检索时间,以及模型的预填充阶段。
高 TTFT 是聊天框让人感觉死气沉沉的原因。
每输出 Token 耗时(Time Per Output Token,TPOT) 是首个 Token 出现后,生成各 Token 之间的平均时间。
高 TPOT 是流式输出感觉像滴水龙头的原因。
端到端延迟 是从请求到最终答案的完整时间。
end_to_end_latency = TTFT + (output_tokens - 1) * TPOT
这个公式并非对每个提供商都精确,但足以用来分析用户体验。
一个常见错误是设置一个全局目标,比如"AI 响应必须在 5 秒内完成"。听起来干净利落,但很快就会失效。
不同的工作流需要不同的预算。
关键是为体验制定预算,而不是为原始模型调用制定预算。
用户可以原谅一个 40 秒的后台报告生成——只要 UI 告知了正在发生什么。同一个用户可能会放弃一个 6 秒的内联写作助手——如果什么都看不到的话。
为每个 AI 工作流创建一个预算对象。
{
"workflow": "support_rag_answer",
"max_ttft_ms": 2500,
"max_total_ms": 15000,
"max_input_tokens": 12000,
"max_output_tokens": 900,
"stream": true,
"cache_policy": "semantic_and_exact",
"fallback_model": "fast_general_model",
"requires_citations": true,
"async_after_ms": 12000
}
这将"让它更快"转化为了工程约束。你的应用现在可以决定是否裁剪上下文、启用流式、路由到更快的模型、切换为异步、拒绝超大型请求,或使用缓存答案。
先为每个 AI 请求记录延迟和 Token 数据。在购买新工具或更换提供商之前就这样做。
以下是一个 TypeScript 风格的简单示例。
type LlmTrace = {
requestId: string;
tenantId: string;
workflow: string;
model: string;
inputTokens: number;
outputTokens: number;
ttftMs: number | null;
totalMs: number;
costUsd: number;
cacheHit: boolean;
status: "success" | "timeout" | "error";
};
async function runWithTrace(input: {
tenantId: string;
workflow: string;
prompt: string;
}) {
const started = Date.now();
let firstTokenAt: number | null = null;
let output = "";
const stream = await llm.stream({
model: "fast-general",
prompt: input.prompt,
max_tokens: 700
});
for await (const chunk of stream) {
if (!firstTokenAt) firstTokenAt = Date.now();
output += chunk.text;
sendToClient(chunk.text);
}
const finished = Date.now();
const trace: LlmTrace = {
requestId: crypto.randomUUID(),
tenantId: input.tenantId,
workflow: input.workflow,
model: "fast-general",
inputTokens: estimateTokens(input.prompt),
outputTokens: estimateTokens(output),
ttftMs: firstTokenAt ? firstTokenAt - started : null,
totalMs: finished - started,
costUsd: estimateCost(input.prompt, output),
cacheHit: false,
status: "success"
};
await saveTrace(trace);
return output;
}
保持埋点简单。如果你捕获了请求 ID、租户 ID、工作流、模型、Token 数、TTFT、总时间、成本、缓存命中和状态,就能回答大多数早期性能问题。
长 Prompt 损害 TTFT。长上下文意味着在首个 Token 出现之前要做更多工作。
对于 AI SaaS 产品,输入膨胀通常来自:完整聊天历史、太多 RAG Chunk、原始 HTML、未使用的工具描述、重复的系统指令,或者传入整个客户记录而实际上只有几个字段有用。在优化 GPU 或更换供应商之前,先删掉无用的上下文。
使用上下文打包器。
type ContextItem = {
id: string;
text: string;
priority: number;
tokenEstimate: number;
};
function packContext(items: ContextItem[], maxTokens: number) {
const sorted = [...items].sort((a, b) => b.priority - a.priority);
const selected: ContextItem[] = [];
let used = 0;
for (const item of sorted) {
if (used + item.tokenEstimate > maxTokens) continue;
selected.push(item);
used += item.tokenEstimate;
}
return selected;
}
这并不花哨。这正是它的要点。基于优先级的简单打包器往往优于"发送所有内容然后祈祷"。
对于 RAG,使用更少但更好的 Chunk。对于 Agent,每步暴露更少的工具。对于浏览器自动化,在将页面内容放入 Prompt 之前先清洗一遍。
输出 Token 决定总延迟和成本。许多 AI 功能并不需要长答案。
按工作流设置输出上限:
同时给模型一个阻止废话的结构。
Answer in this format:
1. Direct answer: 2 sentences max
2. Steps: up to 5 bullets
3. Caveat: 1 short note if needed
这提高了可扫描性并减少了 Token 漂移。
流式输出可以让 AI 功能感觉更快,但它不能修复一切。
适用流式的场景:
不适用的场景:
对于 Agent 工作流,流式输出状态事件,而不仅仅是文本。
{ "type": "status", "message": "Searching relevant docs" }
{ "type": "status", "message": "Checking account permissions" }
{ "type": "status", "message": "Drafting answer with citations" }
这让用户在系统执行实际工作时保持知情。
不是每个请求都值得使用你最强的模型。
创建延迟等级:
简单的路由器可以从规则开始。
function chooseModel(workflow: string, risk: "low" | "medium" | "high") {
if (workflow === "autocomplete") return "small-fast";
if (workflow === "bulk_report") return "batch-careful";
if (risk === "high") return "careful-reasoning";
return "fast-general";
}
之后,你可以根据测量到的性能、租户套餐、队列深度或失败率来路由。先从开发者能够理解和调试的规则开始。
缓存是改善延迟和成本最简单的方法之一,但要缓存正确的内容。
好的缓存候选:
不好的缓存候选:
始终在缓存键中包含租户和权限上下文。
function cacheKey(input: {
tenantId: string;
userRole: string;
workflow: string;
normalizedQuery: string;
sourceVersion: string;
}) {
return [
input.tenantId,
input.userRole,
input.workflow,
input.sourceVersion,
hash(input.normalizedQuery)
].join(":");
}
一次泄露数据的缓存命中比没有缓存更糟糕。
你的应用需要一个应对坏日子的计划:提供商变慢、队列峰值、长文档,或者租户运行大型作业。
有用的降级模式:
if (queueDepth > 100 && workflow === "support_rag_answer") {
budget.max_input_tokens = 6000;
budget.max_output_tokens = 500;
budget.fallback_model = "fast-general";
}
这不是在任何地方都降低质量,而是在压力下保护体验。
平均延迟会说谎。你的快乐路径可能看起来很好,而真实用户却在受苦。
按工作流和租户层级追踪这些指标:
起初一个简单的告警规则就足够了。
Alert when support_rag_answer p95 TTFT > 3000ms for 10 minutes.
Alert when cost per successful task rises 30% above 7-day baseline.
Alert when timeout rate > 2% for any paid tenant tier.
将延迟与成本挂钩。如果 p95 延迟和成本同时上升,你可能有上下文膨胀、重试循环、路由不当,或者某个工作流应该改为异步。
重试在代码里感觉无害,在生产环境中却很昂贵。
重试可以加倍成本、增加延迟,并产生重复的工具操作。对于 Agent,重试循环风险更大,因为模型可能再次调用工具。
const retryPolicy = {
maxAttempts: 2,
retryOn: ["rate_limit", "network_timeout"],
neverRetryOn: ["invalid_json", "permission_denied", "policy_blocked"]
};
如果一个工作流需要三次重试才能感觉可靠,它可能需要更好的设计,而不是更大的重试循环。
有些 AI 工作不应该假装是即时的。
适合异步的场景:
好的异步 UX 包括:
这保护了你的聊天界面不会变成候诊室。
在新 AI 功能上线前使用:
LLM 延迟预算不是官僚主义。它是产品质量的护栏。
当预算缺失时,每个 Prompt 都可以膨胀,每个 Agent 都可以游荡,每次重试都可以加倍支出,每个慢请求都可能变成一个谜。当预算存在时,你的团队可以做出明确的权衡:更快的首 Token、更短的输出、更好的上下文、更安全的缓存、异步工作流,或者只在需要的地方使用更强的模型。
快速的 AI 不仅仅关于速度。它关乎尊重用户时间的同时保护你的利润。
什么是 LLM 延迟预算?
LLM 延迟预算是 AI 工作流的一套限制:首 Token 最大时间、最大总响应时间、输入 Token 上限、输出 Token 上限、模型路由、缓存规则和兜底行为。
AI 功能的良好 TTFT 是多少?
取决于工作流。内联建议应该几乎即时有感。聊天回答通常应该在一到两秒内开始流式输出。如果 UI 显示有意义的进度,RAG 或 Agent 工作流可以花费更长时间。
如何快速降低 LLM 延迟?
首先从裁剪输入 Token、限制输出长度、流式响应、缓存重复工作和将简单任务路由到更快的模型开始。这些改变通常比改变基础设施更容易。
每个 AI 工作流都应该流式输出吗?
不。流式输出对可读文本和进度更新效果良好。对于严格的 JSON、隐藏的工具调用工作流,或部分输出可能使用户困惑的任务,它不太有用。
延迟与 AI 成本如何关联?
长 Prompt、长输出、重试和工具循环通常同时增加延迟和成本。这就是为什么生产团队应该一起追踪 Token 数、延迟、缓存命中率和每个成功任务的成本。
自托管比使用 API 更快吗?
不会自动更快。自托管可以减少控制平面的不确定性,但良好的模型服务需要批处理、内存管理、扩展、监控和硬件调优。在假设自托管更好之前,先测量 TTFT、TPOT 和总成本。