LLM 应用的冷启动与预热策略:第一个请求为什么总是慢
很多团队在做 LLM 应用性能优化时,盯着的是”稳态延迟”——也就是服务跑起来一段时间之后,每个请求大概多久能拿到响应。但一个经常被忽略的现象是:同样的接口、同样的 Prompt,第一个请求往往比后面几个明显慢,有时候能差出几百毫秒甚至几秒。这就是冷启动问题。降低整体延迟的通用方法可参考《降低 LLM 延迟的 10 种实战方法》,本文专门拆解”冷”这一类延迟的成因和预热对策。
一、冷启动到底冷在哪几层
LLM 应用的请求链路比一般 Web 服务长,冷启动可能发生在链路上的任何一层,先分清楚是哪一层慢,才知道该预热什么。
| 层级 | 冷启动表现 | 典型场景 |
|---|---|---|
| 网络连接层 | TLS 握手 + TCP 建连耗时,首次请求多出几十到上百毫秒 | 应用刚启动,还没和 API 网关建立长连接 |
| 计算资源层 | Serverless 函数/容器从零启动,加载运行时和依赖 | 用 Lambda、Cloud Run 等按需扩容的架构部署 Agent 后端 |
| 模型服务层 | 模型实例需要从冷状态加载到显存,或者路由到新扩容的实例 | 服务商侧的弹性扩容,用户侧不可控但可以规避触发条件 |
| Prompt Cache 层 | 长 system prompt 或长文档第一次没有缓存命中,全量计算 | 使用 Prompt Caching 功能但缓存刚好过期或从未建立 |
| 应用层缓存/连接池 | 数据库连接池、向量库连接、SDK 内部连接池尚未预热 | RAG 应用的检索层在冷启动时同样会慢 |
多数团队只关注模型服务层(以为是”模型慢”),但实际排查下来,很大一部分冷启动延迟来自网络连接层和应用层连接池——这两层是用户自己能完全控制、性价比最高的优化点。
二、网络连接层:保持连接常温
如果客户端每次请求都新建 TCP 连接和 TLS 握手,尤其是跨境访问海外模型 API 时,单次握手的往返延迟可能就有大几十毫秒。常见对策:
- 使用 HTTP 长连接(Keep-Alive)并复用连接池:确保 SDK 或自己封装的 HTTP 客户端开启连接复用,而不是每次请求都新建连接。大部分主流语言的 HTTP 库默认支持,但要检查连接池的最大空闲时间设置,太短会导致连接频繁重建
- 应用启动时主动发一个探活请求:服务刚启动、连接池是空的这段时间,主动打一个轻量请求(比如查模型列表这类不计费或计费很低的接口)把连接预热起来,再开始处理真实流量
- 对延迟敏感的场景,评估就近接入点:如果通过中转层访问模型 API,中转节点和模型服务商机房的网络距离也会影响握手和数据传输耗时,这一层用户侧能做的优化有限,更多依赖服务商基础设施质量
三、Serverless 部署的冷启动:典型的”按需付费换来的延迟税”
如果 Agent 后端部署在 Serverless 平台(Lambda、Cloud Run、Vercel Functions 等),函数长时间没有请求会被回收,下一个请求进来时要重新拉起容器、加载依赖,这个过程可能是几百毫秒到几秒不等,和代码体积、依赖数量强相关。
对策思路和传统 Serverless 冷启动优化基本一致,这里只强调 LLM 场景特有的两点:
- 精简依赖,尤其是模型 SDK 的按需加载:很多 LLM 相关 SDK(尤其是同时装了多家厂商 SDK 用于路由)体积不小,如果不是每次调用都需要全部厂商的 SDK,考虑懒加载或者拆分成独立函数,减少冷启动时的依赖加载时间
- 用定时心跳保持”温实例”:对于调用量稳定但有间歇的场景(比如工作时间集中调用),用定时任务每隔几分钟发一次轻量探活请求,防止实例被平台回收。这是用少量探活成本换取用户请求不撞上冷启动,对预算敏感型场景需要计算这笔账是否划算——探活频率太高本身也会产生调用成本
四、Prompt Cache 预热:长 System Prompt 场景的关键一步
如果应用用了较长的 system prompt(比如几千字的角色设定、工具说明、few-shot 示例),并且模型服务支持 Prompt Caching,缓存是否命中直接决定了这次请求是”快”还是”慢”——未命中缓存时,模型需要对整个长 prompt 重新做一遍前向计算,命中时可以直接复用之前的计算结果,速度和成本差异都很明显。
预热策略:
- 应用启动或部署更新后,主动发一次”预热请求”,把固定不变的 system prompt 部分喂给模型一次,建立缓存,再开始接收真实用户流量
- 注意缓存的有效期:多数厂商的 Prompt Cache 有几分钟到十几分钟不等的存活时间,如果业务的请求间隔经常超过这个时间窗口,单纯预热一次没有用,需要用心跳请求周期性”续热”缓存,间隔要小于缓存 TTL
- 把易变内容和固定内容分层组织:system prompt 里如果混杂了少量经常变化的内容(比如当前时间戳),会导致整个 prompt 因为几个字符不同而缓存失效。把固定不变的大段说明放在前面、易变的小段内容放在后面,能显著提高缓存命中率——这个原则同样适用于《LLM 上下文工程方法论》里提到的上下文组织方式
五、什么场景值得投入预热成本
预热不是免费的——探活请求、心跳续热都会产生额外的调用次数和费用,不是所有场景都值得做。一个简单的判断框架:
- 面向终端用户的实时交互场景(聊天、客服):值得投入,因为用户对首次响应延迟的感知非常敏感,几百毫秒的冷启动差异直接影响体验评价
- 后台批处理、离线分析类任务:通常不值得,因为这类任务本身对单次延迟不敏感,累计延迟对整体吞吐影响很小,预热带来的额外成本反而不划算
- 调用频率本身就很稳定、几乎不会触发冷启动的场景:不需要额外做预热,把资源花在别处
六、上线前的一个简单自检清单
部署新的 LLM 应用之前,建议做一次冷启动专项测试,而不是只看稳态压测数据:
- 服务重启后,记录第 1、第 2、第 10 个请求的延迟,对比差异是否明显
- 检查连接池的空闲超时配置,确认低频调用场景下连接不会被过早回收
- 如果用了 Prompt Caching,检查缓存命中率监控指标,确认预热和续热逻辑生效
- 如果部署在 Serverless 平台,评估心跳保温的成本收益是否合理
冷启动优化的收益不会体现在平均延迟(P50)上,而是体现在尾部延迟和首次体验上——这也是为什么很多团队做了大量稳态优化,用户还是反馈”感觉偶尔会卡一下”的原因。