我们的产品接入了通义千问的API,上线之后用户反馈最多的问题就是"慢"。有时候一个问题要等十几秒才能出结果,用户等得不耐烦就走了。
花了两周时间做性能优化,把平均响应时间从8秒降到了2秒以内。这里把优化的过程和经验分享出来。
先搞清楚慢在哪
优化之前,先做了一轮性能分析,搞清楚时间都花在哪了。
用日志记录了每次API调用的各个阶段耗时:网络传输、排队等待、模型推理、结果返回。分析之后发现,模型推理占了大部分时间,尤其是长文本的生成,一个回答生成几百个字就要好几秒。
还有一个问题是,很多请求其实是重复的。用户经常问类似的问题,每次都重新调用API生成,既慢又浪费钱。
搞清楚了瓶颈,就有了优化的方向。
提示词优化
提示词对性能的影响比想象中大。
最初的提示词写得很啰嗦,给了很多背景信息和示例,每次请求都要把这些内容传一遍。这些内容虽然不影响生成速度,但增加了输入token的数量,API是按token计费的,输入多了费用也高。
优化之后,把提示词精简了。去掉了不必要的背景说明,示例从五个减到两个,系统提示也压缩到最核心的要求。输入token减少了将近一半,费用降了,响应也快了一点。
还有一个技巧是,把通用的系统提示和用户的问题分开。系统提示用参数单独传,不要拼到用户消息里。这样API端可以缓存系统提示,不用每次都重新处理。
流式输出
流式输出是提升用户体验最有效的手段。
原来的做法是等模型把完整回答生成完,再一次性返回给前端。用户要等好几秒才能看到内容,体验很差。改成流式输出之后,模型生成一个字就推一个字,用户几乎立刻就能看到回答在逐字出现,心理上会觉得快很多。
通义千问的API支持SSE流式输出,接入也不复杂。前端用EventSource接收,收到数据就追加到页面上。虽然总生成时间没有变,但用户感知到的等待时间大大缩短了。
有一点要注意,流式输出的时候要处理好网络中断的情况。如果连接断了,要支持从断点继续,或者让用户重新生成。我们做了一个简单的断点续传,记录已经生成的内容,断了之后从最后一个字继续。
缓存策略
缓存是降本增效的利器。
我们做了两层缓存。第一层是精确匹配缓存,把用户的问题做hash,完全一样的问题直接返回之前的结果,不用再调API。第二层是语义缓存,用embedding计算问题的相似度,相似的问题也可以复用之前的答案。
精确匹配缓存命中率不高,因为用户的问法千奇百怪。语义缓存效果好很多,命中率能到30%左右。也就是说,将近三分之一的请求不用调API,既快又省钱。
缓存的过期时间要设好。大模型的回答可能会更新,缓存太久了答案会过时。我们设的是24小时过期,重要的问题缓存时间更短。
还有一点,缓存的答案要能人工干预。如果发现某个问题的回答不好,可以手动清除缓存,让用户重新生成。
并发控制
并发控制是稳定性的保障。
大模型API都有并发限制,超过了就会被限流。我们刚开始没注意这个,高峰期大量请求同时发过去,很多被拒绝了,用户看到的就是报错。
做了一个请求队列,所有API调用都先入队,按固定的并发数消费。这样既不会超过API的限流,也能保护自己的服务不被打垮。
队列里还做了优先级处理。付费用户的请求优先级高,先处理;免费用户的请求排队等。虽然这样对免费用户不太友好,但保证了核心用户的体验。
超时控制也很重要。给每个请求设一个超时时间,比如15秒,超过了就返回失败或者降级结果。不能让一个慢请求把整个队列堵死。
模型选择
通义千问有不同大小的模型,性能和效果差别很大。
我们一开始全用最大的模型,效果好但慢。后来做了分流,简单的问题用小模型,复杂的问题才用大模型。比如用户问"你好""谢谢"这种闲聊,小模型完全能应付,响应速度快很多。
怎么判断问题简单还是复杂?我们用了一个简单的分类器,先判断问题的类型和难度,再路由到不同的模型。分类器本身很快,几乎不增加延迟。
还有一个技巧是,先让小模型生成,如果小模型的回答质量不够,再用大模型重新生成。这样大部分请求都走小模型,只有少数需要大模型,整体性能提升明显。
前端优化
后端优化之外,前端也有很多可以做的。
最基本的是加载状态。用户点了发送之后,立刻显示"正在思考"的动画,不要让页面毫无反应。有了加载动画,用户的等待焦虑会减轻很多。
打字机效果也很重要。流式输出的内容用打字机效果展示,一个字一个字地出现,比一下子蹦出一大段文字体验好很多。
还有一个细节是,用户输入的时候就开始预连接。用户在输入框里打字的时候,前端就和API建立连接,等用户点发送的时候,连接已经建好了,省了握手的时间。
历史消息的处理也要注意。对话越长,每次请求带的历史消息越多,速度越慢。我们做了历史消息的压缩,只保留最近几轮的完整对话,更早的对话做摘要,这样既能保持上下文,又不会让输入太长。
优化效果
做完这些优化之后,效果很明显。
平均响应时间从8秒降到了2秒以内,其中流式输出让用户感知到的等待时间更短。API调用量因为缓存和模型分流减少了40%,费用也降了不少。
用户反馈也好了很多,之前抱怨慢的评论基本消失了。留存率和使用时长都有提升。
当然还有继续优化的空间。比如可以做更智能的模型路由,更精准的缓存策略,更高效的提示词模板。性能优化是个持续的过程,没有最好只有更好。
几点经验
第一,先测量再优化。不要凭感觉改,先用数据搞清楚瓶颈在哪,再针对性地优化。
第二,用户感知比绝对速度更重要。流式输出、加载动画这些手段,虽然没有减少总时间,但用户体验提升很大。
第三,缓存是性价比最高的优化。既能提速又能省钱,一定要做。
第四,不要追求极致。性能优化到一定程度,再提升的边际成本就很高了。够用就好,把精力放在更重要的事情上。
大模型应用的性能优化是个新领域,大家都在摸索。希望这些经验能帮到正在做类似事情的朋友。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录