dsh-layered-memory
Health Uyari
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Gecti
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
让 DeepSeek Harness 拥有长期记忆:对话自动蒸馏为事实/场景/画像三层记忆,每步自动召回注入——让 AI 基于证据说话,零操作无感使用 | Long-term memory for DeepSeek Harness: conversations auto-distilled into facts, scenes & persona, recalled before every step — so the AI speaks from evidence, not guesses. Zero effort.

dsh-layered-memory
DeepSeek Harness 的分层蒸馏记忆插件:对话在后台自动完成 L0 捕获 → L1 原子记忆 → L2 场景整合 → L3 画像蒸馏,模型每一步前自动把相关记忆注入上下文。
快速开始
需要 Node ≥ 22.16。两种调用方式任选(npx 前缀可替换下面任何 dsh 命令):
# 方式一:npx 直接跑官方 CLI(无需预装 dsh;可 pin 版本,如 [email protected])
npx -y @deepseek-ai/dsh plugin --profile web add dsh-layered-memory
# 方式二:已装 dsh CLI(dsh 是 pnpm 转发器,未装 pnpm 时先 npm i -g pnpm)
dsh plugin --profile web add dsh-layered-memory
# 包源备选:GitHub 仓库 / 本地路径(开发调试,link: 指向仓库,npm run build + 重启 dsh 即生效)
dsh plugin --profile web add https://github.com/JunNanLYS/dsh-layered-memory
dsh plugin --profile web add /path/to/dsh-layered-memory
让 Agent 安装(推荐)
如果当前 Agent 可以执行终端命令,把下面这段话完整发送给它:
请为 DeepSeek Harness 的 web Profile 安装 dsh-layered-memory 插件。
只执行下面两条命令,不要修改其他 Profile:
dsh plugin --profile web add dsh-layered-memory
dsh --profile web --dump-config
确认输出中出现 dsh-layered-memory 后告诉我安装结果。
不要替我关闭或重启正在运行的 DSH;安装完成后提醒我手动重启 DSH Web Host。
Agent 应当返回安装结果,并明确告诉你配置中是否已经出现 dsh-layered-memory。
本包声明了 dsh.bundle 组合包层(cordis.patch.yml),安装后会自动挂载插件行——
不需要再手改 $DSH_HOME/profiles/web/cordis.patch.yml。然后重启 DeepSeek Harness,
验证:~/.dsh/memory/ 下出现 conversations/ records/ scenes/ 目录和 memory.db
即插件 apply 成功;设置页出现"记忆"页面、输入栏出现档位 pill 即 client 半边就绪。
卸载:dsh plugin --profile web remove dsh-layered-memory + 重启。数据保留在~/.dsh/memory/,不需要时手动删除整个目录即可。
从源码开发
git clone https://github.com/JunNanLYS/dsh-layered-memory
cd dsh-layered-memory
npm install && npm run build
dsh plugin --profile web add . # link: 安装,改代码后 npm run build + 重启 dsh 即生效
npm run smoke # 冒烟测试(先重编:见下方命令)
npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop
运行时数据流
插件挂在 dsh 原生事件上(session/event 捕获、agent/pre-step 注入),蒸馏调用复用宿主 ctx.llm。召回以消息侧注入呈现:相关记忆作为一条合成消息排在用户新消息之前,会话流里显示为**"上下文注入 · memory"**行(点开看命中内容)——用户能直接看到"记忆生效了";注入内容有长度预算与时间预算,超限截断/超时跳过,绝不拖慢对话。
记忆工具(3):
- memory_search
- conversation_search
- memory_read_scene
真机实录:召回注入与工具调用在对话里的样子——"上下文注入 · memory"行先带出相关记忆,模型再按需调 memory_read_scene 读取场景块,凭记忆直接作答:
在只开放代码执行入口的受限会话中,模型经由 run_code 间接调用记忆工具(轨迹视图中的 SUBTOOL 嵌套):
分层记忆(L0–L3)
会话级记忆档位
- 控件:输入栏内、模式选择器右侧的 pill(
记忆·自动),点击在上方浮出档位滑块深浅主题自适应; - 每会话的选择按 sessionId 持久化到
session-modes.json,重启/恢复会话不丢;
与全局开关叠加(全局是总闸);L2/L3 完全分类,分类内容不渗透。
界面预览
实测对比(DSH-MemBench:自动化基准)
图文回答"长什么样",这一节用自动化基准的实测数字回答"开了到底有什么用"(bench/,一条命令可复现)。方法:同场景库、逐字相同输入,A 组(记忆开)跑 3 次取合并值,B 组(记忆关)跑 1 次(无记忆的长任务每场景要吞数倍 token,成本护栏);对话赛道只跑 A 组(B 组会话独立无记忆必然失败,对照无信息量,已下线)。工作流赛道环境:DeepSeek 官方 deepseek-v4-flash(思考档 high)、判卷 glm-5.3、插件 0.8.3、Windows;题型设计借鉴 LongMemEval / LoCoMo / AMB。
对话赛道(15 场景 × 6 题型 × 3 次 = 270 题):答得准吗
0.8.0 留档基线(A 组数据;此后对话赛道 B 组下线,只跑 A 组)。
召回双通道(A 组):被动注入召回率 75.1%(该题要点出现在召回注入中,169/225),其余多数由模型主动调用记忆工具查回——84 题主动查询、60 题靠工具兜底答对;端到端 92.6% 是两通道 + 模型利用的合成结果。记忆库跨场景全程累积下,探针召回注入混入其他场景记忆 144 次(已如实计数),总准确率仍稳在 92.6%——抗干扰能力经受住了膨胀记忆库的考验。
工作流赛道(7 场景 · A 组 3 次 / B 组 1 次,真实工具沙箱):做得对、做得省吗
探针段完成度 85.5% vs 43.5%(+42pp):教学/变更段两组都有现场上下文,探针段(新会话延续任务)才是纯记忆窗口——A 组三个新考法场景(流程知识更新 / 双胞胎消歧 / 风格规范延续)全部 12/12 满分且三轮一致;B 组在风格规范场景探针 0/4(命名/结构/千分位/页脚约定只存记忆,沙箱探不出来),在流程更新场景则能靠读脚本逆向(判别力受沙箱可供性限制,已如实标注)。
长任务成本:B 组每场景输入 token 是 A 组的 6.8 倍(1.81M vs 266k)——无记忆时 agent 靠重新探索前进,high 思考档下甚至会自建工程去探测本可用一条脚本约定完成的流程;输出 token 3 倍(46.2k vs 15.4k)、步骤 +70%。这正是记忆的核心价值:省掉的不是任务难度,是无谓的往返与重复探索。
方法论与复现
node bench/harness/run.mjs --arm A --repeats 3 --provider deepseek-official --model deepseek-v4-flash # 对话赛道(只跑 A 组)
node bench/harness/run.mjs --track workflow --arm AB --repeats 3 ... # 工作流赛道(A/B 双组并行)
node bench/harness/report.mjs --latest [dialog|workflow] # 汇总报告
- 判分:
contains-all程序判 + 判卷模型按要点判(答案原文与判分理由全部留痕result.json可人工复核);工作流完成度为产物文件 + 关键内容程序化校验(四型判据:正检查/禁词/产物缺席/存在性); - 实时进度:跑基准时自动拉起本地进度面板并打开浏览器(
--no-panel关闭)——A/B 双臂场景/阶段/消息粒度进度、心跳与活动新鲜度(直判"卡住 vs 进程挂了")、累计成本随跑随涨; - 指标全部来自供应商上报 usage(输入含缓存命中拆分)与会话事件折叠;稳态缓存率剔除每会话首请求(0.8.0 留档基线:A 88.7% vs B 85.4%——记忆注入不伤缓存);
- 回归用途:改插件前后各跑一遍,
compare.mjs出对比表(环境头校验含 gitSha + B 组对照组漂移告警); - 局限(诚实声明):单机;A 组 ×3 合并、B 组 ×1(成本护栏,噪声更大);判卷与被测模型:对话留档基线同源、工作流新跑为异构(glm-5.3 判 v4-flash);作者自建场景库(倾向记忆优势场景,欢迎自行复现);沙箱文件的可供性会部分泄露流程(B 组可读脚本逆向,判别力受限处已如实标注);工具审计双档(严格违规判负/宽松提示),实测双方 0 违规。
完整报告与逐题数据:bench/baseline/。
存储布局
向量能力默认关闭(纯 FTS)。DSH 的 ctx.llm 无 embeddings 端点,语义检索由
三态嵌入源提供(关闭 / 远程 / 本地),设置页可运行时切换——见下节。
语义检索(嵌入源)
设置页(记忆 → 概览 → 语义检索)选择嵌入源,即时生效、无需改配置重启:
三种嵌入源:关闭(默认,纯 BM25 关键词检索)、远程(自备任意 OpenAI 兼容/embeddings 服务,embedding.* 四件套配齐才可选)、本地(内置模型目录选一款,
ONNX 量化 CPU 推理——无需 API Key,数据不出本机)。本地模型目录是插件内置
白名单(每款锁定 revision + 每文件 sha256,不可下载任意仓库)。
- 下载:模型卡一键下载(默认镜像
hf-mirror.com,断点续传 + sha256 完整性
校验;直连不可达时可走代理——默认自动探测HTTPS_PROXY/ALL_PROXY等环境
变量,见embedding.proxy)。单文件失败自动重试且换缓存键(?dshmem-retry=N,
绕开镜像 CDN 偶发的坏缓存对象),校验失配从零重下、网络错误保留断点续传;
落盘数据目录models/<id>/,不用了随时在设置页删除; - 按需运行时:首次切换本地档才安装推理运行时(transformers.js,约 100~200MB,
装进数据目录runtime/——不进插件依赖树,不碰插件安装目录); - 活切换:一键换源——自动后台全量重嵌(进度可见、可取消,期间检索自动降级
关键词,不影响对话;维度变化时向量表按新维度重建);切换失败保持旧源,重启仍按原源运行; - 生效规则 = 部署上限 AND 运行时选择:
embedding.allowLocalModels=false可整体
禁用本地档、未配embedding.*四件套则远程档不可选(企业部署可收口),状态持久
化在embedding-source.json。
配置
覆盖配置写在 profile 自己的 cordis.patch.yml,用顶层裸 patch 条目(直接 id:,
不要包在 insert: 里——insert 与 bundle 层同 id 追加会导致 duplicate loader entry id
启动失败):
- id: dsh-memory
name: dsh-layered-memory
config: # 键按行整体替换(不深合并),按需写全要保留的键
family: auto # 新会话默认档:auto | chat | work
llm: # 蒸馏模型静态路由(双字段齐 = 部署 pin,优先于设置页选择;
provider: '' # 留空则跟随设置页"蒸馏模型"选择器或当前默认模型)
model: ''
| 字段 | 默认 | 说明 |
|---|---|---|
family |
auto |
新会话默认记忆档位:auto(双族自动)| chat(个人)| work(工作);会话内可用输入栏控件临时切换 |
dataDir |
$DSH_HOME/memory |
数据目录 |
capture.enabled |
true |
L0 捕获 |
capture.stripCodeBlocks |
true |
助手消息剥离代码块 |
capture.maxMessageChars |
4000 |
单条消息最大字符数 |
extract.enabled |
true |
L1 抽取 |
extract.minMessages |
6 |
稳态触发阈值:单会话攒够 N 条新消息跑一次 L1 抽取。起步阶段生效阈值从 1 翻倍爬坡到此值(首轮即出记忆,随后自动攒批省调用) |
extract.idleSeconds |
300 |
闲置兜底:会话静默 N 秒后把未蒸馏切片落袋(接住"没攒够阈值用户就离开");0 关闭 |
extract.backgroundMessages |
10 |
抽取时附带的背景消息条数(按会话从 L0 现查,会话间互不污染) |
extract.candidatePool |
5 |
去重候选池大小 |
l2.enabled |
true |
L2 场景整合 |
l2.minNewMemories |
5 |
距上次 L2 整合的新记忆阈值 |
l2.maxScenes |
12 |
场景块数量上限 |
l2.sceneContextLimit |
3 |
L2 prompt 附带的相似场景全文上限 |
l3.enabled |
true |
L3 画像蒸馏 |
l3.interval |
20 |
L3 蒸馏间隔(新记忆条数) |
recall.enabled |
true |
自动召回 |
recall.maxResults |
5 |
每条新用户消息前注入的 L1 条数上限 |
recall.maxCharsPerMemory |
500 |
单条注入记忆的字符上限(超限截断并提示用记忆工具查全文);0 不限 |
recall.maxTotalRecallChars |
2000 |
整轮注入总字符上限(超限按相关性丢尾部);0 不限 |
recall.timeoutMs |
5000 |
召回总预算(ms):超时跳过本轮注入、不阻塞对话;0 不限时 |
recall.includePersona |
true |
系统提示注入画像上下文(<user-persona>,稳定区) |
recall.includeSceneNav |
true |
系统提示注入场景导航(<scene-navigation>,稳定区) |
recall.strategy |
hybrid |
检索策略:keyword / embedding / hybrid |
recall.scoreThreshold |
0.3 |
召回分数阈值(低于不注入;仅 keyword/embedding 策略生效,hybrid 融合前不过滤;工具路径不过滤) |
embedding.enabled |
false |
向量检索开关;关闭即纯 FTS 运行 |
embedding.baseUrl |
空 | OpenAI 兼容 /embeddings 地址(如 https://api.siliconflow.cn/v1) |
embedding.apiKey |
空 | API Key |
embedding.model |
空 | embedding 模型名 |
embedding.dimensions |
0 |
向量维度(启用时必填,须与模型输出一致) |
embedding.maxInputChars |
5000 |
单条文本最大字符数(超长截断) |
embedding.timeoutMs |
10000 |
单次 embedding 调用超时(ms) |
embedding.allowLocalModels |
true |
允许本地嵌入档(部署上限:关闭后设置页不能下载模型、不能切本地档) |
embedding.mirror |
https://hf-mirror.com |
本地模型下载镜像根地址(可改回官方 https://huggingface.co) |
embedding.proxy |
'' |
模型下载代理三态:''(默认)= 自动探测代理环境变量(HTTPS_PROXY/ALL_PROXY 等,尊重 NO_PROXY);none = 禁用强制直连;其他值 = 代理 URL(如 http://127.0.0.1:7890)。镜像直连在国内网络间歇不可达(直连超时与污染字节交替出现过),开代理的机器建议保持默认自动探测 |
llm.provider/model |
空 | 蒸馏模型静态路由(部署 pin):provider 与 model 双字段齐时锁定蒸馏路由,优先于设置页的运行时选择与默认模型(部署可强制蒸馏走指定路由);留空则跟随"设置页选择 → 默认模型"。运行时可在设置页 → 记忆 → 概览的"蒸馏模型"选择器从已配置的供应商(含 dsh 设置 → 模型里添加的自定义供应商)中切换,即时生效无需重启 |
llm.maxTokens |
65536 |
未分层调用的兜底输出总闸。各蒸馏层有独立预算(抽取 16k / 去重 8k / L2 32k / L3 16k;思考档 high/xhigh/max 时自动 ×4,防 reasoning 吃光预算),分层预算可在设置页 → 记忆 → 概览 → 蒸馏参数运行时调整(留空/0 = 跟随内置默认) |
llm.reasoningEffort |
空 | 蒸馏思考档位:空串 = 自动(按模型能力解析:模型默认档 → high);显式值(off/none/minimal/low/medium/high/xhigh/max)仅在该模型声明支持时发送——跨供应商 effort 词汇表不同(deepseek 认 off,OpenAI 系是 none,未声明档位的模型不传),不支持的档位自动降级为不传并告警一次;思考档 high/xhigh/max 时输出预算自动 ×4。运行时在设置页 → 记忆 → 概览切换,可选档位表跟随当前模型实时显示 |
llm.temperature |
0.3 |
蒸馏温度 |
llm.maxInputChars |
700000 |
单次蒸馏输入字符预算(超限的 L1 输入自动分块抽取);运行时可在设置页 → 蒸馏参数 → 输入预算调整(留空/0 = 跟随本值) |
llm.timeoutMs |
120000 |
单次蒸馏调用超时(ms) |
tools |
true |
是否注册模型可调用的记忆工具 |
日志与故障排查
dsh 宿主把插件日志打到控制台;插件另把 info 级以上镜像到数据目录的 memory.log。
一轮对话的典型日志路径:L0 捕获 → L0 落盘 → 蒸馏管线开始 → LLM 调用(输入/输出 字符数、耗时) → L1 阶段完成 → 管线结束;下一轮开头是 召回注入 N 条 L1。LLM 空输出
带完整诊断(finish reason / token 计数 / reasoning 摘录);JSON 解析失败记录模型原始输出
前 400 字符;所有失败告警带堆栈首帧。JSONL 事实源按轮次追加、依赖操作系统写回(不做逐条
fsync),断电等极端崩溃最多丢最后一小段尾部,检索库可用「重建记忆」从事实源全量重导。
与 MemoryCore 的差异
- 内嵌完整管线(不依赖外部 Gateway),蒸馏复用 DSH 自己的 LLM;
- L2/L3 由"LLM 操作文件工具"改为"LLM 输出操作 JSON / 完整文档,工程侧执行";
- 召回注入点在
agent/pre-step(消息侧合成消息,官方 pre-step 替换语义)+ agent 作用域systemPrompt.context(画像/导航稳定区,DSH 原生事件/服务); - 存储/检索即官方 sqlite 后端的单机裁剪版(裁掉多租户隔离列、TCVDB 云后端、审计表;
分词与官方一致用 jieba——@node-rs/jieba 预编译二进制 + CJK 二元组并集,
词元供 BM25 精确整词命中、二元组保子词召回;加载失败自动回退纯二元组,
FTS 索引按分词器版本戳自动重建)。
路线图
以下为规划中的功能,欢迎在 Issues 反馈需求与优先级:
- Git 分支感知:记忆与当前 git 分支关联,召回可按分支过滤/加权(与现有记忆档位正交)
- Claude Code / Codex 记忆导入:一键迁移既有记忆资产(
CLAUDE.md、Claude Code 记忆文件、CodexAGENTS.md等),导入后进入分层蒸馏管线
致谢
记忆核心能力(分层蒸馏管线、Prompt 设计、双写存储架构)参考自
TencentCloud/TencentDB-Agent-Memory
项目中的 MemoryCore,感谢原项目开放的设计与实现。
License
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi