结合架构设计范式讲清大模型copilot推理高并发架构设计

文摘   2024-07-31 11:45   陕西  

    说起当前阶段大模型在研发领域应用的发展趋势,目前大家公认的一般可以分为辅助智能-》部分智能-》高度智能-》成熟智能-》完全智能等几个阶段,基本上可以概括为:

    1、以人为核心牵动整个工作流,AI作为助手辅助人开展工作,常见的比如chat方式。

   2、人和AI无缝衔接,完成浸入式工作,最典型的就是目前大行其道的copilot方式。

   3、以AI为主体,人提供辅助和参与评审,最典型的是多智能体协作方式。

    当前主要集中在人和AI无缝衔接阶段,从软件编程中日常新增代码这一个活动看,目前copilot是当前阶段性价比最高的实践。

    copilot的本质其实还是通过动态prompt的方式跟大模型交互,通过自动感知IDE打开文件光标附件的代码上下文和加载的工程中其他文件信息,并有机结合外挂知识库(通过多级缓存),拼接详尽的场景化prompt喂给大模型,从而获得大模型更精准的输出,其实是更加自动化生成动态更加精细化prompt的chat。

    考虑到私域知识的安全性、网络效率等要求,公网的很多copilot插件在公司内使用会受限,这就需要自研或私域部署copilot服务,我们需要进行copilot规模高并发推理的系统架构设计。

    这里我们先抛出一个系统架构设计的第一性原理:脱离业务场景的架构设计都是耍流氓。

    后续我们要牢记这条原理。

    大型服务系统的架构设计需要按照下列5步法模式开展:

    明确问题-》估算容量-》建立模型-》设计核心数据结构-》选择算法

一、明确问题

1、确认目标    

    对于copilot应用来说,好用的关键有两点:

    a、丝滑

    即补全速度要快,低时延

    b、准确性高

    即采纳率要高。

    我们这里聚焦低时延,采纳率取决模型能力、代码光标附件上下文动态提示词组装、知识库等,参加另外的文章。

    对于低时延的目标,结合代码补全的场景,需要满足在输入输出token数的低时延的要求下,追求最新请求的高成功率,大我们给出:

    a、时延&并发度

    对于高并发,低延时的服务,业务约束于话务模型,话务模型主要由以下维度决定: 单会话时延、并发度(qpm,大模型推理一般用分钟级别进行估算),见下表:

   

    b、成功率

    我们是追求哪个目标:

    所有补全请求都要处理成功?


    系统吞吐量最大?

    

    系统周转率最大?

      

    。。。。

    

    大家可以思考下,后面会有答案(提示:目标一定不能脱离具体的使用场景)。


2、给出约束

    a、补全服务的并发极限是所有开发人员同一时间触发补全。

    b、推理服务极限是资金预算内所有卡批次都同时跑满。

    a是并发度上限,b一般是小于a的;正常场景下,b也是跑不满的。

3、设定观察指标

    这个要结合目标给出,可以不是很全面,但是一定要有,这里先卖个关子,后面给出。

    

二、估算容量    

    服务集群规模、计算资源规模(这里最核心的是GPU推理卡的数量)、存储规模,一般要考虑近两年的业务发展(2年内业务如果火了,就大规模扩容;否者就要下线了。

    其中实时续写占比80%以上,我们以实时续写为样例,展示下估算的过程:

    公司2024年人均日代码行65行(DT数据,未刨除开源组件、测试代码、配置文件等),另外电信行业/系统软件人均日代码行数75-120(来自《软件估算-黑匣子揭秘》,基本对应),按65行算;每行平均申请1次(每个单词停顿500ms就会触发一次补全请求,但是客户端无效请求拦截+客户端/服务端/推理缓存可以拦截50-75%的请求),这样共65次请求,公司按12000开发人员计算,共780000次请求;峰值请求集中在上午9-11点和下午2-4点之间,共4个小时,240分钟;780000/240=3250qpm;峰值因子一般为3,也就是极端峰值为9750qpm。

    有了单会话时延和流量单元(2k(输入)+0.05k(输出)),再根据模型大小(7b)+单卡(A40、壁韧104s、寒武纪x2000,h20等)在不同TP和最优batchsize下的推理qpm,即可以推算出所需gpu的数量。具体实测数据较多,这里就不一一罗列了。

三、建立模型

    一般大模型推理应用都是求高吞吐率,具体的做法如下:

    考虑单次推理中一般prefill占比较低(prefill单字后持续decode)且prefill和decode不能并行,需要尽可能优先处理每个批次中的prefill,然后再并行处理decode,这样整体才能达到较高的吞吐率(见下图上半部分),这就会造成老的batch中decode尚未完成,新的batch中的请求会打断老的decode,先进行新batch的prefill,从而造成老的请求的时延会增长。

    高并发场景下,打断是非常频繁的,造成平均请求时延大幅增加。

    而补全场景中,追求的是低时延,即满足时延的周转率,需要保证一个一个batch的decode完成后,再承接下一个batch,decode过程不能被打断,加快周转;见下图下半部分。

    

   

    这样做的不足是稀疏请求数量,即降低batchsize,极端场景下可以降低到1(视GPU能力)。

    设计本质是紧密贴合业务。所有的取舍也要以此为依据。

    由于该种情况下,单请求推理过程不能被打断,就需求在推理服务前加一个schedule。

    这个schedule是整个推理集群低时延设计的关键。

    这里的业务约束是输入输出token 2k+0.05k前提下时延<600ms,尽可能提升业务补全率。

    数学模型:典型的生产者消费者模式

四、设计核心数据结构

    这里数据结构请大家想想设计成什么样呢?即上图的内存缓冲区。

    这里停顿10秒,留一屏空白,请大家思考下再回答。

    --------------------------------------------------------------




































 --------------------------------------------------------------

    恭喜你答对了,这里选用的核心数据结构是stack。

    为什么选stack而不是其他数据结构呢?

    还是要回头看细分业务约束,代码补全场景并不需要所有的请求都能够成功处理,而是要保证最新的请求能够成功处理,即保障最新请求的成功率。

    why?

    因为从用户的角度看,每次代码补全请求都有个时间窗(500ms左右),超时后用户光标很大概率已经移到了别处并触发了新的补全请求,老的超时的请求没有任何意义了。

    大家仔细品味下这个具体业务场景,自然就会选用stack。

    到这里我们给出第一部分中目标的设定:

    a、补全请求时延模型侧<600ms

    b、补全请求成功率:80%

五、算法

    补全请求上来后,schedule发现推理集群有空余,就直接转发请求进行推理;如果发现推理集群全忙,就入stack;推理集群有空余且stack中有推理请求时,弹出请求处理(缓存的最新请求)。

    对stack中的请求增加老化机制,超过时限(比如100ms)的都清除掉即可,超时请求处理了也没有应用价值了。

    小结,大型服务系统架构设计,首先要确定业务目标,然后进行估算容量,接着再设计数学模型、设计核心数据结构,最后选择算法这5步。

    这个过程中,需要谨记结合业务场景,任何脱离业务场景的架构设计就是耍流氓

丁辉的软件架构说
代码匠艺,软件系统架构,AI平台和应用,生活趣事。
 最新文章