手机派活:一套自建的「云端常驻 + 本地执行」工作流

最近的ai真是厉害,已经能充分理解我的意思了。然后就让ai自己干活,联动我的手机、电脑以及云服务器。以下为ai自动生成的过程。

起点:三个约束撞在一起

这套东西不是为了「玩 Agent」而造的,它是三个现实约束逼出来的:

  • 电脑不常开:家里的 Windows 只有晚上开机,白天派了活也没人干
  • 手机想干活:通勤路上、午休时想起一件事,希望立刻能派出去
  • 有一台闲服务器:白天十几个小时完全闲着
  • 隐私要留本地:日记、想法这类内容,长期不该堆在公网机器上
    前两个互相矛盾(要派活 vs 没人干活),第三个提供了一个解法,第四个给所有解法加了一条红线。

最后定型的方案,一句话概括:

手机只负责「说」,服务器只负责「记」,家里的电脑负责「做」,做完的东西搬回家,云端不留副本。

总体架构

        ┌─────────────┐
        │  手机 PWA   │  派活 / 记想法 / 看订阅更新
        └──────┬──────┘
               │ HTTP + 令牌
               ▼
   ┌───────────────────────────────┐
   │  控制面 · 境外轻量服务器      │
   │  任务队列 / 令牌鉴权 / 长轮询  │
   │  暂存区(同步后即删)          │
   │  定时收集器                    │
   └───────┬───────────────▲───────┘
           │ 长轮询(出站)  │ 结果回传
           ▼               │
   ┌───────────────────────────────┐
   │  执行端 · 家里 Windows        │
   │  worker 主动外连               │
   │  白名单 / 超时保护             │
   └───────┬───────────────────────┘
           ▼
   本地:拉取 → 落盘 → 确认 → 删除

关键点:家里的电脑不开放任何入站端口。它主动连出去长轮询,所以不需要内网穿透、不需要公网 IP、不需要动路由器。

七个组件

1. 控制面

单文件、零外部依赖。职责被刻意压到最小:收任务 → 排队 → 派给执行端 → 收结果;令牌鉴权;暂存区读写删。
它不执行任何任务,也不直接调用模型 API。这样即使服务器被攻破,攻击者拿到的也只是一个队列,而不是一个能执行任意命令的入口。

2. 执行端

启动后立刻发一次心跳,然后进入长轮询循环(每轮 25 秒)。拿到任务后:

  1. 查白名单:文本任务交给 Agent,脚本任务必须是配置文件里登记过的
  2. 子进程输出重定向到临时文件(不是管道),定时读增量推给服务器,手机上能看实时日志
  3. 结束后回传结果,附带退出码
  4. 超时直接终止,绝不允许任务无声挂着
    第 2 点是个刻意的工程选择:用文件描述符而不是管道,既避免 Windows 下的缓冲问题,也让「随时读增量」变成可能。

3. 手机端

单页 PWA、无框架。三个视图:任务(输入框 + 派发 + 记想法)、订阅(更新列表)、状态(一个圆点,绿=执行端在线)。专为单手操作设计。

4. 暂存区

服务器上的一个目录,两类东西:随手记的想法(按日期分文件,带时间戳)、定时收集的周报。四个接口:写、列表、读、确认删除。所有路径都过一遍越界检查。

5. 收集器

每天跑几次,抓几个 RSS 源。按唯一 ID 去重,给新文章配一句话概括,双写(一份给手机随时看,一份进周报归档)。
第一次运行只建基线,不倒灌历史——否则订阅的瞬间会收到几十篇旧文。

6. 本地同步

四步协议:拿清单 → 逐个下载 → 写进知识库 → 确认删除(只删成功的那些)。
目标文件已存在且内容相同就跳过;内容不同就加后缀另存,不覆盖。

7. 自启动

执行端挂在系统启动项,服务器用 systemd:控制面常驻,收集器用定时器。

七个关键决策

① 执行端主动外连,而不是服务器推

备选是内网穿透、隧道、组网工具。最终选长轮询:穿透要额外组件、要维护隧道、要处理断线重连,而且等于在家里开了一个入口。出站连接天然躲过所有入站限制,代码只有二十行。
代价是任务最多 25 秒的派发延迟——对「晚上跑批」完全无感。

② 白名单放在执行端,不放在控制面

服务端只规定「任务的形状」,真正的命令映射在执行端配置里,遇到不认识的直接拒绝。
理由:控制面是公网暴露的那一端。被攻破时,攻击者也只能提交「任务」,不能提交「命令」。安全边界必须在受保护的那侧。

