JunNanLYS/dsh-layered-memory ↗★ 16

dsh-layered-memory

L0~L3分层蒸馏记忆自动捕获与召回注入 适合需要自动捕获对话、提取原子记忆并自动在模型步骤前召回注入的用户。

包名
dsh-layered-memory
兼容性
待验证
Harness 依赖范围
^0.1.2-alpha.1
Cordis 依赖范围
^4.0.1
版本
0.11.0
许可证
MIT
最近更新
2026年9月7日

同名包的其他仓库

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:JunNanLYS/dsh-layered-memory

配置

覆盖配置写在 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: ''
字段默认说明
familyauto新会话默认记忆档位:auto(双族自动)| chat(个人)| work(工作);会话内可用输入栏控件临时切换
dataDir$DSH_HOME/memory数据目录
capture.enabledtrueL0 捕获
capture.stripCodeBlockstrue助手消息剥离代码块
capture.maxMessageChars4000单条消息最大字符数
extract.enabledtrueL1 抽取
extract.minMessages6稳态触发阈值:单会话攒够 N 条新消息跑一次 L1 抽取。起步阶段生效阈值从 1 翻倍爬坡到此值(首轮即出记忆,随后自动攒批省调用)
extract.idleSeconds300闲置兜底:会话静默 N 秒后把未蒸馏切片落袋(接住"没攒够阈值用户就离开");0 关闭
extract.backgroundMessages10抽取时附带的背景消息条数(按会话从 L0 现查,会话间互不污染)
extract.candidatePool5去重候选池大小
l2.enabledtrueL2 场景整合
l2.minNewMemories5距上次 L2 整合的新记忆阈值
l2.maxScenes12场景块数量上限
l2.sceneContextLimit3L2 prompt 附带的相似场景全文上限
l3.enabledtrueL3 画像蒸馏
l3.interval20L3 蒸馏间隔(新记忆条数)
recall.enabledtrue自动召回
recall.maxResults5每条新用户消息前注入的 L1 条数上限
recall.maxCharsPerMemory500单条注入记忆的字符上限(超限截断并提示用记忆工具查全文);0 不限
recall.maxTotalRecallChars2000整轮注入总字符上限(超限按相关性丢尾部);0 不限
recall.timeoutMs5000召回总预算(ms):超时跳过本轮注入、不阻塞对话;0 不限时
recall.includePersonatrue系统提示注入画像上下文(``,稳定区)
recall.includeSceneNavtrue系统提示注入场景导航(``,稳定区)
recall.strategyhybrid检索策略:keyword / embedding / hybrid
recall.scoreThreshold0.3召回分数阈值(低于不注入;仅 keyword/embedding 策略生效,hybrid 融合前不过滤;工具路径不过滤)
recall.decayHalfLifeDays30召回时效衰减半衰期(天,0=关):排序按 相关度 × max(0.5, 0.5^(距更新天数/半衰期)) 软加权——相关度相近的候选间新鲜记忆优先(名额轮转),老记忆最多损失一半排序分(地板兜底,长期事实不沉底)
embedding.enabledfalse向量检索开关;关闭即纯 FTS 运行
embedding.baseUrl空OpenAI 兼容 /embeddings 地址(如 https://api.siliconflow.cn/v1)
embedding.apiKey空API Key
embedding.model空embedding 模型名
embedding.dimensions0向量维度(启用时必填,须与模型输出一致)
embedding.maxInputChars5000单条文本最大字符数(超长截断)
embedding.timeoutMs10000单次 embedding 调用超时(ms)
embedding.allowLocalModelstrue允许本地嵌入档(部署上限:关闭后设置页不能下载模型、不能切本地档)
embedding.mirrorhttps://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.fallbacks[]蒸馏回退链:主路由失败(报错/被掐断/网络异常/空输出)后按条目顺序逐个降级尝试的备用路由列表,条目 = {provider, model, reasoningEffort?}(档位非空覆盖全局 llm.reasoningEffort,仍按模型能力钳制);与主路由完全相同的条目自动跳过;每条路由各享全额 timeoutMs;全部失败交既有按会话退避重试。空数组(缺省)= 单路由行为不变(详见下方蒸馏回退链与慢 TTFT 模型);设置页运行时路由链(distillChain)非空时整体接管主路由与回退链(单行链 = 显式无回退),空 = 跟随本配置
llm.layerRoutes{}蒸馏按层路由:层键 l1/l2/l3 各配一条完整链(条目同 llm.fallbacks,头行必须 provider+model 双显式),非空即完整替换该层解析(该层主路由与回退都归层链管,全局链对该层不参与),空/缺省 = 该层跟随全局;l1 同管抽取+去重两个调用点。运行时可在设置页「蒸馏参数」分段面板里按层编辑(优先于本静态配置);部署 pin 不废静态层链(同为部署配置,同回退链先例)。与回退链正交可组合——每层各自一条链(ADR-0005)
llm.maxTokens65536未分层调用的兜底输出总闸。各蒸馏层有独立预算(抽取 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.temperature0.3蒸馏温度
llm.maxInputChars700000单次蒸馏输入字符预算(超限的 L1 输入自动分块抽取);运行时可在设置页 → 蒸馏参数 → 输入预算调整(留空/0 = 跟随本值)
llm.timeoutMs120000单次蒸馏调用超时(ms)
tokenCost.retentionDays365蒸馏成本明细(token_cost 表)保留天数,写入时滚动清理更早行;0 = 永久保留。成本看板「近 N 天」窗口上限同此值
toolstrue是否注册模型可调用的记忆工具
benchControlfalse注册 bench 控制服务(进程内 rebuild 触发/会话档位设置/蒸馏用量快照,供基准 lifecycle 赛道)。默认关——生产部署零表面积,勿随意开启

蒸馏回退链与慢 TTFT 模型

部分推理供应商的免费/慢速档位首 token 延迟(TTFT)可达 20 秒以上,而部分上游网关会在连接静默约 20 秒时掐断——蒸馏调用以固定 ~20s 失败(llm aborted),插件侧 120s 超时根本轮不到生效(#31 的实测场景)。三层缓解按需取用:

  1. 换路由(最直接):设置页 → 记忆 → 自动化 → 高级路由与预算的路由链编辑器即时改主路由(或把快路由排到链首),或静态 pin llm.provider/llm.model。

  2. 回退链(自动降级):主路由失败时按序自动换备用路由,无需人工干预:

    llm:
      provider: opencode-go          # 主路由(也可不 pin,跟随设置页路由链主路由/默认模型)
      model: ox-alpha-free
      fallbacks:                     # 条目顺序 = 降级优先级;不配置 = 单路由行为不变
        - provider: opencode-go
          model: deepseek-v4-flash
          reasoningEffort: low       # 可选:该路由的档位覆盖(缺省跟随全局)
        - provider: deepseek-official
          model: deepseek-v4-flash
    
  3. 按层路由(各走各的通道):不同蒸馏层对模型诉求不同(L1 高频要便宜快稳、 L3 低频可容忍慢首包但要强能力),可给差异层单独配链——每层一条完整回退链, 未配置的层照走全局链:

    llm:
      layerRoutes:                  # 按层独立路由(#34);头行必须显式 provider+model
        l1:                         # l1 同管抽取 + 去重两个调用点:配条便宜快稳的链
          - provider: opencode-go
            model: deepseek-v4-flash
            reasoningEffort: low
          - provider: deepseek-official   # 层内回退:L1 故障只降级到这里,不落全局链
            model: deepseek-v4-flash
        l3:                         # L3 画像蒸馏:低频大输入,配强能力链
          - provider: deepseek-official
            model: deepseek-v4-flash
            reasoningEffort: high
    

    也可在设置页 → 记忆 → 自动化 → 高级路由与预算的分段面板(全局默认 / L1 / L2 / L3) 里按层运行时编辑,层内优先级:运行时层链 > 本 YAML 静态层链 > 全局默认链, 逐级兜底。

    失败 = 报错 / 被掐断 / 网络异常 / 空输出(流正常结束但 0 字符——对蒸馏而言必然在解析阶段报废,改判为该路由失败而非返回空串);调用方主动取消不降级;每条路由各享全额 llm.timeoutMs(共享预算会让慢 TTFT 的回退路由拿到的窗口小于它真实需要的首包时间,回退链形同虚设);token 成本逐次尝试记账(失败尝试也计一行,含流中断前已到的 token),成功调用归因到实际服务的路由。路由链也可在设置页 → 记忆 → 自动化 → 高级路由与预算的「蒸馏路由链」编辑器里运行时调整(无需改配置重启);本 YAML 适合部署者固化静态链。

  4. 调高超时:llm.timeoutMs 只在路由确实慢但网关不掐时有用;网关 20s 掐断的场景调插件超时无效,请用前两层。