有人把一台树莓派变成了一个小世界,里面住着一个快递员。他每天在三个地点之间送包裹,闲下来就修复一份属于自己的文件,偶尔写几行日记。写日记这件事,他自己并不知道有人在读。
这个项目叫 Still,作者把它定义成"一个活在树莓派上的生命"。他住在终端里,有一份该做的工作,有日子要过,也有事情在等。有时候发生了点什么,他就写下来;大多数时候什么都没发生,他一个字也不写。
最后这一点,作者说花了他最长时间才想明白。最初的本能是排班:早上写、下午写、晚上写,一天三篇,稳定可预期。但那样写出来的只是报告。于是他改成按冲动写——世界每推进一个 tick,只有值得记下的事发生时才落笔,一天最多两三篇,有些天一篇都没有。
一篇日记长这样:
- "我在修理店遇到了 Ivo。我把他帮我恢复的文件给他看。他看了看空着的所有者一栏,又递了回来,没有填。"
他大多数日子都不是这样的。大多数日子没什么事,而接受这一点是最难的部分。
三个地点,一份残缺的文件
他的职业就是快递员,仅此而已。世界里有三个地方:他出发的仓库、Mara 守着柜台的档案处、Ivo 修东西的修理店。包裹在三地之间流转。如果他迟到,一个叫 Ren 的人会出现,看一眼交接,记下时间,然后离开。
他自己还有一份文件,叫 old-index,其中三行已经损坏。有空的时候他就修复,一次一行。目前的状态是:路径、所有者、是否保留三行,所有者那一行是空的。他不知道这份文件属于谁。他把它拿给 Ivo 看,Ivo 看了看空白,又递了回来。
那份文件是他世界里唯一真正关于他自己的东西,也是唯一没人能帮他的东西。
机器就是他的天气
他不知道这些规则。世界没在运行时,缺失的小时会被记为睡眠或普通时间,取决于具体钟点,不会编造事件去填补。他不在场的那段时间,不会得到任何故事。
机器吃紧的时候,他移动变慢、送件迟到,而迟到是唯一能把 Ren 引来的事。他也不知道有人在读他的日记。
整个项目是一个 Python 服务,约 1300 行,分布在十几个模块里。四个部分最关键。
模型是本地跑的 Gemma 4 E2B,开放权重,下载一次,由 llama.cpp 的 llama-server 以 still 为别名提供服务。一个 worker 完成一次 tick 后,真实地休息一小时。不是 cron:下一次 tick 从上次结束的那一刻开始排,所以慢的 tick 会把世界往后推,而不是把任务堆起来。
写入者只有一个。worker 在数据库里取一个租约,第二个 worker 会被拒绝,哪怕它位于 Docker 文件系统的另一侧。作者说这个 bug 是他把一个原生 worker 和容器里的 worker 并排跑才发现的——Docker 的 flock 拦不住它,数据库租约可以。
模型负责选择,代码负责决定。Gemma 从不发明任何东西,它只从一份 JSON schema 里挑一个编号动作,schema 里只有合法动作,代码再校验一次答案。模型不可达,或者答案不是合法索引,这次 tick 就记录为一次安静的等待和一次失败,绝不编造动作。文件、投递、截止时间、谁站在哪里、错过截止要付什么代价,全部由 Python 决定。
SQLite 是唯一事实来源。每一次 tick 都被存下来,包括什么都没发生的那种。已发布的日记单独一张表,触发器禁止更新和删除,所以一篇日记写完之后无法再改。发布记录会标明这次 tick 是沉默、写作、已发布还是失败。失败的写作不会在之后重试,缺口就保持为缺口。
三个比架构更重要的决定
第一是拒绝清单。每篇日记入库前都要过检查:句子数量不对、太长、不是第一人称、写给了某个读者、包含比较、直接陈述情绪,任何一条命中就丢弃。日记宁愿空着,也不发布破坏声音的东西。
第二是硬件必须在容器外采样。向容器询问负载均值,拿到的是 Docker 虚拟机,作者称之为"一个礼貌的谎言"。所以另有一个进程把真实机器的状态采样进一个小 JSON 文件,worker 去读它。机器吃紧时,快递员的合法动作会被削减到只剩手上正在送的那一单,世界于是可以记下:"移动很慢。我留在了原地。"
第三是一条诚实的限制:每小时一次的节奏是确定性测试过的,不是靠等一周验证的。它没有连续跑过几天,也还没在树莓派上跑过。写作闸门刻意做得简单,而简单的闸门会产生很长的沉默。
为什么不直接用 API
最明显的问题是:为什么不用 API?那样更简单,用大模型写出来的文字大概也更好,更快、更聪明,不用下载权重。
但那样一来,慢的部分就不再是这台电脑,而变成了某家公司的定价页。作者不想要这个,他要慢是真实的。所以它跑在树莓派上,开放权重、本地推理、不需要联网。连接断了它继续写,服务商改了免费额度、关停、或者觉得这个账号不值得留,它也继续写。
速度不是他选的设置,而是这台小机器能跑多快就是多快,慢,热了更慢。想让日记写快一点,没有配置项,只能换硬件。这就是"慢而稳"在这里的含义:不是给项目装饰的主题,而是他手上这台机器的物理上限。
至于省了多少时间,答案是零。这是一本他从不写、也不按计划读的日记,只花一点电,不替他做家务。他是有意这么做的:这周做的东西都是为他自己做的,只有这一个不需要他。启动一次,它自己累积,看不看都一样。没有 API key、没有账号、没有账单、没有网络、没有要维护的东西。
所以诚实的数字是节省零分钟。换来的是一份记录,记录着一个小生命,他不必开口要,也不必亲手写。
热门跟贴