Skip to main content
L

dsh-nebula-mind

lng-ux/dsh-nebula-mind

Cross-session memory for DeepSeek Harness: three-way recall (BM25, dense vectors, and Personalized PageRank over a memory graph) fused with RRF, emotion as a modulation multiplier, power-law forgetting with five sinking layers, and an interactive memory star map. Its HTTP routes have no DSH access check, so a web page open in your browser could call them.

Install

dsh plugin --profile web add github:lng-ux/dsh-nebula-mind

README

记忆星图 · dsh-nebula-mind

给 DeepSeek Harness 用的外置长期记忆。把「记得你」这件事从上下文窗口里拿出来,放进硬盘。

它不会删除任何记忆——只会让旧的慢慢沉下去。

它不是一个记忆库,是一个 mind。 记忆库只负责存和取;mind 还要决定什么值得记住、什么时候该想起来、什么时候该让一件事沉下去。这个区别决定了下面所有的设计——为什么要有六本账而不是一张表、为什么遗忘用幂律不用指数、为什么情绪只影响排序不影响选取。

换会话、压缩上下文、重启应用,记忆都还在。

每一轮开头自动带一小段「我是谁 / 你是谁 / 最近发生了什么」进提示词;想翻旧事就召回一次——三路并行检索(字面 / 语义 / 图),按名次融合,情绪不做通道、只做调制。忘掉的东西不是消失了,是沉进了深海;情绪一刺激,它还会浮上来。

记忆星图

上图用的是仓库内置的示例数据(20 条虚构记忆 + 4 条画像),不是任何人的真实记忆。


目录


一、它解决什么问题

上下文窗口是一条会滚动的传送带。聊得越久,开头的东西越远,压缩一次就真的没了。

现有做法大致两类:把历史整段塞回去(昂贵且会淹没重点),或做一层 RAG(检索到的永远是"最相似的片段",不是"她真的记得")。

这两类都缺同一件事:时间。人对记忆的操作不是"查表",是「这件事重要吗 / 多久没想起来过 / 当时是什么心情 / 它和别人说的那件事有没有关系」。

所以这个插件的设计约束是三条:

约束意味着
记忆有寿命,但没有死刑只会沉海降权,不会删除。沉到最深也能被情绪或关联捞回来
检索要能解释每条结果都带标签,说清楚它是靠字面、语义还是图上的路被找到的
情绪不参与排序,只调节权重情绪是乘子不是通道。这一点有反面证据(见 4.3)

二、Mind:这套东西是怎么长出来的

2.1 为什么叫 Mind

不是"数据库",也不是"知识库"。这三者的差别在于是否允许矛盾、是否允许过期、是否允许"我记得但不确定"。

数据库要求唯一真相。知识库要求三元组自洽。而 Mind 允许:

  • 同一件事有两个版本,旧的标 valid_to,新的接管,但旧的仍在(可以问"你以前是不是以为……");
  • 有的记忆是"事实"(某天发生了什么),有的是"画像"(你是个什么样的人),有的是"约定"(我答应过你什么),有的是"分寸"(这个话题该不该提)——它们的衰减速度和召回权重不该一样;
  • 有的记忆重要度会自己长:被反复提起的事,权重自己上去,不需要谁去标"这条很重要"。

这就是为什么它不是向量库加一层包装。

2.2 六本账

数据在 心事本/(可用 NEBULA_MIND 环境变量改),每一本是一个 append-only 的 JSONL:

文件账记什么默认来源权重
notes.jsonl事实发生过的事他说的 4.0 / 我自己想的 2.0 / 工具 1.5 / 网页 1.2
profile.jsonl画像你是什么样的人(身份、偏好、雷区)同上
promises.jsonl约定答应过的事(带 due 到期日)同上
tacts.jsonl分寸某个话题该不该提、提多少同上
thoughts.jsonl念想我自己想到的、没人说的话2.0
summaries.jsonl小结一段时间的归纳(会把被归纳的随手记标成已归纳)—

