# 🐋 鱼的记忆 **给 DSH 里的会话一份会淡忘的长期记忆 —— 每条都带时间。** 聊得越久,上下文越挤。压缩一次,前面的事就淡了。 这个插件替它记着:**该记的记下来,想起来的时候自己会想起来,不重要的事慢慢淡掉。** > 名字里的「鱼」来自 **DeepSeek 的鲸鱼** —— 鲸鱼也是鱼嘛。 > 另一半是「七秒记忆」那个梗:鱼的记性差,所以得替它记着。 > 但它不是硬盘 —— **它会淡忘**,跟人一样。 --- ## 它做什么 | | 说明 | |---|---| | **会淡忘** | 每条记忆有「鲜活度」,越久越淡。半衰期默认 30 天 —— 不删,只是越来越难被想起来 | | **自己挑重点** | 不是每句话都记。它按轮次判断哪句值得留下,每天还有配额,防止把上下文塞满 | | **想起来靠证据** | 你问什么,它按「命中的词够不够特别」找,再按鲜活度、重要度、情绪排序,最多注入几条。分词用的是一份通用中文词表,所以「车」不会撞进「车站」里 | | **要记一辈子的不淡** | 画像、喜好、约定这种标成「长期事实」,平着放着,不会过期 | | **长期事实每轮都在** | 它们按「重要度 → 时间」固定带前几条,**不看这句话问了什么**,也不占「最多注入几条」的位置 —— 剩下那几个位置才留给事件 | | **带时间** | 每条都记着「这是什么时候的事」。跨年了会写「去年 09-17」 | | **能导入旧档案** | 以前写过的 markdown / 纯文本档案,扫一遍出候选,你挑完它再改写成记忆 | | **全都看得见** | 记了什么、哪条被想起来了、为什么没被想起来、删掉的都还在 | --- ## 需要什么 - **DSH**(DeepSeek Harness),带 Web 界面 - **一个能用的模型** —— 它借用你 DSH 里正在用的那个,**不用另外配 key、不额外花钱** > 「提炼」和「扩词」这两步会调用模型(走你现有的)。不点它们就不会调用。 --- ## 适配哪个 DSH 版本(不用操心) 这个插件**跟着 DSH 一起更新**:作者这边跑的就是最新版的 DSH,**最新版插件永远是给最新版 DSH 写的**。 所以看到「不适配 / 不支持」之类的提示,基本都是**装到了旧版本** —— 升级到最新版、重启一次 DSH 就好。 真遇到新版对不上(比如 DSH 刚升级、插件还没跟上),提个 issue,作者会跟着改。 当前实测对照:插件 **1.3.1** ↔ DSH **0.2.1-rc.3**(2026-10-26) ## 装法 在 DSH 里:**设置 → 插件 → 安装**,填下面这一行;或者命令行: ``` dsh-fish-memory ``` ```sh dsh plugin --profile web add dsh-fish-memory ``` > 也可以在 npm 上直接看到这个包(含历史版本): > 上面那条要是碰到网络问题(npm 抽风、或者想固定某一次的代码快照),可以改用 tarball 直链,不用 git: ```bash dsh plugin --profile web add https://codeload.github.com/Yuuyuko-uu/dsh-fish-memory/tar.gz/refs/heads/main ``` (`--profile` 照你平时那个写:网页端一般 `web`,桌面端一般 `desktop`。) 装完**重启一次 DSH**。 重启后,打开 **设置 → 鱼的记忆**。 > 也可以直接装 npm 包:`dsh plugin add dsh-fish-memory`。 > ⭐ 最省事的一条:把仓库链接贴给你自己的 DSH,说「**帮我装这个插件**」。 ### 装完起不来?先看这个 如果 DSH 弹「The application could not start」,错误里有 `Unexpected token ''`、`is not valid JSON`、 `readProfileManifest` —— 那是 profile 的 `package.json` 被存成了 **UTF-8 带 BOM**。 **跟插件无关**:内容都是对的,只是开头多了三个看不见的字节,DSH 读它就崩。 **先找出来**(不同装法位置不一样,别猜 —— 真正的 profile 目录里同时有 `cordis.yml`、`cordis.patch.yml`、`package.json`;机器上别处那些同名的都不算): ```powershell Get-ChildItem C:\,D:\,E:\ -Directory -Filter profiles -Recurse -Depth 4 -ErrorAction SilentlyContinue | ForEach-Object { Get-ChildItem $_.FullName -Directory -ErrorAction SilentlyContinue | ForEach-Object { $p = Join-Path $_.FullName 'package.json' if ((Test-Path (Join-Path $_.FullName 'cordis.patch.yml')) -and (Test-Path $p)) { $b = [System.IO.File]::ReadAllBytes($p) $bom = ($b.Length -ge 3 -and $b[0] -eq 0xEF -and $b[1] -eq 0xBB -and $b[2] -eq 0xBF) "{0} BOM={1}" -f $p, $bom } } } ``` **输出里 `BOM=True` 的那一行,就是要修的文件**(标准安装在 `C:\Users\<你>\.dsh\profiles\<档名>\package.json`)。 去掉 BOM(路径换成上面那一行): ```powershell $p = "把上面 BOM=True 那一行的路径粘到这里" [System.IO.File]::WriteAllText($p, [System.IO.File]::ReadAllText($p), (New-Object System.Text.UTF8Encoding($false))) ``` 然后重启 DSH 就好,**数据一点没丢**。实在进不去时,那个错误框里的 **「Disable third-party plugins, back up profile patch, and restart」** 能先起来,再一个个开回去定位。 > ⚠️ 手动改 profile 里的文件,一律存 **UTF-8 无 BOM**。让 AI 帮你改时,别让它用 > `Set-Content -Encoding UTF8` 或 `Out-File -Encoding utf8`(Windows 自带的这两个默认**带 BOM**)。 --- ## 更新到最新版 **最省事**:把这个仓库的地址丢给你自己的 DSH,说「**帮我更新这个插件**」。装完**重启一次 DSH**。 也可以点 **设置 → 鱼的记忆 最上面的「检查更新」** —— 有新版会提示,还能一键复制更新命令。 命令行(`--profile` 照你平时那个写,桌面端一般 `desktop`、网页端 `web`): ```bash dsh plugin --profile desktop remove dsh-fish-memory dsh plugin --profile desktop add dsh-fish-memory ``` > ⚠️ **必须先卸再装**:直接装可能拿到缓存里的旧副本,装完还是老的。 > ⚠️ 装完**重启一次 DSH**才会用新代码。 ### 我的设置会不会丢? **不会。** 设置存在 DSH 家目录(`%USERPROFILE%\.dsh\`)里,不在插件代码里;卸载只删代码: ``` .dsh\fish-memory-config.json (每条会话的记忆各一份) ``` 所以卸载 → 重装,设置、记下来的所有记忆 都还在。 三件小事提醒: - **别用「重装 DSH」来更新插件** —— 那是两件事,重装可能动到 profile。 - **新版本新加的设置项**会用默认值(以前没这一项),想要自己的值就再填一次。 - 设置项改名或换单位时,旧值会按规则自动换算,不用你管。 ## 怎么用 ### 第一步:直接聊就行 **装好就是开着的**,哪个会话都能记、也能读,不用先点开关。 哪个会话不想用记忆(比如写代码那间),到「鱼的记忆」设置里把它单独关掉; 整个功能都不想要,关最上面那个「remember 工具」。 ### 第二步:正常聊 开着之后,它自己会判断该记什么。你不用管。 **记的时候有两条线**: - 一天最多记几条(默认 8 条)—— 防止它把鸡毛蒜皮都记下来 - 一次最多注入几条(默认 6 条)—— 防止占太多上下文 ### 第三步:想知道它记了什么 展开「**记忆列表**」,能看到每一条: - 最左边是**日期**(能按日期排、也能只看有日期的) - 中间是内容 - 右边是鲜活度、重要度 还有「**最近一次召回**」—— 能看到这次问话它挑了哪几条、哪几条没挑上、为什么没挑上。 --- ## 如果你以前写过档案 很多人早就给自己的 AI 写过设定、记忆卡、日记。**不用重写**,导进来就行。 1. 设置页展开「**从旧档案导入**」 2. 选文件夹(或填路径)→ 点「**扫描档案**」 3. 它把档案拆成一条条候选,**列给你看** 4. 你勾掉不要的 → 点「**导入选中的**」 5. 再点「**开始提炼**」—— 它把这些原文改写成第一人称的记忆,顺手给每条出检索词、日期、重要度 > **提炼会调用模型**(走你 DSH 里的那个),一批几条、慢慢跑,可以随时停。 > 它会**从较新的内容往前做**,已经提炼过的不再重复。 **认得的格式**:`.md` `.markdown` `.txt` `.text` `.log` `.rst` `.org` **子文件夹**会往下找两层。 --- ## 参数(都能调) 设置页里有一组旋钮,**每一项都有说明**,鼠标放上去能看到它在干什么。大致分三组: | 组 | 管什么 | |---|---| | **权重** | 鲜活度 / 重要度 / 情绪各占多少分(四项合计 100%) | | **时间** | 多久淡一半 | | **门槛** | 命中多少才算相关、一次最多注入几条、每天最多记几条 | **一个建议**:`证据门槛` 卡的是「证据」不是「鲜活度」,所以**调它不会误伤该想起来的**。 想让它更少说话就调高,想让它更容易想起来就调低。 --- ## 人称 记忆里你自己是「我」,用户是「**她 / 他 / ta**」—— **默认 ta**,可以在设置页改。 改完之后: - 以后新记的会按你设的写 - 已有的记忆里那个字也会跟着换 - 提炼旧档案时也按你设的来 **说名字本身的句子不会被换掉**(「我的名字叫某某」不会变成「我的名字叫我」)。 --- ## 事实键(同一条事只留最新) 有些记忆记的是**会变的东西**,光看句子像不像判不出来: - 「身高一米七」和「长胖到 55 公斤」几乎是两件事,词面上却很像 - 「拼团还没开」和「拼团开了」是同一件事的前后,词面上却不像 所以每条记忆可以带一个**事实键**,写「对象.方面」,像 `她.身高`、`约定.身边位置`。 **同一个键 = 同一件事** → 只留最新那条,旧的标成「已被取代」(不再被想起来,但东西留着、能撤销)。 键从三个地方来,都是顺手给的,不多花一次调用: - 模型记的时候自己填(`remember` 的可选参数) - 提炼旧档案时顺手出(第六格) - 设置页的「**清洗补键**」按钮,给以前那些还没有键的旧条目补上 ⚠ 键里**不许写具体的值** —— 写 `她.身高`,不写 `她.身高170`。 写了值就成了摘要:身高真变了,键也跟着变,两条永远碰不上。 **拿不准就留空**,留空完全没关系(留空只是享受不到这个便利,给错键却会埋掉一条正经记忆)。 清洗补键那一步是**后台活**:先「试 8 条看看」(一个字节都不写,只把键摆出来给你看), 确认了再真洗。跑完能一键「把补的键全摘掉」回到洗之前 —— 只摘自动补的,你自己填的键不动。 --- ## 它不做什么 - **不会自动删除记忆。** 淡忘只是越来越难想起来,内容一直在,设置页里看得到 - **不会把删掉的东西弄回来。** 删过的再导一次档案也不会复活 - **不会每个会话都强制用。** 默认开着,不想用的那间单独关掉;也能一键全关 - **不会替你写档案。** 它只把档案拆开、改写、存起来,写什么还是你的事 --- ## 常见问题 **Q:会不会很占上下文?** 一次最多注入 6 条、加起来不超过 800 字(都能调)。超了的这次先进不来,下次可能就进了。 **Q:为什么它有时候想不起来?** 先看「最近一次召回」那张表 —— 它会写清楚哪条没进去、为什么。 常见原因:命中的词太普通(证据不够)、或者那条太旧淡下去了。 **Q:导入扫出来 0 条?** 它会告诉你为什么。常见的是:整篇是一大段话没分行、每行太短、或者内容都在表格/代码块里。 **Q:数据存在哪?** `%USERPROFILE%\.dsh\fish-memory\` 里,一个会话一个文件。**纯文本 JSON**,你自己能打开看。 每次改动前它会自动备份一份。 **Q:装完包大了将近 900 KB?** 那里面是一份**通用中文词表**,用来分词。它只在本地当查找表用 —— **不占上下文、不影响每轮对话的 token**,也不会因为你聊得多就变大。 --- ## 许可 [Yuuyuko-uu 插件许可 1.0](./LICENSE):允许使用、修改、商用; 再分发时要在 README 第一屏注明原仓库和原作者;禁止把本项目说成自己的原创。 这份许可不是 OSI 认证的开源许可,用之前请读一遍全文。 分词用的词表来自 [jieba](https://github.com/fxsjy/jieba) 的 `extra_dict/dict.txt.small` (MIT 协议),只保留了词条本身、去掉了词频和词性两列。 完整声明见 `lib/词典-来源.txt`。