前言
这是我之前为了配合业务需求(公司的想法)将大模型私有化部署到生产环境的探索和实践,其中也是有一些细节值得记录下来的。
主要是记录下,我如何用很低的成本完成这个过程的。
背景与需求
目前在职的公司有做短信相关的业务,其中一个重点环节,就是诈骗短信的过滤。尤其是现在全民防诈,诈骗短信的识别和拦截便更重要了。
因此,在我司应用大模型的主要场景就是诈骗短信的识别。
对于我来说,想要落地这个方案的难点,不只是大模型识别的准确率,还有其它如下:
- 没有GPU服务器,且可以使用的CPU服务器的资源也有限,部署大模型的硬件环境受限
- 模型的性能要高,如果识别一条短信的耗时在十几秒甚至几十秒,则无法使用
- 考虑数据安全及成本,不能调用大模型厂商的API
- 生产环境带宽有限,每次训练一个服务后传输验证要花很多时间
- 还有一些其它坑会在后文中涉及到时说明
领导最初是想所有短信都过大模型。我当时想的是大模型作为兜底手段,减少人工审核的成本。
对,你没看错,是有人工审核的,因为目前的手段不太好保证,短信都能正常识别能否下发,所以有人工审核。这里也不只是诈骗短信,也指的是其它场景,细节不说。
我之前对于机器学习和深度学习也有一点研究和实践,因此对于在cpu上跑这些模型的性能,心中还是有点数的。所以我的想法是把关键字识别、域名检测、机器学习、深度学习、大模型识别、人工审核等等手段根据不同的请求延迟和性能,针对不同的场景进行编排。毕竟短信还是个请求延迟相对敏感的业务,如果处理太久,体验还是蛮差的。
不过,看起来领导是不接受这个方案。
所以,现在出现了这个需求:CPU服务器、大模型识别诈骗短信、延迟不能太高、性能还得尽量跟上。
实践
模型选择
deepseek-r1这种肯定不选,原因有二:
- 我用的环境运行不了这么大的模型
- 这种推理类模型不适合这个场景,推理类的模型有一个思考的过程,耗时太长
因此,过大的模型,比如7b及以上的模型,还有推理类的模型,都不在选型范围。在cpu环境下,越小的模型每秒处理的的token数越多,对于一条几十到数百字的短信,自然也是输入+输出的token数,越少,这个识别的过程越快。
所以,选型侧重于传统的中小模型。
选型初期,Qwen3还没正式发布,我以Qwen2.5系列为主。 因为7b及7b以上的模型都不考虑,在cpu上运行,模型太大性能真的是个问题。
那问题来了,7b以下的准确率很低。相当低。
1.5的模型(占用两个cpu核)预测一条不太长的短信,大概2-3秒,我如果想增加吞吐,部署几十个进程即可。但1.5b的准确率,几乎没有准确率。。。
要解决这个准确率,并保持性能,只有:微调+量化。
我使用Qwen2.5的1.5b和3b的instruct模型进行微调(使用base模型发现效果相对instruct更差点)。
提示词
提示词大概如下:
请判断以下短信是否为诈骗短信, 请返回诈骗短信的概率值, 除了概率值,其它内容都不要返回, 短信内容:xxxx
我的方案是让大模型返回一个诈骗短信的概率,如果概率很高,就认为是诈骗短信,如果很低就认为是正常短信,如果不高不低(有个上下阈值),就认为未知,交由其它环境处理,比如人工审核。
提示词要尽可能短,如果提示词太长,处理耗时也会相应增加。
微调
样本准备
历史积累的诈骗短信+其它类型的短信,准备了几万条。
然后调用deepseek-v3的api,给我识别,就是按我的提示词返回一个概率值。我再使用脚本进行整理。没有使用ds-r1的原因,还是前面说的,推理类的模型太慢,准备这些样本就会花很多时间。这里我可是充钱了,前后调用API花了快10块钱吧。
但是在这一步,我才发现最难的地方: 即使用这种大模型,它的准确率才50%。我当时就在怀疑,我即使微调小模型,又能有多高的准确率。至于为什么这些大模型准确率也没预期的高,我分析了下,但不是本文重点,忽略。
我写脚本整理过滤之后,保留了17000条、9000条、4000条、2000条等几种情况。
LlamaFactory
用的github.com/hiyouga/LLa… 进行微调。
这个东西怎么用,不是一两句话可以说明白,但是github的文档说的可太清楚了,建议小白仔细看几遍,就直接上手即可。而且也确实方便,使用的入门门槛低。想用好另说。
微调环境
微调肯定是用GPU服务器了,如果是CPU服务器,可以放弃了,一个1.5b的小模型,几千个样本,都不知道要多少天。
服务器是某个云厂商的,在网上搜到,新用户有个活动。所以,为了省钱,就买了几天这个服务器。
这几种卡,除了3080Ti都用过,RTX40系和T4这两张卡,我试过,都可以用来微调。3080Ti应该也是可以,我没验证过。
P40去年使用bert预训练过。但是能否在我的场景(微调大模型)下使用(推理是一定可以用的),我也不太确定。我问了大模型,得到的回复是部分数据结构好像不太支持(这个我不确认)。但是为了保险起见,最终我用的是T4这张卡来微调的。
微调方式
我最终是使用lora微调。
也尝试过使用0.5b的全参微调,可能是模型太小,结果很不预期。
lora微调Qwen2.5-3b的模型,内存占用最多的时候13G多吧,我有点记不清楚了。1.5b应该是7~9G。全参就别想了。
微调参数
对于不同的样本数,微调方式,预计的内存占用等情况也挺多的,参数的配置也不太一样。
llamafactory的参数介绍:llamafactory.readthedocs.io/zh-cn/lates…
在样本数不足5000的时候,我配置的训练轮数是5~6轮,学习率:5e-6。样本数在1~2万的时候,训练轮数我一般设置为了2~3轮,学习率: 5e-5。
显存就16G,1.5b的模型,批量大小及截断长度都是默认的或者(截断长度1024)。使用3b的模型的时候这两个参数都对应调小的,怕内存不足。
Lora+的学习比例,我也是根据样本数分别设置了8、16、32微调验证吧。
等等等等。
模型保存
模型导出后,要先在训练的服务器上测试下准确率,验证下效果,看效果O不OK。
准确率感觉可以了,就要用实际的CPU配置来验证性能了,但是公司的生产环境带宽有限,一个模型1~5G,在不确定最终结果前,我也不太想往生产环境验证上传部署验证,耽误时间,又占用生产带宽。
我家里有个好几年前的笔记本,淘汰下来的,CPU是7代i7,我把硬盘换个固态盘,加个内存条(弄到了16G),做个内网穿透,就相当于是我随身背了个小服务器。内网转发流量用的服务器,是我在阿里云买的99/年的,配置低,带宽还凑合,正好干这个。
我家里的网速也行,我就把云服务器训练好的模型,使用llama.cpp的脚本转换为ollama要的格式,再拉到家里的服务器上,在公司我也能直接验证了(真相当于付费上班了)。
运行环境的选择
首先,排除transformers,性能很低,试了下真的很低,至于量化后再配合CPU加速插件效果怎样,没有验证。
其次,VLLM用不了,没GPU。
相对llama.cpp,我直接用ollama,更方便点。初期我还用llama.cpp量化,再注册到ollama,后来,我直接用ollama量化了。
其实我现在日常用的这个笔记本还是有个3050ti的卡,有时候一个小模型推理还能凑合用下。
安装ollama
在linux上直接安装ollama,在我们的生产环境不太方便,但是可以手动安装:github.com/ollama/olla…
量化
1.5b的模型我是量化q8,小一半。
后来在实际生产验证后发现1.5b的准确性还是不太预期。后来就开始尝试3b的模型,但是资源占用多了,预测耗时反而增加了,干脆用ollama量化为q4_k_m,也将将达到预期。
比1.5b的资源占用也就多200M内存,性能差不多,准确率提高了不少。
生产实践
权衡准确性和性能,模型的大小和量化,我基本做到了极致。但是这种情况下,预一条短信1条大概耗时在1-2秒(占用2个CPU),慢的话也可能超过3秒。
我的解决方案是多进程提高并发,ollama进程多开,每个进程的cpu使用限制到300%以内(占用3个核),预测耗时快的话能低于1秒(3b的模型哦~)。
然后,又写了个负载均衡器,没有考虑直接使用相关的开源网关。因为要避免阻塞,每次请求的时候,我的负载均衡器,会遍历当前的ollama server服务,看哪个ollama server的连接是闲置的,如果遍历一轮都没有闲置的,直接进入下面的流程,不要阻塞在这里。
判断是否闲置也很简单,就相当于写了个分布式的连接池,每个请求获取到连接的时候,锁定资源。用完释放。
末语
其实中间还是有很多坑的,但是这一整套方案的验证,我确实没有花太多机器成本,但投入的时间还是花了好几天的,有时候传输个模型至少半天,时间就这样过去了。微调训练也是需要不少时间的。
另外上面那版提示词,是我最开始考虑的方案,在实际场景中验证了几天,发现效果还不太理想。现实场景的短信还是太多样化。所以后面又调整了一版方案和实现,整个提示词和推理思路都换了,这一版最终也算勉强达到效果了。
至于网络上问题不大,我个人在网络的原理及实操上还是有些心得,所以这方面问题不大,至于什么网络问题,懂的自然懂。