最近我们的项目接入了GPT-4o的多模态能力,用来处理图片理解和图文混合输入的任务。
刚接入的时候,响应速度很慢,一次请求经常要等十几秒甚至更久,用户体验很差。经过一系列优化,我们把平均响应时间从12秒降到了2秒左右,提升了6倍。
这篇文章,我想分享一下这次性能优化的实战经验,包括我们遇到的问题、采取的优化手段,以及最终的效果。
背景
先说说项目背景。
我们的产品是一个智能文档处理系统,用户上传图片或者PDF之后,系统会用GPT-4o的多模态能力来理解图片内容,提取关键信息,然后生成结构化的结果。
这个功能对响应速度要求比较高。用户上传图片之后,希望能在几秒内看到结果。如果等十几秒,用户就会觉得系统很慢,体验不好。
刚接入GPT-4o的时候,我们直接用了官方的API,参数都是默认的。测试的时候发现,平均响应时间在12秒左右,最慢的时候甚至超过20秒。这个速度完全达不到产品要求。
于是,我们开始了性能优化的过程。
第一步:分析瓶颈
优化的第一步,是搞清楚时间都花在哪里了。
我们给请求加了详细的日志,记录每个阶段的耗时:图片上传、API请求建立连接、首token返回、完整响应返回。
分析之后发现,时间主要花在两个地方:
第一个是图片传输的时间。GPT-4o的多模态API需要把图片转成base64编码,然后放在请求体里发送。一张几MB的图片,base64之后会更大,传输需要时间。尤其是在网络不好的情况下,传输时间占比很高。
第二个是模型推理的时间。GPT-4o处理图片和文本的混合输入,推理本身就需要时间。图片越复杂、输入的token越多,推理时间越长。
还有一个发现是,API的响应是流式返回的。首token返回的时间大概是3-5秒,之后的token逐个返回。如果能利用流式响应,用户体验会好很多。
第二步:图片优化
针对图片传输的问题,我们做了几个优化。
第一个优化是图片压缩。用户上传的图片往往很大,尤其是手机拍的照片,一张就有好几MB。但GPT-4o处理图片的时候,并不需要这么高的分辨率。我们在上传之前,先把图片压缩到合适的尺寸,最长边不超过2048像素,质量调到85%。这样处理之后,图片大小从几MB降到了几百KB,传输时间大大减少。
第二个优化是图片格式转换。我们把图片统一转成JPEG格式。JPEG的压缩率比较高,而且GPT-4o对JPEG的支持很好。相比PNG,JPEG的文件大小要小很多。
第三个优化是使用URL而不是base64。GPT-4o的API支持两种图片输入方式:一种是base64编码,另一种是图片URL。如果图片已经在公网上可以访问,直接传URL比传base64更高效,因为不需要把图片数据放在请求体里。我们把用户上传的图片先存到对象存储,然后把URL传给API,这样请求体就小了很多。
这三个优化做完之后,图片传输的时间从平均3秒降到了0.5秒左右,效果很明显。
第三步:请求优化
针对API请求本身,我们也做了一些优化。
第一个优化是合理设置maxtokens。默认的maxtokens很大,模型会生成很长的回复。但我们的场景只需要提取关键信息,不需要很长的输出。我们把max_tokens调到了合适的值(根据任务类型,一般在200-500之间),这样模型生成的时间就减少了。
第二个优化是使用更高效的prompt。我们发现,prompt的长度和结构对响应时间也有影响。简洁明了的prompt,比冗长复杂的prompt响应更快。我们对prompt做了精简,去掉了不必要的说明,只保留核心指令。同时,我们用了结构化的prompt模板,让模型更容易理解和执行。
第三个优化是使用temperature=0。我们的任务是信息提取,需要稳定准确的结果,不需要创造性。把temperature设为0,可以让模型的输出更稳定,同时也能稍微加快响应速度。
第四个优化是合理使用system prompt。system prompt可以设置模型的角色和行为,但过长的system prompt会增加输入token,影响响应速度。我们把system prompt控制在合理的长度,只包含必要的角色设定和规则。
第四步:流式响应
前面提到,GPT-4o的API支持流式响应。利用流式响应,可以大幅改善用户体验。
之前我们是等完整响应返回之后,再把结果展示给用户。这样用户要等十几秒才能看到任何内容。改成流式响应之后,首token返回之后就开始逐字显示结果,用户3-5秒就能看到内容开始生成,虽然完整结果还是需要等,但感知上快了很多。
实现流式响应也不复杂,用SSE(Server-Sent Events)把API的流式输出转发给前端,前端逐字渲染就可以了。我们用的是OpenAI官方的SDK,它原生支持流式响应,处理起来很方便。
流式响应还有一个好处是,可以提前取消。如果用户发现结果不对,或者不想等了,可以随时取消请求,节省资源。
第五步:缓存策略
对于一些重复的请求,我们加了缓存。
比如,用户上传同一张图片,或者请求相同的内容,我们会把结果缓存起来。下次再请求的时候,直接返回缓存的结果,不需要再调用API。
缓存的key是根据图片的hash和prompt的内容生成的。如果图片和prompt都一样,就直接返回缓存。缓存的有效期设为24小时,因为模型可能会更新,结果可能会变化。
加了缓存之后,对于重复请求,响应时间从十几秒降到了几十毫秒,效果非常好。在我们的场景中,大约有20%的请求是重复的,缓存命中率还不错。
第六步:并发和队列
对于批量处理的场景,我们做了并发和队列处理。
用户有时候会一次上传很多张图片,需要批量处理。如果一张一张顺序处理,总时间会很长。我们用了并发处理,同时处理多张图片。
但并发也不能太高,因为API有速率限制。我们根据API的速率限制,设置了合理的并发数(一般是3-5个并发),同时用队列来管理任务,确保不会超过速率限制。
对于超过并发数的任务,放在队列里等待。用户可以看到处理进度,知道还有多少张在排队。这样既充分利用了API的能力,又不会因为超过速率限制而被限流。
第七步:模型选择
最后一个优化是模型选择。
GPT-4o虽然能力强,但响应速度相对慢一些。对于一些简单的任务,比如只需要识别图片中的文字,或者做简单的分类,其实不需要用GPT-4o,可以用更轻量的模型。
我们做了一个路由层,根据任务的复杂度选择合适的模型。简单的任务用GPT-4o mini或者其他轻量模型,复杂的任务才用GPT-4o。这样既保证了效果,又提升了整体的响应速度。
在我们的场景中,大约有40%的任务可以用轻量模型处理,这些任务的响应时间从12秒降到了3秒左右。
优化效果
经过以上这些优化,我们的系统响应速度有了很大的提升。
优化前:
- 平均响应时间:12秒
- 首token时间:5秒
- 最慢响应时间:25秒
优化后:
- 平均响应时间:2秒(含缓存命中)
- 首token时间:1.5秒
- 最慢响应时间:8秒
- 缓存命中响应时间:50毫秒
整体响应速度提升了6倍,用户体验有了质的飞跃。用户上传图片之后,很快就能看到结果,不再需要漫长的等待。
一些经验总结
这次优化过程中,我总结了一些经验。
第一,先测量再优化。不要凭感觉优化,一定要先测量,找到真正的瓶颈。我们一开始以为是模型推理慢,测量之后才发现图片传输也占了很大比例。
第二,从用户感知的角度优化。有时候,实际响应时间没有变,但用户感知变快了,体验就好了很多。流式响应就是一个很好的例子。
第三,合理利用缓存。缓存是提升性能最简单有效的手段之一。只要有重复请求,缓存就能带来巨大的提升。
第四,不要盲目追求最强的模型。根据任务需求选择合适的模型,简单任务用轻量模型,复杂任务用强模型,这样性价比最高。
第五,关注API的限制。速率限制、token限制、图片大小限制,这些都要考虑到。合理设计并发和队列,避免被限流。
第六,持续监控和优化。性能优化不是一次性的工作,需要持续监控,发现新的瓶颈,持续优化。
写在最后
GPT-4o的多模态能力很强大,但要用好它,不仅要会调用API,还要做好性能优化。
通过图片优化、请求优化、流式响应、缓存、并发处理和模型选择,我们把响应时间从12秒降到了2秒,用户体验有了很大提升。
希望这篇文章能给正在使用GPT-4o多模态能力的朋友一些参考。如果你也有性能优化的经验,欢迎在评论区交流。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录