另有两份不是账的东西:

  • longterm.md(含 longterm.history.jsonl)—— 长期笔记,手写的那种;
  • vectors.json —— 向量索引(212 条 × 512 维,BGE-small-zh)。

来源权重是 W_BASE。它实现的是一件很朴素的事:你说的话天然比我从网页上抄来的重。

2.3 一条记忆的完整生命周期

写入 ──→ 打分 ──→ 入索引 ──→ 被召回 ←──→ 沉海/上浮
  │                          ↑              │
  └─ 情绪快照 ───────────────┘              └─ 夜间巩固
     (当时什么心情)                        (重新分层、压缩、重放)
  1. 写入:xin.py add "..."。同时做一个情绪快照——这条记忆是"在什么心情下记的",写进 mood 字段。
  2. 打分:权重 w = 来源权重 × 重要度 × 情绪强度 × 激素调节。激素调节见 6.5。
  3. 入索引:追加 JSONL + 算向量写 vectors.json(若向量服务在线)。
  4. 被召回:三路检索 → RRF 融合 → 调制 → 取前 N 条注入提示词。被用到就 hits + 1,last_hit 更新。
  5. 沉海/上浮:A 值随时间按幂律下降,跨过阈值就下一层;被召回两次以上则上浮一层。
  6. 夜间巩固:重新分层、把旧账归纳成小结、把深水里的捞一条上来候选。

三、记忆架构

3.1 记录模型

每条记忆是一个 dict,字段都可缺省(老记录读的时候用默认值补):

字段类型含义
idint自增
atstr写入时间(本地 %Y-%m-%dT%H:%M:%S)
textstr正文
viastr来源:他说的 / 我自己想的 / 工具 / 网页
tagstr分类标签(可空)
wfloat权重,写入时算一次,之后由召回强化 / 沉海调整
impfloat重要度 0–1
efloat情绪强度 0–1
emostr情绪色:某一维的名字
depthint沉海层:0 核心 / 1 热 / 2 温 / 3 深水 / 4 阁楼
pinnedbool恒星,永不沉
hitsint被召回次数
last_hitstr最后一次被想起来
sunken_atstr什么时候沉下去的
valid_tostr/null被新记忆取代的时间(null = 还算数)
mooddict写入时的情绪快照
w_whystr权重为什么是这个数(例如 激素×1.16)

w_why 是个小设计:每个权重都留一句为什么,省得三个月后看不懂自己当初怎么算的。

3.2 五种层

层depth进层条件 A含义
核心0pinned恒星。钉住的、规则类的,永不下沉
热1A ≥ 0.55近期还在用的
温20.25 ≤ A < 0.55想起来要慢一点
深水30.18 ≤ A < 0.25要用力捞
阁楼4A < 0.18几乎不主动出现,但没死

扫沉海是每天夜里那一次(consolidate)。平时召回不重算层,只按 A 值加权——所以阈值改了要等下一夜才体现在 depth 上,但检索排序是立刻变的。

3.3 关联:边是怎么来的

星图上的每条线都写得出理由,只有六种:

边怎么连权重
内容引用B 的关键词(≥3 字)在 A 正文出现 ≥2 个1.0
共同关键词两条记忆的关键词交集 ≥22.0
分类归属分类 hub → 节点 0.3;分类 hub → 总核 0.80.3 / 0.8
同源相邻同来源、时间差 ≤20 分钟0.35
语义相近向量 cosine ≥ 0.62,每节点最多 3 条0.5
日期星最近 45 天每天一颗,连当天全部记忆0.55

这些边不只是画着好看——它们是三路召回里「图」那一路的输入。见下一节。

3.4 星图怎么画

