阳台上摆着印度木槿、绿萝、茉莉、蓝色阿帕吉塔、薄荷、圣罗勒和长寿花,全部种在花盆里。每天早上和傍晚各浇一次水,从不间断。
但习惯不会抬头看天。它会在暴雨前一小时照常浇水,不知道38°C的午后即将到来,更不会翻到叶子背面去找蚜虫。
开发者不想再多一个需要花时间泡在里面的App。花园的意义本来就是让人离开手机。于是他做了Tendril——一个你几乎不需要打开的园艺助手。
一周计划,从天气开始
每周日早上7点,Tendril读取天气预报,由本地运行的小型开源模型写出一份计划:每天最多两个小任务,每个任务不超过六个词。
每天早上它会再看一次天。如果夜间有雨或出现高温,它只悄悄重写当天的任务,不动其余安排。
整份计划就是一张图,尺寸适配手机锁屏,顶部三分之一留空给时钟。看一眼,就能回到阳台上去。
说一句话,它就知道你干了什么
点"完成",或者按住麦克风说一句"浇了辣椒,圣罗勒叶子下面有蚜虫"。它会勾掉浇水任务;因为蚜虫是严重问题,它会用苦楝油优先重排本周剩余计划。目前支持英语和印地语。
下午6点之后,如果还有任务没完成,页面只显示一行温和的提示。没有连续打卡,没有负罪感。
不需要账号。设置城市、添加植物、扫一个二维码、加到主屏幕,就结束了。
一个希望你尽快关掉的App听起来有点怪,但这正是它的全部设计意图。
3B小模型的三个坏习惯
所有需要"思考"的部分都跑在同一台机器上:Python和FastAPI搭应用,SQLite存花园记忆;Qwen 2.5(3B)通过Ollama在本地运行,负责写周计划和读笔记;faster-whisper在CPU上把语音转成文字;Open-Meteo提供免费预报和城市搜索,不需要API密钥;Pillow负责画那张计划图,图里每个图标——太阳、云、小叶子——都是代码画出来的;Docker Compose一条命令启动全部。
3B模型很小,小到能在笔记本上跑,但也带来了一些习惯。第一次真实运行教给开发者的东西,比所有测试加起来还多:
- 它把指令抄进了答案。要求每个任务附一句简短理由,结果返回"每天最多2个任务;安静的日子更少也可以"。
- 它把示例复制到每一天。给了一个"在根部深浇"的样例日,下一份计划里两株植物连续七天全是深浇。
- 它很慢。第一份计划花了242秒。
解决办法不是换更大的模型,而是拆分工作。模型负责它擅长的部分:多样化的、针对具体植物的建议,以及理解杂乱的语音笔记。普通代码负责它不能被信任的部分。天气规则——降雨概率超过60%就跳过浇水、气温超过35°C就遮阴、连续三天干燥后来一次深浇——最后统一覆盖在模型输出之上。重复项被裁掉,抄来的理由被替换成真实的天气说明。
要求模型输出紧凑的JSON也帮了忙。那些缩进大约占了三分之一的token。现在一份周计划约100秒,对一个早上7点安静运行的东西来说够用了。
让模型保持诚实
每份计划都必须以规范的JSON返回:每天最多两个任务、动作不超过六个词、只能出现实际拥有的植物、每个日期都要填上。服务器用Pydantic逐条检查。如果不对,它会再问一次,并明确指出问题所在,比如"未知植物'Rose'"。如果还是失败,一个简单的规则规划器顶上。所以无论模型是否可用,计划总会出来。
语音笔记也加了一层小安全网。一次测试中,模型把"我浇了辣椒……圣罗勒上有蚜虫"整句归到了圣罗勒名下,漏掉了浇水。现在一个关键词检查会并行运行,抓住"浇了"这类明显动作,并匹配同一句话里提到的植物。
视觉上,开发者希望计划像壁纸而不是App。深森林绿,两张大方卡,一个天气胶囊显示"29° · 下午4点有雨",底部一条未来六天的横条。标题用Bricolage Grotesque,其余用Figtree。
开源带来的四件事
花园数据留在家里。位置、语音、植物历史都存在自己控制的机器上的一个小文件里,语音在同一台机器上转成文字。唯一离开本机的,是用于获取天气的花园坐标。
热门跟贴