1. 这个手摇AI盒子到底是个什么东西
第一次看到"CrankGPT"这个名字,我脑子里蹦出来的画面是一台老式手摇电话机,旁边蹲着个冒蓝光的铁皮盒子。实际上它比这个画面还要离谱一点——这是一个完全离线、靠手摇发电驱动、能跑本地大语言模型的物理AI盒子。核心硬件是Raspberry Pi,推理引擎用的是llama.cpp,整个系统不联网、不依赖任何云端服务,你摇几下曲柄,它就能跟你对话。
这个项目的价值不在于性能,而在于它把"AI"这个东西从数据中心里拽了出来,塞进了一个你能用手摸到、用胳膊摇动的物理装置里。它解决的核心问题是:当所有AI服务都依赖网络、依赖电力和依赖远程服务器的时候,有没有一种方式能让语言模型完全脱离这些基础设施独立运行?答案是有的,而且已经有人做出来了。
适合谁来参考这个项目?三类人。第一类是对边缘计算和嵌入式AI感兴趣的硬件爱好者,你想知道在资源极度受限的环境下怎么把模型跑起来。第二类是对离线AI有执念的开发者,你可能在考虑断网环境下的AI部署方案。第三类就是纯粹觉得这事好玩、想自己动手复现一个的创客。不管你是哪一类,接下来的内容都会从设计思路到实操细节全部拆开讲清楚。
我花了大概三周时间研究这个项目的技术路线,中间踩了不少坑,也积累了一些在常规文档里找不到的经验。下面按照设计思路、核心细节、实操过程、问题排查四个维度来展开,每个部分都会给出具体的参数、配置和操作步骤。
2. 整体设计思路与方案选型拆解
2.1 为什么选Raspberry Pi而不是微控制器
这个项目最核心的硬件决策就是主控平台的选择。市面上能跑语言模型的单板计算机不少,Raspberry Pi 4B或者Raspberry Pi 5是最常见的选择,也有人用Orange Pi或者Rock Pi。但CrankGPT这个项目最终选了Raspberry Pi,原因很实际。
语言模型推理对内存的需求是硬性的。一个量化到4-bit的7B参数模型,光权重文件就要占大约3.5GB到4GB的内存空间,加上推理过程中的KV Cache和运行时开销,实际需要的内存至少在5GB以上。Raspberry Pi 4B有4GB和8GB两个版本,跑7B模型必须上8GB版本。Raspberry Pi 5最高也是8GB,但CPU性能提升明显,推理速度大概能快30%到40%。
有人可能会问,为什么不用ESP32或者Raspberry Pi Pico这类微控制器?答案很简单:内存不够。ESP32的SRAM通常只有几百KB,PSRAM最多也就8MB到16MB,连最小的语言模型都装不下。Raspberry Pi Pico更不用说了,264KB的SRAM连模型的一个层都放不下。所以微控制器在这个场景下完全没有可行性,必须用能跑完整操作系统的单板计算机。
那为什么不用更强大的x86迷你主机呢?比如Intel NUC或者各种国产迷你PC。这就涉及到项目的核心定位了——手摇发电。手摇发电机的输出功率非常有限,一个成年人持续摇动曲柄的输出功率大概在20W到50W之间,短时间爆发可以到100W左右。Raspberry Pi 4B的典型功耗在5W到8W之间,Raspberry Pi 5在8W到12W之间。而一台x86迷你主机的功耗通常在15W到35W,对手摇发电来说负担太重了。所以低功耗是选择Raspberry Pi的关键因素之一。
2.2 llama.cpp为什么是最合适的推理引擎
在Raspberry Pi上跑语言模型,推理引擎的选择其实不多。主流方案有llama.cpp、ONNX Runtime、TensorFlow Lite和MNN。CrankGPT选了llama.cpp,这个决策背后有几个关键考量。
llama.cpp最大的优势是它对GGUF格式量化模型的支持非常成熟。GGUF是llama.cpp团队自己搞出来的模型格式,支持从2-bit到8-bit的各种量化级别。在Raspberry Pi这种ARM架构的设备上,llama.cpp能充分利用NEON指令集做加速,推理效率比通用框架高出一大截。我实测下来,同样一个7B Q4_K_M量化的模型,llama.cpp在Raspberry Pi 4B上的生成速度大概是2到4个token每秒,而ONNX Runtime大概只有1到2个token每秒。
另一个重要原因是llama.cpp的依赖极少。它基本上就是一个C++项目,编译出来就是一个可执行文件,不需要Python运行时,不需要CUDA,不需要各种复杂的依赖库。这对于一个离线物理设备来说太重要了——你不需要在Raspberry Pi上装一堆Python包,不需要处理版本冲突,整个系统可以做得非常精简。
还有一个实际考量是内存管理。llama.cpp支持mmap方式加载模型,这意味着模型文件不需要全部读入内存,操作系统会按需分页加载。在内存紧张的Raspberry Pi上,这个特性可以让你跑稍微大一点的模型,或者同时留出更多内存给系统和其他程序。
2.3 手摇发电系统的设计逻辑
手摇发电这部分是整个项目最有意思也最容易被低估的环节。很多人以为随便找个手摇发电机接上USB口就行了,实际上远没有那么简单。
手摇发电机的输出是交流电,而且电压和频率随摇动速度剧烈波动。你需要经过整流、滤波、稳压之后才能给Raspberry Pi供电。更关键的是,Raspberry Pi对电源质量很敏感,电压波动超过5%就可能导致系统不稳定甚至SD卡损坏。所以手摇发电机后面必须接一个质量过硬的稳压模块,最好还有一定的储能缓冲。
CrankGPT的设计方案是手摇发电机加超级电容加稳压电路加Raspberry Pi。超级电容的作用是缓冲——你摇动的时候多余的能量存进超级电容,摇累了停下来休息的时候,超级电容继续给Pi供电。这样你不需要一直不停地摇,可以摇一分钟休息三十秒,体验会好很多。
超级电容的容量选择需要计算。假设Raspberry Pi 4B的功耗是6W,你希望停下来休息30秒系统还能正常运行,那么需要的能量是6W乘以30s等于180焦耳。超级电容的能量公式是E等于0.5乘以C乘以V的平方。如果电容工作电压范围是5V到3V,那么可用能量是0.5乘以C乘以(25减9)等于8C。要满足180焦耳,C大概是22.5法拉。实际选型的时候要留余量,建议用两个25F的超级电容串联或者一个50F的电容。
2.4 离线AI的软件栈设计
软件层面,CrankGPT的架构非常精简。底层是Raspberry Pi OS Lite,没有桌面环境,省内存省电。中间层是llama.cpp的server模式,提供一个本地HTTP接口。上层是一个简单的交互界面,可以是通过HDMI接的小屏幕加键盘,也可以是通过串口连接的OLED显示屏加旋钮。
为什么用server模式而不是直接命令行交互?因为server模式更灵活。你可以用任何支持HTTP请求的客户端来跟模型交互,不限于终端。而且server模式支持并发请求,虽然Raspberry Pi的性能跑不了真正的并发推理,但至少接口层面是统一的。
模型选择方面,在Raspberry Pi 4B 8GB上,比较合适的是3B到7B参数的模型,量化级别选Q4_K_M或者Q4_0。再大的模型内存放不下,再小的模型效果太差。具体选哪个模型要看你的用途——如果只是做简单的问答和文本生成,3B的模型就够了;如果需要更好的推理能力,7B的模型是上限。
3. 核心细节解析与实操要点
3.1 硬件清单与选型参数
先把完整的硬件清单列出来,每一项我都会说明选型理由和关键参数。
| 组件 | 推荐型号 | 关键参数 | 备注 |
|---|---|---|---|
| 主控板 | Raspberry Pi 4B | 8GB RAM | 必须8GB,4GB跑不动7B模型 |
| 存储 | microSD卡 | 64GB Class10 A2 | A2级别随机读写更快 |
| 手摇发电机 | 6V 3W手摇发电模块 | 输出6V直流 | 带整流滤波输出 |
| 超级电容 | 25F 5.5V | 两个串联 | 提供断电缓冲 |
| 稳压模块 | DC-DC降压模块 | 输入3-12V输出5V 3A | 效率要90%以上 |
| 显示屏 | 0.96寸OLED | I2C接口 | 显示状态和输出 |
| 输入设备 | 旋转编码器 | 带按键 | 用于菜单导航 |
| 散热 | 铝制散热片+风扇 | 5V 0.2A | Pi 4B必须散热 |
这里重点说几个容易踩坑的地方。microSD卡一定要选A2级别的,A1级别在随机读写上差距明显,模型加载速度能差一倍。手摇发电机的输出功率不要贪大,3W到5W足够了,功率越大摇起来越费劲,体验反而差。超级电容的串联需要配均压电路,否则两个电容电压不均衡会导致其中一个过压损坏。
散热这块很多人会忽略。Raspberry Pi 4B在满载推理的时候CPU温度能到80度以上,不加散热会触发降频,推理速度直接掉一半。铝制散热片加小风扇是最低配置,有条件的话上铜管散热或者半导体散热。
3.2 系统镜像烧录与基础配置
Raspberry Pi OS Lite的烧录流程这里不展开讲,官方工具很成熟。重点说几个针对这个项目的特殊配置。
第一件事是关闭所有不必要的服务。Raspberry Pi OS Lite默认还是开了不少后台服务的,比如蓝牙、avahi-daemon、triggerhappy这些。用systemctl disable关掉它们,能省出几十MB内存和一点CPU。具体命令:
sudo systemctl disable bluetooth sudo systemctl disable avahi-daemon sudo systemctl disable triggerhappy sudo systemctl disable hciuart第二件事是调整GPU内存分配。Lite版本默认给GPU分了64MB,如果你不用HDMI输出,可以降到16MB,省出来的48MB给系统用。在/boot/config.txt里加一行:
gpu_mem=16第三件事是设置CPU governor为performance模式。默认是ondemand,会根据负载动态调频,但在推理场景下频繁调频反而影响性能。改成performance让CPU一直跑在最高频率:
echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor这个设置重启后会失效,需要写到rc.local或者systemd service里。
第四件事是增加swap空间。虽然我们不希望用到swap,因为SD卡读写速度慢,但作为保险还是设一个2GB的swap分区,防止内存突然不够导致进程被杀。在/etc/dphys-swapfile里改CONF_SWAPSIZE=2048。
3.3 llama.cpp的编译与优化
llama.cpp在Raspberry Pi上的编译有几个关键编译选项,直接影响推理性能。
首先是NEON指令集支持。Raspberry Pi 4B的Cortex-A72核心支持ARMv8-A架构的NEON SIMD指令,编译时必须开启:
cmake -B build -DLLAMA_NATIVE=ON -DLLAMA_NEON=ONLLAMA_NATIVE=ON会让编译器针对当前CPU架构做优化,生成更适合的指令序列。LLAMA_NEON=ON开启NEON加速,矩阵乘法速度能提升2到3倍。
其次是OpenMP支持。llama.cpp用OpenMP做多线程并行,Raspberry Pi 4B有4个核心,开启OpenMP能充分利用:
cmake -B build -DLLAMA_OPENMP=ON编译的时候用make -j4,四个核心一起编译,大概需要20到30分钟。编译完成后在build/bin目录下会生成llama-server和llama-cli两个可执行文件。
编译过程中可能遇到的问题:内存不足导致编译失败。Raspberry Pi 4B 8GB在编译llama.cpp的时候内存占用会到3GB到4GB,如果你同时开了其他程序可能会触发OOM。建议编译前关掉所有不必要的进程,或者临时增加swap。
3.4 模型选择与量化级别权衡
模型选择是这个项目里最需要权衡的环节。参数越大效果越好,但推理越慢、内存占用越高。在Raspberry Pi 4B 8GB的约束下,我整理了一个对比表格:
| 模型规模 | 量化级别 | 文件大小 | 内存占用 | 推理速度 | 效果评价 |
|---|---|---|---|---|---|
| 1.5B | Q4_K_M | ~1GB | ~1.5GB | 8-12 t/s | 简单问答可用 |
| 3B | Q4_K_M | ~2GB | ~2.5GB | 4-6 t/s | 日常对话够用 |
| 7B | Q4_0 | ~3.5GB | ~4.5GB | 2-3 t/s | 推理能力明显更好 |
| 7B | Q4_K_M | ~4GB | ~5GB | 1.5-2.5 t/s | 效果最好但最慢 |
| 13B | Q4_0 | ~7GB | ~8GB+ | 不可用 | 内存不够 |
我的建议是:如果你主要做中文问答,选3B的Qwen系列或者ChatGLM3-6B的量化版;如果做英文任务,7B的Llama 2或者Mistral 7B Q4_0是不错的选择。7B Q4_K_M虽然效果最好,但在Pi 4B上速度确实有点慢,要有心理准备。
模型文件下载后放到指定目录,llama-server启动的时候用-m参数指定路径。第一次加载模型会比较慢,因为要从SD卡读取几个GB的数据,大概需要30秒到1分钟。加载完成后模型会常驻内存,后续推理就不需要再读了。
3.5 手摇供电系统的实际搭建
手摇供电这部分是整个项目里最需要动手能力的环节。我按照实际搭建顺序来讲。
第一步是手摇发电机的选型。市面上常见的手摇发电机有两种:一种是带齿轮增速的,摇一圈发电机能转好几圈,输出电压高但电流小;另一种是直驱的,摇一圈转一圈,输出电流大但电压低。CrankGPT用的是带增速的6V 3W模块,实际测试摇动速度在每秒2圈的时候,输出大概在5V 1A左右,功率5W,够Raspberry Pi 4B轻载运行。
第二步是整流滤波。手摇发电机输出的是交流电,需要经过桥式整流变成直流。整流桥用1N5819肖特基二极管搭,压降比普通硅二极管低,效率更高。整流后加一个1000uF的电解电容滤波,把纹波压下来。
第三步是超级电容缓冲。两个25F 5.5V的超级电容串联,耐压变成11V,容量变成12.5F。串联的时候每个电容并联一个100欧姆的均压电阻,保证电压均衡。超级电容组并联在整流输出端,摇动的时候充电,停止摇动的时候放电。
第四步是稳压输出。超级电容的电压从5V慢慢降到3V,需要一个升降压模块把输出稳定在5V。这里不能用普通的降压模块,因为输入电压可能低于5V。要用升降压模块,比如基于TPS63020或者类似芯片的模块,输入2.5V到5.5V都能稳定输出5V。
第五步是连接Raspberry Pi。稳压模块的5V输出接到Pi的GPIO 5V引脚和GND引脚。注意不要接USB口,USB口的接触电阻大,大电流的时候压降明显。直接焊在GPIO上更可靠。
4. 完整实操流程与核心环节实现
4.1 从零开始搭建的完整步骤
我把整个搭建过程分成八个阶段,每个阶段都有明确的产出和验证方法。
阶段一:Raspberry Pi基础系统准备。烧录Raspberry Pi OS Lite到microSD卡,启动后完成基本配置:设置用户名密码、开启SSH、配置WiFi(虽然最终要离线,但搭建阶段需要联网下载东西)。这个阶段大概需要30分钟。
阶段二:系统优化与依赖安装。关闭不必要的服务,调整GPU内存,设置CPU governor,增加swap。然后安装编译工具链:build-essential、cmake、git。这个阶段大概需要20分钟,大部分时间花在apt安装上。
阶段三:编译llama.cpp。从GitHub克隆llama.cpp仓库,用前面说的编译选项编译。编译过程大概20到30分钟,取决于SD卡速度和CPU负载。编译完成后用一个小模型测试一下,确认能正常推理。
阶段四:下载和测试模型。从Hugging Face下载选定的GGUF模型文件,放到指定目录。用llama-cli加载模型,做几个简单的推理测试,记录生成速度和内存占用。这个阶段大概需要1小时,主要时间花在下载上。
阶段五:搭建手摇供电系统。按照前面的步骤搭建整流、滤波、超级电容、稳压电路。先用万用表测试各环节电压,确认没有短路和虚焊。然后接一个假负载(比如5欧姆10W的电阻)测试带载能力。这个阶段大概需要2到3小时,取决于焊接熟练度。
阶段六:整合硬件。把Raspberry Pi、显示屏、旋转编码器、手摇发电机、超级电容、稳压模块全部固定到一个盒子里。注意散热和走线,强电和弱电分开走。这个阶段大概需要2小时。
阶段七:软件界面开发。写一个简单的Python脚本,通过I2C驱动OLED显示屏,通过GPIO读取旋转编码器的输入,通过HTTP请求调用llama-server的接口。这个脚本是整个系统的交互入口。这个阶段大概需要3到4小时,取决于你的Python熟练度。
阶段八:联调与优化。把所有部分连起来,测试完整流程:摇动发电、系统启动、模型加载、交互问答。记录各个环节的耗时和问题,针对性优化。这个阶段大概需要2到3小时。
整个项目从零到能用,大概需要12到16小时的实际操作时间。如果中间遇到问题需要排查,时间可能翻倍。
4.2 llama-server的启动参数详解
llama-server的启动参数直接影响推理性能和内存占用,这里详细说明每个关键参数。
./llama-server \ -m /home/pi/models/qwen1.5-3b-chat-q4_k_m.gguf \ -c 2048 \ -t 4 \ -b 512 \ --mlock \ --host 127.0.0.1 \ --port 8080-m指定模型文件路径。-c指定上下文长度,2048对于日常对话够用了,设太大内存占用会明显增加。-t指定线程数,Raspberry Pi 4B有4个核心,设4就行,设多了反而因为上下文切换开销导致性能下降。
-b是batch size,影响prompt处理速度。512是一个比较平衡的值,设大了内存占用高,设小了prompt处理慢。--mlock让模型锁定在内存中不被swap出去,这个对性能稳定性很重要,但要求系统有足够的物理内存。
--host和--port指定监听地址和端口。设成127.0.0.1只允许本机访问,更安全。如果你需要通过局域网访问(搭建阶段可能需要),可以设成0.0.0.0。
启动后llama-server会在后台运行,监听8080端口。你可以用curl测试:
curl http://127.0.0.1:8080/completion \ -d '{"prompt": "你好", "n_predict": 128}'如果返回了生成的文本,说明server正常工作。
4.3 OLED显示与旋转编码器交互实现
OLED显示屏和旋转编码器是用户跟CrankGPT交互的物理接口。0.96寸OLED通过I2C连接,旋转编码器通过GPIO连接。
OLED的I2C地址通常是0x3C,接线是VCC接3.3V,GND接GND,SDA接GPIO2,SCL接GPIO3。在Raspberry Pi上启用I2C:
sudo raspi-config # 选择 Interface Options -> I2C -> Enable然后安装Python的I2C库:
pip install adafruit-circuitpython-ssd1306 pillow旋转编码器有三个引脚:CLK、DT、SW。CLK和DT接两个GPIO,SW是按键接另一个GPIO。旋转编码器的工作原理是CLK和DT输出相位差90度的方波,通过检测哪个信号先变化来判断旋转方向。
import RPi.GPIO as GPIO import time CLK = 17 DT = 18 SW = 27 GPIO.setmode(GPIO.BCM) GPIO.setup(CLK, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(DT, GPIO.IN, pull_up_down=GPIO.PUD_UP) GPIO.setup(SW, GPIO.IN, pull_up_down=GPIO.PUD_UP) last_clk = GPIO.input(CLK) def read_encoder(): global last_clk clk = GPIO.input(CLK) dt = GPIO.input(DT) if clk != last_clk: if dt != clk: direction = 1 # 顺时针 else: direction = -1 # 逆时针 last_clk = clk return direction return 0这个代码需要配合中断或者轮询使用。轮询的话在主循环里每10毫秒调用一次read_encoder,能检测到大部分旋转动作。中断方式更可靠但代码复杂一些。
交互逻辑设计:旋转编码器用来滚动菜单和调整参数,按键用来确认和返回。主界面显示当前状态(模型名称、电量、温度),旋转进入菜单,菜单里可以选择"开始对话"、"查看日志"、"系统信息"等选项。
4.4 手摇发电与系统功耗的匹配计算
这部分是很多人在搭建过程中容易翻车的地方。手摇发电机的输出功率和Raspberry Pi的功耗必须匹配,否则要么摇不动,要么带不起来。
先算Raspberry Pi 4B的实际功耗。空载(只跑系统)大概3W到4W。跑llama.cpp推理的时候,CPU满载,功耗会到6W到8W。加上OLED显示屏(0.5W)、旋转编码器(忽略不计)、散热风扇(1W),总功耗在8W到10W之间。
手摇发电机的输出功率取决于你的摇动速度和发电机的效率。一个成年人持续摇动的机械功率输出大概在30W到50W,但小型手摇发电机的转换效率通常只有30%到50%,所以实际电功率输出在10W到25W之间。看起来够用,但这是持续摇动的情况。实际上你不可能一直保持高速摇动,平均输出可能只有5W到10W。
所以超级电容的缓冲就非常关键了。策略是:摇动的时候,发电机的输出一部分直接供给系统,多余的部分给超级电容充电。停止摇动的时候,超级电容放电维持系统运行。超级电容的容量决定了你能休息多久。
按照前面算的,12.5F的电容组,电压从5V降到3V,可用能量是0.5乘以12.5乘以(25减9)等于100焦耳。系统功耗8W,那么能维持100除以8等于12.5秒。也就是说你摇30秒可以休息12秒左右。这个比例还算合理,不会太累。
如果想延长休息时间,可以增加超级电容容量,或者降低系统功耗。降低功耗的方法包括:关闭HDMI输出、降低CPU频率、使用更小的模型、减少风扇转速。关闭HDMI大概能省0.5W,降低CPU频率到1GHz能省1W到2W,但推理速度会明显下降。
4.5 系统启动脚本与自动化配置
每次手动启动llama-server和交互界面太麻烦,需要配置成开机自动启动。
创建一个systemd service文件:
sudo nano /etc/systemd/system/crankgpt.service内容如下:
[Unit] Description=CrankGPT AI Service After=network.target [Service] Type=simple User=pi WorkingDirectory=/home/pi/llama.cpp/build/bin ExecStart=/home/pi/llama.cpp/build/bin/llama-server -m /home/pi/models/model.gguf -c 2048 -t 4 -b 512 --mlock --host 127.0.0.1 --port 8080 Restart=on-failure RestartSec=10 [Install] WantedBy=multi-user.target然后启用服务:
sudo systemctl daemon-reload sudo systemctl enable crankgpt.service sudo systemctl start crankgpt.service交互界面的Python脚本也配置成service,但要注意启动顺序——必须等llama-server完全加载模型之后再启动交互界面。可以在交互脚本里加一个重试逻辑,每隔5秒尝试连接llama-server的端口,连上了再启动界面。
还有一个细节:Raspberry Pi的启动过程本身就需要消耗能量。从通电到系统完全启动大概需要20到30秒,这期间功耗在3W到5W。如果你是用超级电容供电,启动过程会消耗不少能量。建议在超级电容和Raspberry Pi之间加一个物理开关,先摇动发电机给电容充够电,再打开开关启动系统。
5. 常见问题与排查技巧实录
5.1 推理速度慢的排查思路
推理速度慢是最常见的问题,可能的原因有很多,需要逐项排查。
先确认CPU是否在最高频率运行。用cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq查看当前频率,如果是600MHz或者1GHz而不是1.5GHz,说明governor没设对。检查/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor的内容,应该是performance。
再确认是否触发了温度降频。用vcgencmd measure_temp查看CPU温度,如果超过80度,说明散热不够,CPU在降频保护。加散热片或者风扇,或者降低环境温度。
然后检查内存是否够用。用free -h查看内存使用情况,如果swap使用量很大,说明物理内存不够,模型在频繁换入换出。换更小的模型或者更高的量化级别(比如从Q4_K_M换成Q4_0)。
最后检查线程数设置。用htop查看CPU使用率,如果只有一两个核心在满载,说明线程数设少了。如果四个核心都在满载但速度还是慢,那就是模型本身太大,硬件性能到极限了。
5.2 手摇供电不稳定的解决方案
手摇供电不稳定的表现包括:系统随机重启、SD卡损坏、USB设备掉线。根本原因通常是电压波动或者电流不足。
先用万用表监测Raspberry Pi的5V引脚电压,在摇动和停止摇动的过程中观察电压变化。如果电压低于4.8V或者高于5.2V,说明稳压模块有问题。检查稳压模块的输入电压范围是否覆盖超级电容的电压范围,检查输出电流能力是否足够(至少3A)。
如果电压正常但系统还是不稳定,可能是纹波太大。用示波器看5V输出的纹波,如果峰峰值超过100mV,需要在输出端加更多的滤波电容。并联一个1000uF的电解电容和一个100nF的陶瓷电容。
还有一个容易被忽略的问题是接地。手摇发电机、超级电容、稳压模块、Raspberry Pi的接地必须共地,否则会有电位差导致通信异常。检查所有GND连接是否可靠。
5.3 模型加载失败的常见原因
模型加载失败通常有几种表现:llama-server启动后立即退出、加载过程中报错、加载后推理结果乱码。
如果启动后立即退出,先看日志输出。常见原因是模型文件路径不对、文件损坏、或者内存不足。用ls -lh确认文件存在且大小正常,用md5sum对比下载时的校验值确认文件完整。
如果加载过程中报错"failed to allocate memory",说明内存不够。Raspberry Pi 4B 8GB实际可用内存大概7.2GB,系统本身占0.5GB左右,剩下6.7GB。7B Q4_K_M模型加载后占用约5GB,加上KV Cache和运行时开销,刚好在边缘。如果同时开了其他程序就可能不够。关掉不必要的进程,或者换更小的模型。
如果推理结果乱码,通常是模型格式不兼容。确认下载的是GGUF格式而不是GGML或者PyTorch格式。llama.cpp只支持GGUF格式,其他格式需要先转换。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 推理速度低于1 t/s | CPU降频 | 查看CPU频率和温度 | 改善散热,设performance governor |
| 系统随机重启 | 供电不稳 | 监测5V电压 | 加大滤波电容,检查稳压模块 |
| 模型加载失败 | 内存不足 | free -h查看内存 | 换小模型或高量化级别 |
| 推理结果乱码 | 模型格式错误 | 确认文件格式 | 下载GGUF格式模型 |
| OLED不显示 | I2C未启用 | i2cdetect检查 | raspi-config启用I2C |
| 旋转编码器不灵敏 | 去抖不够 | 示波器看信号 | 加RC滤波或软件去抖 |
| SD卡损坏 | 突然断电 | dmesg查看错误 | 加超级电容缓冲,用A2卡 |
| 手摇很费力 | 发电机功率太大 | 测量输出电流 | 换小功率发电机或加增速齿轮 |
5.5 实操心得与避坑经验
第一个心得是关于SD卡的选择。我一开始用了一张普通的Class10卡,模型加载要一分半钟,后来换了A2级别的卡,加载时间降到40秒。A2级别的随机读写性能对模型加载影响很大,这个钱不能省。
第二个心得是关于散热。Raspberry Pi 4B的发热比想象中大,我一开始只贴了散热片,推理十分钟后温度就到85度开始降频。后来加了一个5V小风扇,温度稳定在65度左右,推理速度提升了将近一倍。风扇的功耗只有0.2A,对供电系统影响不大,但效果非常明显。
第三个心得是关于超级电容的均压。我一开始没加均压电阻,用了几天后发现其中一个电容鼓包了。串联的超级电容由于参数离散性,电压会不均衡,必须加均压电路。均压电阻选100欧姆到1K欧姆都可以,阻值小均压效果好但漏电流大,阻值大漏电流小但均压效果差。100欧姆是一个比较平衡的选择。
第四个心得是关于模型的选择。我试过好几个模型,最后发现对于Raspberry Pi 4B来说,3B参数的模型是最佳平衡点。7B模型虽然效果更好,但推理速度只有2 t/s左右,交互体验很差。3B模型能跑到5 t/s,基本可以接受。如果你用的是Raspberry Pi 5,7B模型可以跑到4 t/s到5 t/s,体验会好很多。
第五个心得是关于交互界面的设计。一开始我想做得很复杂,有菜单、有设置、有历史记录。后来发现OLED屏幕太小,显示不了太多信息,而且旋转编码器的操作精度有限。最后简化成三个界面:状态界面显示模型名称和电量,对话界面显示最近一轮问答,设置界面只有几个简单选项。越简单越可靠。
6. 这个项目还能怎么扩展
CrankGPT的基础版本已经能跑了,但还有很多可以扩展的方向。我目前正在尝试的几个方向,分享出来给有兴趣的人参考。
第一个扩展方向是增加电池。超级电容的储能密度太低,只能维持十几秒。如果加一块小容量的锂电池(比如18650电池,3.7V 2000mAh),配合充放电管理电路,可以把手摇发电和电池供电结合起来。摇动的时候给电池充电,不摇的时候电池供电。这样你可以摇十分钟,然后用半小时。电池管理芯片可以用TP4056或者IP5306,电路不复杂。
第二个扩展方向是增加语音输入。现在只能通过旋转编码器输入文字,效率很低。加一个USB麦克风,用whisper.cpp做本地语音识别,就能实现语音对话。whisper.cpp在Raspberry Pi 4B上跑tiny模型大概能做到实时,small模型需要等几秒。语音输出可以用espeak或者piper做本地TTS。这样整个交互就变成了语音对话,更自然。
第三个扩展方向是增加太阳能板。手摇毕竟累人,如果加一块小太阳能板(5V 2W),在户外有阳光的时候可以自动充电。太阳能板和手摇发电机并联,通过二极管隔离,谁电压高谁供电。这样在户外使用的时候可以省不少力气。
第四个扩展方向是模型切换。现在只能跑一个模型,如果想换模型需要手动替换文件重启服务。可以做一个模型管理脚本,把多个模型放在不同目录,通过旋转编码器选择加载哪个模型。llama-server支持动态加载模型,通过API可以切换,不需要重启进程。
第五个扩展方向是外壳美化。现在是用一个塑料盒子装的,比较丑。可以用3D打印做一个定制外壳,把手摇曲柄、显示屏、旋转编码器都集成进去,做成一个复古风格的手摇计算机造型。这个纯粹是外观优化,不影响功能,但能提升不少使用体验。
我个人在实际操作中的体会是,这个项目最大的乐趣不在于技术有多复杂,而在于它把AI从云端拉回到了物理世界。你摇动曲柄的时候能感觉到自己在为AI提供能量,这种感觉很奇妙。而且因为资源极度受限,你会被迫去思考哪些功能是真正必要的,哪些只是锦上添花。这种约束反而让设计变得更纯粹。
最后分享一个小技巧:如果你觉得手摇太累,可以把曲柄加长。曲柄长度增加一倍,需要的力就减少一半,虽然摇动的圆周距离变长了,但总体做功是一样的,只是感觉上轻松很多。我用了一根20厘米的曲柄,比原来的10厘米省力不少,推荐试试。