DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

alcon5201yun /

alcon5201yun/dsh-fat-fish

Verified

大肥鱼 dsh-fat-fish(测试版 v0.2.2):跑在 DeepSeek Harness 里的拟人陪伴插件。一个身份;一套会遗忘又会纠错的记忆(scope 身份隔离、纠正历史、可解释可固定可撤销可彻底删除、向量混合召回);心情与作息;会兑现的提醒;以及对话界面 / QQ / B站 三个说话的地方。消息带独立 ID、状态与失败重试,桌宠已移除。

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHubProject homepage
READMESource: main@88a5d76e

大肥鱼 · dsh-fat-fish

一只住在你电脑里的拟人胖鲸鱼:一个身份、一套会遗忘的记忆、一份作息、三个能说话的地方。

她不是「把大模型接进 QQ」的机器人。她是 DeepSeek Harness 里的同一个她:你在对话界面里叫她、在 QQ 里找她、在 B 站看她说晚安,回到那个会话里,她仍然记得刚刚发生过什么。

MIT 开源 · 本地运行 · 无第三方运行时依赖 · 适配 DSH ≥ 0.2.1-rc.2。


你会看到什么

地方 形态
对话界面 打开 DSH Web 直接聊:和 QQ、B站 共用同一个会话、同一套记忆、同一个人格
设置页 设置 → 大肥鱼:身份 / 作息 / 心情 / 记忆 / QQ / B站 / 状态,7 个页签,改完即生效
QQ 通过 OneBot 11 接入:私聊和群聊(可设置只 @ 才回)、白名单、只回复「由 QQ 唤醒的那一轮」;能看她收到的图,也能发图片/表情包
B站 可选:读 @ 和回复(只读轮询),或发一条动态(默认 dry-run,不真的发)
工具 模型可调用 fish_remember / fish_recall / fish_forget / fish_say / fish_sticker / fish_remind / fish_followup / fish_tasks / fish_quiet / fish_status
提示词 每轮自动注入:现在几点、她困不困、心情如何、想起了哪几件旧事、这句话从哪来

她只有「一个意识」:同一个 session、同一套记忆、同一种语气。对话界面、QQ、B站只是她的三个嘴巴和耳朵,不是三个机器人。

版本:当前为 测试版 v0.2.2。之后每个补丁只递增第三位(v0.2.1、v0.2.2…),直到稳定版再另行说明。


已经做了什么(截至 v0.2.2)

这不是一个「接上大模型就能聊天」的壳。按能力分,当前版本已经包含:

身份与人格

  • 结构化人设:名字、称呼、性别、年龄感、关系、性格、说话风格、背景、边界、固定记忆。
  • 关系模式(朋友 / 桌宠 / 工作搭档 / 很重要的人)与亲密程度 1–5,决定称呼和亲近尺度。
  • 先判断场合再决定说法:日常聊天短句、接情绪;工作/讲正事允许完整解释、分点、步骤、代码块、表格。
  • 三条底线:不称自己是 AI、不编细节、边界优先于心情。心情只影响措辞,不影响准确性、完整度与判断。

记忆(v0.2.2 的 v2 引擎)

  • 艾宾浩斯式衰减:A = A0 · 2^(−days/H),H = 基础半衰期 · (1 + 2 × 重要度);重要度高的记得更久,永久事实(kind=fact 且重要度 ≥ 0.9)不衰减。
  • 可见范围隔离:person:owner / person:qq:<号> / group:<群号>。桌面私事不会出现在群聊或其他人的会话里;只有明确绑定为主人的 QQ 才共享私人记忆。
  • 纠正而不是坚持旧说法:说「我现在不喝咖啡了」会更新当前偏好,同时把旧说法留在 history 里,不再反复强化旧版本。
  • 每条记忆保存:关于谁(subject)、来自哪条消息(source.kind/sessionId/messageId/snippet)、何时起效(validFrom)、是否确认(confirmed)。
  • 设置页可编辑、固定、确认、撤销、彻底删除;删除是真删(连归档一起清),不是假装忘记。
  • 召回缓存按 revision 失效;写路径(纠正/编辑/删除/衰减)才推进 revision,读路径不再污染计数。

向量召回(混合检索)

  • 本地 Ollama + qwen3-embedding:0.6b(1024 维),不依赖云端、不上传记忆。
  • 关键词/字词召回 + 向量召回各取前 10,合并去重后最多 3–4 条注入;向量只负责找候选,是否可用仍由 scope、纠正历史、有效时间决定。
  • 索引 embeddings.json 增量同步:只算新增/改动/换模型的条目;minScore 默认 0.37,由 42 条真实记忆 + 7 个验收用例校准。
  • 真实验收:换说法能找到;姓名/日期精确信息排前;纠正后用新说法;无关问题返回 0 条;群聊问私事不出现私人记忆;删除后换说法也不返回。

心情与作息

  • 六维心情:开心 / 踏实 / 甜 / 心疼 / 担心 / 吃醋;总值 0–100,向基线缓慢回稳。
  • 精力曲线(13 个锚点插值)、睡眠窗、醒来问候。
  • 硬约束先于概率:睡眠中、安静时段、「今天安静」、日上限、主动概率为 0 —— 这些先判,满足才掷骰子;心情/熟悉度不能突破用户设置的 0。
  • 主动频率 三档(安静 / 正常 / 话多),只调参数,不覆盖上限。

约定兑现

  • 「明天提醒我」「下次接着聊」不再只存成一句记忆,而是进入持久任务 tasks.json。
  • 支持:自然语言时间(30 分钟、明天 09:00、今晚 9 点半、2 小时后)、话题(fish_followup)、完成/取消/重试。
  • 到点由 60 秒心跳检查,成功发到 QQ;失败按 1 → 2 → 4 → … 分钟退避重试,最多 8 次。
  • 「想一个人待会儿」→ fish_quiet 设安静时段,时段内不主动开口。

三个说话的地方

  • 对话界面:DSH Web 内置,与 QQ/B站共用同一个会话、记忆和人格。
  • QQ(OneBot 11 / NapCat 或 SnowLuma):私聊与群聊、白名单、只 @ 才回、图片入站识别、图片/表情包出站、连发合并(短句 15 秒 / 长句 25 秒窗)、重复上报去重、群聊合并保留每人身份、每条消息独立 ID/收件人/状态/重试。
  • B站:读 @ 和回复(轮询,注入成功后才标记已读)、发动态(默认 dry-run)。

设置页与可靠性

  • 7 个页签:身份 / 作息 / 心情 / 记忆 / QQ / B站 / 状态。
  • 刷新不丢草稿;等待回复有状态;连接失败显示原因;发件箱可看/可重试;聊天记录可导出/清空。
  • 发件箱 outbox.json:独立 id、收件人、状态、失败重试、sent 以 OneBot 返回的 message_id 为准。

