最近我们团队做了一个AI编程辅助系统,能帮程序员自动补全代码、生成单元测试、做代码审查。刚上线的时候,用户反馈很差,说响应太慢,等半天才能出结果,体验很不好。
我们花了一个月的时间,对整个系统做了全流程的性能优化,把平均响应时间从8秒降到了1.5秒,用户满意度大幅提升。
这篇文章我想分享一下这次性能优化的完整过程,从问题分析到各个环节的优化,再到最终的效果。如果你也在做AI相关的应用,遇到了性能问题,希望这篇文章能帮到你。
问题分析
优化之前,我们先做了详细的问题分析,搞清楚慢到底慢在哪里。
我们的AI编程系统的流程是这样的:用户在编辑器里输入代码,触发补全请求,请求传到后端,后端做一些预处理,然后调用大模型API,大模型返回结果,后端做后处理,再返回给前端展示。
我们在每个环节都加了耗时统计,然后分析了上千个请求的耗时数据。结果发现,耗时主要分布在三个地方。
第一个是大模型API的调用,占了总耗时的60%左右。大模型推理本身就比较慢,特别是生成比较长的代码的时候,可能要等好几秒。
第二个是网络传输,占了总耗时的20%左右。用户的请求从前端传到后端,后端调用大模型API,结果再传回来,这些网络传输加起来也不少。
第三个是前后端的处理,占了总耗时的20%左右。包括代码的预处理、上下文的拼接、结果的后处理、前端的渲染等。
找到了瓶颈之后,我们就开始针对性地优化。
优化一:大模型调用优化
大模型调用是最大的瓶颈,我们花了最多的精力在这上面。
第一个优化是模型选型。我们最开始用的是最大的模型,效果最好,但也最慢。后来我们做了测试,发现对于代码补全这种任务,中等规模的模型效果已经足够好了,而且速度快很多。我们把默认模型换成了中等规模的模型,只有在复杂任务的时候才调用大模型。这样平均响应时间降了不少。
第二个优化是流式输出。以前我们是等大模型把所有结果都生成完了,再一次性返回给前端。后来改成了流式输出,大模型生成一个token,我们就传给前端一个token,前端边接收边展示。这样用户不需要等全部生成完,就能看到结果,感知上快了很多。虽然总生成时间没变,但首字响应时间从3秒降到了0.5秒,用户体验好了很多。
第三个优化是缓存。我们发现很多代码补全的请求是重复的,或者是相似的。我们加了一个缓存层,把常见的补全结果缓存起来。如果用户的请求和缓存里的匹配,就直接返回缓存的结果,不用调用大模型。缓存命中率大概在30%左右,这部分请求的响应时间从几秒降到了几毫秒。
第四个优化是批量处理。对于一些不需要实时响应的任务,比如批量生成单元测试,我们改成了批量处理。把多个请求合并成一个大模型调用,提高了模型的利用率,也降低了平均耗时。
第五个优化是参数调优。我们对大模型的参数做了调优,比如maxtokens、temperature、topp等。把max_tokens设得更合理,避免生成不必要的长内容。把temperature调低,让输出更稳定,减少因为输出不稳定导致的重试。
通过这些优化,大模型调用的平均耗时从5秒降到了1秒左右。
优化二:网络传输优化
网络传输是第二大瓶颈,我们也做了不少优化。
第一个优化是就近部署。我们的后端服务器部署在国内,但大模型API的服务器在国外,每次调用都要跨国传输,延迟很高。后来我们把后端服务也部署到了和大模型API同一个区域,网络延迟从500毫秒降到了50毫秒。
第二个优化是使用长连接。以前每次调用大模型API都要新建一个HTTP连接,握手和TLS握手都要花时间。后来我们改成了HTTP长连接,复用连接,减少了握手的开销。
第三个优化是压缩传输。我们在前后端传输的时候,对数据做了压缩。特别是代码内容,压缩率很高,能减少传输的数据量,加快传输速度。
第四个优化是CDN加速。前端的静态资源都放到了CDN上,用户访问的时候从最近的节点获取,加载速度快了很多。
通过这些优化,网络传输的耗时从1.5秒降到了0.3秒左右。
优化三:前后端处理优化
前后端的处理虽然占比不高,但也有优化的空间。
第一个优化是上下文裁剪。AI编程需要把用户的代码上下文传给大模型,包括当前文件的内容、相关文件的内容、项目的结构等。如果上下文太长,不仅传输慢,大模型处理也慢。我们做了上下文裁剪,只把最相关的内容传给大模型,去掉了无关的内容。这样既减少了传输量,也提高了大模型的处理速度。
第二个优化是异步处理。对于一些不需要实时返回的操作,比如代码审查、文档生成,我们改成了异步处理。用户提交请求之后,立刻返回一个任务ID,后台慢慢处理,处理完了再通知用户。这样用户不需要等待,体验好了很多。
第三个优化是前端渲染优化。前端在展示大模型返回的代码的时候,需要做语法高亮。如果代码很长,语法高亮会比较慢,导致页面卡顿。我们做了虚拟滚动,只渲染可视区域的代码,不渲染全部内容。这样不管代码多长,渲染都很快。
第四个优化是预加载。我们在用户输入代码的时候,就提前预测用户可能需要的补全,预加载一些常见的结果。等用户真正触发补全的时候,结果已经准备好了,能立刻返回。
通过这些优化,前后端处理的耗时从1.5秒降到了0.2秒左右。
优化四:架构层面的优化
除了上面这些具体的优化,我们还在架构层面做了一些调整。
第一个是微服务拆分。以前我们的系统是一个单体应用,所有功能都在一起。后来我们拆成了多个微服务,代码补全、单元测试生成、代码审查,每个功能一个服务。这样每个服务可以独立扩展,哪个功能压力大就扩容哪个,资源利用更合理。
第二个是负载均衡。我们在大模型API前面加了一层负载均衡,把请求分发到多个模型实例上。这样不会因为某个实例过载而导致请求变慢,整体的吞吐量也提高了。
第三个是降级机制。我们加了降级机制,当系统负载高的时候,自动降低一些非核心功能的质量,比如减少上下文的长度、用更小的模型,保证核心功能的响应速度。等负载降下来了,再恢复正常。
第四个是监控和告警。我们建立了完善的监控体系,实时监控每个环节的耗时、错误率、吞吐量。一旦出现异常,立刻告警,及时处理。这样能在问题影响用户之前就发现并解决。
优化效果
经过一个月的优化,效果很明显。
平均响应时间从8秒降到了1.5秒,降了80%多。首字响应时间从3秒降到了0.5秒,用户感知上快了很多。
系统的吞吐量也提高了,以前每秒只能处理10个请求,现在能处理50个。服务器的资源利用率也更合理了,不会出现有的服务器忙死、有的闲死的情况。
用户满意度大幅提升,以前很多用户抱怨太慢,现在都说体验很好。用户的留存率和使用频率也提高了不少。
当然,优化是无止境的。我们还在持续做优化,希望能把响应时间降到1秒以内。
性能优化的经验
这次性能优化,给了我很多经验。
第一个经验是,先测量再优化。不要凭感觉去优化,一定要先做详细的性能分析,找到真正的瓶颈。把时间花在真正的瓶颈上,才能事半功倍。
第二个经验是,用户感知比绝对速度更重要。有时候总耗时没变,但通过流式输出、预加载等方式,让用户觉得快了,体验就好了。性能优化不只是追求数字,更要追求用户体验。
第三个经验是,分层优化。性能问题往往不是一个地方造成的,而是各个环节都有。要从前端到后端,从网络到模型,全流程地优化,才能取得最好的效果。
第四个经验是,缓存是个好东西。很多AI应用的请求都是重复的或者相似的,加个缓存就能大幅提升性能。不要小看缓存,它往往是性价比最高的优化手段。
第五个经验是,架构要可扩展。AI应用的流量波动很大,有时候突然就来了很多请求。架构要能弹性扩展,能根据负载自动扩容缩容,这样才能在高峰期也保持好的性能。
写在最后
AI应用的性能优化,和传统应用不太一样。大模型的推理耗时是最大的瓶颈,而且很难通过传统的优化手段来解决。需要从模型选型、流式输出、缓存、架构等多个方面来综合优化。
但只要方法对了,AI应用也能做到很快的响应速度。我们的系统从8秒优化到1.5秒,就是一个证明。
如果你也在做AI应用,遇到了性能问题,不要急,先测量,找到瓶颈,然后针对性地优化。一步一步来,总能把性能提上去的。
最后用一句话来结束这篇文章:"性能优化不是一次性的工作,而是一个持续的过程。"
愿每一个做AI应用的工程师,都能做出又快又好用的产品。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录