减脂用微信零碎记录饮食,剩下的交给 Agent

背景
最近在刷脂,每天热量有个硬指标:TDEE 2400,缺口最多 25%,也就是目标 1800 kcal。
正餐这块好办。我每周备餐,吃什么、吃多少克都是定死的,一顿饭的营养算一次就固定下来了。
麻烦的是零碎饮食。
馒头、嘴馋了的加餐,这些不在备餐计划里的东西,才是热量失控的源头。它们没有规律,全靠”当时吃了什么”这个记忆,而这恰恰是最容易丢的。
以前我也试过正经记录:打开 App,找食物,填克数,算热量。坚持了几天就放弃了。一套动作步骤太多,只要哪一步觉得麻烦,整个习惯就断了。
后来我把这个流程拆开了:记录只留一步,就是发微信;剩下的识别、算热量、汇总、通知,全部交给 Agent。
现在我在微信里发一句”今天吃了一个馒头”,之后 Telegram 就收到一条通知,告诉我这馒头多少热量,今天累计还差多少到目标。


我额外还做了一个页面,可以直观统计我的所有饮食情况:
整条链路
先看完整的数据流:
1 | |
人只需要做最前面那一小步,后面全是自动的。
记录端:发一条微信,别的都不用管
Obsidian 里装了个插件叫 Messager,它绑定了一个微信服务号。我在微信里给它发消息,消息就会被追加到当天日记的 ### Logs 区块里。
所以记录的动作就变成:吃了什么,顺手在微信里打一句话。

微信几乎总是开着的,比专门打开一个记录 App 的成本低太多。这也是整套流程能坚持下来的前提:记录动作必须轻到不需要”专门去做”。
识别端:Agent /loop 轮询
这是核心部分。
日记不是专门给饮食记录用的,### Logs 下面什么都有:工作任务、随想、系统配置想法、吃了什么,全混在一起。所以不能让它无脑解析,得逐条做语义判断。
我把这套逻辑写成了一个提示词(prompts/snack-loop.md),用 CC 的 /loop 模式定期跑,每轮做这几件事:
- 读当天的日记文件;
- 扫描全文,找出所有”未标记”的行;
- 逐条语义判断:这条是不是在说吃了/喝了什么;
- 是食物 → 提取食物名和份量,查
foods.json算营养,写入data/intake.json; - 不是食物 → 在行尾打标记,下次跳过;
- 跑
build.py刷新 dashboard,有新食物就推 Telegram。
判断的标准:
| 信号 | 例子 | 处理 |
|---|---|---|
| 进食动词 | 吃、喝、啃、点了(外卖) | 当饮食处理 |
| 食物名词 | 烤肠、咖啡、奶茶、可乐、包子 | 当饮食处理 |
| 份量词 + 食物 | 一根、一杯、一碗、几块 | 当饮食处理 |
| 工作任务 | - [ ] checkbox、#StarRocks 技术标签 |
标记 ⏭️ 非饮食 |
| 心情/随想 | 没有食物名词的感想 | 标记 ⏭️ 非饮食 |
| 像食物但识别不了 | “刚才吃了点东西” | 标记 ⚠️ 无法识别 |
最后一条我特意强调了保守原则:描述模糊、明显在吃吃喝喝、但又定位不到具体食物时,宁可标”无法识别”,也不强行估算。估算错了就是污染数据,还不如不记。
入库与校验:intake.json 和 build.py
识别出来的食物会追加到当天记录的 零碎饮食 meal 里,再重算当天总热量和三大营养素。
1 | |
营养值不是随手填的。foods.json 里有一份查表,Agent 按名字查 per / kcal / protein / fat / carb / fiber,再乘上实际份量。查不到的就常识估算,build.py 只会 warn,不会挂。
还有个硬校验:build.py 会把当天的顶层合计和所有 meal 加起来的值对一遍,差超过 0.5 就直接失败。所以 Agent 每次写入后必须重算 totals,算错一步就推不出去。这个校验看起来是给自己找麻烦,实际上保证了数据的一致性。
份量这块,Agent 有一张估算参考表,把口语折算成克数:
| 口语描述 | 默认估算 |
|---|---|
| 一根烤肠 / 一根香肠 | 80g |
| 一杯奶茶 / 一杯咖啡 | 中杯 500ml / 350ml |
| 一瓶可乐 | 500ml(罐装 330ml) |
| 一块饼干 | 15g |
| 尝了一口 / 一小口 | ~20g / 20ml |
通知:Telegram 实时反馈
每轮只要识别到了新食物,就会推一条 Telegram 通知。这是整个流程里最重要的一环:反馈。
1 | |
最后那个”已超/未超目标”的对比是点睛之笔。目标热量从 config.json 里算出来(TDEE × (1 − 缺口比例) = 1800),没超就显示”还可吃”,超了就红叉。它把我从”记了但不知道够不够”,变成了”记完立刻知道今天还能不能吃”。
幂等和历史不可变
这两个是我比较在意的设计。
幂等:日记里每条处理过的内容,行尾都会被打上 HTML 注释标记。
1 | |
这个标记是”已处理”的唯一状态。下次轮询扫到带标记的行直接跳过,所以同一个 loop 跑多少遍都不会重复入库。loop 是长期挂着跑的,一旦重复入库,数据就废了,这个设计很关键。
历史不可变:旧的周报和旧的 intake 记录视为历史,只追加新记录,不改写旧数据。减脂是连续观察,昨天的数字一旦被改掉,趋势线就是假的。
数据同步
每轮只要写了新数据,Agent 会自动 git commit 然后 push 到远程。这样即使本机出问题,数据也不会丢。
push 失败也没关系,本地提交会保留,联网后补推就行,不阻塞整个 loop。
总结
回头看这套流程,核心思路很简单:把”记录”这个高频动作的成本降到最低,剩下的计算和汇总全部甩给 Agent。
人这一侧,只有一步:吃的时候顺手发条微信。
Agent 那一侧:识别、查表、算热量、更新 dashboard、推通知、同步数据,全自动。
这套链路能跑起来,主要靠三件事:
- 记录够轻(微信发消息),所以坚持得下来;
- 反馈够快(Telegram 实时通知 + 目标对比),所以愿意记;
- 状态够明确(幂等标记 + 历史不可变),所以长期挂着跑不出乱子。
如果你也在减脂或者控热量,零碎饮食怎么记一直是个老大难,这套”微信 + Agent”的组合值得安利。成本就是一条微信消息,剩下的交给 Agent 就行。
当然整个链路还有优化的地方,比如消息不够及时,因为我的 Agent 是部署在家里的一台闲置的 MacBook 上的,他也是通过定时拉取 Obsidian 数据来同步消息的,Agent loop 也有时间间隔,所以还做不到非常的实时。
同样的受限于现在的 Agent 限制,他们的 loop 周期都不能开很久,导致我隔一段时间就要新建一个 loop。
这个后续考虑会基于 pi 自己定制一个 Agent;可能有人会为为啥不用 openclaw 或者是 workbuddy 这种成熟的产品?
主要还是这些产品满足的都是通用的需求,往往功能复杂、安装包也很大,我的老 mac 运行起来确实有点吃不消,所以一开始就用最简单的方式把整个链路串起来。