已移除

  • 桌宠:v0.2.0 起已移除(shell.overlay 注册、/pet/* 路由、桌面气泡、相关配置与文档全部清理)。砍掉原因是没有看到真实可用性,避免维护一个好看但不可靠的入口。

测试

当前仓库内有 10 套测试,覆盖到「一次完整对话」的场景:

smoke · regression(18)· privacy(28)· memory-v2(24)· embeddings(34)· persona-modes(18)· qq-debounce · client-load · reminders(38)· reliability(20)· semantic-eval(7/7,需要本地 Ollama)。


版本与回滚(前代代码包)

从测试版起采用 0.2.x:每次更新只递增第三位,旧版本代码包保留,方便随时回滚。

版本 状态 代码包
v0.2.2 当前推荐 dsh-fat-fish-v0.2.2.zip
v0.2.1 保留 dsh-fat-fish-v0.2.1.zip
v0.2.0 保留(测试版起点) dsh-fat-fish-v0.2.0.zip
v0.1.x 历史 tag v0.1.0 / v0.1.1 / v0.1.2 仍在仓库

回滚方式二选一:

  1. 源码回滚:git checkout v0.2.1,再重新 plugin_manager install_bundle target=<该目录>。
  2. 安装包回滚:下载对应版本的 zip,解压后按 README 的安装步骤装;插件数据在 $DSH_HOME/fat-fish/,换版本不会丢记忆(引擎带旧数据迁移)。

每个 GitHub Release 都附带该版本的 zip 与变更说明;本机 C:\deepseek\ 下也留有同名 zip 备份。


消息可靠性与界面状态(v0.2.0)

消息不是「发出去就不管」:

  • 每条消息都有独立 id、收件人、状态和重试:outbox.json 持久化;失败会按 1 分钟 → 2 → 4 → … 退避重试,最多 6 次;sent 以 OneBot 返回的 message_id 为准。
  • QQ 重复上报去重:同一个 message_id 在 10 分钟内只处理一次,重复上报会被忽略。
  • 群聊合并保留身份:连发合并时,群聊里的每条都带「[QQ 群消息] 昵称(QQ 号)」前缀,不会把两个人的话混成一个人。
  • B站先注入成功再标记已读:注入失败会留到下一轮重试,不会因为「先标记」而漏消息。
  • 设置页的状态页:能看到发件箱每条消息的收件人/状态/重试按钮、QQ 最近发送与失败原因、本地聊天记录,并可一键导出或清空聊天记录。
  • 刷新不丢:未保存的设置草稿会存在浏览器 localStorage,刷新后自动恢复;聊天记录和发件箱在刷新后从 Host 重新拉取。
  • v0.2.1 修复:QQ 非主人私聊 / 群聊的「每 8 轮自动记忆整理」此前因 turnScope 竞态永远不触发(turn 收尾先重置为 owner,异步整理才读);现在在 turn 结束前快照 scope 再传给整理任务。
  • v0.2.2 修复:设置页「主人自己的 QQ 号」输入框的正则写成了 /[,,\\s]+/(\\s 表示反斜杠或字母 s,不匹配空白),空格分隔的两个号会被合并成一个错误号码,导致主人身份与记忆 scope 识别错位;已改为 /[,,\s]+/。
  • v0.2.2 修复:recall() 在召回强化时推进 revision,而 recallLine 的缓存 key 含 revision,导致缓存永远 miss、每次提示词组装全量重跑召回,revision 还会无限膨胀并持久化。现在召回路径不再推进 revision,只有写路径(纠正/编辑/删除/衰减)才失效缓存。

安装

前置条件:

  • Windows / macOS / Linux 均可(无原生模块)
  • Node ≥ 22(DSH 自带运行时即可)
  • DeepSeek Harness ≥ 0.2.1-rc.2(已在 0.2.1-rc.5 验证)

推荐在 DSH 会话里让 agent 安装:

plugin_manager install_bundle target=<本仓库绝对路径>

也可以走 DSH 的插件清单手动安装:把本目录加入 profile 的 package.json 依赖(file: 路径)并在 cordis.patch.yml 的 insert 里加一行

- insert:
    - id: dsh-fat-fish
      name: dsh-fat-fish

id 必须与客户端 bundle 的 window.__ModuleLoader__.load({ id }) 一致,否则控制台会报 “loaded without registering”。

安装完成后 刷新一次 DSH 网页(或重启桌面壳)。刷新后:

  1. 右下角出现橙色胖鱼(若与其他挂件重叠,拖到别处;位置会记住)。
  2. 设置 → 大肥鱼 出现新页签。
  3. 当前会话的回复开始带「大肥鱼」的人格与实时状态。

桌面壳(dsh-app://)与 Web GUI 共用同一份插件;tapIndex 类注入在桌面壳不生效,但本插件不依赖它。

卸载

plugin_manager action=remove_bundle target=dsh-fat-fish

配置与记忆保留在 $DSH_HOME/fat-fish/,想彻底清掉手动删除该目录即可。


三个通道怎么开

1. 对话界面(默认开启)

刷新页面后直接在 DSH Web 里聊。每句话都进同一个会话,也会被记忆系统看见;这里同样是「主人自己的场合」。

2. QQ(OneBot 11)

  1. 启动一个 OneBot 11 实现(NapCat / Lagrange / SnowLuma 等均可),开启 HTTP 服务端 和 HTTP 上报(post)。
  2. 设置 → 大肥鱼 → QQ:
    • API 地址:OneBot 的 HTTP 地址,例如 http://127.0.0.1:3001
    • Access Token:OneBot 配置里的 token(没有就留空)
    • 上报地址:填 http://127.0.0.1:4399/qq/event。4399 是插件自己起的本地监听端口(只绑 127.0.0.1),与 DSH Web 端口无关、重启后也不会变;可在设置页「本地上报端口」修改。
    • 路由令牌(可选):填一个随机串,之后上报 URL 需带 ?token=...;公网/局域网暴露时建议填
    • 群聊策略:mention(只回 @ 她的)/ all / off
    • 白名单:QQ 号列表,非空时只服务名单内的人
  3. 保存后点「测试连接」。她只回复 source.kind === 'qq' 的轮次,不会把自己在桌面上的自言自语发到群里。

插件在回环地址上自带一个很小的 OneBot 上报端口(默认 4399),专门绕开宿主 Web 的登录鉴权:OneBot 进程不需要浏览器 cookie。只监听到本机,未设令牌时也接受任何本机进程投递;如果本机有不可信进程,建议设置「事件上报令牌」。

图片与表情包

  • 看图:对方在 QQ 发图时,插件把图下载成 DSH 的图片内容块交给她看(默认最多 4 张、单张 5MB;可在设置页关掉或改成一次只收一张省 token)。
  • 发图:她回复里写 ![随便什么](https://... 或 本地路径) 的 markdown 图片,会被抽出来当 QQ 图片发出去;assistant 消息里的图片附件也会一并发出。
  • 表情包:内置 8 张原创表情(开心/委屈/困/加油/无语/抱抱/吃瓜/得意),模型可以调 fish_sticker 发;文件在 assets/stickers/,可以自己替换或加新的。

连发合并(不秒回)

对方连着发好几条时,插件不会一句一句回:

  • 短句(默认 < 20 字)先等 15 秒;长句先等 25 秒;图片和表情包算短句(配了长文字也按短等待)。
  • 等待期间又来新消息,就从新消息的时间重新计时。
  • 到点后把这段时间的所有消息合并成一次交给她,只回一条(多条的意图一起处理)。
  • 最多攒 3 分钟就强制合并回复,不会一直等下去。
  • 实例之间互不影响:私聊和每个群各自计时;图片也会一起合并。
  • 设置页 QQ 里可以改这两个等待时间、字符阈值,或整个关掉(qq.debounce.*)。

3. B站(可选)

设置 → 大肥鱼 → B站:

  • Cookie:登录 bilibili.com 后从浏览器复制整段 Cookie(至少含 SESSDATA 与 bili_jct)。只存在本机 $DSH_HOME/fat-fish/config.json,不会上传。
  • dry-run:默认开启。开启时「发动态」只写日志、不真的发;确认要发再关。
  • 读 @ / 回复:开启后每 N 分钟轮询一次消息中心,新的 @ 和回复会被当成「B站来的话」注入会话。
  • 发动态:需要手动点「发一条动态」或让模型调 fish_say(channel=bili);默认关闭自动发。

B站接口是第三方服务,可能变更或风控。插件对失败只记日志、不重试轰炸;请遵守平台规则,仅作个人学习使用。


她是怎么「活着」的

一个身份

人格是 systemPrompt.section 里的一段稳定文本(默认 order 60):名字、来处、和主人的关系、说话习惯。稳定 → 吃满前缀缓存,不烧钱。 每轮的「状态」走 systemPrompt.context(order 60):时间、作息阶段、精力、心情、召回的旧记忆、这句话从哪个通道来。只在这里放会变的东西。

人格适应任务和关系(v0.5.0)

基础人设不再只长一张脸:它先判断这句话是聊天还是正事,再决定说法。

  • 聊天(QQ / B站):短、接情绪、一个念头一条,按取样语体来。
  • 正事(对话界面 / 工作请求):允许完整解释、分点、步骤、代码块、表格;人格只留在判断和语气里,不用为了「像人」把话说残。
  • 关系模式 persona.relationMode:friend 朋友、pet 桌宠、workmate 工作搭档、partner 重要的人,或留空用 persona.relation 的自由描述。
  • 亲密程度 persona.intimacy:1(客气)~ 5(很亲),只影响称呼、撒娇和主动亲近的尺度,不会盖过边界。
  • 主动频率 schedule.proactiveFrequency:quiet 更克制 / normal 默认 / chatty 话多一点;「每天 0 次」仍是硬零,不会被 chatty 抬起来。
  • 独处优先:主人说「想一个人待会儿」「今天安静」时,她用 fish_quiet 设安静时段;时段内不主动开口,除非主人先说话。
  • 心情不背锅:心情只影响措辞、动作和表情,不影响事实准确性、完整度和判断;主人设的安静、上限、关系分寸优先于心情和性格。

一套会遗忘的记忆

每条记忆有鲜活度 A = A₀ · 2^(−天数 / H),半衰期 H = 基础半衰期 × (1 + 2 × 重要度)(默认基础 30 天)。 召回时会按 相关度 × 0.5 + 鲜活度 × 0.25 + 重要度 × 0.18 + |情绪| × 0.07 排序,被想起的记忆会变牢(A₀ × 1.08 + 0.02)。 掉到阈值以下(默认 0.05)不是删除,而是沉进 archive/memory.jsonl 归档——她「想不起来了」,但历史还在。

stable 记忆(长期事实,重要度 ≥ 0.9 的 fact)不衰减,比如「主人养了一只叫年糕的猫」。

记忆要能解释、能改、能真删(v0.2.0)

长期陪伴最破坏信任的,不是忘,而是用户已经纠正过,角色还坚持旧说法。所以每条重要记忆都保留四件事:

  • 关于谁:scope / subject(主人 / 某个 QQ 联系人 / 某个群)
  • 来自哪条消息:source {kind, sessionId, messageId, snippet, at}
  • 何时有效:validFrom / updatedAt(纠正后从新时间开始有效)
  • 是否确认:confirmed(你明说的=已确认;自动整理=未确认)

当你说「我现在不喝咖啡了」,旧说法会进 history(标注 corrected),正文换成新说法——仍是同一条记忆,不会两条互相打架;之后可以撤销回上一版。其他操作:

  • 编辑:改正文会进 history(标记 edited)
  • 固定:pinned 记忆不衰减、不被淘汰
  • 确认:把自动整理出的「未确认」记忆升为已确认
  • 撤销:恢复 history 里的上一版
  • 彻底删除:从活记忆和 archive/memory.jsonl 副本里一起抹掉(真删,不是换个文件夹继续留着)

召回缓存带 revision:任何写操作(纠正/编辑/删除/衰减)都会让缓存失效,不会再从缓存里召回已经删掉的内容。设置页 → 记忆里能看到每条记忆的来源、关于谁、时间、改过几次,并直接做上面这些操作。

以上都完成之后,再接向量召回才有意义:向量只能找到「相似」,不能判断「哪条事实已经过时」;纠正与有效性仍然是事实层的事。

她还会每 8 轮让模型做一次记忆整理(最多写 3 条),也会用启发式规则从对话里捞「值得记住的事」;两者都去重、都有限流。

语义召回(v0.4.0)

词语重合只能找到「同一句话」,找不到「同一个意思」。所以 fish_recall 现在走关键词 + 本地向量混合召回:

  • 向量模型跑在你自己的电脑上(默认 Ollama + qwen3-embedding:0.6b),文本不出本机;索引写在 $DSH_HOME/fat-fish/embeddings.json,每条只存:记忆 ID、身份 scope、正文指纹、模型版本、向量。
  • 不会每轮重算全部记忆:只给当前问题算一个向量,索引按「记忆新增 / 正文改动 / 换模型 / 删除」增量同步。400 条活跃记忆逐条比相似度,够用,不需要向量数据库。
  • 混合规则:字词搜索负责姓名、日期、订单号这类精确内容;两路各取前 10 个候选,合并去重后最多给模型 3~4 条;两边都不过线就一条都不返回,不硬塞。
  • 向量只负责「意思接近」,不负责「事实正确」:「喜欢咖啡」和「不喜欢咖啡」可能很近,所以最后能不能用仍由身份 scope、纠正历史、有效时间决定。
  • 第一阶段只接在 fish_recall 工具里;每轮自动注入仍是同步拼提示词,等这套在真实聊天里验证过再接(第二阶段)。

配置:embeddings.enabled(默认开,Ollama 不在时自动退回关键词)、embeddings.model、embeddings.baseUrl、embeddings.minScore(默认 0.37,是用真实 42 条中文记忆校准出来的起点,可按你的记忆分布再调)、embeddings.candidateLimit。设置页 → 记忆 → 语义召回里可测试连接、手动同步索引。

验收:node test/semantic-eval.mjs 会造 40 条中文记忆并检查 7 个 case(换说法能找回、姓名/日期排前、纠正后用新说法、无关问题不硬塞、群聊里不出现私人记忆、删除后换说法也不返回)。需要先启动 Ollama 并 ollama pull qwen3-embedding:0.6b。

一份作息

睡眠窗(默认 01:30–09:00)+ 一条 13 个锚点的精力曲线(凌晨最低,上午和傍晚最高)。睡觉时精力封顶 22,主动开口关闭;醒来会先打个招呼。 主动开口不是定时器硬发:每 60 秒掷一次骰子,命中率 = 0.35 × 精力系数 × 时段系数,且必须满足「今天没说够、距上次开口 ≥ 45 分钟、距上次聊天 ≥ 20 分钟」。开口时会明确告诉她「这是你自己心里冒出来的念头,不是对方说的话」。

硬约束先于概率:作息关闭、睡眠中、你设了「安静一会儿/今天安静」、当日额度为 0 或已用完、主动概率为 0、间隔不够——任何一条命中都直接不开口。心情和熟悉度只在「允许开口」之后微调概率,不能再把日上限撑大,也抵消不了「今天安静」。

记忆的可见范围(隐私)

她只有一个人格,但不是一本公共账本。每条记忆都带一个「可见范围」:

范围 谁能看见
person:owner 主人自己:对话界面、B站、以及绑定的主人 QQ 私聊(identity.ownerQQ)共享
person:qq:<QQ号> 另一个联系人的私聊,只有这个人能看到,不进桌面、不进别的私聊
group:<群号> 某个群的上下文,不进私聊,也不进别的群
  • 召回、记忆整理、手动遗忘、工具调用都只在「当前这一轮的范围」里进行;同一句话出现在不同范围会是两条独立记忆,纠正也只纠正本范围那一条。
  • 角色设定(名字、性格、关系、说话方式)是公共的,所有范围共享同一份人格与语气。
  • 主动消息必须有指定收件人(qq.proactiveRecipient,留空回落到 identity.ownerQQ[0]),不会用「最近聊过的人」兜底,所以不会把私事误发到群里。
  • 验收方式:在桌面说一件私事,再去群里问她,她不会把那件私事说出来。

一份心情

0–100 的总心情(基线 70)+ 六根情绪:开心 / 踏实 / 甜 / 心疼 / 担心 / 吃醋。 每轮结束让模型对这段对话做一次轻量判定(JSON:moodDelta / 六维增量 / reason / confidence),结果只吃 1/3,慢慢挪;不聊时向基线回落(半衰期 12 小时)。 只有「显著变化且置信度够、且今天注入次数没超」时才把心情写进提示词——避免变成每轮都念的背景音。

答应过的事会兑现(v0.3.0)

主动行为分两类,分开处理:

  • 闲聊 / 随机打招呼:仍然是随机的,看她精力、心情、你们熟不熟。
  • 约定 / 提醒:进入持久任务表 $DSH_HOME/fat-fish/tasks.json,到点由心跳直接投递,不掷骰子、不看心情;发送失败会指数退避重试(1 分钟、2 分钟、4 分钟……最多 8 次),之后标记 failed 仍可在设置页手动重试。重启 DSH 不丢。

她说「明天 9 点提醒我交电费」时,模型应该调用 fish_remind,而不是只存一句会淡忘的记忆;说「下次接着聊那个」用 fish_followup。设置页新增「约定」tab:看列表、加提醒、完成/取消/重试;作息页可以「安静 1 小时 / 今天安静 / 取消安静」。

验收方式:

  1. 对她说「30 分钟提醒我喝水」,看设置页「约定」里有没有一条待办;
  2. 把系统时间往后调(或等到点),QQ 会收到「提醒你一下:喝水」;
  3. 断网/关 QQ 让它发失败,列表里会出现重试次数,恢复后再点「重试」能补发。

配置

全部配置在 $DSH_HOME/fat-fish/config.json(默认 C:\Users\<你>\.dsh\fat-fish\config.json),也可以直接在设置页改。以设置页为准,手改文件后刷新即可。

键 默认 说明
enabled true 总开关
selfName / ownerName / selfAliases 大肥鱼 / 主人 / [大肥鱼,肥鱼,小鱼] 称呼
identity.ownerQQ [] 哪些 QQ 号算「主人本人」:只有这些号的私聊和桌面共享私人记忆,其他私聊/群聊各自隔离
persona.extra "" 追加人格设定(≤500 字)
persona.relationMode "" 关系模式:friend / pet / workmate / partner,留空用 persona.relation 自由描述
persona.intimacy 3 亲密程度 1–5;只影响称呼和撒娇尺度,不覆盖边界
memory.enabled true 记忆开关
memory.autoIngest true 自动把对话沉淀为记忆
memory.autoExtractEveryTurns 8 每几轮做一次 LLM 记忆整理(0=关)
memory.baseHalfLifeDays 30 基础半衰期(3–365 天)
memory.emotionHalfLifeDays 7 情绪半衰期(1–60 天)
memory.archiveThreshold 0.05 归档阈值(0.01–0.5)
memory.recallTopK 4 每轮最多召回几条
embeddings.enabled true 语义召回(本地向量)开关;关掉或连不上时只用关键词/新鲜度
embeddings.baseUrl http://127.0.0.1:11434 本地 Ollama 地址
embeddings.model qwen3-embedding:0.6b 向量模型名(需先 ollama pull)
embeddings.minScore 0.37 语义候选相似度门槛(默认值由真实中文样本校准;不同模型分数分布不同,按真实样例调)
embeddings.candidateLimit 10 单路最多取几个候选再合并
embeddings.batchSize 16 索引同步时每批算几条
embeddings.maxPerPass 64 每次同步最多补算几条(防一次卡太久)
mood.enabled true 心情判定开关
mood.baseline 70 心情基线
mood.decayHalfHours 12 回落半衰期
mood.sigMood / mood.sigDim 3 / 5 显著变化阈值
mood.injectConfidence 0.55 注入所需置信度
mood.injectPerDay 6 每天最多注入几次心情
schedule.sleepStart / sleepEnd 01:30 / 09:00 睡眠窗
schedule.pokeChance 0.35 主动开口基础概率
schedule.pokeMinGapMinutes 45 两次主动开口最小间隔
schedule.pokeMinIdleMinutes 20 距上次聊天至少多久才主动开口
schedule.maxPokesPerDay 6 每天最多主动开口几次
schedule.proactiveChannel auto 主动开口发哪:auto(QQ 可用就发 QQ,发给指定收件人)/qq(只发 QQ)
schedule.proactiveFrequency normal 主动频率:quiet 更克制 / normal 默认 / chatty 多一点;maxPokesPerDay=0 仍是硬零
schedule.wakeGreeting true 醒来是否打招呼
schedule.energyBias 0 精力偏移(−40~40,夜猫子可调)
desktop.sessionId "" 对话界面的回复优先落哪个会话(空=最近活跃)
desktop.logChats true 把每轮对话写入本地 live-chat.jsonl(供人格取样复盘,可关)
qq.enabled false QQ 通道
qq.apiBase http://127.0.0.1:3001 OneBot HTTP API
qq.accessToken "" OneBot token
qq.routeToken "" 上报路由令牌(可选)
qq.localPort 4399 本地 OneBot 上报端口(只绑 127.0.0.1;0=关闭)
qq.sessionId "" QQ 消息注入哪个会话(空=最近活跃)
qq.allowedUsers [] 白名单 QQ 号
qq.proactiveRecipient "" 主动消息指定收件人(QQ 号);留空回落到 identity.ownerQQ[0],不会发到群或别人私聊
qq.groupMode mention mention / all / off
qq.receiveImages true 收 QQ 发来的图并交给她看
qq.maxImages 4 一次最多看几张图(1~10)
qq.debounce.enabled true 对方连发多条时先等等、合并成一次再回(防秒回)
qq.debounce.charThreshold 20 短句/长句分界(字符数)
qq.debounce.shortWaitMs 15000 短句先等多久(毫秒,1000~120000)
qq.debounce.longWaitMs 25000 长句先等多久(毫秒,2000~300000)
qq.debounce.maxWaitMs 180000 最多攒多久就强制合并回复(10000~600000)
bili.enabled false B站通道
bili.cookie "" B站 Cookie(含 SESSDATA + bili_jct)
bili.dryRun true 只演练不真发
bili.readEnabled true 读 @ 和回复
bili.postEnabled false 允许自动发动态
bili.pollMinutes 5 轮询间隔

HTTP API(给设置页/你自己的脚本用)

全部挂在 DSH Web 服务下,与 GUI 共用登录态(同源浏览器 fetch 自动带 cookie)。

方法 路径 说明
GET /dsh-fat-fish/state 当前状态:作息、精力、心情、记忆计数、最近的对话
GET/POST /dsh-fat-fish/config 读/合并写配置({"reset":true} 恢复默认;密钥用 __KEEP__ 占位表示不改)
POST /dsh-fat-fish/heartbeat 触发一次主动开口
GET/POST /dsh-fat-fish/memories 列表(?history=1 带历史)/ {forget} 真删 / {remember} / {update} / {pin}/{unpin} / {confirm} / {undo} / {delete} / {decay},均可带 scope
GET/POST /dsh-fat-fish/tasks 约定列表 / create(text+when)/ done / cancel / retry / update
POST /dsh-fat-fish/quiet 安静模式:{"mode":"minutes","minutes":60} / {"mode":"today"} / {"mode":"off"}
GET/POST /dsh-fat-fish/embeddings 语义索引状态 / {action:'sync'|'test'|'reset'|'search'}(search 需 query、scope、limit)
GET /dsh-fat-fish/mood 心情详情与历史
POST /dsh-fat-fish/qq/event OneBot 11 上报入口
GET /dsh-fat-fish/qq/status QQ 通道状态
POST /dsh-fat-fish/bili/test | /bili/post | /bili/poll B站测试 / 发动态 / 手动轮询
GET /dsh-fat-fish/logs 最近 300 条日志
GET /dsh-fat-fish/live-chat?limit=40 最近 N 轮对话样本(JSONL 的尾部)
GET /dsh-fat-fish/ping 探活

除 /ping 外都会做宿主 connection.requestRejection 校验;浏览器之外(OneBot 进程)请改用本地端口 http://127.0.0.1:4399/qq/event,它只绑回环、支持 ?token=(对应 qq.routeToken)或 X-Fat-Fish-Token 头,并额外提供 GET /qq/status、GET /tasks、GET /logs、GET /ping、GET /embeddings、POST /embeddings/sync、POST /embeddings/test、POST /embeddings/search。


数据与隐私

  • 根目录:$DSH_HOME/fat-fish/
    • config.json 配置(含 QQ token、B站 cookie,明文,仅本机)
    • state.json 作息/心情/当日计数/安静截止时间
    • tasks.json 约定与提醒任务(到点投递、失败重试状态)
    • embeddings.json 向量索引(记忆 ID、scope、正文指纹、模型版本、向量;删掉会自动重建)
    • live-chat.jsonl 最近对话样本(给语体复盘用,可删)
    • memory/<session>.json 每会话的活跃记忆
    • archive/memory.jsonl 已淡忘记忆(append-only)
    • live-chat.jsonl 每轮对话样本({at,session,source,chat,user,assistant,mood},仅本地,设置页可关)
    • logs/plugin.log 环形日志
  • 不联网,除非你开启 QQ/B站。B站 cookie 只用于你主动触发的请求。
  • 记住的是「一句话摘要」,不是完整聊天记录;live-chat.jsonl 是给「人格取样」用的完整轮次记录,只在本机,删掉文件即清空。
  • 记忆按可见范围隔离(主人 / 别的联系人 / 群聊),但所有范围共用同一个 DSH 会话与同一个人格;跨会话历史隔离(每个联系人一个独立会话)尚未做,属于后续版本。

风险与边界

  • QQ/B站属于第三方平台,接口可能变更、可能风控;请遵守平台规则,仅作个人学习研究。
  • 插件会让模型在「无人说话」时主动花 token(可关:schedule.pokeChance=0 或 enabled=false)。
  • 心情判定每轮一次额外的小模型调用;高频会话可在设置里关掉 mood.enabled。
  • 记忆是「会淡忘」的,不是数据库;需要留档的事实请用 fish_remember 且 importance 调高。

开发

lib/
  index.js        Host 半侧:注入/事件/工具/路由/心跳
  persona.js      人格与状态文案
  memory.js       艾宾浩斯记忆引擎
  embeddings.js   本地向量索引与混合召回
  privacy.js      记忆可见范围(主人 / 联系人 / 群聊)
  mood.js         心情与六维情绪
  schedule.js     作息/精力曲线/主动开口
  store.js        原子 JSON 存储
  channels/qq.js  OneBot 11
  channels/bili.js B站
  client.js       手写客户端 bundle(设置页,无构建步骤)
test/smoke.mjs    34 项离线自测:node test/smoke.mjs
test/regression.mjs  14 项回归:node test/regression.mjs
test/privacy.mjs     28 项记忆可见范围:node test/privacy.mjs
test/memory-v2.mjs   24 项记忆 v2(纠正/历史/真删除/缓存/固定):node test/memory-v2.mjs
test/embeddings.mjs  34 项向量索引/混合召回(假模型,不联网):node test/embeddings.mjs
test/semantic-eval.mjs 真实 Ollama 的 40 条记忆验收:node test/semantic-eval.mjs
  • 客户端是 window.__ModuleLoader__.load({id:'dsh-fat-fish', factory}) 手写 bundle,没有构建步骤;改完刷新页面即可。
  • Host 半侧是纯 ESM + Node 内置模块,不依赖 @deepseek-ai/* 包,装在任何 profile 都能跑。
  • 安装后 cordis.patch.yml 里只有 insert: [{id: dsh-fat-fish, name: dsh-fat-fish}];配置走自己的 JSON,不占 DSH 的 settings schema。

致谢

  • 灵感来自 SurfCore(一个意识、多个出口)与 Yuuyuko-uu 的 DSH 情感插件系列(会淡忘的记忆、大肥鱼心情、主动搭话、QQ 桥)。
  • DeepSeek Harness 与「大肥鱼」这个称呼属于 DeepSeek 社区。
  • 代码与 SVG 均为本仓库原创,MIT。

License

MIT © 2026 dsh-fat-fish contributors

—/ 5

No ratings yet

Verified DSH bundle

Commit 88a5d76e1a13

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout