Notion Blog
十年前的骁龙 835 旧手机,被我改成了 24 小时在线的 AI 电脑
技术分享1 分钟阅读

十年前的骁龙 835 旧手机,被我改成了 24 小时在线的 AI 电脑

十年前的骁龙 835 旧手机,被我改成了 24 小时在线的 AI 电脑

起因特别简单:我想有个随时能用的 AI 编程助手,但又不想天天开着电脑。

电脑性能强,但开着费电、占地方,而且我不可能为了问 AI 几个问题专门把电脑点亮。手机倒是一直在身边,可安卓本身干不了正经开发——没有像样的终端,装个 Python 都费劲。

后来我琢磨,能不能把一台旧安卓手机整个改成跑 Linux 的 AI 电脑,插上电往角落一扔,24 小时挂着,随用随问。

还真搞成了。这篇文章把整套东西的架构、关键实现和踩过的坑都记下来,给想折腾的人一个参考。

先说说这台宿主机

可能有人好奇,到底什么手机。说出来可能有点好笑:这是一台差不多十年前的旧手机,芯片是高通骁龙 835(MSM8998),2016、2017 年那会儿的旗舰。放到今天,连入门机都算不上,早就吃灰好几年了。

它的配置放现在看很寒酸:8 核 CPU、5.6G 内存、51G 存储。这个内存水平,跑个大型 App 都可能卡,更别说当电脑用了。

但我不需要它快。我要的只是一台能 24 小时插电、能跑 Linux、能挂几个轻服务的机器。这些要求,十年前的旗舰芯片绰绰有余——毕竟人家当年也是旗舰。与其让它吃灰,不如物尽其用。

当然,正因为配置不高,后面折腾时踩了不少性能的坑,这个后面细说。

整体架构

先上一张图,整个系统从下到上分四层:

┌─────────────────────────────────────────────┐
│  第 1 层:安卓手机(物理宿主)                │
│  · aarch64 8 核 / 5.6G 内存                  │
│  · 内核 5.4.0-aidlite                        │
│  · 电池供电,插智能插座自动充放电             │
└───────────────┬─────────────────────────────┘
                │ AidLux 在安卓上跑 Linux 容器
┌───────────────▼─────────────────────────────┐
│  第 2 层:Linux 容器(AidLux)               │
│  · 完整 bash / apt / Python / Node           │
│  · 和安卓共用内核,非模拟器,几乎无性能损耗   │
│  · crontab 调度所有常驻服务                  │
└───────────────┬─────────────────────────────┘
                │
┌───────────────▼─────────────────────────────┐
│  第 3 层:常驻服务                            │
│  · AI 微信网关(收发消息 + Agent)           │
│  · Home Assistant 虚拟机(管智能插座)       │
│  · 代理 / DDNS / 日报定时任务                │
└───────────────┬─────────────────────────────┘
                │
┌───────────────▼─────────────────────────────┐
│  第 4 层:AI 助手(Agent)                   │
│  · 读容器文件、执行 shell、改代码            │
│  · 通过微信接口被人远程使唤                   │
└─────────────────────────────────────────────┘

关键点在第 2 层:安卓底层本来就是 Linux 内核,但正常摸不到(没 root、没完整 shell、装不了包)。AidLux 的思路是在安卓上起一个完整的 Linux 容器,和安卓共用内核,所以不是慢吞吞的模拟器,性能几乎无损耗。

装好后 uname -a 一下,aarch64、8 核、内存能用到 5.6G。这台吃灰的旧手机摇身一变,成了台能跑服务的小主机。

AI 微信网关:怎么跟它说话

光有 Linux 还不够,我要的是能随时对话的 AI。这里我踩的坑最多,单独展开。

整体消息流是这样的:

微信用户
   │ 发消息
   ▼
[iLink Bot 接口] ──长轮询──> main.py(只负责收发)
                                │ 把消息写成 pending 文件
                                ▼
                          pi_worker.py(管 Agent 进程)
                                │ spawn / RPC
                                ▼
                            AI 助手(Pi)
                                │ 处理完写回结果
                                ▼
                          main.py 取结果回发微信

设计上有个我挺得意的点:收发消息和处理任务拆成两个进程。main.py 只管轮询微信、收消息、回消息,本身不碰 AI;真正的 Agent 跑在 pi_worker.py 里。这样即使 Agent 卡死或者我重启它,消息收发链路也不受影响,不会出现「Agent 一崩就收不到消息」。

防止消息重复发也是个细节。轮询时可能两个进程同时读到同一条待处理消息、各发一次,导致用户收到重复回复。我的做法是给待处理队列加文件锁:

