说起当前阶段大模型在研发领域应用的发展趋势,目前大家公认的一般可以分为辅助智能-》部分智能-》高度智能-》成熟智能-》完全智能等几个阶段,基本上可以概括为:
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步。
这个过程中,需要谨记结合业务场景,任何脱离业务场景的架构设计就是耍流氓。