slow-stack/mneme

dsh-mneme

DeepSeek Harness 跨会话记忆引擎:SQLite 存储 + 可人工编辑的 Markdown 镜像、autoDream 自我巩固、离线语义搜索(本地向量/精排/聚类)、实体-属性-时间轴、Sleep Mode、autoSummarize 自定义模型,共 7 个记忆工具。

记忆agent-memoryagent-memory-systemautodream

dsh-mneme

给 DeepSeek Harness 的跨会话记忆插件:让 Agent 记住你、记住项目、自动整理记忆。Mneme(Μνήμη)——希腊记忆女神 Mnemosyne 之名,掌管记忆与梦境,正如 autoDream 在后台巩固记忆。

dsh-mneme 是一个 DeepSeek Harness (DSH) 插件,为 Agent 提供持久的跨会话记忆能力。它借鉴了 Claude 的 Dream 机制 与 cc-haha / Claude Code 的 autoDream 记忆巩固功能——不仅存储记忆,还会自动巩固(去重、合并、冲突裁决、摘要生成),让记忆库越用越精炼。完整溯源与致谢见文末「🙏 致谢」。

⏱️ 30 秒理解

一句话:给 Agent 装上跨会话记忆——记住你、记住项目,并在后台自动整理,越用越懂你;v0.8.0 起记忆可按 agent 与工作区隔离(scopeEnabled),多 Agent / 多项目互不串台;v0.9.0 起「这件事怎么跑」也能落进项目仓库(M.O.,actionPipelineEnabled,默认关)。

① 写入 · ② 存储 · ③ 进化 对话中模型主动记录(memory_save,可带敏感度与事件时间);会话结束自动提炼(autoSummarize) · SQLite 主库 + 人类可编辑 Markdown 镜像;实体 / 属性 / 时间轴三层结构化;记忆带 agent / workspace / 敏感度 / 发生时间标注 · 新会话自动注入相关记忆(按当前作用域加权,strictScope 开启后显式收窄的归属硬隔离);autoDream 后台去重 / 合并 / 归档,冲突冻结待人工裁决

# 30 秒上手
dsh plugin --profile web add @modusensus/dsh-mneme
dsh web

它不是什么(边界声明):

  • 不是向量数据库——语义搜索是可选增强,默认零额外依赖
  • 不替代会话日志——它存的是「值得跨会话记住的」精炼知识
  • 不改变模型本身——进化的是记忆库与每次注入的上下文
  • 删对话 ≠ 删记忆——记忆是跨会话的全局知识(v0.7.11 起不再与会话绑定),删除会话不影响已存入的记忆

✨ 功能

