最近在一台没有独显的旧机器上,从零部署了一个本地小模型,打算先把流程摸熟,再搬到有显卡的机器上。本来以为半小时的事,前后折腾了两个晚上。踩的坑按顺序记下来,有几个是真没想到的。
用的是 llama-cpp-python 加 huggingface-hub,都是 pip 装,模型是 Qwen2.5 0.5B 的 GGUF 文件。选这么小的,是因为这台机器只有 CPU。
坑一:pip 装不上,原来是没有 C++ 编译器
第一步就卡住了。pip install llama-cpp-python 跑了半天,最后报 CMake 错误。
关键那一行是 CMAKE_CXX_COMPILER not set。这个包默认是装的时候现场编译 llama.cpp,机器上没有 g++ 就编不了。
两条路:装编译器自己编,或者用项目提供的预编译 CPU 版本。我这台只是用来摸流程,选了后者,指定只要二进制包,几秒钟就装好了。要是以后上显卡,需要带 CUDA 的版本,那时候还得回来面对编译这件事。
坑二:同一个模型,Q4 输出一串感叹号
装好以后下了两个量化版本:Q4_K_M 484M,Q8_0 645M。先试小的,问"用一句话介绍苏州"。
Q4_K_M 回了我一串感叹号。换 Q8_0,正常回答。
我一开始以为是模型文件下坏了,重新下了一遍,还是一样。换线程数、关 flash attention,都没用。目前我只能确定:在这台机器、这个预编译包上,这个 Q4 文件不能用,Q8 能用。根本原因我还没查到底,可能跟预编译包的指令集和这种量化格式的配合有关。
这个坑给我的教训是:量化版本不是"小一点、差一点"那么简单,有可能直接不能用。下了模型,先拿一个固定的问题在每个版本上问一遍,对上了再往下走。
坑三:显存够不够,先算一下再买卡
这台机器没有显卡,但后面要搬到有卡的机器上,我就先把"什么卡能跑什么模型"粗算了一遍。公式很粗:参数量乘以每个参数占的位数除以 8,再加一点余量给上下文和杂项。
图片:PantheraLeo1359531 / Wikimedia Commons / CC BY 4.0
算完心里有数多了。7B 的模型,8G 显存只能跑 Q4;想跑 Q8,得 12G 起。14B 的 Q4,12G 刚好能塞进去。32B 的,就算 Q4 也得 24G。
这张表是估算,实际还要看上下文开多长、同时几个人用、驱动占多少。我自己的习惯是:算出来刚好够的,按不够处理。
坑四:上下文开太长,内存悄悄就没了
模型能跑以后,我顺手把 n_ctx(上下文长度)开到了 32768,想着越长越好。结果机器明显变卡。
测了一下三个长度下进程的内存峰值:
2048 时 775MB,8192 时 851MB,32768 时 1140MB。模型本身才 645M,光上下文就多吃了将近 400MB。这还只是 0.5B 的小模型,换成 7B、14B,上下文占的就是几个 G,放在显卡上就是直接挤爆显存。
我后来按实际用法定:问答场景,一问一答加上检索出来的资料,4096 足够了。
坑五:开机自启,别等停电了才想起来
能跑起来只是开始,真要给别人用,得保证机器重启以后它自己会起来。我写了个 service 文件,截图里只放了几行关键的:
After=network-online.target,等网络起来再启动,不然对外的接口可能起不来。
Restart=on-failure 加 RestartSec=5,挂了五秒后自动拉起来。
WantedBy=default.target,开机就启动。
这里要老实说一句:这台是摸流程的测试机,service 文件我写好、检查过,但还没在正式机器上装上去。我给自己定的规矩是,装上去以后第一件事就是真重启一次,再拔一次电试试。Restart=on-failure 有个容易忽略的地方:要是工作目录或者模型路径写错了,它会一直启动失败、自动重启,在循环里转,表面上看"服务在",其实一次都没起来成功。所以光看状态不够,得真去问它一句。
回头看
编译:先看有没有编译器,没有就用预编译包,但要记住以后上显卡还得面对它。
量化:每个版本都用同一个问题试一遍,别默认小一点就只是差一点。
显存:先算,算出来刚好够的按不够处理。
上下文:按实际用法定,别图大。
自启:配完一定真重启一次。
这些都是在一台没有显卡的机器、一个 0.5B 小模型上踩出来的。换了显卡、换了大模型,可能还有新坑,我也说不准。
这次部署的完整记录我放在 evafang.com 。
你们本地部署模型的时候,卡得最久的是哪一步?