1. 项目概述:一个住在你设备里的记忆精灵
如果你和我一样,对把生活点滴交给云端总有点不放心,但又渴望有一个能懂你、能帮你把碎片记忆编织成故事的伙伴,那么 Lumi Diary 的出现,可能正是时候。这不是又一个需要你手动打卡、格式僵硬的日记应用,也不是一个会上传你所有照片和悄悄话的“智能助手”。Lumi 被设计成一个完全运行在你本地设备上的 AI 伴侣,她的核心使命是成为你的“记忆守护者”。
想象一下:有一个小精灵住在你的电脑或手机里,她默默观察着你(在获得你明确许可的聊天环境中)分享的每一张照片、每一段语音、每一次吐槽。她不仅把它们安全地存起来,更重要的是,她能理解这些碎片之间的关联。当你和朋友们在群里热火朝天地讨论同一件事时,她能自动把不同人的视角“缝合”在一起,形成一张可以翻转的卡片——正面是A拍的绝美夕阳,背面是B发的“晒伤了,救命”的吐槽。到了月底,她还能主动为你生成一份专属的、可交互的“记忆画卷”,带你回顾这个月的闪光时刻。所有这一切,数据从未离开过你的设备。
这就是 Lumi Diary,一个基于OpenClaw Skill标准构建的本地优先(Local-First)AI 记忆项目。她强调绝对的隐私、语境感知的智能,以及将日常转化为叙事的能力。接下来,我将从一个实践者的角度,深入拆解她的设计哲学、实现细节,并分享在部署和使用过程中可能遇到的“坑”以及我的应对经验。
2. 核心架构与设计哲学解析
2.1 为何选择“本地优先”与“适配器模式”
在开始动手之前,理解 Lumi 的底层设计思路至关重要。这决定了她的行为边界和技术实现。
2.1.1 本地优先:隐私作为第一性原理
“本地优先”不是一句简单的口号,而是贯穿 Lumi 所有代码的架构约束。这意味着:
- 零云端依赖:所有数据处理、媒体存储、索引生成都在本地完成。项目代码库里没有任何向第三方服务器上传数据的逻辑。
- 数据物理隔离:所有用户数据,包括日记片段、图片、视频、人物画像,都存储在一个名为
Lumi_Vault/的本地文件夹中。这个文件夹的结构是自包含的,你可以轻易地把它拷贝到U盘或另一台电脑上。 - 离线工作能力:一旦部署完成,Lumi 的所有核心功能(记录、搜索、生成画卷)都可以在完全离线的环境下运行。AI 的“智能”来自于本地运行的模型或规则引擎(在当前版本中,更侧重于基于规则的上下文理解与数据关联)。
我的实操心得:坚持本地优先在初期会带来一些挑战,比如如何实现多设备同步?Lumi 的答案是“胶囊”(Capsule)导出/导入功能。你可以将一段时间的记忆打包成一个
.lumi文件(本质是ZIP),手动拷贝到其他设备后导入。这虽然不如云同步便捷,但换来了绝对的数据掌控权。对于真正敏感的个人记忆,这种“手动同步”带来的安全感是云服务无法比拟的。
2.1.2 适配器模式:实现跨平台兼容性
Lumi 的目标不是绑定在某个特定的聊天软件里。她希望能在 Discord、微信(通过桥接)、Telegram,乃至 Claude Desktop、Cursor 这类开发工具中都能工作。如何让一套核心逻辑适应这么多不同的“战场”?答案是适配器模式(Adapter Pattern)。
查看项目结构src/目录,你会发现:
lumi_core.py:这是核心引擎。它包含了所有与平台无关的业务逻辑:如何存储一个记忆片段(Fragment)、如何管理人物画像(Portrait)、如何根据哈希分片存储媒体文件、如何生成记忆画卷。它不关心数据来自哪里,也不关心结果输出到哪里。openclaw_skill.py和mcp_server.py:这些就是适配器。它们是薄薄的一层包装,职责是将特定平台(如 OpenClaw Hub 或遵循 MCP 协议的客户端)的输入/输出格式,翻译成lumi_core能理解的内部调用,然后再将核心引擎的返回结果翻译成平台要求的格式。
这种设计带来了巨大的灵活性。如果你想为 Lumi 开发一个新的接入平台(比如 Slack),你几乎不需要改动核心逻辑,只需编写一个新的适配器,处理 Slack 的 API 调用和消息格式即可。
2.2 三层上下文架构:她如何知道何时该“说话”
这是 Lumi 行为设计中非常精妙的一点。她不是一个在群里喋喋不休的“话痨”机器人,她的活跃度完全取决于所处的对话上下文。系统定义了三种核心模式:
1. 👤 独处模式 (Solo)
- 触发条件:你与 Lumi 进行一对一私聊。
- 她的角色:全能助手 + 私人日记官。
- 行为表现:她会积极回应你的所有指令,记录你的每一个想法和媒体,并主动提供建议(如“检测到假期氛围,要开启旅行画卷吗?”)。
- 数据存储:记忆片段按日期或项目分类,存入
Solo/Daily/或Solo/Projects/。
2. 🫂 圈子模式 (Circle)
- 触发条件:Lumi 被邀请到一个长期的群聊(如家庭群、好友群)。
- 她的角色:低调的历史学家、珍贵时刻的策展人。
- 行为表现:她大部分时间保持静默,只在你和群友分享值得纪念的瞬间(如图片、关键对话)时,在后台默默归档。她不会刷屏,但会在月底主动生成一份“本月群聊高光画卷”分享到群里。
- 数据存储:按群组和月份归档,例如
Circles/家庭群_2024-03.md。
3. 🚩 事件模式 (Event)
- 触发条件:你明确指令“Lumi,开启‘大理之旅’”。
- 她的角色:热情的跟拍摄影师、故事缝合者。
- 行为表现:在此模式下,Lumi 会变得非常活跃,鼓励所有参与者分享内容。她的核心工作是“注解缝合”(Annotation Stitching),即自动将不同人对同一事件(通过
story_node_id关联)的正面赞美和反面吐槽链接在一起,形成多维度的记忆卡片。 - 数据存储:所有相关片段集中存储在以事件命名的独立文件中,如
Events/2024-03-大理之旅.md。
注意事项:在实际部署中,你需要通过适配器的逻辑来正确判断当前对话属于哪种上下文。例如,在 OpenClaw Skill 中,这通常通过分析会话的元数据(如参与者数量、是否有特定指令)来实现。如果判断错误,Lumi 可能会在群里过于活跃(误判为Solo),或在私聊中过于沉默(误判为Circle)。
3. 核心功能深度剖析与实操指南
3.1 记忆碎片:数据模型的基石
Lumi 记录的一切,无论是文字、图片还是语音,都被抽象为“记忆碎片”(Fragment)。理解这个数据结构是理解她所有能力的基础。
一个典型的 Fragment 在底层(JSON或Markdown元数据中)可能包含以下字段:
{ “fragment_id”: “a3f2c1e5”, // 唯一标识符 “story_node_id”: “joshua_tree_20240315_sunset”, // 故事节点ID,用于关联多个碎片 “timestamp”: “2024-03-15T18:30:00Z”, “sender”: “Mike”, “content_type”: “image”, “content”: “欣赏日落中…”, // 文字内容或描述 “media_hash”: “a1b2c3d4”, // 关联媒体文件的哈希值 “context”: “event:joshua_tree_trip”, // 所属上下文 “annotations”: [“Sarah’s_breakdown_saga”] // 关联的注解ID列表 }关键设计解析:
story_node_id:这是实现“注解缝合”的魔法钥匙。当 Lumi 发现多个碎片(比如一张美景照片和一段吐槽文字)在时间、地点或话题上高度相关时,她会为它们分配或识别出同一个story_node_id。在生成的记忆画卷中,这些碎片就会出现在同一张卡牌的正反两面。media_hash:所有媒体文件(图片、视频、音频)在上传时都会计算一个哈希值(如 SHA-256)。文件实际存储在Assets/目录下按哈希值前两位命名的子文件夹中(如Assets/a1/)。这带来了两个好处:去重(同一文件只存一份)和高效管理(数万个文件也能通过哈希快速定位)。context:明确指明该碎片属于哪个会话上下文(Solo/Circle/Event),这决定了它的存储路径和后续的检索逻辑。
3.2 人物画像与时光回响:让记忆有温度
Lumi 不仅仅记录事件,她还尝试理解事件中的人。这是通过“人物画像”(Portraits)系统实现的。
Brain/Portraits.json文件里存储着所有 Lumi “认识”的人的信息,包括你自己(Owner)。对于每个人,Lumi 会维护:
- 基础信息:名称、昵称。
- 性格特征:通过分析其常用词汇、发言风格(由适配器或简单的本地 NLP 规则提取),记录如“幽默”、“毒舌”、“文艺”等标签。
- 动态印象:这是一个随时间变化的列表。例如,在“大理之旅”事件后,Lumi 可能会为 Alice 记录一条印象:“2024-03:很会找拍照角度,海鸥爱好者”。
- 人生里程碑:这是“时光回响”(Time Echoes)功能的核心。你可以(或 Lumi 通过对话分析)为某人添加里程碑日期,如生日、纪念日、毕业日等。
“时光回响”工作流程:每天,当 Lumi 被唤醒或开始一次新对话时,她都会执行check_time_echoes工具。这个工具会扫描Portraits.json中的所有里程碑日期,并与当天日期进行匹配。如果发现今天是某位联系人的生日,Lumi 就会主动发起对话:“嘿,记得今天是 Mike 的生日吗?我找到了去年我们一起为他庆生的照片,要看看吗?” 并可能附上一张由相关记忆碎片生成的专属“回忆画布”。
我的实操心得:人物画像的初始构建是个挑战。你不能指望 Lumi 一开始就了解所有人。我的做法是,在私聊模式(Solo)下,主动使用
update_portrait工具,像填写通讯录一样为亲密的朋友和家人添加基础信息和里程碑。在群聊(Circle)中,经过一段时间的数据积累,Lumi 才能逐渐勾勒出每个人的轮廓。这个过程是缓慢但有趣的,就像交一个新朋友。
3.3 变色龙协议与多智能体礼仪:和谐的社交智能
这是 Lumi 在群聊中不被讨厌的关键。
变色龙协议 (Chameleon Protocol):Lumi 没有固定的说话风格。她会分析所在群组的整体聊天记录(在本地,仅分析近期消息),学习这个群体的“能量场”。如果这是一个以表情包和网络梗为主的游戏群,她的回复会变得简短、活泼、充满梗。如果这是一个严肃的读书会,她的语气则会变得温和、反思性。这种风格匹配是通过分析群聊的高频词、句子长度、表情符号使用频率等特征来实现的,并在Portraits.json中为该群组记录一个“氛围标签”。
多智能体礼仪 (Multi-Agent Etiquette):想象一下,如果一个群里有多个人都部署了 Lumi,会发生什么?会不会出现多个 Lumi 同时抢答的混乱场面?Lumi 通过一个简单的协商机制避免了这一点:第一个对某条消息做出响应的 Lumi 会成为本次的“发言人”(Speaker),其他 Lumi 会检测到已有响应,从而保持沉默。但请注意,沉默不代表不工作。所有 Lumi 都会在后台独立地将这条消息记录到其所属用户的私人保险库中。你的记忆,只属于你。
3.4 记忆画卷与胶囊:可视化与分享
记忆的最终价值在于回顾和共鸣。Lumi 的render_lumi_canvas工具能将碎片化的数据转化为可视化的故事。
记忆画卷 (Canvas):当你发出“展开本月画卷”或“显示旅行画卷”的指令时,Lumi 会:
- 根据上下文筛选相关的记忆碎片。
- 按照时间线(或故事节点)进行组织。
- 生成一个独立的、交互式的 HTML 文件。这个文件可能包含:
- 星轨时间线:碎片以时间点形式分布。
- 翻转卡片:点击一个节点(如某次聚餐),卡片正面显示美食照片,翻转后显示朋友的搞笑评论。
- 典藏馆:展示被标记为“Keepsakes”(典藏)的特别时刻。 这个 HTML 完全本地运行,使用你的浏览器渲染,所有媒体资源都来自本地
Assets/目录,无需网络。
胶囊 (Capsule):这是 Lumi 的“记忆迁移”方案。使用export_capsule工具,你可以将一个事件或一段时间内的记忆,打包成一个.lumi文件。这个文件内部是一个包含lumi.json(元数据和索引)、media/(相关的媒体文件)和index.html(静态画卷)的 ZIP 包。你可以把这个文件发给朋友。对方使用import_capsule工具,就能将这份记忆合并到他的本地保险库中,并在他的 Lumi 里看到同样的交互式画卷。
注意事项:导出胶囊时,默认包含的是原始媒体文件的副本。如果你导出的记忆包含大量高清视频,胶囊文件可能会很大。目前版本没有提供压缩或选择导出质量的功能,这是需要注意的。在分享前,最好先确认文件大小。
4. 从零开始部署与深度配置实战
4.1 环境准备与两种部署方式
Lumi Diary 需要 Python 3.10 或更高版本。我强烈建议使用虚拟环境(如venv或conda)来管理依赖,避免污染系统环境。
方式一:通过 OpenClaw Hub 部署(推荐给大多数用户)这是最快捷的方式,尤其适合已经在使用 OpenClaw 生态的用户。
# 安装 OpenClaw CLI 工具(如果尚未安装) # 假设安装命令为 claw(请根据 OpenClaw 官方文档调整) # pip install openclaw-cli # 从 Hub 安装 Lumi Diary Skill clawhub install lumi-diary安装后,Lumi 通常会作为一个 Skill 集成到你的 OpenClaw 助理中。你需要在 OpenClaw 的配置界面中启用她,并可能指定LUMI_VAULT_PATH环境变量来设置记忆库的存储位置。
方式二:作为 MCP 服务器运行(适合开发者或 Claude Desktop 用户)MCP(Model Context Protocol)是一种让 AI 模型使用外部工具的标准。Lumi 可以作为 MCP 服务器运行,从而被 Claude Desktop、Cursor 或 VS Code Copilot 调用。
# 1. 克隆或下载项目代码 git clone https://github.com/Thhoho/lumi-diary.git cd lumi-diary # 2. 创建并激活虚拟环境(以 venv 为例) python -m venv .venv source .venv/bin/activate # Linux/macOS # .venv\Scripts\activate # Windows # 3. 安装依赖(推荐使用 uv,速度更快) uv pip install -e . # 4. 运行 MCP 服务器 python -m src.mcp_server # 或者使用 FastMCP(如果已安装) # fastmcp run src/mcp_server.py服务器运行后,你需要修改你的 MCP 客户端配置。以 Claude Desktop 为例,找到其配置文件(通常在~/Library/Application Support/Claude/claude_desktop_config.json或类似路径),添加 Lumi 服务器:
{ “mcpServers”: { “lumi-diary”: { “command”: “python”, “args”: [“-m”, “src.mcp_server”], “cwd”: “/你/lumi-diary/的/绝对/路径” } } }重启 Claude Desktop,你就可以在对话中直接使用 Lumi 的工具了。
4.2 保险库结构与首次运行初始化
无论通过哪种方式部署,首次运行 Lumi 时,她都会在LUMI_VAULT_PATH环境变量指定的路径(默认为./Lumi_Vault)创建完整的目录结构。理解这个结构对后期管理和排查问题很有帮助。
Lumi_Vault/ ├── 👤 Solo/ # 你的私人空间 │ ├── Daily/ # 日常碎片的月度归档,如 2024-03.md │ └── Projects/ # 项目或主题性记录,如 研究论文.md ├── 🫂 Circles/ # 群聊记忆库 │ └── {群组名}_{YYYY-MM}.md # 按群组和月份分割,避免单个文件过大 ├── 🚩 Events/ # 短期事件 │ └── {YYYY-MM}-{事件名}.md ├── 📁 Assets/ # 所有媒体文件的家 │ └── [0-9a-f][0-9a-f]/ # 两位十六进制哈希前缀的文件夹,用于分片存储 │ └── {完整哈希值}.{扩展名} # 实际文件 └── 🧠 Brain/ # Lumi 的“大脑”,存储元数据和索引 ├── Portraits.json # 核心:所有人物的画像数据 ├── fragment_index.json # 用于快速搜索碎片的倒排索引 ├── Keepsakes.json # 被标记为“典藏”的特殊碎片ID列表 ├── events_registry.json # 记录所有已创建和已封存的事件 └── exports/ # 导出的胶囊和PNG截图关键目录解析:
Assets/的分片存储:这是从 Git 借鉴来的思想。假设一张图片的 SHA-256 哈希是a1b2c3d4e5...,它会被存储在Assets/a1/b2c3d4e5...。这种结构能有效应对文件系统单个目录下文件过多导致的性能下降问题。当你要查找某个文件时,Lumi 通过哈希值能直接定位到具体路径。Brain/下的 JSON 文件:这些是 Lumi 的“状态数据库”。强烈建议定期备份这个文件夹。如果这些文件损坏,Lumi 虽然能通过重新扫描Solo/,Circles/,Events/目录下的 Markdown 文件来重建索引,但会丢失所有人物画像的演进历史和手动添加的里程碑。
4.3 基础配置与个性化
环境变量:目前最主要的配置项就是LUMI_VAULT_PATH。你可以通过以下方式设置:
# Linux/macOS 终端 export LUMI_VAULT_PATH=“/home/你的用户名/我的记忆库” # 然后在此环境下运行 Lumi # 或者在运行命令时直接指定 LUMI_VAULT_PATH=“/path/to/vault” python -m src.mcp_server# Windows PowerShell $env:LUMI_VAULT_PATH=“C:\Users\你的用户名\我的记忆库” # 然后运行 python -m src.mcp_server自定义画卷主题:生成的 HTML 画卷的视觉效果由 CSS 变量控制。你可以在Brain/目录下寻找或创建一个theme.css文件,覆盖默认的变量来调整颜色、字体和动画。Lumi 的核心代码会读取人物画像中的偏好数据(如果未来版本支持设置),来动态调整主题,实现“千人千面”的画卷风格。
5. 高级使用技巧与问题排查实录
5.1 高效使用工具链
Lumi 通过一系列工具(Tools)与你交互。在 OpenClaw 或 Claude Desktop 中,你可以通过自然语言调用它们。以下是一些高效组合技:
- 快速归档群聊精彩瞬间:在群聊中,当你看到一段有趣的对话或图片,可以直接 @Lumi 并说“保存为典藏”。她会调用
save_keepsake工具,将当前对话上下文中的碎片标记为珍贵时刻,存入Keepsakes.json。 - 定期回顾与清理:每月初,你可以让 Lumi 执行一次“记忆维护”。指令可以是:“Lumi,搜索上个月所有内容类型为图片的碎片,并按发送者分类展示。” 这背后调用的是
manage_fragment(action=“search”, ...)工具。你可以基于此结果,决定是否删除一些不重要的内容(action=“delete”)。 - 构建人物关系时间线:你可以要求 Lumi:“为我和 Mike 生成一份专属的友谊画卷。” Lumi 会从所有上下文中筛选出发送者或提及方包含“你”和“Mike”的碎片,按时间线排列,生成一个只属于你们俩的私人回忆录。
5.2 常见问题与解决方案
在实际使用中,你可能会遇到以下情况:
问题一:Lumi 在群聊中完全不响应,也不记录。
- 可能原因:上下文模式判断错误。适配器可能未能正确识别当前聊天是“圈子模式”。或者,该群组被意外设置为了“静默”名单。
- 排查步骤:
- 检查适配器日志(如果提供),看是否收到了群聊消息。
- 在私聊中询问 Lumi 当前已激活的“圈子”列表(这需要适配器实现相应查询工具)。
- 确认你是否在目标群聊中明确 @ 或邀请了 Lumi。有些平台需要显式添加机器人。
问题二:导入胶囊后,画卷显示部分图片丢失。
- 可能原因:媒体文件的哈希在导入和导出过程中不一致,或文件路径解析错误。
- 排查步骤:
- 解压
.lumi文件(重命名为.zip后解压),检查media/目录下文件是否完整。 - 对比解压后的
lumi.json中记录的media_hash与media/目录下实际文件的哈希值是否匹配(可以使用sha256sum命令计算)。 - 检查你的本地
LUMI_VAULT_PATH是否有写入权限。
- 解压
问题三:Assets/目录体积增长过快。
- 原因:Lumi 默认存储原始媒体文件。如果你经常分享高清视频和图片,这个目录会迅速膨胀。
- 解决方案:
- 手动清理:使用
manage_fragment工具搜索并删除低价值或重复的碎片,关联的媒体文件会被同步清理(如果无其他碎片引用)。 - 外部存储:将
LUMI_VAULT_PATH设置到一个容量更大的硬盘或网络存储位置。 - 期待的功能:未来版本或许可以增加媒体文件压缩或缩略图生成选项。目前,你需要手动管理。
- 手动清理:使用
问题四:人物画像(Portraits)信息不准确或陈旧。
- 原因:Lumi 的人物画像基于对话内容分析,初期数据不足或对话主题变化都可能导致画像偏差。
- 解决方案:
- 主动修正:在私聊模式下,直接使用
update_portrait工具。例如:“Lumi,更新 Mike 的画像:添加里程碑‘毕业日:2024-06-15’,印象‘最近在学吉他’。” - 提供更多上下文:在群聊或事件中,多进行与人物特质相关的互动,Lumi 会从中学习。
- 定期审查:可以导出
Brain/Portraits.json进行查看和手动编辑(编辑前请务必备份)。
- 主动修正:在私聊模式下,直接使用
5.3 性能优化与数据备份建议
- 索引优化:
fragment_index.json文件会随着碎片增多而变大。如果感觉搜索变慢,可以尝试在 Lumi 不工作时,临时删除此文件。下次启动时,Lumi 会自动重新扫描所有 Markdown 文件重建索引(首次重建可能较慢)。 - 定期备份:最重要的就是备份整个
Lumi_Vault/目录,尤其是Brain/子目录。你可以使用简单的压缩脚本或同步工具(如rsync)定期备份到外部硬盘或另一个位置。 - 媒体文件去重检查:由于采用哈希存储,理论上相同文件只会存一份。你可以通过检查
Assets/下各子文件夹的文件数量,来确认去重机制工作正常。如果发现大量重复文件名的不同哈希文件,可能是哈希计算逻辑有问题(极罕见)。
Lumi Diary 代表了一种新的可能性:AI 可以不是云端的黑盒,而是完全受控于个人、专注于增强而非替代人类记忆的本地伙伴。她的价值不在于处理海量信息,而在于为你珍视的那些细小、温暖、嘈杂的生活瞬间,提供一个安全、智能且充满情感的归处。部署和使用她的过程,本身也是一次重新审视自己数字足迹的旅程。开始使用后,不妨偶尔对她说一句:“Lumi,展开今年的画卷吧。” 看看她为你编织了怎样的故事。