dsh-plugin-lrc
zhibaiyingchuan/dsh-plugin-lrc
把 DeepSeek Harness 接到 LRC 的本地结构化记忆:每 8 轮提炼一次结论,按字符级 Jaccard 相似度(≥ 0.85)去重后写入本地 LRC 库。五个工具 lrc_recall / lrc_forget / lrc_remember_now / lrc_handoff / lrc_status 分别负责按需召回、撤回错误条目、立即写入、会话交接与状态行。首次运行会按平台下载 LRC 二进制(win32-x64、darwin-arm64、linux-x64,带 SHA256 校验)并启动隔离实例,因此无需先装 LRC 桌面端;数据默认写在 $DSH_HOME/cache/lrc-plugin/data,设置 LRC_BASE 可复用已有实例。
安装
dsh plugin --profile web add github:zhibaiyingchuan/dsh-plugin-lrcREADME
dsh-plugin-lrc
把 LRC 的长期记忆接进 DeepSeek Harness(DSH): 边聊边沉淀、按需召回、可纠错,让上下文不再需要频繁压缩。
版本 0.2.0 · MIT License · 适配 DSH
>=0.2.0-rc.1 <0.3.0-0
一句话说清它解决什么
DSH 的上下文会一直涨,涨到阈值就压缩,压缩就丢约束:
压缩前:40 轮对话,其中 3 条关键决策
压缩后:"前面聊了包管理器。" ← 决策没了
本插件不是"压缩时抢救",而是根本不让它涨到需要压缩:把对话里的决策、约束、结论持续搬进 LRC 长期记忆库,上下文里只留一行状态快照。AI 需要细节时,再按需召回。
对话(线性、易失)
↓ 每 8 轮增量提炼
结构化记忆(决策 / 约束 / 结论 / 报错)
↓ 语义查重后写入
LRC 长期记忆库(持久、可检索)
↓ 回填一行状态快照
上下文(始终很小)
AI 看到的不再是几十轮原文,而是:
[LRC 状态] 已确定用 pnpm(放弃 npm 因兼容问题);端口纪律 3099/3111。
细节在 LRC,需要时 recall。
它能给你带来什么
| 能力 | 你感知到的效果 |
|---|---|
| 自动沉淀 | 每轮对话的决策 / 约束 / 结论自动存进本地记忆库 |
| 按需召回 | 新会话里 AI 能想起"上次为什么这么定""你偏好用什么" |
| 主动纠错 | AI 发现记错了,能主动撤回,不让错误结论污染后续 |
| 会话交接 | 上下文快满时,整理成交接摘要,另起会话继续 |
| 状态自检 | 随时查插件是否正常、哪些能力可用 |
| 上下文裁剪 | 自动裁剪旧历史,让长对话不中断 |
安装
前置条件
- DSH
>= 0.2.0-rc.1 - Node.js
>= 20
方式一:从 GitHub 安装(推荐)
# 把 desktop 换成你的 profile 名(web / desktop / ...)
dsh plugin --profile desktop add github:zhibaiYingChuan/dsh-plugin-lrc
确认它真的进了插件树:
dsh --profile desktop --dump-config | grep dsh-plugin-lrc
方式二:从 npm 安装(发布后可用)
dsh plugin --profile desktop add dsh-plugin-lrc
关于 LRC 本体:你不需要先装它
插件启动时会自动处理:
- 探测本地已有 LRC(环境变量 / 3099 端口)→ 有就直接用
- 没有 → 检查内置二进制,缺失则按平台下载
- 启动隔离实例(独立数据目录,不碰你的生产记忆库)
- 失败 → 降级为纯客户端模式,静默跳过沉淀
数据到底写在哪,取决于模式:
| 模式 | 数据目录 | 说明 |
|---|---|---|
external(复用已有实例) | 那个实例自己的目录,例如 ~/.loong-recall/global/data | 插件不拥有这份数据,删 ~/.dsh/cache/lrc-plugin/data 清不掉它 |
managed(插件自启) | $DSH_HOME/cache/lrc-plugin/data | 只有这个目录是插件自己的 |
清理测试数据前先看日志里的 复用已有实例 / 已启动隔离实例,别删错。
使用
安装后无需额外操作,插件会自动工作。你也可以让 AI 主动调用这些工具:
| 工具 | 用途 |
|---|---|
lrc_recall | 召回相关记忆(涉及项目历史、用户偏好、之前决策时先调它) |
lrc_forget | 删除一条错误记忆(id 从 lrc_recall 输出里取) |
lrc_remember_now | 立即把当前对话沉淀到记忆库 |
lrc_handoff | 整理交接摘要并新建会话 |
lrc_status | 查看插件运行状态(能力矩阵、熔断、阈值、上下文画像) |
DSH 没有 MCP 客户端,AI 看不到 LRC 原生的 MCP 工具。所以插件把读 / 写 / 纠错都注册成了原生工具,AI 直接就能用。
配置
在 cordis.patch.yml 的 config: 下配置(或通过 DSH 配置界面):
| 配置项 | 缺省 | 说明 |
|---|---|---|
baseUrl | 空 | 指向已有 LRC 实例;留空则自动探测 / 启动 |
token | 空 | 服务端设了 LRC_API_TOKEN 时必填 |
project | dsh | 记忆归属项目 |
offloadTurns | 8 | 每多少轮沉淀一次 |
offloadChars | 6000 | 累计多少字符沉淀一次 |
offloadSteps | 8 | 累计多少步沉淀一次(长任务里正文很少,靠步数兜底) |
maxItems | 40 | 单次最多提炼条数 |
contextWindowTokens | 0 | 显式指定模型窗口;0 = 自动探测 |
trimRatio | 0.03 | 裁剪阈值占窗口比例 |
trimMinTokens | 30000 | 窗口未知时的裁剪阈值(绝对值) |
trimMinSteps | 10 | 两次裁剪之间至少间隔多少步 |
pruneResultThreshold | 4096 | 工具输出超过多少字符才剪枝 |
工作原理:三层过滤,LRC 只存不筛
筛选和提炼全部在插件端完成,LRC 端不加任何 LLM,保持毫秒级写入。
| 层 | 做什么 |
|---|---|
| 1. 硬规则 | 丢寒暄、代码围栏、正常终端日志、过短且无关键词的行 |
| 2. 宿主 LLM 提炼 | 系统提示要求模型在回答末尾输出 <lrc_memory>决策/约束/结论</lrc_memory>,插件用正则抠出 |
| 3. 本地查重 | Jaccard ≥ 0.85 视为复述,连 HTTP 都不发 |
触发沉淀的条件(任一):累计 8 步 / 8 轮正文 / 6000 字符,外加 turn 结束时无条件兜底 —— 长任务的最终报告只在 turn 末尾出现一次。
实测数据(2026-11,真实 DSH 会话 1855 步)
- 缓存命中率 91.4%(稳态 93.8%,裁剪当步 60.8%)。
- 裁剪是必要的:完全不裁剪要 $64.54,裁剪后 $4.46,相差 14 倍。
- 当前阈值接近最优:成本随阈值呈 U 形,最低点约 53K,现状 35.5K 仅差 11%(约 $0.50),不值得为这点差价冒险。
- 功能全部打通:写入 / 召回 / 纠错 / 交接 / 状态 / 裁剪 / 剪枝均正常。
一句话:命中率下降是"把大上下文换成小上下文"的必然代价,不是浪费;用户实际付的钱更少,换来的是"长对话不中断 + 跨会话有记忆"。
诚实说明
- 上下文仍会增长(用户消息、工具输出)。插件做的是把结论性内容持续搬走,让增速降到原来的 1/5 ~ 1/10,压缩很少触发。
- 不承诺"永不压缩",承诺"压缩频率大幅下降"。
- 插件依赖 AI 主动调用
lrc_recall才能用上记忆;如果 AI 不调,记忆就用不上。这一点靠系统提示引导,不是 100% 可靠。 - 模型窗口探测:宿主对未知模型可能返回
1,000,000哨兵值,插件会保守降级到trimMinTokens=30000。若确知模型窗口,请显式配置contextWindowTokens。
开发
npm install
npm run build # 构建 dist/index.js
npm test # 运行全部 e2e 测试