README.md
8.19 KB
微信自动回复系统(Pixel 端上)
2026-07-08 ~ 07-10 建成。别人给微信发消息(私聊 / 群@我 / 群引用我)时,Pixel 上的 Hermes 自动读上下文、按火星人口吻生成回复,走确定性安全闸判定:白名单直发,其余进本地 Web 审批页 等人工点发送。全链路端上,不经 Mac/云。
数据流
微信来消息
│
① watcher(7×24, inotify 事件驱动, Magisk service.d 自启 + 看门狗)
│ su 解密读 message → 分类(私聊/群@我/群引用我) → 写 incoming.jsonl → fire-and-forget 触发 ↓
② orchestrator --drain(cursor 增量 + 单实例锁 + 首跑基线)
│ ├─ env2 查上下文:rcontact 身份(备注>昵称>别名) + 最近 N 条历史(一次拷库全批复用)
│ ├─ env3 生成:hermes -z(deepseek-v4-pro,SOUL.md=火星人手机助手口吻)
│ └─ env4 判定:policy.decide() 确定性安全闸(白名单读 circle.db)
│ ├─ auto → send_text_via_hook 直接发 + reply_queue(auto_sent)
│ └─ review→ reply_queue(pending)
│
③ wechat-viewer(Flask, 手机端 :5000)
├─ /approvals 待审列表 + 可编辑草稿 + 【✅发送】【🗑取消】
└─ /whitelist 白名单增删(联系人 / 群)
文件清单
| 文件 | 位置 | 作用 |
|---|---|---|
wechat_reply_watcher.py |
设备 ~/.hermes/wechat_reply/ |
① 通知触发:inotify 监听微信 DB → 增量读新消息 → 分类 → 写 incoming.jsonl → 触发编排器 |
wechat_reply_daemon.sh |
同上 | watcher 监督器:root+Termux 环境、单实例、等微信登录、看门狗崩溃重启 |
service.d__wechat-reply-watcher.sh |
设备 /data/adb/service.d/wechat-reply-watcher.sh |
开机拉起监督器 |
wechat_reply_orchestrator.py |
设备 ~/.hermes/wechat_reply/ |
②③④⑤ 编排:消费队列→上下文→生成→判定→落地 |
wechat_reply_policy.py |
同上 | ④ 确定性策略引擎 `decide()→skip |
wechat-viewer 改动 |
设备 ~/wechat-viewer/(Flask) |
④⑤ UI:/whitelist + /approvals,新表 reply_whitelist/reply_queue,发送复用 send_text_via_hook。详见 wechat-viewer-changes.md + viewer_templates/ |
wechat-db-decrypt skill |
设备 ~/.hermes/skills/ |
② 上下文查询配方 + 密钥推导(skill/ 留档) |
SOUL.md |
设备 ~/.hermes/SOUL.md |
③ 人设=火星人手机助手(留档一份) |
本目录是 Mac 侧留档 / 版本源;设备是运行时。
wechat-viewer在手机上有自己的 git 工作树, 那部分改动已部署但由用户自己在该 repo 提交(本仓库只存改动说明 + 新模板)。
关键设计决策
- 环节1 为何事件驱动:定时轮询要每次拷 90MB 微信库,耗电。改用 ctypes inotify 监听 DB 文件写入(SELinux 放行,零轮询、空闲零 CPU),失败退回 stat mtime。
- 环节2/3 为何不写模块:Hermes 本身是有 shell+SQL 的 agent,查上下文=skill 配方,生成=它自己。只有编排器把这些串起来才需要代码。
- 环节4 为何必须是确定性代码:环节3 实测「SOUL.md 里的软约束会漏」(约饭案例模型仍主动接话)。安全门必须是 LLM 说服不动的硬规则:default-deny + 敏感词(钱/承诺/约时间/隐私,白名单也拉回)+ skip(群没@我/公众号/系统消息/自己发的)。
- 账号自适应:运行时
MD5("mm"+uin)定位当前登录账号,MD5("1234567890ABCDEF"+uin)[:7]推导 SQLCipher key,多账号切换自动跟随(不硬编码)。 - 失败即静默:生成超时/失败 → 无草稿 → policy skip → 不发。最坏情况是不回,绝不误发。
- API 发送的两个坑(2026-07-11 硬仗定位,详见 memory
wechat-api-send-onresume-flush):- 中文必须走
--es text_b64(--es text被 shell/am 弄乱 → 卡 status=1)。 z2.b只入队(status=1 转圈),WeChat NetSceneQueue 要一次真实的 app 切换(切走→切回微信 = onPause→onResume)才派发。这是设备机制不是代码 bug,别去 diff/重编译 hook。- flush 加固(2026-07-12,
_send_text_verified):发送后time.sleep(4)让消息稳稳落库(太快切换微信还没登记这条)→_onresume_cycle()(KEYCODE_HOME背景化 2.5s →am start LauncherUI切回停 3s)→ 切回后停在前台多轮查 status,不立刻再切走(否则打断正在进行的网络发送)→ 没到 2 再来一轮。真机实测:屏幕亮/灭(Dozing)都 ~15s flush 到 status=2(旧版单次切换+被动等常卡几十秒~分钟)。 - 送达校验:轮询
message.status(1=发送中/2=已达/5=失败);超时仍 1 视为"已入队将送达",不误报失败。
- 中文必须走
运维
看状态
adb shell 'su -c "pgrep -f wechat_reply_watcher.py"' # watcher 活着?
adb shell 'su -c "tail -5 ~/.hermes/wechat_reply/watcher.log"' # 采集日志
adb shell 'su -c "tail -5 ~/.hermes/wechat_reply/orchestrator.log"' # 编排日志
# 审批页:手机浏览器开 http://127.0.0.1:5000/approvals
自检 / 手动跑
python wechat_reply_watcher.py --selftest # 推导key/解密/inotify 是否 OK
python wechat_reply_watcher.py --once # 单读一遍新消息
python wechat_reply_policy.py --demo # 策略 8 用例自检
python wechat_reply_orchestrator.py --drain # 手动跑一轮编排
开启自动发(默认全审核)
- 在
/whitelist加信任的联系人 / 群(xxx@chatroom自动识别为群)。 - 把
~/.hermes/wechat_reply/policy_config.json的auto_send_enabled设true。- 敏感词(钱/承诺/约时间/隐私)即使白名单也仍会拉回人工审批。
- 建议先审核模式跑几天,草稿质量稳了再放开。
真机验证
2026-07-10(各环节)
- inotify 触发读取 → 写队列 → 自动拉起编排器 ✅
- 真实猎头上下文 → 生成火星人口吻草稿「哈哈婷婷,我不是什么总,就是个写代码的,不负责招人这块哈」→ 进 /approvals ✅
- 审批页发送 →
send_text_via_hook广播到 filehelper(sent)、取消(cancelled) ✅ - 策略引擎 8/8、多账号自适应、生成失败静默不误发 ✅
- 单实例防重、杀 watcher 自动重启、纯 root(boot 上下文) selftest ✅
2026-07-12(端到端闭环,系统正式跑通) 🎉
/whitelist页开自动发总开关 + 把火星人加白名单 → 火星人私聊 → 自动回复送达 ✅- 延墨/丁鹏群里 @我 → 自动回复送达 ✅(私聊 + 群@我两条链路全通)
- 发送 flush 加固后真机:屏亮/屏灭(Dozing) 都 ~15s 到 status=2 ✅
待收尾(都非阻塞,系统已可用)
- 群回复 @ 触发者:✅ 文字前缀已做(2026-07-12)——群消息回复自动加
@昵称(U+2005=微信原生分隔符),process_event里确定性拼接(不靠 LLM)。⚠️ 仅文字 @(看得见),红点通知(atuserlist)未成,搁置(跟下面引用气泡一起后面做)。逆向进度/坑见 memorywechat-group-at-atuserlist:atuserlist 不在 message 行、在微信 UI 发送链路(≠我们合成的 r0+z2.b),self-learning z2.b hook 没抓到;WeChatHook 里已有--es at+ 自学习脚手架(WIP,生产不传 at 无影响)。⚠️ 重编译 hook 会强退微信=要重登。 - 原生引用气泡:现发纯文本;微信原生引用(A11y 长按→引用)是环节5 增强。跟上面红点@一起做(都涉及微信发送链路逆向)。
- 日志轮转:watcher/orchestrator log 24/7 会长(ponytail 已标)。
- lifelog 人物增强(二期):回链
com.lemon.lifelog的 Person 库让回复带人物记忆。 auto_send 开关搬进 viewer UI✅ 已做(2026-07-12):/whitelist页顶部开关卡片,GET/POST /api/auto_send读写policy_config.json。
相关文档
../../../md/wechat-auto-reply-requirements.md— 需求 + 逐环节设计/状态wechat-viewer-changes.md— viewer 集成改动全记录skill/wechat-db-decrypt-SKILL.md— 微信 DB 解密 + 上下文查询配方