开发记录:ChatterCatcher——我给家庭群做了个记忆机器人
npm:ChatterCatcher
适合:技术用户自部署 + 飞书/Lark 家庭群
写在前面
最近,飞书新增了很多和AI有关的能力,因此我决定把家庭群迁移到飞书上,不光是为了日后接入AI,也更方便我现在就进行开发。我们家的通知都是我妈转发的,体检时间、学校通知、取餐码、活动改期、各种文件和截图……但是他们最后全都混在几百条闲聊里。每次要找的时候,总得有人去翻聊天记录。
因此,我妈总是红温。
于是,ChatterCatcher 诞生了——一个本地优先、证据驱动的飞书家庭群 RAG 记忆机器人。说人话就是:把它拉进群,它自动记下所有消息和文件,之后你 @ 它问「上次体检几点」,它不光回答你,还会告诉你「是谁在什么时候说的」。
而且他和OpenClaw这些不一样的是,他的上下文不是暴力堆叠的,省Token啊!
调研 & 需求文档
VibeCoding 第一步永远是把问题说清楚。我给自己列的:
-
干什么:做一个飞书/Lark 家庭群的「记忆层」——群里正常聊天,机器人静默记下来,需要时 @ 它提问,它先从本地检索证据再回答。
-
为什么:家庭群的重要信息不是以「文档」形式出现的,而是碎片化地散在聊天里。传统做法是人工翻,又慢又烦。市面上的聊天机器人大多是「万能 AI 助理」,但我不需要万能,我只需要它记住群里说过什么。
-
怎么做:飞书群发消息 → 本地 Gateway 接收 → 消息/文件/图片入库 → 切块 + 索引 → 用户 @ 机器人提问 → 混合检索本地证据 → LLM 基于证据生成回答 → 回复到群里。整个闭环跑在你自己机器上。
-
技术栈:Node.js + TypeScript、SQLite(FTS5 + embedding 向量)、飞书 SDK、OpenAI-compatible LLM/Embedding。选 SQLite 而不是 LanceDB 之类的外部向量库,因为安装成功率比性能重要——我不想让用户卡在
npm install就劝退了。
开发过程
这次我没有用那种全自动 /dev 的方式,而是把工具换成了Claude Code+GPT-5.5,然后用了superpowers这个插件,能够有brainstorm等明确的流程,并且会落成Sepc文档和Plan文档。 通过最近最Superpower的使用,我也掌握了一些新的概念,如worktree。
不得不说,Github拿来开发是真的方便啊,之前不会用branch啥的属实是我蠢了。
整个开发大概分了十几个阶段,挑几个有意思的说。
最纠结的决定:不用外部向量库
一开始用了 LanceDB,功能是跑通了,但这个服务最终是要部署在我爸的古老Intel芯片的Mac上的,而LanceDB没有原生的npm包在这个平台上。纠结了半天,决定把所有 embedding 向量直接存 SQLite,检索时在 Node.js 侧算余弦相似度。
确实没有专用向量库快,但家庭群又不是企业知识库,几千条消息完全够用。更关键的是——npm 全局安装一把过,不用看平台脸色。对 MVP 来说,这个选择是对的。
最惊险的 Bug:工具标记泄露出去了
有一次我发现机器人回复里出现了类似 <tool_call>...</tool_call> 的 XML。吓得我赶紧排查——原来有些 OpenAI-compatible provider 不会按标准 tool_calls 字段返回,而是把 DSML 伪工具调用直接塞进 content。
如果你只检查标准字段,这坨内部标记就原样发到家庭群了。完全看不懂啊
修法是两层防线:第一层在模型适配层把 DSML 解析成内部 tool calls,第二层在飞书发送层兜底——检测到原始工具标记直接拦截。宁可这次回答失败,也别把内部实现细节糊到群里。
最绕的链路:图片记忆
家庭群里的图片不是保存就完了,用户后面可能会问:
- 「那个取餐码是哪张?」
- 「上次发的二维码图片叫什么?」
- 「定时提醒的时候把那张图发出来」
所以我搞了一个链路:飞书下载图片 → 多模态模型描述图片 → 描述文本入库 → 强制保留文件名 → episode summary 也保留文件名 → 定时任务引用已入库文件名 → 发送时由代码解析到本地目录。
简单说就是:模型理解图片内容,人用文件名找回图片,系统守好安全边界。模型只能给文件名,不能给任意路径——这个边界我想了很久才定下来。
最容易被忽略的:时间
群里消息大量是「明天」「今晚」「下周」这种相对时间。如果你不处理,三天后机器人就会说「体检是明天」——用户一看日历,明天是周三,但体检明明是周六啊😮💨
所以我在 episode summary、RAG 检索、最终回答的每个 LLM 路径里都传入了当前时间,并且强制提醒模型:「请结合证据中的消息时间戳,推导出具体日期,不要照搬相对表达」。
这东西实现不复杂,但少了这一步,机器人的回答会非常搞笑。
其他值得一提的
- 自动获取 bot open id:没配置的情况下不会误触发响应,减少手动填错的可能。
- episode memory summary:家庭群聊天是碎片化的,单条消息经常语义不完整,所以按时间窗口把一段聊天整理成 episode summary 再参与检索。
- 定时任务:群内自然语言创建提醒(「每天早上8点提醒我吃药」),支持发送已入库的图片。限制在当前群聊,不能跨群操作。
- Web UI:本地看板,能看到 Gateway 状态、最近消息、QA logs、cron jobs。不花哨,但排障够用。
- 导出/恢复:数据都在本地 SQLite,支持导出和恢复。
当前状态
截止 0.1.28,ChatterCatcher 已经是可用 MVP——安装、配置、接入飞书、沉淀消息、检索回答、引用来源、处理文件图片、定时提醒,完整闭环都跑通了。
但它不是一个「一键安装全家都能用」的消费级产品,目前更适合愿意自己部署的技术用户试用。
下一步不是继续堆功能,而是找真实家庭群场景来打磨:什么信息值得记、什么回答最有用、哪些错误最不能忍。
一句话总结:
ChatterCatcher 的价值不在于「又做了一个聊天机器人」,而在于把家庭群里分散、随口说出的重要信息,变成一个本地、可检索、可追溯、可以被提问的记忆系统。
欢迎使用,如果你觉得好的话也麻烦给我点个Star:[ChatterCatcher Github仓库](GitHub - FlashingChen2024/chattercatcher · GitHub)
PS:如果你也觉得家庭群消息太难找了,欢迎试试 ChatterCatcher。撞到 Bug 直接提 Issue,我改!