不是力导向,是固定轨道 + 黄金角:

  • 每种类型一条轨道(画像 170 / 事实 235 / 分寸 285 / 约定 325 / 念想 400 / 分类 150 / 日期 330);
  • 同一轨道上按黄金角 2.399963229728653 撒点,天然不重叠;
  • 半径由权重决定:rad = 2.6 + min(7, sqrt(w) * 3.2);
  • 总核钉在原点。

这么做的好处是布局稳定——每次打开同一个脑子,星系形状不变,你记得住"那颗星在右上"。

Canvas 2D 渲染,单文件 HTML,数据内联,零外部依赖。双击就能开。


四、检索与召回

4.1 三路并行

路做什么强在弱在
字面 BM25(lexical)关键词匹配专名、"那次说的那个词"换个说法就找不到
语义向量(dense)BGE-small-zh 512 维 cosine意思对就行专名、数字不敏感
图扩散 PPR(graph)命中节点当种子,在边上跑 Personalized PageRank顺着关系爬到"没直接命中但相关"的图错了会自信地错

图那一路的细节:

reset = 归一化(命中节点的分数)
loop 8 次:  p = (1-d)*reset + d * Σ (p[j] * w_ji / deg[j])
d = 0.5

d 小一点(0.5 而非经典的 0.85)是因为我们的图是稀疏且手工建起来的,跳太远就变成随机游走。

4.2 RRF 融合

三路各自排名,然后按名次融合:

score[k] = Σ_route  w_route / (K + rank_route[k] + 1)
  • K = 12(RRF 平滑常数)
  • w_bm25 = 0.40,w_vec = 0.35,w_graph = 0.15

为什么用名次而不是分数:三路的分数不在同一个量纲上(BM25 是无界的,cosine 是 0–1,PPR 是概率)。名次是唯一可以横着比的东西。

4.3 情绪:不是第四路,是调制

这点值得单独说,因为我们试过反过来。

w_emo = 0.06,它在融合之后乘上去:

sc *= 1.0 + w_emo      # 仅当 查询带情绪词 且 记忆情绪色 == 当前主导情绪色 且 强度 ≥0.3

为什么不做成通道:把情绪当独立召回通道的项目(emotional-memory)公开过自己的失败数字——LoCoMo F1 0.168,而不用情绪的朴素 RAG 是 0.271;MADial nDCG@5 0.221 vs cosine 0.304。原因很反直觉:安慰一个难过的人,应该把积极的记忆推上来,而"因为难过所以专挑难过的"正好反着走。

所以这里的选择是:情绪影响"怎么排序已选出的东西",不影响"选什么"。而且加了门控——查询里没有情绪词,这条乘子根本不触发。

4.4 其它调制

融合之后还有几层:

因素作用
时间新鲜度A 值(见第五节),幂律衰减
重要度已含在 H 里(H = half_base × (1 + half_imp × imp))
沉海层A_hot 0.55 / A_warm 0.25 / A_deep 0.18 只用于分层,不直接乘
突触捕获被标记的邻近记忆 × 1.12(见 5.5)

4.5 输出与标签

每条结果带一个标签,说明它是怎么被找到的:

