llama.cpp 运行多个模型

模型与算力

讲清用 llama.cpp 同时跑多个本地模型的几种做法:多实例、路由字段、端口与显存分配,以及怎么测出自己机器的并发上限。

你可能已经能用 llama.cpp 跑起一个模型,但想让它同时伺候两个活:一个专门写代码,一个做中文问答,来回切换太烦。或者团队几个人共用一个端口,谁都不想排队。这篇不讲 llama.cpp 是什么,只讲多模型并存怎么配、显存和端口怎么分、哪里容易翻车,以及怎么量出你这台机器真正扛得住几个。

你可能已经能用 llama.cpp 把一个模型跑起来,但想让它同时伺候两个活:一个专门写代码,一个做中文问答,来回切换太烦。或者团队几个人共用一个端口,谁都不想排队。这篇不讲 llama.cpp 是什么,只讲多模型并存怎么配、显存和端口怎么分、哪里容易翻车,以及怎么量出你这台机器真正扛得住几个。

核心思路是:先把需求分堆,再选实现方式,最后用量化过的资源数字决定开几个实例。顺序错了,后面全在返工。下面按「先想清楚需求→两种实现套路→资源怎么算→脚本与自查→调用方怎么找模型→什么时候别折腾」走一遍。

先想清楚你是「同时用」还是「随时切」

多模型这件事,最容易犯的错是把三种完全不同的需求当成一个问题。第一种是多模型同时常驻,两个模型都要随时能响应;第二种是按需切换加载,平时只跑一个,要用另一个时再换;第三种是多用户各自要不同模型,本质上是个调度和排队问题。这三者的配置方式、资源占用、翻车点都不一样,方案不能互借。

同时常驻
每个模型都占着显存待命,吃的是显存总量,响应快但资源不能复用
按需切换
同一份显存轮流装不同模型,吃的是加载时间,省显存但每次换模型都要等
多用户各自要模型
本质是排队和配额问题,光靠多开实例解决不了,需要在调用方或网关层做调度

建议先把任务分堆:长文本处理、代码生成、轻量对话各归一类,再看这些任务能不能压到同一个模型上。很多时候你以为是两个模型的活,其实一个模型加不同的提示词模板就能覆盖。什么情况下这条不适用:只固定用一个模型,或者机器显存只够装一个模型时,做多模型调度纯属自找麻烦,先把单模型跑顺更有价值。

套路一:一个进程一个模型,多个端口并排跑

最直接的做法是每个模型起一个独立进程,各自绑不同端口、加载不同模型文件。互不干扰是最大的好处:某个实例崩了不影响另一个,排查时能单独重启、单独看日志,出问题定位成本最低。对个人开发者和小团队来说,这是出错率最低的一种方式。

要注意的是参数别用默认值。上下文长度和显存卸载层数一定要显式写出来,否则默认值很可能把整张卡占满,导致第二个实例根本起不来,报错信息还未必直白。模型文件建议分目录放,命名带上量化档位和用途,比如用目录名区分代码模型和对话模型,不然过两周自己都分不清在跑哪个。

配置维度做法不这么做的后果
端口每个实例绑不同端口,按用途或编号分段端口撞车,后起的实例直接失败
模型路径分目录存放,目录名体现用途和量化档位分不清在跑哪个模型,改错文件
上下文长度按实际需要显式指定,不要用默认最大值显存被 KV 缓存吃掉,第二个实例起不来
显存卸载层数按单卡可用显存算出合适层数并写进命令要么浪费显存,要么部分层留在内存拖慢速度

这种方式的短板是资源不共享:两个实例各自的 KV 缓存是各算各的,哪怕请求量很小,显存也是按最大上下文预留。所以它适合模型个数不多、显存有余量的场景,不适合把一整张卡塞满还要硬开五六个进程。

套路二:一个服务托管多个模型,靠请求字段切换

另一种做法是一个服务进程挂多个模型,只暴露一个端口,客户端在请求字段里指定要用哪个模型。接进现有应用时这种方式最省事,调用方不用记住一堆端口,也方便统一加日志和鉴权。代价是服务端要处理模型加载和切换,行为没多实例那么透明。

  • 切换开销要提前知道:不在显存里的模型被请求时要先加载,这一个请求会卡住,客户端超时要设得足够宽松
  • 常驻与否要手动控制,否则会出现「越用越慢、越用越占显存」的现象,看起来像内存泄漏,其实是模型没被释放
  • 并发一高,多个请求同时抢同一份显存和算力,容易互相拖累,表现是整体变慢而不是单个报错
  • 适合请求量不大、模型个数不多的场景;如果你是多个用户高频使用,多实例或外部接口往往更稳

判断标准可以简化成两句:如果你需要精确控制每个模型占多少显存、什么时候释放,多实例更合适;如果你更在意调用方接口统一、不想维护端口映射,单服务多模型更合适。两边都不是绝对好,取决于你是资源紧张还是运维精力紧张。

显存、端口、并发三件事怎么算

显存是这整件事的硬约束,算不清就会反复失败。粗算逻辑是:单模型占用约等于模型权重的显存占用加上 KV 缓存的开销。权重占用主要看量化档位,KV 缓存随上下文长度线性增长,上下文开得越大,缓存部分的占比越可观。两项相加才是真实占用量,具体换算到站内工具页对着输入算一遍,别凭印象估。

  1. 第一步:算单模型占用按量化档位估权重占用,再加上按上下文长度算出的 KV 缓存,两项相加。具体数值到站内显存与耗时测算页面填参数核对。
  2. 第二步:留余量再分配多个实例并排时,总占用别贴着卡的上限配,给系统和其它程序留出余量,否则跑一段时间后容易因为碎片或临时峰值挂掉。
  3. 第三步:规划端口按模型用途或编号分段,把端口和模型的对应关系写进启动脚本的注释里,不然一周后没人能说清哪个端口是谁。
  4. 第四步:验证并发上限先开一个实例压一压,观察延迟变化,再逐步加实例,找到延迟开始明显恶化的那个点,那就是你这台机器的实际并发上限。别一次开满再回头猜哪里不够。

