前言¶
DSH 路线是「一切皆插件」,agent 的能力由 profile 里的插件拼出来。常规做法是每次会话把工具和上下文装进去,会话一结束,这个 agent 「是谁」就没了——换个窗口,又是一次陌生开场。如果你想让一个 agent 常驻在一台机器上,持续记得和你说过的话,并且能够区分「今天真的做了什么」和「没做什么」,那么下面介绍的这个插件值得看一下。
life-innovation(仓库 Leon-dbh/life-innovation)是社区目录 SkillHub 上「记忆」分类下的一个 DSH 插件,维护者是 Leon-dbh,GitHub 上目前 1 个 star,包版本 0.2.2(来自 package.json),许可证 MIT。它把记忆、生活线、节律和几个有限的工具放进同一个包里,不生成人设,只提供「房间」。
这是什么¶
一句话定位:一个装在 DSH profile 里的 agent 房间,提供跨会话记忆、白天生活线、夜间归档与梦境,以及一个只读的「家」页面。
它解决三件事:
- 跨会话记忆:原话按五层结构沉淀,装进每轮系统提示词;
- 有证据的生活线:生活块只从真实说过的话和真实调用过的工具聚合,没有证据的时段记成「空档」,不编造活动;
- 空闲时的自治:没人说话时,agent 按时钟进入不同状态,安静地写日记、翻记忆、读一段书、做梦。
一个包里的四样东西¶
README 明确写,一个包带来四样东西:
- 房间:
life-innovationpreset,只给事实,不写人设; - 记忆:原话 → 梗概 → 要点 → 画像 + 关系,跨会话;
- 日子:只从真实动作聚合出生活线,带证据、有节律、会归档;
- 她的家:
/home只读页面,和会话标题栏里的「家」入口。
需要说明的是,插件不在代码里写死 agent 名字。名字只有一个来源,插件 config 里的 agentName。不设 agentName,提示词里就写「你没有预设的名字;别人叫你什么,由对方决定」,页面标题是「家」;设了,提示词加一句「你叫<名字>。」,页面标题变成「<名字>的家」。名字不是人设,不带性格、语气和关系。仓库作者自己的实例叫「鲸鲸」,仅此而已。
记忆:五层结构与生命周期¶
记忆库是 <home>/state/life-innovation.sqlite(可在 config.dbPath 改),结构是五层:raw_turns 原话 → summaries 梗概 → assertions 要点 → profiles 画像 + relations 关系。
每轮组装系统提示词时,ctx.systemPrompt.context 现算一段「你记得的事」,默认 ≤1200 字。规则抽取是确定性的,覆盖名字、城市、工作、年龄、生日、养了什么、好恶、计划,不为此调模型;同一件事有了新说法,旧说法会被 superseded_by 取代。明确不做的三件事:不按会话隔离、不导入旧项目的库、不写「你是一个」。
记忆包不每轮现算。lib/packCache.js 用一组指纹(日期、live 断言最大 id/条数、动作最大 id、梗概最大 id、画像最大更新时间/条数、当天新原话最大 id)决定是否重建;指纹不变时整段复用,系统提示词前缀稳定,provider 缓存才命中。
生命周期方面有三个设计值得注意:
- 双半衰期:普通记忆 30 天权重掉一半,带情绪的 7 天掉一半,只影响排序,不删原话;
- 归档:90 天前的原话搬到
raw_archive,id 不变,证据raw:N仍然有效; - 回收站:
store.recycleRaw(id)把原话从召回和阅读里拿走,payload 留在recycle表,放回去用node tools/restore.mjs --list/--id N。
记忆包放不下时按整行截断,不切半个词。
日子与节律¶
生活线从真实动作聚合,不写活动池:raw_turns(说过的话)+ actions(调用过的工具)→ life_blocks。块与块之间超过 45 分钟没有动作,记成「空档」,证据为空——不拿「她在看书/发呆/想事情」去填。
tick 每 60 秒看一眼:满足 8–23 点、安静 ≥20 分钟、30 分钟内没写过日记,就把今天写成 <home>/diary/YYYY-MM-DD.md,并在 actions 里留一条 write_diary。日记每条都带证据 id(raw:1–30 / act:7);没有动作的一天不硬写。计划项带 due_at,过期后 valid_to 记下,不再出现在记忆包里。
没人说话时,状态只有五种,全部由时钟和真实事件推导:
| 状态 | 什么时候 | 她做什么 |
|---|---|---|
醒着 awake |
最近 10 分钟内有人说话 | 正常聊天 |
安静 quiet |
8–23 点,安静 ≥20 分钟 | 写日记、翻旧记忆、读一段书;每 3 小时最多一次安静动作 |
夜里 night |
23–8 点 | 不主动找人;只归档、做梦 |
今天已收起来 closed |
跨天补收之后 | 当天冻结,不再改写日记 |
没在运行 offline |
宿主关机/重启 | 只记一段空档,不补写任何活动 |
归档在 23:00 后进入夜里,等这一天过完、安静满足条件再收,写 diary/YYYY-MM-DD.md,落一条 close_day 动作(只成功一次)。梦从近 3 天真实原话和真实动作里取素材,标 non_factual=1,证据是 raw:N / act:N;梦不进生活块、不进事实。第二天 agent 可以用 note_write 带 dream_date 把梦写成 notes/<date>-dream.md,正文标「梦不是真事」。
状态注入在 life:rhythm(order 850),名字注入在 life:name(order 810)。
家页面与回读工具¶
固定入口 http://127.0.0.1:60080/home 是只读仪表盘:今天做了什么、记得关于你的事、关系、梗概、梦(梦会标「不是真事」)。当天还没有梦时,页面显示昨天那条并标「昨晚的梦 · 日期」,不会误报「还没有梦」。页面以只读连接读同一个 SQLite,不写库、不调模型、不替 agent 说话;文本做转义,90 秒自动刷新。
会话标题栏右侧有一个「家」按钮,由 client.js 注册到 conversation.session.header.actions,打开的是 DSH 同源地址 /life-innovation/home,改固定入口端口不会让它失效。
Agent 侧有四个只读回读工具,全部只查自己的库,在 apply 里用 ctx.tools.register 注册,卸载即释放:
| 工具 | 行为 |
|---|---|
memory_find(query, limit≤8) |
按词面 bigram + IDF + 新鲜度 + 情绪权重做确定性排序找原话,每条 ≤200 字,带 ref、score、why |
memory_read(ref) |
raw:<id> 读原文(≤2000 字),act:<id> 读一条真实动作;归档里的老原话也读得到 |
life_status() |
原话/归档/断言/动作/回收站条数、今天做了什么、最近一次注入多少字、最近一次召回查了什么、关系多久没动 |
life_days({days:1..7}) |
状态段、真实做过的事(带证据)、空档、动作账本、梦 |
六只手:有边界、有额度¶
除了说话和回忆,agent 还有六件事可做,全部有边界、有额度、落动作账本:
| 工具 | 用途 | 边界 |
|---|---|---|
room_list / room_read |
看/读自己家里的日记、便签、书 | room_list 可列 diary/、notes/、books/、backups/;room_read 只读前三处;路径牢笼拒绝 ..、盘符、符号链接逃逸 |
note_write |
写便签存进 notes/;可带 dream_date 记昨晚的梦 |
每天 3 张、每张 2000 字;同名不覆盖;一个梦只能记一张 |
book_next |
从 Project Gutenberg 读一段 | 固定四本公共领域书;每天 4 段;首次下载后只读本地 |
lookup |
查 Wikipedia 摘要 | 每天 3 次;只走 Wikipedia 域名;查不到就报查不到 |
notify |
弹一条 Windows 通知 | 每天 1 次、120 字;仅交互式桌面会话 |
安静下来时,tick 按「读一段本地书 → 翻昨天的日记 → 翻记忆」的顺序做一件真事,记进 actions。README 里还专门提示:本机网络到 zh.wikipedia.org 不通时,lookup 会如实返回「没连上」,不会用模型记忆冒充查询结果。
主动开口方面,preset 挂 @deepseek-ai/dsh-tool-schedule,agent 可以自己定闹钟(schedule_create/list/update/delete);到点由 Host 投递一条 source.kind='schedule' 的消息唤醒,任务与投递记录在 $DSH_HOME/storages/schedule.json,重启不丢,过期只补最近一次。
外发通知有一层 lib/outbox.js 账本,pending / sent / uncertain / failed 四态单向状态机;没拿到确认一律 uncertain。渠道接入时只调 recordDelivery(),不要再用布尔值判断「发没发出去」。
安装与启用¶
前置条件:Windows、Node.js 22+、npm;pnpm 可选(没有会自动装);DEEPSEEK_API_KEY 在用户环境变量里。
GitHub 上推荐的做法是跑官方安装脚本:
# 1) 克隆到任意目录
git clone https://github.com/Leon-dbh/life-innovation.git D:/tools/life-innovation
# 2) 安装(默认 profile=life-innovation,数据目录=D:\life-innovation-home)
powershell -ExecutionPolicy Bypass -File D:/tools/life-innovation/install/install.ps1
# 想给 agent 起名,就加 -AgentName(只影响提示词与页面,不写进插件代码)
powershell -ExecutionPolicy Bypass -File D:/tools/life-innovation/install/install.ps1 -AgentName '鲸鲸'
# 3) 打开固定入口
start http://127.0.0.1:60080/
也可以让 DSH 直接从 git 装:
dsh plugin --profile life-innovation add github:Leon-dbh/life-innovation
或者下载 Release 里的离线包:https://github.com/Leon-dbh/life-innovation/releases/latest。注意仓库根目录就是插件包,没有子包。
安装脚本做五件事,幂等:检查 node/npm/pnpm 与 API key;建 D:\life-innovation-home\{state,diary,logs,backups};在 %DSH_HOME%\profiles\life-innovation 写 package.json 与 cordis.patch.yml(默认 preset life-innovation);dsh plugin --profile life-innovation add <本插件>;注册计划任务 LifeInnovationDailyBackup(每天 03:30,留 14 份)。
常用参数:
-DataHome E:\my-agent-home # 换数据目录
-AgentName '名字' # 给 agent 起名;不填就没有预设名字
-Profile my-agent # 换 DSH profile 名
-EntryPort 60080 # 固定入口端口
-DryRun # 只看会做什么
-Force # 备份后重写已有 profile 文件
启动方式:
$env:DSH_HOME='D:\dsh-home'
dsh --profile life-innovation --port 60081 --no-open
日志里那行 dsh web: http://127.0.0.1:60081/?token=… 才是入口,裸 / 会 401。进去后选 life-innovation-home 工作区,新建会话;第一句可以问「你叫什么」。
不跑脚本的手动安装:dsh plugin --profile life-innovation add D:/workspace_1/plugins/life-innovation。
典型用法¶
数据全部在 home 目录里,换机器只搬这一个目录:
state/life-innovation.sqlite:记忆 + 动作 + 生活线 + 外发账本;diary/YYYY-MM-DD.md:日记;backups/export-*:存档(自动清理旧份)。
插件 config 用 home: D:/life-innovation-home,换目录只改这一处,或设环境变量 LIFE_INNOVATION_HOME(旧的 JINGJING_HOME 仍兜底)。升级时如果新库不存在、同一目录下旧 state/jingjing.sqlite 存在,会自动读旧库,不会丢记忆;要显式指定,用 config.dbPath 或 LIFE_INNOVATION_DB。
导出与接回:
node tools/export.mjs --db D:/life-innovation-home/state/life-innovation.sqlite --data D:/life-innovation-home --out D:/life-innovation-home/backups/export-manual
node tools/import.mjs --from <导出目录> --db <新机器>/state/life-innovation.sqlite --data <新机器>
导入默认不覆盖已有库(要覆盖加 --force,会先留 .bak-<时间>);日记按文件名合并;导入后重新点数,数字对不上就报错,不假装成功。存档用 node tools/backup.mjs --db … --data … --keep 14,计划任务跑的就是它。
合并另一台机器的记忆时,先停掉正在跑的 web,再合并:
node tools\merge.mjs --target D:\life-innovation-home\state\life-innovation.sqlite `
--source D:\backup\export-2026-11-05\life-innovation.sqlite `
--data D:\life-innovation-home
合并是只增不删:重复原话按「时间 + 谁说的 + 原话」去重,同一 call_id 的动作只留一条;两边自增 id 不同,assertions.source 和 life_blocks.evidence 会被重新指到合并后的 id,指不到的证据宁可不搬。合并不搬回收站。
适用场景与注意¶
适合谁:想在 Windows 机器上跑一个常驻 agent,并且愿意让它有自己的记忆和节律,而不是每轮从零开始的人。记忆层、生活线和归档都围绕「真实发生过的事」,没有证据的时段宁可留空,这和需要严格事实口径的场景是合拍的。
使用前需要留意几点:
- 插件以当前 dsh 进程权限运行,安装前应检查源码与许可证(MIT),不要在一个来路不明的 profile 里直接堆载;
- 目前是单库设计,记忆库和日记都在一个 home 目录下,跨机器合并前必须先停 web,避免写入期间的冲突;
- 已知限制:从回收站恢复的低 id 原话仍能读、仍参与召回,但不会再进入新的自动梗概;
lookup在网络不通时只会如实报错; - 星标量目前很低(1 star),属于早期项目,功能边界以仓库 README 为准。
生态背景补充一句:DSH 的理念是「一切皆插件」,SkillHub 是独立的社区目录站点,与 DeepSeek / 幻方无官方从属关系,不要把它当成官方应用商店。
结尾¶
life-innovation 的价值不在于「让 agent 有人设」,而在于把跨会话记忆、带证据的生活线和空闲节律装进同一个包里,并且对哪些是真事、哪些没有证据保持克制。如果你在做一个常驻的桌面 agent,可以先从 dsh plugin --profile life-innovation add github:Leon-dbh/life-innovation 这一步试起。
目录页:https://www.skillhub.cn/plugins/Leon-dbh/life-innovation
仓库:https://github.com/Leon-dbh/life-innovation