# 防止两个进程同时读到同一条 pending 各发一次
import fcntl
lock = open(state_home() / "pending.lock", "w")
fcntl.flock(lock, fcntl.LOCK_EX)
# ... 读取并处理这条 pending ...
fcntl.flock(lock, fcntl.LOCK_UN)

微信排版这个坑我单独写过一篇,这里只说结论:微信不渲染 Markdown,而且把单个换行当空格。所以网关在发送前会过一遍清洗函数,把 ##、**、表格、链接全部降级成微信能正常显示的纯文本,并把所有换行统一成双换行。完整实现我贴在那篇文章里了。

常驻服务怎么不挂:进程守护

这套东西要 24 小时跑,最怕进程悄悄挂了没人知道。我的做法是用 crontab 做进程守护,每几分钟检查一次,挂了就拉起来。

守护脚本用 flock 防止自己重复运行:

# monitor.sh 核心:flock 保证同一时刻只有一个守护实例
LOCK="/tmp/wechat-pi-gateway.lock"
exec 9>"$LOCK"
if ! flock -n 9; then
    echo "[$TIMESTAMP] lock busy, skip" >> "$LOG_FILE"
    exit 0
fi
# ... 检查 main.py 是否存活,不在就拉起 ...

flock -n 是关键:如果上一个守护实例还在跑(拿着锁),本次直接退出,避免自己把自己搞成好几个。配上 crontab 每 5 分钟跑一次,进程基本能做到秒级自愈。

我机器上现在的定时任务长这样:

*/5  * * * *  wechat-pi-gateway/monitor.sh      # 网关进程守护
*/10 * * * *  check_ha_vm.sh                    # HA 虚拟机健康检查
*/10 * * * *  check_battery.py                  # 电池电量检查 + 控插座
*/8  * * * *  ddns.sh                           # 动态域名解析
15   8 * * *  daily-report/run.sh gen           # 每天早上生成日报
30/0 8,9,21 * *  daily-report/run.sh send       # 定时推日报
@reboot       mihomo/start.sh                   # 开机自启代理

电池保电:让手机安全地 24 小时插电

这手机要一直插电当服务器,但锂电池常年充到 100% 会加速老化。所以我搞了个智能插座,写脚本每十分钟读一次电量,自动控制充放电。

核心逻辑很简单:

max_battery = 75
if datetime.now().weekday() == 5 and datetime.now().day <= 7:
    max_battery = 100   # 每月第一个周六充满,校准电量

if battery_level < 25:
    turn_on_plug()      # 低于 25%,开插座充电
elif battery_level >= max_battery and plug_is_on:
    turn_off_plug()     # 高于上限,关插座
# 25% ~ 上限之间:保持现状,不动作

把电量锁在 25%~75% 这个区间,是锂电池保养的常见策略:不过充、不过放,延长寿命。毕竟这手机是要 7×24 小时当服务器用的,电池健康是头等大事。

几个印象深的坑

内存。5.6G 听着还行,但 AI 网关、Home Assistant 虚拟机、一堆服务一起跑,物理内存经常吃紧,系统会把东西换到 swap。我有次去看,swap 用了快 1G,吓一跳以为哪里炸了。后来才搞明白,那是之前某次内存尖峰留下的,物理内存够用就不影响,属于历史遗留,不用管。

HA 虚拟机太重。为了控一个智能插座,我一开始跑了个 2 核 2G 的 x86 虚拟机专门装 Home Assistant,常年吃掉近 1/4 内存。后来降到 1.5G 才勉强平衡——再低(1G)HA 直接起不来。这块现在是我最想优化的,琢磨着要么换轻量方案,要么干脆绕过它直连插座。

微信排版。就是上面说的那个,为此专门写了清洗函数,篇幅关系不在这篇展开。

值不值

说实话,这台「AI 电脑」性能比不上正经电脑,跑不了大模型、编译大项目会喘。但它胜在便宜、省电、随身,而且 24 小时在线。

对我这种「主要拿来问问题、写写小脚本、查查状态、挂几个轻服务」的需求,刚刚好。而且折腾这一路学到的东西,比买台现成设备多多了——Linux 容器、多进程设计、文件锁防重、进程守护、锂电池保养、微信接口,全是自己一路踩出来的。

如果你也想搞一个,我的建议是:别追求性能,先想清楚要它干什么。如果只是要个随身的 AI 助手加几个常驻小服务,一台吃灰的旧安卓手机就够了,成本几乎为零。真正值钱的不是那台手机,是你为了让它跑起来而搞懂的那一整套东西。

读者评论

评论会同步写入该文在 Notion 中的页面底部(与正文同页,便于管理)。

0/1500

暂无评论,欢迎抢沙发。