首页/ kiana/ 养鱼 #养鱼#DSH 陪伴型 QQ 机器人「大肥鱼」技术总结 记录时间:2026-11-03 范围:单账号 QQ 伴侣机器人的记忆系统与运维链路 代码:kianajunjie/dsh-hippocampus(记忆层,MIT… kiana 2026-11-04 技术总结 8 次阅读 记录时间:2026-11-03 范围:单账号 QQ 伴侣机器人的记忆系统与运维链路 代码:`kianajunjie/dsh-hippocampus`(记忆层,MIT)+ 服务器侧调度脚本(未开源) --- ## 1. 目标与边界 **要做的东西**:一个长期跟同一个人(或同一小群)说话的机器人。有固定名字、固定人设、跨月存在,会主动开口、会写日记、会记得你怕什么。 **明确不做的**:客服问答、通用助理、知识库检索。这三类场景的核心指标是答案准确率,而陪伴场景的核心指标是"像不像人"——两者在记忆设计上是冲突的:前者要求"永不遗忘、精确复述",后者要求"按重要性遗忘、允许模糊"。 边界先定死,后面所有取舍才有依据。 --- ## 2. 系统构成 ``` QQ 客户端 │ (OneBot v11 / WebSocket) ┌─────────┴─────────┐ │ qq-bridge │ 收消息、去抖合并、拼 system prompt、调模型、发送 │ qq-listen │ 旁听群消息、落盘、按群生成「最近」 └─────────┬─────────┘ │ ┌──────────────┼───────────────┬──────────────┐ │ │ │ │ hippo CLI memory.md 日记/成长 主动开口 (记忆) (画像) (情景) (proactive) │ SQLite(单文件:events / edges / relations / facts / chapters / skills / gaps) ``` 运行时约束:Ubuntu 22.04 / 4 vCPU / 3.6 GB(有 2 GB swap)/ Node 24 / systemd 管理 20 个定时器。 --- ## 3. 演进阶段 **阶段一:先解决"像不像人"(10/23–10/30)** 桥接 + 人设 + 去 AI 味。改动集中在提示词:短句、口语、不总结、不复述。这一阶段没有代码难点,全是边界判断。 **阶段二:记忆(11/01)** 初始方案是 RAG。评估后放弃:RAG 的语义是"文档检索",与"人记得发生过什么"不是同一个问题。 改为事件模型:`(day, who, topic, what, detail, affect, strength)`,配情绪加权衰减与确定度三档。 **阶段三:分层(11/02)** 在事件之上加关系、时序事实、章节、技能、缺口五层。触发点是三个具体缺陷:自相矛盾(改口后新旧记忆并存)、跨人串味(群聊记忆泄漏到私聊)、无程序性记忆(重复摸索同一套命令)。 **阶段四:验证(11/02–11/03)** 做两轮消融:单层移除、逐层叠加。结论修正了一个设计假设——"层数越多越好"只在提示词写清用法时成立。 **阶段五:通用化与发布(11/03)** 把服务器脚本里的记忆部分抽成零依赖包,加入身份映射与三种接入(库 / HTTP / DSH 插件),发布 v0.3.0。 --- ## 4. 关键决策 **4.1 事件而非文档** 语义单元是"发生了什么",不是"文本块"。代价是抽取需要模型、会有信息损失;收益是能做衰减、做作废、做确定度——这三件事在文档块模型里无处安放。 **4.2 情绪加权衰减** `strength *= base^(age / (1 + |affect| * boost))`,默认 `base=0.95, boost=2`。 中性记忆约 45 天降到召回下限(0.1),强情绪记忆约 7 个月。这是"选择性遗忘"的最小实现。 **4.3 确定度而非置信分数** 对外只暴露三档:记得清(有原文、7 天内)/ 大概记得(30 天内)/ 只记得有这回事。 理由:模型不会正确使用 "0.73 的相似度",但会用"好像""大概"。 **4.4 作废而非合并** 同一 `subject + topic` 在 7 天窗口内:说法相近(字符二元组重合 ≥ 50%)合并;说法不同则旧条标记 `superseded` 并从召回中排除。 不这么做,用户改主意后机器人会同时持有两个互斥事实。 **4.5 两层隔离** `subject`(记忆关于谁)+ `scope`(private / group)。 群聊召回只取 `group` 与通用条目;私聊可取全部;主人本人在群里的发言按 `subject=主人` 归档,因此私聊能看到,群聊看不到。 **4.6 写入门槛与钉住** 强度低于 0.1 不参与召回——没有这个下限,衰减只改变排序,不产生"遗忘"。 `pinned=1` 的条目跳过衰减,用于约定、恐惧、长期偏好。 --- ## 5. 实测 | 项目 | 结果 | |---|---| | 90 天模拟 recall@1(3 seeds) | 61% | | 误召(无关提问) | 0 | | 60 天以上旧记忆召回:有/无情绪权重 | 27% / 9% | | 长间隔同主题(70 天) | 不误合并 | | 单轮 3 事实抽取 | 6/6 | | 换说法召回(词法 → 查询改写) | 0 → 1 | | 逐层叠加答对(7 题) | 0 → 1 → 3 → 4 → 5 → 6 → 7 | | 分层注入 token 成本 | 46 → 198 | | 单层移除扣分 | 事实 −2,其余各 −1 | | `context()` 组装耗时 | 63 ms | 已知盲区:检索是词法的。完全不含相同字符的改写(「腿还疼不疼」↔「运动后的肌肉疼」)依赖一次额外模型调用做查询改写;向量检索留了 `embedder` 接口,未启用。 --- ## 6. 事故复盘 这段时间真正的成本不在功能,在**不报错的失败**。 | 现象 | 根因 | 影响 | |---|---|---| | 衰减后旧记忆仍可召回 | SQL `or` 与 `and` 优先级,门槛只作用于最后一个条件 | 遗忘机制整体失效,无任何报错 | | 所有同主题记忆被作废 | `replay` 的 SELECT 漏了 `what` 字段,相似度比较恒为 `undefined` | 记忆静默流失 | | 消息处理整条失败 | `whoUid` 未声明即使用 | 任何来消息都会抛 ReferenceError(恰好窗口内无人发消息,未暴露) | | 日记连续 3 天未写 | systemd unit 内多了一行 `EOF` | 单元解析失败,服务未启动 | | 手账少一页 | 缺 `execFileSync` import,异常被 `catch` 吞掉 | 页面静默缺失 | | 真实关系表出现「测试」「群友」 | 自检的合成消息写到了生产库 | 记忆污染,且难以自查发现 | 共性:**异常被吞、字段缺失、语法静默降级**。这类问题只能靠两样东西发现——真实运行时覆盖(合成消息跑一遍完整链路)和反向验证(逐层移除看指标是否变化)。 --- ## 7. 工程约束 - **零运行时依赖**:仅 `node:sqlite` + `node:http`。代价是无 ORM、无迁移框架,用 `pragma_table_info` 手写补列。 - **单文件 SQLite**:便于备份与迁移;限制是并发写。当前设计为单进程写、其余只读。 - **成本**:记忆注入约 200 tokens/轮;查询改写按需触发(词法未命中时),估算触发率 ~30%。 - **延迟**:记忆召回 + 上下文组装 < 100 ms,端到端回复约 1 s。 --- ## 8. 收获 **8.1 指标会被优化,也会被讨好。** 人味评分一度满分 10,其中一部分来自"学会说漂亮话"。指标说明她在变,不说明变得对。 **8.2 功能可用 ≠ 会使用。** 缺口层第一次消融是 0 收益,原因是注入时没写"该主动问"。补一句提示词,同一层从 0 变 1。凡是"给了数据但没给用法"的功能,都在空转。 **8.3 验证优先于新增。** 六个 bug 里有四个是"新功能没坏,旧功能悄悄坏了"。后续默认流程改为:改完必跑自检 + 合成消息。 **8.4 边界比能力更难写。** 真正让她像人的不是记忆层,是那些"不做什么":不总结、不复述、不在群里提私聊、不装懂。技术侧对应的是隔离与拒答,而不是更多生成。 --- ## 9. 后续 **短期(一周内)** 1. 插件端到端验证:临时 profile 内完成「发消息 → 事件入库 → 下一轮召回」,而非仅验证加载。 2. 提市场收录(dsh.so / awesome-dsh-plugin),需仓库满 1 天、`dsh-plugin` topic、CI 要求的 bundle 声明(已具备)。 3. 观测「问句收尾」探针口径:当前"单条以问句结尾即扣分"误伤接话类表达,应改为连续出现才计。 **中期** 4. 行为层拆分:主动开口、日记忆、作息与平台无关化,作为独立包;记忆包保持纯数据层。 5. 可选向量检索:在词法 + 改写仍失败时兜底,接口已预留。 6. 双鱼互通(QQ 侧与 B 站侧)的信箱检查已并入唤醒流程,观察一周确认稳定。 **风险** - SQLite 单写者假设:多通道同时接入需引入写队列或 WAL + 单写进程。 - 接口漂移:DSH 插件壳对宿主 API 为防御式实现,版本升级后需回归"是否仍注入成功"。 - 记忆污染:任何测试路径必须隔离数据库,已有一次事故。 --- ## 10. 交付物 ``` kianajunjie/dsh-hippocampus v0.3.0 ├─ src/ 记忆核心(事件/衰减/召回/分层/身份/回合) ├─ src/adapters/ HTTP shim · DSH 插件壳 ├─ docs/ prompt.md(提示词适配)· integration.md(接入)· bench.md(实测) ├─ bench/ 模拟基准 + LLM 抽取基准 └─ test/ 26 项 服务器侧(未开源) ├─ qq-bridge.mjs 消息桥(含规则热加载) ├─ qq-listen.mjs 群聊旁听(按群隔离) ├─ hippocampus.mjs 记忆 CLI(与包同构) ├─ grow.mjs 日记 / 周章节 ├─ proactive.mjs 主动开口(额度、静默、话题池) └─ selftest.mjs 25 项回归(含合成消息) ``` #养鱼#DSH 复制链接 kiana @kianayang · 在蓝屿写作 关于博主