并发不是靠「多开几个」堆出来的。同一张卡上的多个实例会互相抢算力,总吞吐未必随实例数线性增长,很可能开两个比开一个快一点,开四个反而比两个还慢。到站内接口测速页面按模型和量化档位实际量一遍,再决定开几个,比拍脑袋靠谱。

启动脚本与状态自查清单

多模型运行最容易乱在启动环节。建议把启动命令收进一个脚本,每个实例一行,参数里带上模型路径、端口、上下文长度、卸载层数这几项。这样改配置只改一处,回滚也有依据,不用去翻历史命令。

  • 逐个启动、逐个确认:端口能通、模型名对得上、发一条短请求能正常出字,确认一个再起下一个
  • 不要四个实例一起启动再一起排查,出问题时根本分不清是哪个实例的问题
  • 记一次冷启动耗时和首次响应耗时,作为一个基线值,之后变慢时能对比出是模型变复杂还是机器变忙
  • 显存占用和响应延迟定期量一下,用系统工具或站内接口测速页面都行,别等用户来报慢才发现
  • 把每个实例的用途写在脚本注释里,谁接手都能看懂,这一步比事后调参省事得多

监控不必做得很重,关键是把「正常长什么样」记录下来。有了基线,异常判断就简单了:延迟在同一模型同一参数下明显偏离基线,多半是实例互相抢资源或者系统在干别的活。

先量一遍你的机器与其猜能开几个实例,不如到站内测算页面按你的模型和量化档位跑一遍,拿到单模型占用和延迟数字,再决定并行几个。

让调用方知道该找哪个模型

多个模型跑起来之后,下一个问题是谁该用哪个。最省事的办法是在应用侧维护一张极简映射表:任务类型对应到端口或模型名,写死在一个地方,别散落在各个脚本和分支里。表越小越好维护,能三行说清就别写成三十行。

任务类型对应目标兜底策略
代码补全与改写代码模型所在实例该实例无响应时退到通用对话实例
中文问答与总结对话模型所在实例退到代码实例或直接返回排队提示
长文本处理长上下文实例上下文超限时截断并提示调用方
临时小请求轻量实例直接复用任一空闲实例

加一条兜底规则很有必要:目标模型实例挂了就退到备用实例,哪怕效果差一点,也好过直接报错让整个功能不可用。同时给每个模型写一句用途说明和已知短板,比如某模型中文不错但长文本容易丢信息,写清楚之后接手的人不用靠试错去猜。不适用的情形也说一句:如果任务本身对模型差异不敏感,多模型路由带来的复杂度可能大于收益,那就别硬做路由。

什么时候别折腾多模型,直接换更省事的路

多模型不是默认更优的方案,它是在特定条件下才划算。显存只够跑一个模型又要随时切,说明这台机器该升级,或者该考虑把部分请求放到外部接口,而不是在本地硬挤出第二个实例。这属于硬件边界问题,靠配置技巧绕不过去。

  • 模型之间的差异只在中文表达或格式偏好上:优先用提示词约束单模型,多开实例收益有限
  • 多用户共享且要求互不干扰:这需要排队和配额机制,不是 llama.cpp 层面能解决的,得在网关或应用层做
  • 任务对模型差异不敏感:用一个模型加不同模板更简单,路由反而增加故障面
  • 切换频率低、每次只用一个模型:按需切换就够了,常驻多个实例纯浪费显存
把判断标准写下来:切换频率、显存余量、并发要求三项里有两项不满足,就别上多实例,先把单实例调稳。

最后留一个自查习惯:每加一个模型之前,先问自己这次加它是为了解决哪个具体问题,以及这个问题单模型加提示词能不能解决。能解决就不加,解决不了再加。这样多模型配置才不会越滚越乱,也更容易在出问题时快速回退。价格、能力这些会变的数字,统一到站内价格与模型资料页面核对当时的数值,别照抄别人文章里的旧数据。

常见问题

llama.cpp 能同时加载两个模型吗?

看具体实现和版本,有的服务端支持一次挂多个模型,有的只能一个进程一个模型。稳妥的做法是先确认你用的服务端参数支不支持模型列表,不支持就用多实例多端口的方式,效果一样,只是各自占显存,改起来更直观。

同时跑多个模型会很吃显存吗?

吃的是每个模型自身占用加上各自 KV 缓存的总和,上下文设得越长,缓存占得越多。所以开几个模型不是拍脑袋定的,要按量化档位和上下文长度算总量,再到站内部署测算页面把数字对一遍,留出余量再启动。

多实例会不会让每个模型都变慢?

同一张卡上多个实例共享算力,同时有请求时确实会互相争抢,表现是响应时间变长而不是出错。判断能不能接受,要在你的真实请求节奏下测一次,看峰值时段的延迟是否还在容忍范围内。

端口和进程怎么管才不乱?

一个模型对应一个固定端口,写进启动脚本并加注释,顺序按用途分组而不是按启动先后。再准备一个停止脚本,先停哪个后停哪个也写清楚,避免留下占着显存的僵尸进程。

要不要给每个模型都单独下一种量化档位?

可以,但要按用途分配:常驻高频的模型留给质量更高的档位,偶尔用的压到更低档位省显存。具体取舍原则和显存换算方式,到站内量化档位选择与部署测算相关页面确认,别凭感觉。

本文依据各平台公开文档与官方公告整理,只做中文归纳;具体做法、参数与限制以官方文档为准。