21 QPS 只有 100,业务要 1000:AIGC 接口的成本与并发设计
面试官看着简历上那个 AI 客服项目,问了一句很实在的话:"你们这个问答接口,压测过吗?QPS 能到多少?"候选人不假思索:"我们用了 Spring Boot,Tomcat 线程池默认 200,理论上没问题。"面试官接了一句:"假设上游大模型 API 给你的配额,一秒钟只允许 100 次请求。现在业务方说下周搞活动,峰值要 1000 QPS。你怎么设计?"候选人愣了一下:"加……加机器?""你加十台机器,上游还是只给你 100 的配额,你打算怎么办?"候选人答不上来了。这个问题问得好。因为它把很多人对"高并发"的惯性认知一刀切开了。传统 Web 接口扛不住,加机器、加线程、加连接池,确实能堆。可大模型接口不一样——你的瓶颈根本不在自己这台机器上,而在上游 API 的配额,以及你老板盯着的那张 Token 账单。这篇就聊聊,配额只有 100、业务要 1000,你到底该怎么设计。先想清楚:瓶颈到底在哪加机器之前,先搞清楚一件事:你的请求慢,慢在哪?普通接口慢,通常是自己 CPU 算不过来,加机器有用。大模型接口慢,卡在三件事上:-上游配额:厂商给你的账号有 RPM(每分钟请求数)和 TPM(每分钟 Token 数)上限,不是你机器多就能多调。-单次耗时:一次生成动辄几秒到几十秒,请求都堵在"等上游回话"上,线程白占着。-钱:每一次调用都按 Token 计费,1000 QPS 全打到大模型上,账单能把预算爆掉。看懂这张图,思路就有了。从 100 撑到 1000,不是让上游多干活,而是让自己少调用上游。少调的每一分,都是省下的钱和腾出来的配额。下面一条条拆。第一招:语义缓存——从根上减少调用最省钱的优化永远是"压根不调用"。普通缓存用请求参数做 key,问题在于大模型场景里,用户提问很少一字不差。今天问"怎么退货",明天问"我要退东西怎么办",字面完全不同,意思一模一样。用老式缓存,两条都命中不了,白白调用两次大模型。语义缓存解决的就是这个:不比对文字,比对"意思"。原理不复杂:把用户的问题先转成向量,再去缓存里找"意思最接近"的历史问题。相似度超过阈值,就直接把当时存的答案返回,一次大模型调用都省了。伪代码长这样:@Service public class SemanticCache { private final EmbeddingModel embeddingModel; // 缓存结构:key = 问题向量, value = 当时生成的答案 // 生产上一般放进向量库(Milvus / pgvector),这里先用内存示意 private final ListCacheEntry entries = new ArrayList(); public SemanticCache(EmbeddingModel embeddingModel) { this.embeddingModel = embeddingModel; } // 返回 Optional:命中就给缓存答案,没命中返回空 public OptionalString lookup(String question) { float[] queryVec = embeddingModel.embed(question); // 1. 问题向量化 return entries.stream() .map(e - Map.entry(e, cosine(queryVec, e.vector()))) // 2. 算相似度 .filter(pair - pair.getValue() = 0.9) // 3. 阈值判定 .max(Map.Entry.comparingByValue()) .map(pair - pair.getKey().answer()); // 4. 命中,取答案 } public void remember(String question, String answer) { entries.add(new CacheEntry(embeddingModel.embed(q
上一篇/下一篇内容由系统自动关联
返回资讯列表 →