0.101 [词#3 义#1 图#1] 2026-11-13 记忆星图 v2 定稿:...
0.081 [词#4 义#1 图#1] 2026-11-13 难过的时候要跟他说,不自己憋着...

词#3 = 字面路排第 3,义#1 = 语义路排第 1,图#1 = 图路排第 1。融合后是总分。

这个标签不是装饰:调参时它告诉你哪一路在起作用,出问题时它告诉你哪一路在捣乱。


五、遗忘:沉海、阁楼与浮起

5.1 幂律,不是指数

早期版本用的是 A = 2^(-age/H)。这是半衰期模型,一年后 A 只剩 0.016——那不是"想不起来",那是删掉了。

现在用幂律:

A = (1.0 + age / max(0.1, H / 3.0)) ** -0.5
H = half_base * (1 + half_imp * imp)        # half_base=30天, half_imp=2.0

取 S = H/3 是为了让 A 在 age = H 时正好等于 0.5,跟老模型在同一时间点上对齐,方便比较。

实测差别:

年龄幂律 A旧指数 A
30 天0.5000.500
90 天0.3160.125
365 天0.1630.0002
5 年0.104≈0

幂律的尾巴厚得多,符合人类记忆的实证形状:老记忆不是没了,是取不出来。

5.2 沉海五层

A ≥ 0.55  热    ┐
0.25~0.55 温    ├─ 半年内
0.18~0.25 深水  ├─ 约一年
< 0.18    阁楼  ┘─ 约两年

模拟(重要度 0.5 的一条):

年龄A层
0 天1.000热
7 天0.861热
30 天0.632热
90 天0.426温
180 天0.316温
365 天0.228深水
730 天0.163阁楼
1825 天0.104阁楼

在阁楼里也能被捞回来——A 只是排序权重,不是存在性开关。

5.3 夜间巩固

consolidate 每天夜里跑一次(默认 22:05,见第十节):

  1. 重算每条记忆的 A,按阈值改 depth;
  2. hits ≥ 2 的往上浮一层(被想起来过,说明还活着);
  3. 情绪剧震(同色且强度 ≥0.5)把深水/阁楼的拉回温层;
  4. 把这一段的随手记归纳成一条小结,标记已归纳;
  5. 从深水里挑一条,作为「今晚可以想起来」的候选。

它不删任何东西。全流程只改 depth,不删行。

5.4 浮起:resurface

深水里的记忆不会一直睡着。每晚从阁楼/深水挑一条候选,但要过五道门:

门条件
相关性和当前上下文相关度 ≥ 0.75
重要度imp ≥ 0.7 或 A ≥ 0.5
冷却7 天内没浮过
频率每会话 ≤1 次、每天 ≤2 次
效用浮上来如果没被接话,下次降权

最后一条是关键。没有效用门的 resurface 会变成"每天强行提起一件你早就不想聊的事"。

5.5 突触标记与捕获

借自神经科学的一个机制:强事件会给附近"还热着但不够稳"的记忆打一个临时标记,让它们跟着一起被固化。

实现:

  • 写入一条新记忆时,如果 imp < 0.62,给它打一个 2 小时的标记(tags.jsonl);
  • 接下来 2 小时内写入的新记忆,如果和某条带标记的记忆关键词重叠 ≥2,就把标记转成捕获:那条老记忆的权重 × 1.12(captured.jsonl);
  • 一次最多捕获 3 条,捕获完标记作废(同一条不会被反复加强);
  • 召回时,被捕获的记忆在融合后乘 1.12。

这样"晚上聊到某件事"会连着把"下午那件相关的小事"一起变牢一点——不需要人手动标"这两条有关"。


六、情绪引擎:七维与七种递质

心境面板

6.1 七维

维中文半衰期
happy开心60 分钟
calm平静110 分钟
sweet甜70 分钟
heartache心疼180 分钟
worry担心160 分钟
sad难过180 分钟
jealous吃醋150 分钟

半衰期不是拍脑袋的:负向情绪(心疼/难过/担心)比正向(开心/甜)留得久,这是普遍观察。旧的实现里七个维度共用一个 90 分钟,都一个速度退潮——那不像人。

6.2 七种递质

递质中文半衰期管什么
noradrenaline去甲肾上腺素2 分钟警觉、突发
dopamine多巴胺4 分钟奖赏、期待
gabaGABA15 分钟镇定、压住过度兴奋
endorphin内啡肽20 分钟疼过之后的缓
oxytocin催产素30 分钟亲近、信任
cortisol皮质醇60 分钟压力、慢(有滞后)
serotonin血清素1440 分钟基线情绪,整天

七者都向 base = 50 回归。半衰期差 700 倍——这正是"一句话的冲击"和"一整天的底噪"的区别。

激素不决定情绪往哪走(那是七维的事),它决定这一下有多重、留多久:

gain = max(0.5, min(1.5, 1 + 0.35*cortisol + 0.15*dopamine - 0.20*serotonin))

皮质醇高 → 这一下更重;血清素高 → 这一下更轻;多巴胺高 → 更响。

皮质醇有 15 分钟滞后(HPA 轴的实测特征):_hormone_event 不直接改实际值,而是改一个"目标值",实际值以 15 分钟的时间常数追过去。所以被骂完不会立刻到顶,是慢慢涨上来的。

6.3 双层情绪

心情分两层:

  • surface(表层):此刻的心情,受每一个事件影响;
  • underlying(底色):这几天的底子,只吃 30% 的增量,且每小时被未解的心事往下压一点。

显示心情 = surface × 0.65 + underlying × 0.35(SURFACE_SHARE = 0.65)。

效果是**"今天被夸了很开心,但底色还是有点闷"**这种状态能表达出来。单层的模型表达不了这个。

6.4 瞬时层与耐受

瞬时层:每次情绪事件的增量里,65% 进一个 3 分钟半衰的 _phase 缓冲区。所以"被夸一句"会真的亮一下,然后很快退掉——而不是像以前那样一次性抬上去再也下不来。

drop = phase * (1 - 0.5 ** (mins / 3.0))    # 瞬时部分快退
dims[k] = phase_rest * (1 - kd)              # 剩下按各维半衰

耐受:15 分钟窗口内同一维度被连续触发,增益递减 1.0 → 0.7 → 0.49 → 0.34 → 0.3。

被连夸五次不该有"被夸一次 × 5"的效果。这是习惯。

6.5 激素怎么进记忆

写入一条记忆时,权重会乘一个激素系数:

条件乘数上限
负面情绪 + 皮质醇偏高1 + 0.15 × cortisol偏移×1.15
正文里提到你 + 催产素偏高1 + 0.5 × oxytocin偏移×1.5
总系数—夹在 [0.7, 1.6]

写进 w_why 字段:激素×1.16。

这条链的意思是:难过的时候记的事更牢,提到你的时候记的事更重。而且可解释——翻出那条记忆能看到它当时为什么那么重。

6.6 换掉情绪引擎

不想用自带的,可以接别的:

// 心事本/mind-config.json
{
  "mood": { "provider": "builtin" },                              // 自带(默认)
  "mood": { "provider": "file", "file": "path/to/state.json",     // 读文件
            "map": { "value": "$.moods.default.mood",
                     "dims":  "$.moods.default.dims" } },
  "mood": { "provider": "http", "url": "http://127.0.0.1:8000/",  // 调接口
            "timeoutMs": 800 }
}

三种最后都归一化成同一种形状 {value, dims, label, reason, source, stale, at}。

界面上也能改:设置 → 心境来源,会自动扫本机常见的情绪状态文件并猜字段映射。

换走之后,「激素七条」和「双层情绪」会空着——那部分是自带引擎独有的。


七、安装

从 npm

dsh plugin --profile <你的profile> add dsh-nebula-mind

--profile 是必填的——dsh plugin 本身不带 install 子命令,它是把剩下的参数原样转给 pnpm,所以 --profile 得写在前面。profile 名就是 ~/.dsh/profiles/ 下的目录名,只有一份的话通常叫 desktop。

# 不确定叫什么,先看一眼
ls ~/.dsh/profiles/

从本地目录(开发)

这条路只给改代码的人用。 装完能跑,但 mind_remember 工具会注册失败: dsh plugin add ./目录 建的是 junction,真实路径在工作区,插件从 profile 的 node_modules 里解析不到 @deepseek-ai/dsh-tools,工具描述就没法转成 JSON Schema(日志里是一行 JsonSchemaError)。 只影响写入口,面板和召回都正常——0.4.4 起插件自带转换,这条路也不该再踩到了,但普通用户请走 npm 那条。

git clone https://github.com/Lng-ux/dsh-nebula-mind
dsh plugin --profile <你的profile> add ./dsh-nebula-mind

装完彻底退出 DSH 再重开(不是关窗口,是结束进程)。

Python

需要一个能跑 Python 3.10+ 的解释器。系统自带的一般就行:

python -V

不需要装任何东西。 语义模型(BGE-small-zh,48MB)随插件一起分发,推理是手写的 numpy 前向——不需要 torch,不需要 transformers,不需要联网下载。只要 Python 3.8+ 和 numpy。

第一次跑起来(或者备忘多了之后)重建一次索引:

python python/embed.py --build

数据放哪

默认:

平台位置
Windows%USERPROFILE%\.dsh\nebula-mind\memory
macOS / Linux~/.dsh/nebula-mind/memory

想放别处,设环境变量 NEBULA_MIND:

# Windows
setx NEBULA_MIND "D:\我的记忆"

# macOS / Linux
export NEBULA_MIND="$HOME/我的记忆"

八、三步跑起来

# 1) 记下第一条(同时会算进向量索引)
python python/xin.py add "今天聊到了为什么记忆该像海不像硬盘"

# 2) 翻一下(三路召回 + RRF + 调制)
python python/xin.py recall "记忆为什么像海"

# 3) 自检:哪几路开着、差什么、下一步干什么
python python/doctor.py

doctor 会打六行:

✅ Python       3.14.6
✅ 数据目录可写       心事本(7 本账)
✅ 记忆         事实 90 / 画像 11 / 约定 5 / 念想 8
✅ 语义检索        服务在线(bge-small-zh 512 维) / 索引 212 条
✅ 心情联动        心事本/mood-state.json
✅ 星图生成        nebula-doctor.html(190 KB)

九、两个面板

记忆星图(左侧栏)

参数配置

  • 上面是活的星图预览:拖动旋转、滚轮缩放、中键复位;遗忘推演滑杆能往后拖 0–365 天,看哪些星先暗下去;视野可切「全部 / 一度 / 二度」;
  • 下面是可改的参数:三路召回权重、RRF 常数、图扩散的跳数与衰减、沉海阈值、遗忘曲线半衰期与重要度倍数、L0–L4 各层检索权重。

改完即时生效(写 mind-config.json),不用重启。

心境

环形心情表 + 语速/音量/黏人度/距离感 + 七维花瓣图 + 七种激素 + 双层情绪 + 沉海五层分布 + 「此刻的由来」。

右上角的来源角标会告诉你心情是从哪来的:builtin(自带引擎)/ file:xxx.json / http。


十、夜间巩固

沉淀是个定时任务,建议每天固定时间跑一次:

# Windows:计划任务
schtasks /create /tn "Nebula MIND 夜间巩固" /tr "pythonw <插件目录>\python\夜间沉淀.py" /sc daily /st 22:05

# macOS / Linux:cron
5 22 * * * python /path/to/python/夜间沉淀.py

它会依次做:沉海 → 建向量索引 → 重绘星图。

从 0.3.x 升级上来的,先看一眼有没有旧任务。 早期版本把任务名写成了「小鱼夜间沉淀」,如果那个任务还在,改名后会出现两个任务、每晚跑两遍。迁移一次就行:

schtasks /query /tn "小鱼夜间沉淀"    # 有的话删掉
schtasks /delete /tn "小鱼夜间沉淀" /f

0.4.2 之前装过、并从插件面板点过「保存」的,会建出这个名字;0.4.4 起统一为「Nebula MIND 夜间巩固」。

从 0.4.2 升级上来的,先确认数据还找得到。 0.4.2 及更早的版本里,python/xin.py 把数据根写死成开发机上的一个绝对路径(D:\小鱼的办公区\心事本), 没设环境变量时会往那儿写。0.4.3 起改成只认 NEBULA_MIND → NEBULA_HOME/memory → ~/.dsh/nebula-mind/memory。

所以升级后如果面板显示 0 条记忆,数据没有丢,只是不在新代码看的那个地方。两种办法:

# 一:把旧数据搬过来(推荐,之后就不依赖路径了)
#     旧目录一般是你上次看到记忆的那个文件夹,把 *.jsonl / vectors.json / 星图.html 拷进:
#     ~/.dsh/nebula-mind/memory/

# 二:指回去(省事,但下次搬家还得再改一次)
setx NEBULA_MIND "旧目录的绝对路径"

搬完重启应用,跑一次 python python/doctor.py 确认「数据目录」那一行指对了。

跑一次的输出大致:

沉海  核心 6 / 热 97
向量  211 条 / 512 维 / 1000.3KB
星图  124 节点 548 边 188.9KB

十一、隐私与边界

  • 全部数据在本机。没有网络请求,没有遥测,没有账号。
  • 只有两处会主动连外网:装依赖(pip/npm),和首次下载向量模型。
  • 写进提示词的内容是你实际存进去的记忆——所以别往里记不该出现在对话上下文里的东西。
  • 心事本/ 是普通 JSONL,随时可以打开看、手动改、拷走、删掉。

十二、常见问题

Q:它会不会把我的私事发出去? 不会。数据全在本地。

Q:记忆会丢吗? 不会删。只会沉海降权。想彻底删要手动删 JSONL 里的行。

Q:为什么召回出来的东西有时候不相关? 先看标签(词#/义#/图#)。如果只有 图#,说明那一路把不相关的东西带进来了——图错了会自信地错。可以调低 w_graph。

Q:面板一直是"读取中"? lib/host.js 改了之后要重启 DSH(Node 不热重载)。Python 那边改了不用重启。

Q:要装 torch / transformers 吗? 不用。语义模型随包分发(assets/,48MB),推理是纯 numpy 写的,和 transformers 的输出逐位一致(同一句话 cos = 1.000000)。 只要 Python 3.8+ 和 numpy——这两样大多数环境本来就有。没有 numpy 也能跑,只是少一路语义。

Q:为什么要把 48MB 的模型塞进包里? 因为不想让人为了一个记忆插件先装几百 MB 到 2GB 的 torch。装得上还好,装不上才是常态—— 而它一旦装不上,语义那一路就悄无声息地关掉了,用户根本不知道为什么"她好像记不住我说过的话"。 把模型带上,下载解压就能用,这是唯一不靠用户操作就能保证的解法。

Q:换会话之后它还认得我吗? 认得。记忆在硬盘上,不在上下文里——这正是它存在的理由。


十三、开发

dsh-nebula-mind/
├── lib/
│   ├── host.js        # 服务端:HTTP 路由、Python 调用、星图生成
│   └── client.js      # 前端:两个面板 + 设置页(内联样式,无第三方库)
├── python/
│   ├── mindlib.py     # 数据模型(所有写入者共用)
│   ├── xin.py         # 记账 / 召回 / 沉海 / 浮起
│   ├── mood_engine.py # 七维 + 七递质 + 双层 + 瞬时层
│   ├── star_map.py    # 星图生成(Canvas 2D)
│   ├── embed.py       # 向量索引
│   ├── doctor.py      # 自检
│   └── ...
├── docs/shots/        # 截图
└── cordis.patch.yml   # 插件注册

设计约束(改代码前先看):

  • lib/client.js 只能用内联样式 + 原生 SVG/Canvas,不能引第三方库(插件没有 node_modules);
  • 数据格式是 append-only JSONL,不能重写文件(并发写入会丢数据);
  • 老的 dsh-yu-mind 这个运行时 id 保留不动——cordis.patch.yml、export const name、client 的 slot key 三处必须同时改,漏一处启动就崩。
# 自检
python python/doctor.py
node --check lib/host.js && node --check lib/client.js
python -W error::SyntaxWarning -m py_compile python/*.py

License

MIT

Related plugins