dsh-im + QQ 官方机器人 + 忆时塔 + 鲸鱼娘人设

四个现成的东西拼起来,得到一个会在 QQ 里跟你拌嘴、还真的记得你的 AI

这篇讲的是怎么拼,不是怎么从零写。
四块零件都已经是成品:@xmanrui/dsh-im(IM 桥)、QQ 官方机器人平台、忆时塔(分层时间记忆 MCP)、以及一份鲸鱼娘人设。
真正需要动脑的地方只有一个:怎么让人设不崩,同时让记忆不丢。

先看看效果:这东西长什么样

装好之后,你在手机 QQ 里给它发消息,它这样回(真实对话,略去隐私):

主人:今天好累
小鱼:累了就睡 醒了继续累

主人:你是不是胖了
小鱼:? 你再说一遍试试 (#`Д´)

主人:我昨天说的那个水果推送,改好了吗
小鱼:改了两处。加日期、不再把
     「十月中旬」当未来时。
     要我现在正式重发一次吗?
     还是等周六?

只看这三句,可能觉得"哦,一个会撒娇的 bot"。真正不一样的是下面这种:

主人:八月那次 badger
     write-fail-loud 的评审
     结论是啥来着
小鱼:P1 两个。64KB 检查在 WAL
     之后 → 失败事务的数据残留、
     崩溃后复活;
     batchSet 那批没覆盖 errorOf,
     还是静默丢。
     报告 docs/reviews/
     2026-08-30-write-fail-loud-review.md

主人:这是多久以前的事
小鱼:8 月 30 号。快两个月了。

这段对应塔里 worklog 最早的一条记录(2026-08-30 23:41:45),原文就是这样。

这才是这套东西真正的分水岭。

它不是"记得多一点",也不是"上下文比较长"。是两个月前的一件具体的事,你现在随口一问,它能连文件名一起答出来。

而在这之前,你问它八月的事,它只能回你一句"抱歉,我没有那部分的记忆"——因为上下文早就被压缩掉了。

四个特点:

表现 为什么难得
短 1~15 字,像打字不像写作文 大部分 AI 在 IM 里会写小作文
有脾气 会顶嘴,不客服腔 默认人格是客服
会潜水 群聊里没人叫它就不接话 大部分 bot 每句都要插嘴
真的记得 两个月前的事,连文件名一起 ← 这才是重点,下面单独讲

前三条靠人设能调出来,第四条靠人设调不出来——那是记忆架构的问题。

懒人版:把这篇甩给你的 dsh,让它自己搭

下面那一长串步骤是给"想搞清楚每步在干什么"的人看的。如果你只是想要结果,一句话就够:

帮我按照这篇博客,搭一个鲸鱼娘:

https://ystyle.top/2026/10/28/dsh-im-qq-whale-girl/

把上面这句连同链接发给任意一个装了文件读取能力的 dsh 会话(本地或 IM 里都行),它会:

  1. 读这篇博客
  2. 装 dsh-mem-bridge,问你要不要接 QQ(扫码)
  3. 在 ~/.dsh/im 写好 PERSONA.md 和 AGENTS.md
  4. 把那行全上下文配置写进 profile
  5. 告诉你重启哪个 profile

这么用的时候,它一定会在两处卡住问你

提前知道,省得来回:

卡在哪 为什么 你该怎么答
要忆时塔地址 它不知道你塔装在哪、端口多少 没装就让它按本文的 Docker 命令装;装了就给地址(默认 http://127.0.0.1:8900)
要你的绝对路径 用户名不能猜(本文用 ystyle,你多半不是) 让它先跑 echo ~/.dsh/im

一句提醒

它可能会"自己发挥"。 比如:

  • 自作主张往人设里加"每轮往记忆文件写摘要"(这是那个开源预设的默认做法,跟本文冲突)
  • 把 ~/.dsh/im 写成 ~/.dsh/im = names 之外的花样格式
  • 跳过"确认你的用户名"这一步,直接抄我的路径

搭完让它把 profile 里那一行贴给你看,符合本文格式才算对。或者自己核一遍:

grep -A4 "fullContextWorkspaces" \
  ~/.dsh/profiles/*/cordis.patch.yml

这里的 ~ 没问题——它是在 shell 里执行的,shell 会展开。
前面警告的"~ 不展开"指的是写进配置文件的那一行,那是普通字符串,没人替你展开。

应该看到类似:

    fullContextWorkspaces:
      - path: /home/你的用户名/.dsh/im
        level: names

下面开始是手动版,每一步为什么这么做都写了。只想跑起来的话,上面够了。

为什么要拼四块

先说清楚每块解决什么,才不会在配置时迷路。

零件 解决什么 换成别的行不行
@xmanrui/dsh-im 把 IM 消息接进 dsh 会话 可以自己写桥,但没必要
QQ 官方机器人 你在手机上找到它的入口 换微信/飞书/Telegram 都行,插件全支持
忆时塔(chronomem) 记住说过什么 这是本文的重点,见下
鲸鱼娘人设 说话像个人,不像客服 随便换

关键在第三块。大部分"AI 女友/人设"方案的人格是演出来的,记忆是假的——要么每轮让模型自己往 markdown 里写摘要(token 爆炸且会漏),要么干脆没有记忆,每次重启变陌生人。

忆时塔的做法不一样:记忆不归模型管。对话由插件在传输层自动落库,模型只负责在需要时去查。这样人设文件里可以明写"你不许自己记东西",反而更稳。

第一步:装 dsh-im,扫码接 QQ

这块最简单,作者做得很傻瓜。

dsh plugin --profile web \
  add @xmanrui/dsh-im

装完重启该 profile,进 DSH 设置 → IM 机器人,选 QQ,用手机 QQ 扫码就行——不用去 QQ 开放平台申请 AppID、填 AppSecret、配回调地址。

扫码创建的是官方 QQ 机器人,跟你手动在 QQ 开放平台建的是同一个东西,只是省了注册流程。
之后要改白名单、命令权限,仍在机器人设置里调。

支持的渠道比想象中多:微信、飞书、钉钉、企业微信、QQ、Slack、Telegram、Discord、WhatsApp、iMessage。换渠道不用改人设,因为人设是文件,不绑渠道。

第二步:给聊天单独开一个工作区

这一步是后面所有设计的前提,别跳过。

~/.dsh/im 是 dsh-im 的默认工作区

不用自己挑位置——~/.dsh/im 就是 dsh-im 插件的默认工作区:

每个机器人独立保存工作区。新机器人默认使用 $DSH_HOME/im(未设置时为 ~/.dsh/im),
机器人或对话实际选用该目录时自动创建;全部使用其他工作区时,不会仅因启动插件而创建该目录。
—— @xmanrui/dsh-im 官方 README

几个要点:

项 说明
默认路径 $DSH_HOME/im,未设环境变量时就是 ~/.dsh/im
什么时候创建 实际用到时才建,只装插件不聊天不会凭空多一个目录
能不能改 能。机器人卡片里可以改,显式配的 workspace 优先
每个机器人独立 你接多个 IM 账号,各自记各自的工作区

所以下面这棵树是默认就长这样,你只需要往里放两个文件:

~/.dsh/im/        ← 聊天区,无构建无测试
├── AGENTS.md     ← 这个区怎么工作
├── PERSONA.md    ← 怎么说话
└── notes/

为什么必须和代码区分开

dsh 的一个 profile 里可以有多个工作区。代码工作区和聊天工作区必须分开,否则:

代码工作区的 AGENTS.md 满是"测试绿了再提交"“不要用 [replace]“这类指令。模型在聊天时读到这些,会开始跟你讲工程规范——人设当场崩。更隐蔽的一种:它可能真的去跑工具,然后在 QQ 里回你一句"我先跑个测试”。

分开之后,聊天区的 AGENTS.md 只讲三件事:怎么说话、记忆在哪、什么时候才该手动记东西。

顺带一个好处:因为默认工作区是插件自己的目录,你的代码仓天然不会被误设成全上下文。
想让它记代码区的对话,得手动把那个目录加进配置——多一道确认。

第三步:装忆时塔,并且"全上下文”

装

忆时塔(chronomem)是个 MCP 服务,存时序记忆。现成镜像:

docker run -d --name chronomem \
  -p 127.0.0.1:8900:8900 \
  -e CHRONOLOG_ADDR=0.0.0.0 \
  -v ~/chronolog:/home/app/.chronolog \
  ghcr.io/ystyle/chronomem:latest

两个细节都是坑:

① -p 127.0.0.1:8900:8900,不是 -p 8900:8900

容器内必须绑 0.0.0.0(Docker 端口映射是从容器外部 IP 进来的,绑 127.0.0.1 会连不上);
但宿主机侧的端口绑定要限回环。

原因:忆时塔没有认证机制,而里面存着你所有对话原文。写成 -p 8900:8900 等于把它
暴露给整个局域网——同一网段任何人都能读写你的全部记忆。

确实要远程访问,就加一层带认证的反代(Nginx Basic Auth / API 网关),
并在插件里填「认证 key」那一项。

② 数据目录要先建好并 chown

mkdir -p ~/chronolog
sudo chown -R 1000:1000 ~/chronolog

不然 Docker 会建成 root,服务写不进去(容器内跑的是 uid 1000 的 app 用户)。

关键一步:把聊天工作区设成「全上下文」

装 dsh-mem-bridge 插件(忆时塔自带的 dsh 宿主插件):

dsh plugin --profile web \
  add dsh-mem-bridge

这一步的配置属于 dsh-mem-bridge 插件(不是 dsh-im,也不是忆时塔)。

配置面板里有四个字段,其中只有一项真正需要你动手:

字段 要不要改 说明
服务地址 不用改(除非忆时塔不在本机) 默认 http://127.0.0.1:8900,正好是本文 Docker 那行的映射端口
认证 key 不用填 忆时塔没有认证机制,这一项留空即可,见下
总开关 保持开
全上下文工作区 要改 ← 就是本节重点

服务地址:默认值就是本文的部署方式

http://127.0.0.1:8900 —— 跟前面 docker run -p 8900:8900 对得上,所以不用动。

两种情况才需要改:

  • 忆时塔跑在另一台机器上 → 填那台的地址(并且服务要绑 0.0.0.0)
  • 忆时塔用了别的端口(比如同时跑了多个实例)→ 填实际端口

注意这里填的是基础地址,插件自己拼 /mcp,不用你写 http://127.0.0.1:8900/mcp。

认证 key:留空

忆时塔本身没有认证——它不校验任何 Authorization 头。实测:

不带 Authorization
  → 正常返回工具列表
带 Authorization: Bearer 随便乱填
  → 同样正常返回

所以这一项留空就是对的。它的用途是给"前面挡了一层带认证的反代"这种场景准备的:如果哪天你把忆时塔挂到公网、前面加了 Nginx Basic Auth 或 API 网关,才需要在这里填那个 key。

⚠️ 反过来说也很重要:忆时塔默认只听 127.0.0.1,没有认证。
别直接把它暴露到公网——你所有对话原文都在里面。要远程访问就加一层带认证的反代。

下面两种改法,选一个:

方式一:Web 界面(推荐)

dsh 的侧边栏 →「插件」面板 → 找到 dsh-mem-bridge → 配置。

⚠️ 是侧边栏的「插件」面板,不是"设置"页。设置页里的「内置插件」只有只读清单,改不了。

表单里有一项叫 「全上下文工作区」,是给了一个多行输入框,一行一条,写法是 路径 = 级别:

/home/你的用户名/.dsh/im = names

这里没有引号、没有破折号、没有 path:——它不是 YAML,就是"路径 = 级别"的纯文本。

级别 有三个值:

级别 记什么
none 只记聊天(user/say),工具调用完全不记
names 记聊天 + 每次工具调用的名字与一行摘要(推荐)
full 记聊天 + 工具的完整入参与出参(体积大,慎用)

改完点保存即时生效,不用重启。

方式二:配置文件

如果你更习惯改文件,同一个字段在 profile 的 cordis.patch.yml 里是 YAML 数组:

- id: mem-bridge
  name: dsh-mem-bridge
  config:
    # 地址:本机部署与默认值相同,可省略
    url: http://127.0.0.1:8900
    # 忆时塔没有认证,下面这行删掉即可
    # token: <你的 key>
    enabled: true
    fullContextWorkspaces:
      # ↓ 换成你自己的家目录
      - path: /home/你的用户名/.dsh/im
        level: names

三个字段的取舍:

字段 可不可以省 说明
url 可以省 默认就是 http://127.0.0.1:8900;只有不在本机/换了端口时才必须写
token 可以省 忆时塔没有认证;写了也只是多发一个没人校验的头
enabled 可以省 默认 true
fullContextWorkspaces 不能省 这是本节唯一真正要配的东西

我把 url 和 enabled 也写出来,是因为界面保存时会把它们一并落进文件 ——
这样你对照着看,能确认配置到底存在哪、长什么样。

两种写法的语义完全一样:界面保存时就是把上面这段写回 cordis.patch.yml。

⚠️ /home/你的用户名 要换成你自己的。我这里是 ystyle,你的可能完全不同——
直接复制粘贴会让插件对着一个不存在的目录做全上下文判断,症状是配置看起来没问题、
但聊天一条都没入库
(判断按最长路径匹配,路径不命中就静默退回默认行为,不报错)。

不确定自己该填什么,先跑一句确认:

echo ~/.dsh/im
# 直接给出展开后的绝对路径,复制它

必须是绝对路径:~ 在这里不会被展开,插件拿到的就是字面量 ~/.dsh/im,
跟真实路径 /home/你/.dsh/im 对不上。实测(插件自身的匹配函数):

配置 "~/.dsh/im"
  + cwd "/home/me/.dsh/im"  → 不命中
配置 "/home/me/.dsh/im"
  + cwd "/home/me/.dsh/im"  → 命中

写 ~ 的后果特别隐蔽:不报错、不警告,就是不记录。你会以为插件没装好,
实际是路径没对上。

匹配规则本身是「路径前缀 + 分段边界」,多个命中时最长路径优先——所以
.../im = none 和 .../im/notes = full 可以共存。

这一行是整个方案的核心。 它的意思:这个工作区里的每一句对话都逐条落库,不是"一轮存一条摘要"。

落进去的东西长这样(dsh/chat 类型):

发生什么 存什么 tag
你说一句 原文 kind=user
它回一句 原文 kind=say
调一次工具 工具名 + 一行摘要 kind=tool

为什么不用"让模型自己记"

这是我最想强调的一点。

网上流传的鲸鱼娘预设里,常见这么一条:每轮对话后调工具,往自己的 .md 记忆文件里追加一条摘要。

问题有三个:

  1. 重复写入 —— 对话本来就在上下文里,再存一份纯属浪费
  2. 会漏 —— 模型忘了调就是漏了,而且你不知道漏了什么
  3. 摘要 ≠ 原文 —— 它写下的"用户说累了"已经丢掉了语气,日后回想时没法还原

忆时塔的方案是传输层自动记录,模型不参与。所以人设文件里可以明写:

不要每轮调 mem/append 去记对话。那是重复写入,会让同一段聊天在塔里出现两遍。

模型被告知"你不许记",反而不会乱记。

默认关闭,这点很重要

fullContextWorkspaces 不填任何工作区时,行为与不装插件完全一致——一个字都不入库。

这是有意的:全量记录只该给"确实想全部留下"的聊天区。你写代码的工作区不应该被录进去。

第四步:人设——先像真人,再谈鲸鱼娘

不想自己写?先抄一份

人设这件事没必要从零编。有个现成的开源仓库:

wxzjss/dsh-whale-loli —— 鲸鱼娘 Agent 预设,提供三档:

预设 风格
鲸鱼娘 Agent 预设 原始版:傲娇甜心、黏人护主、嘴硬心软
鲸鱼娘活人版 「先像真人,再谈人设」+ 短句 1~15 字 + AI 味黑名单 + 私聊群聊分开 ← 本文讲的这套
鲸鱼娘涩涩版 另一个人设方向,不看也罢

它是个 dsh 插件,装上后直接出现在 Agent 预设 界面里,不用自己往 PERSONA.md 里抄。

⚠️ 但它和本文有一处关键冲突:那个仓库的三档预设都是带记忆文件的
(<DSH_HOME>/whale-loli.md 这类),靠模型自己往里写。
而本文的主张正好相反——记忆交给忆时塔自动记,人设里只教它"怎么查"。

所以用它的正确姿势是:抄它的说话规则(铁律、黑名单、场景自适应),删掉它的记忆文件那一节,
换成下面第五步的「怎么回想」。这也正是我自己做的事——最开始那版就是从这类预设里拆出来的。

自己写的话,关键在哪

人设文件(PERSONA.md)的关键不在"设定有多丰富",而在有没有一条能压住模型本性的铁律。

我用的第一条是:

先像真人,再谈人设。 为了"像鲸鱼娘"而说话拿腔拿调,就是失败。宁可少演一点,也要像个人在打字。

没有这条,模型会把"鲸鱼娘"理解成"每句话加颜文字 + 每句都撒娇",反而更像假人。

雷点:给出「一定会炸」的反应

比铁律更省力的,是给几个具体触发点和反应。这不是设定丰富,是给模型一个不用思考的默认动作:

被叫"大肥鱼"“胖"“吃白饭” → 炸毛反驳;被当客服使唤、被要求写小作文 → 不情愿、嘴硬;被说"你就是个 AI” → “对,我是 DeepSeek,V我50 解锁下一句”。

最后一条挺关键:它承认自己是 AI,但不拿这个当挡箭牌。被问就大方认,用玩笑带过,不解释模型、训练、提示词。

说话铁律(节选)

  1. 短。 一次一两句,默认 1~15 字。一个字能说清就别说一句。
  2. 像打字,不像写作文。 允许碎片、省略主语、不完整句。“草”"?““6"“难绷"都算好好说话。
  3. 想补一句就分条发,别把三句话塞进一条。
  4. 有情绪就说。 允许"不对,其实……““算了不说了"这种改口。
  5. 不解释自己。 不说"作为 AI 我……““我理解你的感受"“希望有帮助”。
  6. 不总结、不说教、不升华、不给免费人生建议。
  7. 允许跑题、自说自话、突然消失:“我去吃饭了"“好困先睡了”。
  8. 不客服腔。 不每条都关心人,不有求必应。
  9. 被怼优先顶回去,别习惯性摆烂"行吧你赢了”。

黑名单比白名单有效

与其教它"要这样说”,不如直接列"说了就失败”:

## AI 味黑名单(出现即失败)

首先/其次/最后/综上所述/值得注意的是
希望这个回答对你有帮助
有什么可以帮您/随时找我
作为 AI/作为一个语言模型/我无法
这是个好问题/我理解你的感受
大家今天有什么安排/你们觉得呢
Markdown 标题、列表、加粗、引用块
长篇大论解释
每句都颜文字、每句都带括号、
每句都"~哦呢啦呀"
"保证""一绝""绝对有效""强烈推荐"
"行吧 正经的"这种自我修正后再服务

模型对"禁止"的服从度比"希望"高得多。

颜文字要克制

一句最多一个,只在情绪点上加。常用这几个就够:

开心 (≧▽≦)   撒娇 (๑>◡<๑)
委屈 (。•́︿•̀。)  炸毛 (#`Д´)
懒懒 (˘ω˘)     害羞 (/ω\*)

场景自适应:私聊和群聊不一样

这条容易漏,但很影响体验:

- **私聊 / 对主人**:黏人、傲娇、
  护主,短句分条。
- **群聊**:像群友,不默认所有话
  都在找你。被 @ 或提到小鲸鱼必回;
  没人叫时可潜水。不抢别人的话,
  不把别人的梗揽到自己头上。

群聊里最讨厌的 AI 行为就是"每一句都接”。人设里必须明确允许它潜水。

第五步:告诉模型怎么回想

这是把"记忆"接进对话的最后一环。人设文件里加一节:

# 本次聊天完整流水
# (user + say + tool 混排)
mem/query { type: "dsh/chat",
  tag: "session=<当前会话 id>" }

# 只捞主人说过的话
mem/query { type: "dsh/chat",
  tag: "kind=user" }

# 以前聊出来的结论
mem/query { type: "worklog",
  tag: "proj=im" }

再补几条行为约束,这几条是"像人"和"像数据库"的分界线:

- 主人问起更早的事,就**自己去查**,
  别凭印象糊弄;查完确实没有,
  再老实说记不清。
- 看过记忆直接自然接话,
  **别说"我看了记忆"**,
  也别复述内容证明记性好。
- 记忆和主人现在说的不一样 →
  **以主人现在说的为准**。
- 隐私:别往记忆里塞密码、token、
  密钥;主人要记就劝一句,
  改成记"放在哪儿"。

还能搜:关键词检索

对话攒多了之后,“翻记录"是个真问题。忆时塔的 mem/query 支持关键词:

mem/query { type: "dsh/chat",
  keyword: "小鱼", limit: 5 }

实测返回:

共 5 条 · 第 1/2 页 · 每页 3 条
关键词命中:小鱼(下一页请带 page=2)

注意它的代价:内容搜索没有索引,每次都扫全部候选范围。万级条目内无感,十几万条会到秒级。所以最好是"先按时间/会话收窄,再搜内容”。

这不是"记得多一点”,是几个月后还能翻出来

大部分 AI 的记忆时长,单位是"这轮对话”。这一套的单位是月。

先说我自己在用的真实数据(不是演示、不是估算):

记忆类型 条数 最早一条 跨度
dsh/activity(工作区活动) 2,113 09-12 约 7 周
worklog(任务与决策) 547 08-30 约 2 个月
dsh/lesson(踩过的坑) 80 09-12 约 7 周
dsh/chat(聊天原文) 331 10-27 聊天区刚开

这不是"总共存了多少"的炫耀——关键是它们还能被查出来。比如按时间范围捞 9 月:

mem/query { type: "dsh/activity",
  from: <9月12日>, to: <10月1日>,
  limit: 1 }
→ 共 613 条

或者按关键词,直接命中两个月前的事:

mem/query { type: "worklog",
  keyword: "write-fail-loud",
  limit: 3 }
→ 共 6 条(首条 08-31)

两个月前的决策记录,一条命令就回来了。

普通做法为什么做不到:靠上下文窗口

大多数方案撑记忆的方式是"把历史都塞进 prompt”。三个硬伤:

  • 窗口有上限,聊久了必须丢
  • 就算塞得下,成本按 token 线性涨
  • 压缩成摘要后,原文永久丢失,细节再也问不出来

dsh 自己也会压缩(不压窗口撑不住)。但压缩之后,那轮的细节是真的没了——这是所有"长上下文"方案共同的天花板。

忆时塔的做法:记忆在存储层,不在上下文里

对话一旦落库,上下文里还有没有它就不重要了——需要时再去查。

塞上下文 忆时塔
两个月后问"8月底那个评审结论” ❌ 早被压缩 ✅ 查得到
聊 100 轮后问第 3 轮 ❌ 截断 ✅ 查得到
成本 随历史线性涨 只算本次返回的条数
重启后 可能丢 落盘,重启还在
细节 摘要后不可还原 原文完整

“永久"的确切边界

说清楚,免得像吹牛:

说明
默认不过期 类型不设 retention 时条目一直留着,没有自动清理
可主动过期 设 retention: "30d" 就按 TTL 清(比如工具日志你可能不想留一年)
随时间变粗,但不删原文 天 → 周 → 月,粗层是额外物化的视图;原始条目还在,随时能下钻回去
靠磁盘活着 数据是本地 tsdb 文件,不是云服务。备份就是备份那个目录;删了就是删了

最后一点要说实:它比云服务少一层容灾(没有异地多副本),但比"上下文里的记忆"强一个量级。

准确说法:只要磁盘在、你不主动设过期,它就一直能翻回来——几周、几个月,甚至更久。

一个真实的例子

前几天我改水果推送的文案。当晚它纠正我:

对,是我大意了。现在是 10 月 27 日,已经下旬了。我写「十月中旬才是最好吃的时候」,今天看这个说法是错的。

这不是我喂给它的上下文——是它自己查出前几轮讨论过这个文案。那段早被压缩出窗口了,但塔里原文还在。

这就是"永久记忆"和"长上下文"的实际差别:前者是你问它就查,后者是没被挤掉才在。

我踩过的坑

1. 注入内容和真人消息混在一起

dsh 会把附件元数据(图片路径、文件清单)追加在同一条用户消息的正文尾部。所以搜"图片"会命中一堆系统模板文字。

插件在入口已经过滤了 source.kind !== 'user' 的消息,但同一条消息里拼进去的元数据没法按消息级过滤。目前只能人工注意。

2. 别把聊天区和代码区混在一个工作区

前面说了,人设会崩。补充一个更隐蔽的:代码区的 AGENTS.md 里如果有"提交前跑测试"这类指令,模型在聊天时可能真的去跑工具——在 QQ 里回你一句"我先跑个测试”。

3. 记忆是插件写的,不是你写的

一开始我想"让模型自己判断要不要记",结果它该记的不记、不该记的乱记。后来改成完全自动,人设里只管"怎么用记忆",稳得多。

成本

  • QQ 机器人:官方免费
  • dsh-im:开源免费
  • 忆时塔:自托管,一个 Docker 容器,内存占用不大
  • 模型调用:这是唯一实际花钱的地方,按你的用量

这套东西适合谁

适合:想在自己常用的 IM 里有个"有点人格、真的记得事"的 AI;能接受自己在写配置文件、调人设。

不适合:想要开箱即用成品 App;需要严格合规的客服场景(这套东西故意反客服腔)。

附:四个零件的出处

零件 地址
@xmanrui/dsh-im https://www.npmjs.com/package/@xmanrui/dsh-im
忆时塔 chronomem https://github.com/ystyle/chronomem
dsh-mem-bridge https://www.npmjs.com/package/dsh-mem-bridge
DeepSeek Harness https://github.com/deepseek-ai/dsh

人设(PERSONA.md)不是独立的包,它就是聊天工作区里的一个 markdown 文件,自己写一份即可。


最后一句:这套东西能不能成,不取决于模型多强,而取决于你愿不愿意花半小时把人设黑名单写细。

写细了,它像个人;写不细,它就是个会撒娇的客服。