记忆存储(SQLite + Markdown 镜像)

  • SQLite 主存储:~/.dsh/memory/memory.db,node:sqlite 内置,零原生依赖
  • Markdown 镜像:按类型分文件(preferences.md / projects.md / decisions.md / history.md / summary.md / patterns.md / pitfalls.md / constraints.md / rejected-solutions.md,外加只读视图 documents.md),文件头是 YAML frontmatter(type / generated.by / generated.at / covered / coverage / tags)。人类可读,条目标题与正文可手工编辑(人工修改优先合并回库);documents.md 例外:它只有 document 指针行(id、标题、摘要首句、文件路径),不含正文也不参与人工回填。文件头与条目元数据行由机器维护
  • 10 种记忆类型:preference 偏好 / project 项目 / decision 决策 / history 历史 / summary 会话总览 / pattern 模式 + 编码记忆三型 rejected_solution 被否方案 / pitfall 踩坑 / constraint 约束(v0.7.13 起,codingRetrospect 默认关;v0.7.11 近重写已收窄删除 user/fact 两型)+ document 文档指针(#230,只存摘要与 doc_path,正文留在磁盘由 agent 自管)
  • 镜像同步状态机(v0.3.6+):mirror 与主库强一致,用 generation(期望轮次)/ applied_generation(已应用轮次)建模同步债务
  • 业务写操作在自身事务内原子递增 desired generation——崩溃在 COMMIT 后、渲染前,重启也能凭 durable 债务恢复,绝不静默跳过(v0.3.8)
  • generation 用 SQLite 原子语句递增,多进程并发零丢失;带 CHECK 上界,负数/溢出拒绝
  • 逐 type 记录 committed / failed / pending 回执,健康端点区分 ok / degraded / unknown
  • 状态写失败不静默:同步失败落日志并留债务,重启自动收敛

模型工具(默认注册 11 个;开 organizeEnabled 后 12 个)

工具 · 功能 memory_save · 记录一条记忆(自动按标题去重合并;v0.8.0 起去重键含 agent/workspace/scope 作用域,可选 sensitivity / occurred_at 参数) memory_search · 全文搜索(中文子串友好,可启用向量语义搜索;可选 occurred_from / occurred_to 按事件发生时间过滤) memory_list · 按类型分页列出(include_archived=true 可查看已归档;可选 occurred_from / occurred_to 时间过滤) memory_get · 读取单条记忆完整正文(v0.7.25,按 id;memory_search / memory_list 命中后读全文) memory_update · 修改已有记忆 memory_delete · 删除记忆(按记忆 ID 精确删除) memory_forget · 抑制注入(降权不删除,可恢复) memory_archive · 归档/恢复记忆(v0.2.5;归档后隐藏于列表/搜索/注入/整理,archived=false 可恢复) set_scope_state · 按下/松开某个作用域的可逆闸门(#471:政策轴。暂停期间该作用域的记忆照旧存着,只是不注入、不参与巩固,松开即原样回来;不改任何一条记忆的标注,与上面逐条操作的 memory_forget / memory_archive 是两根不同的轴)。两级开关 scopeState.enabled / .enforce 默认都关,没开时按下不产生拦截效果 memory_register_document · 登记 agent 产长文档的指针行(#230:摘要 + doc_path + evidence 落 document 类型;正文留在磁盘、由 agent 自管,注册口唯一,旁路写入被拒) memory_organize · 主动整理(#231,要 `organizeEnabled` 打开才注册):mode=dryRun 先出比对报告(每条候选 exact / near / new + 命中行,不写一行库、只留审计回执),agent 判断后 mode=apply 引用那份报告的 run_id 落地。两种「不要它」要分清——`discard` = 这条候选不写,什么都不动(只进回执);`archive` = 把报告标为被取代的那条既有行归档(可恢复,绝不物理删除)。没有比对过的候选写不进库,一份报告也只许落地一次 memory_runtime · 本地推理运行时的状态 / 供给 / 校验(v0.7.32,自管运行时三档取件)

工作流(M.O.,v0.9 beta)

记忆库答的是「这件事为什么这么办」,答不了「这件事到底怎么跑」。v0.9 把后者从记忆库里的一行文字变成项目里可提交、可 review、可被 CI 读的一份文件——一条工作流一个 JSON:

<项目>/.mneme/pipelines/<id>.json     ← 项目层(默认;跟着项目提交)
<插件包>/pipelines/<id>.json          ← 全局层(兜底;今天包里没有这个目录,有意为空)
  • 两层来源,顺序即优先级:同 id 两处都有,项目层赢,被挡住的那份进 shadowed 报出来(不静默丢弃);项目层的坏文件进 unreadable 而不拖死全局层——一层写坏不该让人连兜底那份也看不见
  • 校验很硬:id / name / project / version / status / done 与每一步的 phase / title / when / do / done / why 缺一不可,risk 限 R0–R3、needs 必须指向存在的步骤、图里有环直接报错——任何一处不合规整条读不出来,不做「跳过坏文件继续」:半个工作流比没有更危险
  • 护栏,不是轨道:绕行要留出口。自报 R0/R1 且不跨闸门 且兜底清单(IRREVERSIBLE_PATTERNS,机械匹配、不看自报)没命中 → 记账先走;其余 → 停下问人
  • 候选分层:草稿住 /candidates//,只在本地。升格要同时满足「走过两次(至少一次成功)」且「写得出反事实」;够格之后系统只提议,promoteCandidate() 只返回内容不写盘,提交与推送是人握着的那道门
  • 两个指标分开数:跳过(这次不用这一步,≥3 次提议删这一步)与绕开(这条路整个不对,≥3 次提议重看这条路径)各自累加,混在一起两种提议都发不出来
  • 只读路由 GET /api/dsh-mneme/pipeline[?id=&project=](project 非绝对路径回 400 project-not-absolute,不回退 process.cwd());答复契约 mneme.pipeline/v1,面板渲染与 agent 读的是同一份数据
  • 默认关(actionPipelineEnabled),设计取舍见 docs/WORKFLOWS.md

自动注入 + 会话摘要

  • 自动注入:新会话开局注入记忆摘要(summary 优先 + 少量高重要性条目)
  • 会话摘要:turn/end 时用 LLM 提炼本次会话的偏好/决策/教训,自动入库(过滤 plugin 注入上下文,避免污染)

autoDream 自动记忆整理 🧠

溯源:autoDream 的理念源自 Claude Code 的 Auto Dream 记忆巩固功能(Anthropic,Memory 2.0 的后台整理子代理),其「离线巩固」思路与 UC Berkeley & Letta 的 *Sleep-time Compute* 论文(arXiv:2504.13171)一脉相承。dsh-mneme 将其引入 DSH 插件生态,并发展为自己的实现——K-Means++ 聚类预分组、类型化决策清单与可回放的 sha256 摘要审计链,详见文末「🙏 致谢」。
  • 触发:记忆数 > 10 或总字符 > 5000 时,异步自动触发(不阻塞写入)
  • 决策清单式整理:LLM 输出 keep / merge / archive / conflict / update 决策清单,服务端校验后逐条应用
  • merge:合并主题相近的条目,保留信息最完整者
  • archive:归档过时/冗余条目(可恢复,不物理删除)
  • conflict:裁决矛盾信息,胜者保留、败者归档并追加溯源注释;conflictFreezeEnabled(默认关)开启后矛盾对不自动裁决,改为冻结进冲突队列(状态页并排对比,人工选保留方,#166)
  • update(v0.2.1):直接修正单条记忆的过时/错误内容(单 id / 必须实际变化 / 非 summary / 24h 保护 / 每次 ≤2)
  • 失败追踪(v0.2.1):用户纠正记忆时写入 failure_memories 表(旧值/新值),为后续自进化积累数据
  • 摘要生成:整理后生成"记忆库总览"(单一实例),作为下次会话的优先注入
  • Fail-safe:非法 LLM 输出(未知 id / 非法 action / 越界 importance / 跨类型合并等"单条非法"决策,Issue #26)默认跳过该条并应用合法子集(run 记为 degraded),绝不破坏记忆库
  • 裁决审计:每次运行写入 dream_runs 审计表(输入快照 sha256 digest + 完整输入快照 + 决策清单 + 逐 id 去向 + receipt),可离线回放;merge / conflict / update 幂等应用,重放/并发重复执行无累积副作用;update 记录 _before 快照

dreamMaxTokens 调优指南

默认 131072(即上限,#135)已为思考型模型预留推理+正文的双重预算(部分思考型模型仅推理就可能消耗 8k+ token),常规记忆库无需调整。若记忆量大(数万字符以上)且正文仍被截断,优先按下方「巩固模型分类声明」换非思考模型 / 配 dreamReasoningEffort 压低思考,再考虑调大输入侧上限(如 distillMaxChars)——dreamMaxTokens 本身已无上调空间。

不要为了省 token 把它调小(#135 成本审计实测):这个键是上限而非计费口径,流式按实际用量计费,压上限只在真撞顶时生效;而撞顶的后果是整轮失败(截断 → 无完整 JSON → no json array in llm output),且调度器只有 ok 轮才刷新基线,下一次写入会用同一批输入重跑。按 133 个有真实用量的成功轮折算,cap=16384 撞顶 78.9%、净总量 +54.1%;cap=32768 +15.9%。真正的大头(dream_consolidate 输出 token 里约 88% 是推理与 JSON 骨架,只有约 11.8% 是决策正文)由 dreamReasoningEffort 与模型选择决定,与本键无关。相关的数量护栏见 dreamMaxMergePerRun。
若使用思考型模型(如 deepseek-v4-flash / DeepSeek-R1 类),模型可能把全部预算花在 reasoning 上导致正文为空(日志出现 no json array in llm output)。#135 修复后:未配置 dreamReasoningEffort 时会自动取模型支持的最低档发流(不再省略字段让模型自带默认档——v4-flash 系默认 high——顶上烧光预算),默认配置即生效;显式 none = 不发送字段用服务商默认,off/low/medium/high 原样传递,模型不支持的档位自动换用(拒绝原因记入 llm_audit)。正文仍为空时配置 dreamProvider/dreamModel 指向非思考模型(dreamMaxTokens 默认已是上限 131072,无上调空间)。sleep 侧对应 sleepReasoningEffort。

巩固模型分类声明(settings panel「巩固模型」= dreamProvider/dreamModel,睡眠侧对应 sleepProvider/sleepModel):

模型类别 · 例子 · 说明 非思考模型(推荐) · glm-5-2 类等 · 无 reasoning 声明;即使配了 effort 被 harness 拒绝,fallback 去掉字段重试即成功。空体风险最低 思考模型(需实测) · deepseek-v4-flash-ga 等 v4-flash-ga 系 · 默认开推理,可能烧光 token 预算返回空体;部分型号(如 v4-flash-ga)在 harness 侧被声明为不接受任何 reasoning effort(去掉 effort 时 harness 的 defaultEffort 会顶上来再次拒绝)。v0.7.26+ 已根治:resolveDreamEffort 发流前探测模型支持的档位,不支持的配置档位自动换用模型默认/首个支持档位,声明无 reasoning 能力的型号则省略字段。选用时建议配 dreamReasoningEffort 实测(未配置时自动取最低档),不行就换非思考模型

Sleep Mode 系统级睡眠 💤(v0.4.0,opt-in)

从 autoDream 的"被动阈值触发"升级为"主动定时维护 + 分层压缩"。系统空闲 sleepIdleMinutes 分钟自动执行深度维护,默认关闭(sleepModeEnabled: false),开启后行为:

  • 可中断:AbortController 实现,用户恢复活动即中止当前周期(noteWrite 重置空闲计时 + 中断信号)
  • 串行安全:睡眠周期走 service.enqueue 串行队列,与 autoDream 严格不重叠;minRefTimeMs 防止快照后被召回的记忆被误降级
  • 四阶段深度维护:
  1. conflict_resolution:全库冲突消解,strictness 三级可配(gentle 0.92 / normal 0.85 / aggressive 0.75)
  2. archival_demotion:按 last_accessed_at 分层——30 天未召回压成摘要(原文进 _full_content,可无损恢复)、90 天完全归档
  3. pattern_discovery:LLM 扫描近期记忆提炼规律,产出 type=pattern 记忆,evidence 强校验防伪造
  4. relation_completion:检测孤立实体并补全隐含关系(共现 related_to / 项目 part_of / 技术 depends_on)
  • Fail-safe:每阶段独立 try/catch,LLM 故障只跳过对应阶段;无 LLM 路由时纯规则降级(demotion/relations)照常执行
  • 审计延续:睡眠周期写入 dream_runs,run_type='sleep',与 autoDream 共用审计表可追溯
配置详见 docs/SLEEP.md。

官方设置面板 → 「记忆库设置」→「记忆」标签:按类型浏览、全文搜索;启用向量搜索后可用「语义」切换做向量召回。

用户设置(画像 / 规则)与自定义指令 ⚙️

官方设置面板 → 「记忆库设置」标签:

  • 用户画像:一段自由文本描述用户自己(角色、背景、偏好),每轮注入到系统提示,让 Agent 始终遵循
  • 规则:Agent 必须遵守的行为规则列表(如"回答先给结论"),同样每轮注入
  • 自定义指令:注册斜杠命令(/名称 [补充说明]),触发时把用户定义的指令内容作为一条用户消息提交给当前 Agent,命令后缀会作为补充说明一并提交;界面仅显示提交回执(宿主不支持 followup 提交时退回旧行为,指令原文会显示在界面,便于复制后手动发送)。命令持久化到 SQLite,启动时自动注册到 DSH 命令表,增删实时生效
画像与规则通过独立的 [用户设置] 注入区块(优先级高于记忆库),即使记忆为空也会注入。

向量搜索(语义搜索)🔎

可选能力:接入 OpenAI 兼容的 embeddings API,让搜索能命中字面不同但语义相近的记忆。

配置:官方设置 → 「记忆库设置」→ 滚动到底部「向量搜索」区块:

字段 · 说明 启用向量搜索 · 总开关;开启后记忆面板出现「语义」切换 API 地址 (Base URL) · OpenAI 兼容端点,如 https://api.openai.com/v1;也支持 SiliconFlow、智谱、本地 Ollama 等 API Key · 对应服务的密钥 模型名 · embedding 模型,如 text-embedding-3-small、text-embedding-v3、bge-m3 等

保存配置后点「重建索引」,为已有记忆批量补建向量(新写入的记忆会自动嵌入)。之后在记忆面板输入查询并点「语义」,即可用向量召回语义相关结果;向量服务不可用时自动回退全文搜索。

⚠️ 密钥仅保存在本机 ~/.dsh/memory/memory.db 的 user_settings 表,不会上传,也不会写入代码仓库。
需要 embedding 而非 rerank 模型:如阿里云 text-embedding-v3 可用,qwen3-vl-rerank 是 rerank 模型(不走 /embeddings)。

语义增强(Semantic)🧠

v0.2 起新增可以完全离线运行的语义记忆引擎(本地模型 + 精排 + 聚类):

  • 本地 Embedding:三后端可选——ONNX(Xenova/bge-small-zh-v1.5,离线)/ Ollama / OpenAI 兼容,失败自动逐级降级,最差回退关键词搜索
  • Rerank 精排:Xenova/bge-reranker-base 对召回候选交叉编码精排,提升 Top-K 准确率
  • autoDream 语义增强:对记忆向量聚类(clusterMemories),自动发现主题相近 / 疑似矛盾的记忆,巩固更精准
  • 搜索流水线:混合召回(关键词 + 向量)→ Rerank → Top-K
  • 自管运行时:本地推理的依赖闭包(@huggingface/transformers + onnxruntime-node + sharp,从宿主收编时本机实测 49 个包 / 约 393MB)可收编到 ~/.dsh/mneme/runtime/,与 profile 的依赖图解耦——由于 profile 是所有插件共用的依赖图,这份闭包留在此前的位置会让「安装任何插件」都替它重走一遍整条依赖链;收编优先硬链接,同盘时几乎不额外占盘。@huggingface/transformers 已从 dependencies 降为可选 peer,因此安装插件不再携带它;正在使用本地嵌入的用户请先按文档收编,否则升级后本地嵌入不可用(读写信道不受影响)
  • 取回运行时的三条来源:① 收编本机已有(零网络、同盘硬链接)→ ② 本地 .tgz 目录(runtimeTarballDir,某个包网络下不到时用)→ ③ npm registry(runtimeMirror 可换镜像),按随包发布的 runtime-manifest.json 逐个取并先校验 sha512 再落盘(win32-x64 实测约 33 个包 / 2142 个文件 / 数百 MB;清单平台无关,一份覆盖 win32/darwin/linux × x64/arm64;剔除 onnxruntime-web——Node 构建从不 import 它)。面板「向量索引」卡片在不就绪时会给出这段代价说明并提供一个按钮;不想开面板也可以让 agent 用 memory_runtime 工具(status / provision / verify)代做

配置只需在 cordis.patch.yml 里设置 embedProvider(默认 openai,保持 v0.1 行为;改为 local 即离线)。升级无需迁移数据。

node scripts/mneme-runtime.mjs status    # 运行时在哪、来源、结构是否完整(不加载模型)
node scripts/mneme-runtime.mjs adopt --from ~/.dsh/profiles/<profile>/node_modules
node scripts/mneme-runtime.mjs verify    # 真加载运行时并跑一次推理
三个命令的退出码为 0 健康 / 1 不健康 / 2 用法错误,便于脚本 gate;--json 输出机器可读结果。运行时不可用时不会崩——检索降级为关键词/BM25,读写不受影响。详见 本地模型部署指南 §2.5。

实体结构化记忆(Entity Gene)🧬

v0.3.0 起新增记忆基因层:从记忆里抽取命名实体、带时间轴的属性、实体间关系,让搜索从"字面关键词"升级为"按实体/属性精确召回"。

  • 三表:entities / entity_attrs(valid_until 快照式时间轴)/ entity_relations,旧库打开自动建表,幂等无迁移成本
  • 自动抽取:entityExtractionEnabled=true 后,新写入的记忆 fire-and-forget 触发 LLM 抽取(同名实体去重、属性存时间轴、关系追加;失败绝不阻塞写入)
  • 实体搜索(searchMemories 前缀路由,entitySearchEnabled 默认开):
  • entity:阿尔托 → 属性精确关联的记忆(_score 1.0)排在关键词提及(_score 0.7)之前
  • attr:国籍=芬兰 → 精确匹配该属性值的记忆
  • attr:国籍 → 该属性键的全部当前有效记忆(value 为空契约)
  • autoDream 联动:update 决策写 supersedes 自引用(属性版本被替代);merge 决策把 loser 的属性归属迁移到 keeper(keeper 已有同键当前值则失效)
📖 详见 实体结构化记忆设计 · 语义增强架构 · 本地模型部署指南

记忆质量过滤 🧼(v0.4.6,默认开)

写库前对每条记忆做启发式质量打分(纯函数,无 I/O、无共享状态):元记忆词汇(谈论记忆系统本身)、自指类型标签、内容过短、重复度高、与近期记忆近似重复都会扣分(0-100):

  • score ≥ 60:正常存储
  • 30 ≤ score < 60:quality_score 落库,注入排序改为按 importance × quality/100 降权(degraded)
  • score < 30:归档并标记 low_quality——仍可显式搜索召回,只是永不自动注入。例外(#135):importance ≥ memoryQualityFilter.exemptImportance(默认 4)的记忆只降权不归档——评分与信号标签照常落库,归档决定不再静默越过用户标注的重要性

memoryQualityFilter.enabled 可整体关闭,archiveThreshold / degradeThreshold / minContentLength / exemptImportance(1=全部豁免,5=仅最重要豁免)可调。此外更新记忆(memory_update 等)不会抹掉系统信号标签(low_quality / duplicate / meta / self_referential / repetitive / short_content)——它们是「为什么被降权/归档」的审计线索,与用户自传标签并集保留(#135)。

LLM 消耗审计 📊(v0.4.6,默认开)

每次后台 LLM 调用都会写入 llm_audit_logs 表:tokens / duration / status / source(由哪个触发产生)。失败调用记为 status=error,绝不阻塞功能本体;retentionDays(默认 90)在启动时清理超期行。

覆盖的后台调用(source 即触发源,operation_type 区分同一源下的不同调用):

source · operation_type · 说明 autoDream · dream_consolidate / dream_summarize · 巩固的整理裁决与总览摘要,各一行 autoDream · dream_narrative · 叙述条合成,需 dreamNarrativeEnabled(默认关)才跑 autoSummarize · summarize_compress · 空闲蒸馏的压缩 sleep · sleep_conflict / sleep_pattern · Sleep Mode 的冲突裁决与模式挖掘,两阶段各一行 entityExtract · entity_extract · 实体抽取,每次写入记忆都会跑

后两条链路见 #250——它们是结构上漏接的后台路径(sleep 的 streamText 副本没有 onUsage、实体抽取适配器拿不到 service),不是刻意收窄口径。

新增两个只读 API:

  • GET /api/dsh-mneme/semantic/llm-audit?page=&pageSize=&source= — 分页查询 + 按 source 过滤
  • GET /api/dsh-mneme/semantic/llm-audit/stats?days= — 近 N 天按 source 汇总预算(tokens / 次数 / 失败数)

/llm-audit/stats 的 by_source 是服务端 GROUP BY trigger_source,不做任何白名单过滤,因此新链路自动进入汇总。

面板侧现状(#250 之后,未改面板):

  • 「LLM 消耗」卡读 /llm-audit/stats,但只渲染 total_calls / total_tokens 两个总数。新链路的 token 与次数已经计入这两个总数,所以「mneme 总共花了多少」现在是对的;
  • 按链路的拆分(by_source)目前只能从 API 读,面板不展示——「哪条链路最费」在面板上还答不了;
  • 状态页活动流仍只显示 autoDream / autoSummarize 两个硬编码来源(lib/client.js),新链路不会出现在活动流里。

这三处要动面板(活动流还有一处来源白名单加一处二元标签兜底,且 pageSize=12 会被每次写入都跑的实体抽取占满),留到面板批次,不在 #250 内。

实体抽取是每次写入记忆都会跑的链路,计入审计后 llm_audit_logs 的行数会随写入量线性增长(retentionDays 只约束上界、不约束增速)。若实测增速过快,再考虑按 operation_type 采样或单独保留期。
只读端点,与 list/search/semantic 一样在设置 apiToken 后仍保持开放。

记忆库主区视图与记忆图谱 🕸️(v0.5.0)

记忆功能从侧边栏抽屉收进主内容区全宽 tab(conversation.view 插槽,与「对话 / Trajectory」并列),侧边栏「记忆」入口点击后直接激活该 tab。页面顶部子 tab 行切换三个子视图:

  • 记忆(三栏浏览):左栏分类树(类型 + 计数)/ 中栏时间树(月 → 日两级倒序、可折叠)/ 右栏详情(全文不截断 + 复制全文);语义搜索内嵌工具栏开关(防抖 250ms),entity: 前缀可「在图谱中查看」
  • 图谱:输入实体名,加载以该实体为中心的关联网络——
  • 服务端只读 ego-graph API:GET /api/dsh-mneme/semantic/graph/ego?entity=&depth=1|2(BFS 层级遍历,limit 防大图失控,实体不存在 404;配套 /semantic/graph/entity-attrs 查实体属性)
  • 前端零依赖手写 SVG 力导向布局(插件运行时无法 require vis-network 等第三方库):斥力 + 弹簧 + 向心引力物理模拟,节点按类型着色、按提及次数定半径,支持拖拽、点节点看属性、点边跳回来源记忆
  • 设置:画像 / 规则 / 指令 / 向量配置,限宽居中

图谱 ↔ 记忆双向互跳:图谱详情侧的关联记忆可点击,记忆边的「来源记忆」按 memory_id 直跳三栏视图并自动定位。

四路召回融合与会话热记忆 🔎(v0.5.0,v0.8.4 扩四路)

  • BM25 稀疏第三路召回(src/search/bm25.js):与向量召回、FTS5/LIKE 关键词并列——ASCII 词元 + CJK bigram 分词、IDF 加权(归一化 [0,1]),专有名词 / ID / 代码片段等散词查询不再依赖子串命中。融合规则:未召回行按 0.3×BM25分 回填;仅向量召回行获得词法加分;LIKE 已命中行不叠分。bm25SearchEnabled 可关
  • 实体图召回轴(第四路,v0.8.4)(entityRecallEnabled 默认关):开启后检索融合池三源扩四源——store 新增 findEntitiesMentionedIn / getLinkedMemoryIds 反查原语 + idx_relations_memory 索引,命中实体所在记忆按边入池,fuseRecall 的 blend / rrf / minmax 全配方参与;实体轴与 BM25 同为确认/回填信号(we 并入 wb 共用 0.3 回填权重),永不主导语义排序,失败降级空数组;keyword 模式纯文本路径不吃实体轴
  • 自适应阈值(src/search/adaptive.js):取代固定 0.65 截断——entity:/attr: 前缀放宽 0.5,短查询(50)放宽 0.6,Top1/Top5 分差 > 0.3 时放宽让尾部进 Rerank;显式传 threshold 或 adaptiveThresholdEnabled=false 走旧行为
  • 会话级短期热记忆(src/hot-memory.js):最近 N 轮对话(默认 5 轮,hotMemoryRounds)按 token 预算(默认 2000,hotMemoryMaxTokens)滚动截断,从会话事件日志无状态重建、不落库;注入顺序为「短期上下文 → 长期记忆召回 → 摘要」
  • 选择性注入:query 向量可用时注入候选按主题相似度重排(selectiveInjectEnabled 可关);搜索时语义去重为激进选项(searchSemanticDedup=true 显式开启,近重复行 Rerank 前丢弃)
  • 召回基准(scripts/benchmark-recall.js):标准查询集驱动,计算 Recall@5 与 MRR,legacy(三特性全关)vs fused(默认配置)双跑对比