③ 两个令牌 + 角色分离

手机一个令牌,执行端另一个。手机能派活、看状态;执行端才能领任务、回传结果。
这个设计一开始漏了(两个令牌权限相同),后来补上四处角色校验。

④ 不用 git 同步隐私内容

放弃原因:git 的历史是永久的。删掉文件、commit 一次,内容还在 .git 里。对「日记想法」这种东西,这等于没删。
选择:拉取成功才删的四步协议,服务器上物理删除,不留痕。

⑤ 先 IP + 端口,不先上 HTTPS

服务器 80 端口还跑着自己的博客。上 HTTPS 要加子域名、签证书、改反向代理,任何一步出错都可能把博客搞挂。
第一版就是「IP + 端口 + 令牌」。明文传令牌不理想,但传输内容只有任务文本和结果。等确认每天真在用,再花时间上证书。

⑥ AI 只写一句话,不评价

订阅周报里每条只有:谁、什么时候、标题、一句话、链接。提示词明确要求:

用中文,不超过 40 个字,只陈述这篇文章在讲什么,不评价、不推荐、不猜测作者情绪。

理由:这些是朋友的私人写作。抓下来做「人物分析」「情绪分析」是越界的。AI 在这里只做压缩,不做判断。

⑦ 所有产物都有上限

订阅记录留最近 150 条,任务队列留 500 条,单任务日志留 600 条,磁盘按年算几十兆。
真正的风险不是空间,是没人清理的临时文件,所以上限写在代码里,不靠自觉。

一次完整的生命周期

09:12  手机派一个巡检任务 → 进队列,显示「排队中」
09:12~19:00  电脑关着,任务排队;期间记的两条想法直接落服务器
00:17  服务器收集器跑一轮,有新文章就写进订阅记录
19:30  开机,执行端启动 → 心跳 → 圆点变绿 → 领走排队任务
19:30:05  开始执行,日志增量推给服务器,手机看实时输出
19:30:12  结果回传,手机变「完成」
19:35  跑同步脚本 → 拉走想法和周报 → 落进知识库 → 云端删除

最重要的两件事:白天派活不会丢(队列是真队列);想法不用等电脑(写完就落服务器)。

踩过的坑

  • 「命令找不到」而软链接明明存在:sudo 的 secure_path 不含 /usr/local/bin。解法是用绝对路径调起服务,别依赖 PATH
  • 新版本运行时在老系统上跑不起来:CentOS 7 的 glibc 是 2.17,官方二进制要求 2.28。解法是用官方兼容构建,或退回旧大版本,同时去掉代码里对「新版全局 API」的依赖
  • 退出码显示成 [object Object]:Promise 里 resolve 了对象,外面当数字用。只有真跑一次才会暴露
  • 任务卡住、屏幕一片空白:子进程在等一个永远不会来的输入。解法是加超时保护 + 启动时关掉 stdin
  • 令牌权限没分开:文档写「互不通用」,代码里其实都能调所有接口。只能靠重读代码发现
    还有一类不算 bug 的坑:在错误的终端里粘命令。Windows 的 PowerShell 和 Linux shell 混用,报错五花八门。解决办法土但有效——粘命令之前先看提示符。

明确的边界:没做什么

  • 没上 HTTPS——反向代理被博客占用,等确认日常使用后再做
  • 没做推送通知——靠「看一眼手机」,接口已预留
  • 没在服务器上跑 Agent——依赖重、版本受限、每个任务都烧 API
  • 没做多执行端——协议里已有字段,扩展时不用改
  • 没有「代你登录账号操作」——这类产品最贵也最危险的能力,刻意不做
  • 没有全文抓取——订阅只存标题、一句话、链接,不复制原文

结语:这套东西的本质

它不是「AI 助手」,也不是「自动化平台」。它解决的是一个很具体的不对称:

你有想法的时间(白天、路上、床上),和你机器能干活的时间(晚上),是错开的。
传统做法是人迁就机器——想起来记在备忘录里,晚上再翻出来干。这套东西做的是反过来:让机器迁就人的节奏。

所以核心不是模型多强、界面多漂亮,而是三条:

  1. 队列——让派活和干活在时间上解耦
  2. 暂存——让「记下来」不需要等任何设备
  3. 搬运——让数据最终落在它该在的地方,而不是长期堆在公网机器上
    模型只是其中最不重要的一环:任务可以不用 AI,抓取可以不用 AI,同步完全不用 AI。AI 只是让「一句话概括」这种锦上添花的事变得可能。

先把管道修通,再谈智能。