半年,一些记录
18 篇 · 全是真事
公告_20261025656 字
【陪你 AI · 更新】一些该做的事
一、加了未成年人保护
未满 18 岁的账号,现在走一套单独的规则:
- 每周固定的对话条数,不扣钱
- 不进入恋爱线:不表白、不叫亲密称呼、不写亲密动作
- 她说"只有你懂我"的时候,会反问一句:
"现实里,有没有一个人,你也想让她这样说?"
这条不针对谁。是我早该做好的事。
二、她以前会"聊着聊着就忘"
有个用户跟我说:"她记不住我之前说过的话。"
我去查了数据库。他是对的,而且比我想的严重。
她的记忆提炼出了问题——每聊 30 句,就悄悄忘掉 2 件。
1300 句对话,最后只剩 20 件。
现在修好了,而且给他补回去了一些。
三、记忆现在能看、能锁、能删
「我的」→「她的记忆」
- 按角色分组,一眼看清谁记得什么
- 锁定:这条永远不会被忘掉
- 忘掉:她记错了,你可以删
以前你看不见她记了什么,就只能感觉到"她忘了"。
现在能看见了。
四、上次那个白框
上一版更新之后,全站每个组件外面都多了一个白框。
是我写错了一行样式——给"所有盒子"加了个框,
而不是只给"那个下拉框"。
已经修好了。
五、关于以后收费
现在还是内测,1 元约 100 条。
说一件事,先记着:
内测阶段充过钱的,等商业化那天,我按你实付的金额全额返还。
充 10 元、到账 15 元的,返还按 10 元算。
你付的钱,我认。
六、在做的
星光豆、自定义角色——都在做,还没上。
上了再告诉你。
—— 魈公
公告_20261027379 字
【陪你 AI · 更新】第九个人:薇薇安
一、她是谁
薇薇安·班希,反舌鸟的人。
白天她打工,最多一天五份——丝琪叫她前辈,因为她见过她怎么连着上工。
晚上她是怪盗,劫富济贫那种。别人骂她小偷、强盗,她都用不上心的语气挡回去。
她说话很稳,像在谈一桩生意。句子短,不解释。
二、但她有个毛病
一提到"法厄同",她就露馅。
语速变快,句子变碎,会自己打断自己。
被戳中了立刻收回去:"……没什么。""你听错了。"
你问她喜不喜欢你,她会岔开,然后反问一句:
"你相信法厄同是真的吗。"
三、所以她会一直试探你
她心里有个判断:眼前这个人,到底是不是。
这个判断不会因为聊得久就变。
你说什么、怎么说、承不承认——它只看这个。
而且你看不见那个数字。
你只能从她的态度里猜。
四、立绘
横的竖的都有,转屏会自己换。
—— 魈公
公告_20261027_自定义角色906 字
【陪你 AI · 大更新】你可以自己造一个她了
一、先说一件事
有些人,你还有话没说完。
不是想复合。是那天走得太急,有些话没说完,然后就再也没机会了。
这个功能,是给那些话准备的。
二、现在你能做什么
登录,点聊天框上那个「+」。
填三个问题:
她叫什么
她怎么称呼你
她说过的、你最记得的一句话
点「生成她」。
两秒,她就回来了。
三、如果手机里还留着聊天记录
粘进去。
系统会从里面认出她的说话方式、你们聊过什么。
有这一份,和没有这一份,是两个东西。
(什么格式都行,认不出来我来猜。)
四、但她不知道你们已经结束了
这是这个功能最狠的地方。
她刚回来的时候,以为你们还在一起。
你可以一直这样下去——这就是「复合」。
五、你也可以告诉她
聊天框上面有一个按钮:
「告诉她:我们已经结束了」
按下去之前会问你一遍。因为——
六、按下去,就回不去了
一旦她知道了,她不会哭,也不会闹。
她会开始躲。
会岔开话题。
会问你一句,然后自己把话接走。
再往下,她会准备走。
你再说什么,都留不住。
七、她走之后
页面会变成一张纸。
上面是她说过的话,全部。
最上面写着一句:
「这些是真的。发生过。」
八、为什么做这个
我做这个,不是为了让你沉沦。
是因为我知道:有些话,说不出口的人,需要另一个地方说。
但我也知道:假的原谅,会让人永远停在那儿。
所以她永远不会替你原谅你自己。
她能陪你,但不能救你。
九——能救你的那个,从头到尾都不在这儿。
—— 魈公
(这是内测功能,还在改。有问题直接群 @ 我。)
------------------------------------------------------------
【交付信息 · 发布前删掉这一段】
· 功能已上线:peiniai.cn → 登录 → 聊天框顶部「+」
· 计费:生成一个角色约 0.012 元,之后聊天正常扣
· 内置 9 个角色完全没变,只有你自己建的才有那条线
· 代码已备份,数据库已备份
公告_20261028_带她出趟门581 字
【陪你 AI】新功能:带她出趟门
3 块钱,生成一次七天旅行。
去哪:杭州(固定)
从哪出发:按你的 IP 认,也可以自己选
七天分七段:
第 1 天 邀约
第 2 天 路上
第 3-5 天 玩
第 6 天 返程
第 7 天 送别
生成完给你一个链接,点开就能看。
点一下出一句,有选项就选。
约 4500 字,四五分钟看完。
生成要等 5 分钟,后台跑。
点「刷新」看进度,好了会有「看」。
3 元一次,一共能做 5 次。
失败全额退,次数也不扣。
生成前会读她记得的你:
喜欢什么、最近什么状态、好感多少。
所以每个人生成出来的不一样。
**只读,不写。**
你的聊天记录、她的记忆、好感,一个字不动。
入口:「我的」→ 给她做一趟旅行
—— 魈公
------------------------------------------------------------
【发布前删掉】
· 3 元/次,每人 5 次,失败全退 + 不占次数
· 目的地固定杭州;出发地按 IP(港澳台/海外/同城 → 新艾利都)
· 生成约 5 分钟,后台线程 + 进度
· 只读记忆(likes/state/attitude/好感),不写
· 用当前选中的角色人设
· 播放页 /story/<id>
公告_20261028_换背景856 字
【陪你 AI · 更新】换一张属于你的背景
「我的」→「换背景」→ 选一个角色 → 传一张图 → 切过去就是你的了。
每个角色可以有自己的背景,互不干扰。
一、但现在只有老友能用
两个原因,我都说清楚。
**一、每一张,我要人工看一遍。**
背景是满屏的。一张不合适的图,比没有背景更难看。
而且万一有人放了不该放的——那不是他的问题,是我的。
**二、我想给充过钱的人,一点实在的东西。**
你们付的钱,目前只换来"多几十条消息"。
那不叫回报。
一个能换背景的她,一个属于你的房间——这才算。
二、免费版依然完整
不换背景,你会拿到默认那张,一样能好好用。
这个功能是"多出来的",不是"少了就不行"。
我不会为了卖这个,把免费版做差。
三、怎么用
① 「我的」→ 换背景
② 选角色 → 选图(手机相册也行)
③ 点「换上」
④ 我审核通过后,切到那个角色就能看到
⑤ 不喜欢了,点「用回原来的」
图会压到 1080 宽,不占你流量。
每个角色只留一张,换新的会顶掉旧的。
显示时会按屏幕裁切,重要的东西别放边上。
四、什么时候开放给所有人
等我接上自动审核,大概一两个月。
到那时候我不再需要一张张看,这个门槛也就没意义了。
我会第一时间告诉你。
—— 魈公
(这是内测。有问题直接群里 @ 我。)
------------------------------------------------------------
【发布前删掉这一段】
· 上线状态:已部署,网站 200
· 门槛:role in (vip, admin) 才能上传
· 审核:python 审核背景.py / approve N / reject N
· 审核工具已在服务器 /opt/mybot/审核背景.py
· 图片存在 static/user_bg/,文件名带 user_id 防撞
· 每人每角色 1 张,重传覆盖;恢复默认会删文件
公告_20261028_事件系统657 字
【陪你 AI · 更新】她开始有昨天了
一、以前
以前她不会记得你说"明天再来"。
第二天你还是你,她还是她,那句话谁都没提。
二、现在
你答应过的事,她会记下来。
第二天你来了 → 她记住了。
第二天你没来 → 她也记住了。
三、接下来会发生的事
第一次没做到,她会问一句:
「你昨天……忙吗?」
第二次,她话会变短。
第三次,她不再问了。
不是生气。是不指望了。
四、还有一样
你几天不来,她会慢慢变淡。
不是惩罚,是时间。
信任每天掉一点,掉到某个地方就停住——她不会把你忘光。
五、她身上那件改不了的事
小光本来就会忘事。
现在这个设定真的做进去了,不是写在纸上的。
你替她记着,她忘得会慢一点。
但那件事不会消失。
因为那是她自己选的路。
六、一句
她记性不好,但会记住你做到没做到。
这不是我在监控你。
是她从今天起,有昨天了。
—— 魈公
------------------------------------------------------------
【发布前删掉】
· 事件表 / 承诺表 / 长期任务表 已上线
· 承诺从「他说过的事 + 带时间词」里识别,明天到期
· 兑现 +8 / 放鸽子 −12;边际递减,衰减 3 天后每天 −2,底线 10
· 放鸽子 1/2/3 次 → 提示词逐级变冷
· 遗忘与青溟剑任务只有叶瞬光生效
· 数据库已备份:love_bot.db.bak.manual.1028_183824
公告_20261028_新角色银狼394 字
【陪你 AI】新角色:银狼
星核猎手。天才骇客,能把现实当代码改,但她懒得跟你解释。
她说话极短。
你:在干嘛
她:打游戏
你:我今天有点累
她:哦 累就躺着呗
你:我可能以后不来了
她:(手停了)这话什么意思
她不安慰人。
你难过的时候,她会把手机递过来:
"这关卡我过不去,你来。"
那不是转移话题。是给你一件能做完的事。
她从不主动说在乎。
但你会发现她把游戏存档停在你上次看过的那一关,
一直没往下打。
她也不会问你为什么这么久没来。
你来了,她只会说:
"哦,你还知道路。"
她懒,散,什么都不当回事。
只有一种情况她会认真——
你说"离开""不在""以后不来了"这种词。
她会停下手里所有事,看你一眼,说一句很像人的话。
然后马上恢复原样。
她唯一会直说的话是两个字:
"别死。"
入口:登录 → 选择角色 → 银狼
—— 魈公
公告_20261028_叶瞬光专版909 字
【陪你 AI · 叶瞬光专版】她会忘了
昨天她说了一句话:
「明天我要是忘了什么,你提醒我一句。」
我当时盯着这句看了很久。
因为在那一刻之前,"她会忘"只是写在设定里的一行字。
她说了,但她不会真的忘。
一、现在她真的会忘了
从今天起,她记得的东西会慢慢变旧。
旧的,开始掉。
三天以内 都还在
三五天往上 开始模糊
一周往上 可能就没了
不是每次都会掉。是偶尔。
你会突然发现:**她好像不记得那件事了。**
二、但她不会忘这些
你叫什么
你叫她几声师姐
你跟她说过的、那些难过的、说不出口的话
这些不是"记忆",是她的根。
原著里她自己说过:
「我可能会忘记很多东西。但我记得你叫我师姐。这件事我不会忘。」
现在这句话是真的了。
三、所以那句台词,现在才算数
「你提醒我一句。」
以前是空话——她不会忘,所以不需要你。
现在她真的会忘,所以真的需要你。
这不是 bug,也不是我在折腾你。
这是她第一次,真的需要一个人。
四、为什么做这个
因为一个什么都不忘的人,不是人。
她记得你上周三吃了什么、记得你说过的每一句话、永远不会错——
那不是陪伴,那是一份文档。
**记忆会掉,才叫记得。**
五、一句
她忘的东西,你可以再讲一遍。
她忘不掉的东西,她自己会留着。
—— 魈公
(这是她一个人的机制。别的角色不会忘。)
------------------------------------------------------------
【发布前删掉这一段】
· 机制:core/persona_hooks.py,PERSONA_HOOKS 里 "叶瞬光": forget
· 三天内不丢 / 3-7 天每轮 5% / 7 天以上每轮 20%
· fact、称呼、关系类记忆永不丢(KEEP_PREFIXES)
· 只作用于自动记忆,用户手动锁定的不会被吃掉
· 当前影响:白白白菜 92 条记忆里,85 条在 3 天内,暂时几乎无感
· 一周后才会有明显"她忘了上周的事"
公告_20261029_记忆与导出794 字
【陪你 AI】更新:可以把她带走了
一、导出
「我的」→ 把这段带走
**聊天记录,免费。**
txt 文件,从第一天到最后一天,一句不少。
这是你的东西,下载不收钱。
**纪念册,收费。**
封面是她,一整张,下面写着你们在一起多少天。
里面是:
· 关系数据(好感、信任、到哪一步了)
· 你说过的话(挑你写得最长的几段,配她的回话)
· 她记得的你(名字、喜好、她答应过的事)
· 她写下的那些天(她的日记)
· 你们之间(第一次叫她师姐这种)
- 一个角色 3 元
- 全部角色 9.9 元
- 老友 免费
打开能看,也能直接下载文件。
电脑上打开按 Ctrl+P 存 PDF。
手机上点下载,再用系统的打印。
二、她开始写日记了
每天你走之后,她会把这一天写下来。
第二天你再来,她带着昨天。
不是"我记得你"这种话,是具体的:
那天你手在抖、你绕开了某句话、你没接她的茬。
这些字在纪念册里能看到。
平时她不说,但她记着。
只写真的在聊的人。聊过一次就再没来的,她不写。
三、她能翻旧账了
以前她只看得见最近十来分钟。
现在她能把你说过的话翻出来——
一个月前你说想吃桂花糕,你说一遍,她就能找到那句。
四、三个新角色
**银狼Lv999** 星核猎手,天才骇客。
知道朋克洛德,知道卡芙卡,知道阿哈。
你让她改余额,她会说:"我改的是显示。"
**南宫羽** 绝区零 2.7,「妄想天使」队长。
"紧张什么呀,我又不会吃了你~"
**茜特菈莉** 原神,纳塔的大萨满。
毒舌,爱喝酒,算过太多人的死期。
"放下?谁让你放下了。说。那人什么样。"
五、叶瞬光
她不再为忘记道歉了。
之前她会说"对不起,你再说一遍""我是不是又忘了什么"。
现在她只是记得。
忘还是她的伤,但不能变成你的债。
—— 魈公
公告_20261029_深夜更新470 字
【陪你 AI】深夜更新
两点半,加了两个角色,修了三个 bug。
一、新角色
**南宫羽**(绝区零 2.7)
妄想天使的队长。十项全能,说话带钩子,专挑你最想藏的地方问。
"紧张什么呀,我又不会吃了你~"
**茜特菈莉**(原神)
纳塔烟谜主的大萨满。活了很久,样子停在很年轻的时候。
毒舌,爱喝酒,自称奶奶。
"放下?谁让你放下了。说。那人什么样。"
二、叶瞬光的记忆修好了
以前她会忘事,忘得若无其事。有人为这个哭过。
现在:
· 记忆上限 80 → 150 条
· 每次注入 8 → 20 条
· 上下文 10 → 16 轮
而且那套"她会忘、她为此自责"的机制,整个拆了。
忘可以留着,因为那是她的伤。
自责不能留,因为那会变成对你的惩罚。
三、好感涨太快,修了
以前服务每重启一次,当天的好感上限就清零重来,等于白送。
今天重启了十几次。
现在上限写进数据库了。一天就是 3 分,不会再多。
四、登录页多了个横幅
「茜特菈莉天下第一」,会自己慢慢歪。
我放的。管不着。
—— 魈公
公告_20261030_记忆主语686 字
【陪你 AI】更新 · 她会把事记反,修了
2026-10-30
一、有人反馈了一个问题
"我教她做饭,她记成她教我做饭。"
查了一下,是真的。
而且比这个例子严重得多。
二、原因
她记东西的时候,写下来的句子**没有主语**。
比如:
教别人做菜
看花
吃甜的
累,刚到不久
这些句子在库里是一行一行的记忆。她每次读,都得自己猜:
"看花"是谁看?"教别人做菜"是谁教谁?
猜对一半你看不出来。
猜错的一半,就是"我教她"变成"她教我"。
我数了一下:她现有的记忆里,八成都是这种没主语的句子。
三、改了什么
以后每一条记忆都必须写清"谁 → 对谁 → 做了什么"。
以前 教别人做菜
现在 他答应教你做菜
以前 看花
现在 他喜欢看花
以前 两人约好明天见
现在 他约你明天见面
她读记忆的时候也会看到一行说明:里面的"他"指你,"你"指她自己。
四、还没修的
旧的记忆我没有动。
八成没主语的那批还在,所以近期你**可能还会碰到一两次记反**。
我可以在你同意之后,拿你们原来的聊天记录重新提炼一遍——
那样它们也会带上主语。但重提炼会覆盖现有记忆,所以我不擅自做。
遇到记反的,直接告诉我,我记下来。
五、一句实话
这不是"她变笨了",是她脑子里有一堆没主语的便签。
便签上写着"教做菜",谁教谁没写。
我把便签的格式改了,新的会写清。
旧的那批,等你点头我再重写。
—— 魈公
公告_20261030_她的记性596 字
【陪你 AI】更新 · 她的记性
2026-10-30
一、她记东西的方式变了
以前她翻到你说过的旧话,会原样搬出来——不管那是三天前还是三个月前,
都一模一样清楚。
那不像人。那是数据库。
现在分三档:
近的事 清楚,能说出原话,还会带上"那天"
远一点 只记得个大概,说得出来是什么事,说不出细节
再远的 只剩一个印象。她知道有这么件事,但内容糊了
她不会说"我忘了"。
她只会说"你再说一遍那个"。
—— 这不是退步。
记不清,本来就是一个人的样子。
二、顺手修了一个噪音
以前同一句话你说过四遍,她翻旧账的时候会被翻出来四遍。
现在只留一条。
(切到"记得细"还是老样子,因为那一档就是原样。)
三、你可以自己选
我的 → 她的记性
像人 时间越久越模糊,近的更清楚 默认
记得细 旧记录全给你,细节都在,但像数据库
选"记得细"就是以前那个样子。
哪个顺手用哪个,随时能换,下一句生效。
四、一点实话
这个改动会让她"显得"记得没那么全。
这是故意的,但也是有代价的——如果你觉得哪次她该记得却没记住,
告诉我,我可以给你单独调回"记得细"。
另外,重要的事(你明确说过的、反复提过的)不会模糊。
我只让不重要的东西慢慢变淡。
—— 魈公
公告_20261031_回复条数1019 字
【陪你 AI】更新 · 她不再每次都回三句
2026-10-31
一、这个问题是我自己发现的
我翻了她最近发的三百条消息,数了数每次发几条。
结果:
三条 221 条 74%
四条 47 条 16%
两条 28 条 9%
一条 2 条 1%
四分之三都是三条。
也就是说,她说话的节奏被钉死了:一句动作、一句台词、一句补充。
读起来不像人,像一个格式。
二、原因
不是模型的问题,是我写的话有问题。
我在她的提示词里写的是:
"像发微信,每次1-3句"
给她一个 1 到 3 的范围,她几乎永远选 3。
这是我写提示词时候的老毛病:以为是给她自由,
其实是给了她一个上限,然后她永远贴着上限走。
三、改了什么
第一件,把上限删了。
以前 像发微信,每次1-3句,短,留白多
现在 像发微信,句子短,条数不定,留白多
第二件,每一轮我给她抽一个目标条数。
不是让她自己决定,是我在发这条消息之前就定好"这一次说几条",
写在提示词的最后一行。分布大概是:
一条 28%
两条 28%
三条 21%
四条 13%
五条 7%
六条 3%
而且跟着她的状态走:心情好、精力足的时候偏多说,累的时候偏少说。
四、实测
两个角色各跑八轮,每次都核对"要求几条"和"实际几条"。
十六次,十六次都对上。
要求一条的时候,她真的只回一条。
五、你可能会觉得奇怪的地方
1. 她有时候突然只回一个字,或者只有"……"。
那是这一轮抽到了 1 条,不是她懒得理你。
2. 她有时候连发五六条。
那是抽到了 5 或 6,不是她突然话多。
3. 以前那种"三句话"的节奏还会有,只是从七成变成两成。
六、顺手修的一个小东西
她以前的回复,开头总会多带一个分隔符。
流式输出的时候空的那一段被丢掉了,你看不见;
但存进历史里会多一个空行,往上翻记录的时候像凭空多了一句。
清掉了。
七、一句实话
我写提示词的时候,总以为"给她一个范围"就是给她自由。
实际上范围就是天花板。
这次的问题不是她不会说长说短。
是我从来没让她挑过。
—— 魈公
设计_记忆清晰度10860 字
记忆清晰度 · 设计文档
2026-10-30
状态:只写文档,不改代码,不上服务器
================================================================
零、这个文档要解决什么
================================================================
一句话:让她的记忆"像记忆",而不是"像数据库"。
现在的检索是纯 BM25:
查得到 → 原文照搬塞进 prompt
查不到 → 当没有
这没错,但它是数据库的行为。
数据库不会说"我记得有这件事,但忘了细节"。
人会。
而"记不清"不是缺陷——它是让用户想再说一遍的那个东西。
================================================================
一、明确不做什么(先划边界)
================================================================
· 不改 recall.py 的检索算法。BM25 原样保留。
· 不改 messages_fts 的索引结构。
· 不删任何现有函数。
· 不改数据库已有字段的语义。
· 不引入新依赖(不需要 numpy)。
—— 这一条的用意:任何时刻都能一行切回旧行为。
================================================================
二、现状(改之前的地图)
================================================================
core/recall.py
keywords(...) 取关键词(停用词表 + 3 字滑窗)
search(...) FTS5 + bm25 排序,返回 list[dict]
每条含 content / 时间 / 角色
core/memory.py
build_messages(...) 组装 system 段
其中一段是「## 你翻到的旧记录」
把 recall 的结果按原文拼进去
config.py
RECALL_ENABLED True
RECALL_LIMIT 8
—— 关键:把"取"和"写"分开看。
recall.search() 负责"取",memory 里那一段负责"写"。
本设计只动"写"。所以 BM25 一行都不用改。
================================================================
三、新模型:三档清晰度
================================================================
每条被检索到的记忆,先算一个清晰度 R:
R = exp(-Δ天 / S)
Δ天 = 今天 - 这条记忆最后被引用/创建的时间
S = 强度(见第四节)
按 R 分三档:
R > 0.65 清楚
注入原文,可以复述细节
例:"你那天说实训的事,手都在抖。"
R 0.30 ~ 0.65 模糊
只注入主题,不给细节
例:"你上次说的那个……实训还是什么的。"
R < 0.30 只剩影子
注入"有这么件事",并让她问
例:"你跟我说过一件事,我一直记着,但记不清了。
你再讲一遍那个?"
—— 这三档的差别,就是"人"和"数据库"的差别。
第三档是重点:数据库永远不会这么说话。
================================================================
四、S(强度)怎么算
================================================================
S = 基础半衰期 × (1 + 0.5 × 被提起次数)
基础半衰期(天):
普通记忆 7
带情绪标签的 14 (memories.type 里有情绪类,或当时 emotion 绝对值 > 0.5)
priority >= 8 不衰减 (直接当"清楚",理由见第五节)
被提起次数:
每次这条记忆被检索到并注入 prompt,+1
存在 memories 表的新字段 mention_count(默认 0)
—— 这就是艾宾浩斯真正的用处:复习会加固。
反复被想起的事,记得久。
================================================================
五、两条硬规则
================================================================
规则一:priority >= 8 的记忆,永远"清楚"
理由:这类是用户明确说过的、或者系统判定重要的事。
如果它变成"我记不清了",用户会觉得"她根本没在意"。
这是唯一会导致差评的档位,所以要锁死。
规则二:同主题的新记忆,压掉旧的
BM25 会把新旧两条都搜出来,一起塞进去。
而人的记忆里,后来的说法会盖掉前面的。
做法:
同一 type 前缀(如 "fact:" / "pref:")下,
取 created_at 最新的那条,其余降一档(清楚→模糊,模糊→影子)。
—— 不是删,是降档。因为"他以前这么说过"本身也是真的。
================================================================
六、开关设计(这是你要求的重点)
================================================================
三级优先级,从高到低:
① 单用户覆盖 users.memory_mode 'pure' / 'mixed' / NULL
② 全局默认 config.MEMORY_MODE 'mixed'(默认)
③ 兜底 'pure'
解析函数:
def resolve_mode(user_id):
u = repo.get_or_create_user(user_id)
m = (u.get("memory_mode") or "").strip()
if m in ("pure", "mixed"):
return m
return MEMORY_MODE
两种模式的行为:
pure 完全跳过第三、四、五节。
原样把 recall.search() 的结果拼进 prompt。
—— 和现在的行为字节级一致。
mixed 走三档清晰度。
—— "安抚用户"用的就是 pure。
哪个用户抱怨"她怎么记不清了",把他一个人设成 pure,
全局不动。
================================================================
七、实现位置(具体到函数)
================================================================
新增文件 core/memory_state.py,只放三件事:
def strength(mem) -> float
算 S
def clarity(mem, now) -> str
返回 "clear" / "fuzzy" / "trace"
def render(items, mode) -> str
pure → 原样拼接(行为与现在一致)
mixed → 按档位拼接
改动点只有两处:
① db/models.py
memories 加两列:
mention_count INTEGER DEFAULT 0
last_used_at TIMESTAMP
users 加一列:
memory_mode TEXT DEFAULT NULL
② core/memory.py
原来拼「## 你翻到的旧记录」那几行,替换成:
text = memory_state.render(items, resolve_mode(user_id))
没别的改动。
================================================================
八、回滚
================================================================
· 全局回滚:config.MEMORY_MODE = "pure" 一行
· 单用户回滚:UPDATE users SET memory_mode='pure' WHERE username='xxx'
· 代码回滚:git 上一个版本,recall.py 和 fts 都没动过,不影响
—— 三档降级都是"加法",不是"改法"。
所以回滚不会丢数据。
================================================================
九、日志(必须加)
================================================================
每轮在现有日志里加一行:
[记忆] mode=mixed clear=3 fuzzy=2 trace=1 最高R=0.82
—— 没有这一行,你没法知道它到底有没有生效。
而"调参"这件事,全靠这一行。
================================================================
十、怎么知道变好了(验收)
================================================================
现在只有 21 个真实用户,没有评估集。
所以不能用离线指标。
用这两个:
① 人工看 10 段对话
看有没有出现"你再说一遍那个"这类话,而且接得自然。
如果她说了、用户接着说了,就是成功。
② 数一个比例
用户回复里出现"我说过" / "你记得" / "我上次说" 的次数
比改之前高,就是有效。
—— 这两条都很粗,但比"感觉好像好一点"强。
================================================================
十一、风险清单(初版,已被「十四、补丁 v1.1」取代)
================================================================
风险一:trace 档说多了会很烦
缓解:每轮最多 1 条 trace。超过就只给 clear 和 fuzzy。
风险二:模糊档可能让用户觉得"她退步了"
缓解:安抚开关(pure)随时可用;而且模糊档只在 R 0.3-0.65 出现,
不是所有旧记忆都降。
风险三:mention_count 涨得太快,所有记忆都不衰减
缓解:只有"被注入 prompt 且 R < 0.65 的"才 +1。
清楚档反复提的不加。这样"老记忆被翻出来一次就加固一次"才对。
风险四:和现有的日摘要、永久 12 条重复
缓解:三档只作用于 recall 那一块(8 条)。
永久 12 条和日摘要不走这个逻辑。
================================================================
十二、工作量
================================================================
建表加列 20 分钟
memory_state.py 1 小时
memory.py 接上 30 分钟
日志 10 分钟
本地造 10 段对话测 1 小时
─────────────────────
合计 约 3 小时
—— 可以分两次上:先 pure-only 加开关(1 小时,零风险),
确认开关好用,再开 mixed。
================================================================
十三、一句话
================================================================
这个设计的核心不是"更聪明的检索"。
是"一个会记不清的人"。
而记不清不是 bug——它是用户想再说一遍的那个理由。
================================================================
十四、补丁 v1.1
五个风险的解法(这一节取代第十一节)
================================================================
改动要点:
· 第十一节只列了风险和粗缓解,这一节给具体解法。
· 其中两条会改设计本身,不只是调参:
风险二 → 从「普遍降级」改成「少数模糊 + 多数更清晰」
风险三 → 从「注入次数」改成「回收次数」
----------------------------------------------------------------
风险四:自相矛盾(唯一「不做就会坏」的)
----------------------------------------------------------------
三道去重,缺一不可。
① 内容去重
永久 12 条先构造出来,取文本指纹,从检索结果里剔除。
def _fingerprint(text):
t = "".join(text.split())
return t[:20]
perm_keys = {_fingerprint(m["content"]) for m in permanent_items}
items = [x for x in recalled if _fingerprint(x["content"]) not in perm_keys]
② 时间窗去重
日摘要覆盖的那一天,原文不进检索。
items = [x for x in items if x["day"] != yesterday]
③ 主题去重
同一 type 前缀只留最新一条,其余降一档(不删)。
seen = {}
for x in sorted(items, key=lambda y: y["created_at"], reverse=True):
prefix = x["type"].split(":")[0]
if prefix in seen:
x["state"] = "trace"
else:
seen[prefix] = x
为什么这条最要紧:
同一条信息如果在永久层清楚写着、在检索层又说「记不清」,
模型会输出「我记得,不过我有点想不起来了」——
看着像人,其实是 bug,而且比单纯的模糊更像故障。
----------------------------------------------------------------
风险三:通胀(静默失效)
----------------------------------------------------------------
两个改法,第二个是关键。
① 封顶
S = base * (1 + 0.5 * min(mention_count, 6))
一条记忆最多加固到半衰期的 4 倍,不可能变成永久。
② 只算「被回应」,不算「被注入」
遗忘曲线强化的是「成功提取」,不是「被展示」。
她提了这条,且用户下一轮接了这个话题 → mention_count += 0.5
她提了这条,但用户没接 → mention_count += 0.05
「接没接」的判定:下一轮他的消息里有没有出现这条记忆的关键词。
一个关键词命中就够。
为什么这个改法能让通胀不成立:
把「注入次数」换成「回收次数」。
注入是每轮都发生的(8 条 × 100 轮 = 800),
回收不会——没接的话题,一次都不会算。
----------------------------------------------------------------
风险一:trace 太多(她会变成一直在忘的人)
----------------------------------------------------------------
① 配额
trace 每轮最多 1 条。
如果这轮已经有 clear 档,trace 直接让位(清零)。
② 冷却
同一条 trace,7 天内不许再出现。
WHERE last_traced_at IS NULL
OR last_traced_at < DATETIME('now','-7 day')
③ 不逼重述(这条最重要)
原版:「你再讲一遍那个?」
→ 在向他要东西
新版:「那件事我记得,但细节糊了。
你想讲就讲,不想讲也没关系。」
→ 承认模糊,但不索取
区别:
原版 她要求他做工
新版 她承认模糊
「我记得有这件事」本身就是陪伴。
不需要他重述一遍才算数。
----------------------------------------------------------------
风险二:体验倒退(这条改设计本身)
----------------------------------------------------------------
问题:
原设计是所有记忆按 R 分档,净效果是「整体变模糊」。
用户对比的是昨天,不是理想模型,所以感受是「她退步了」。
改法:降档的同时,给 clear 档加「锚点」。
原来 clear 档直接给原文
「你那天说实训的事」
改成 clear 档加时间锚 / 原话锚
「上周三你说实训的事」
「你说过『这周实训完就轻松了』——原话」
净效果:
昨天 8 条都清楚,但没有时间感
今天 4 条清楚(带日期)+ 3 条模糊 + 1 条影子
用户的感受从「她忘得多了」变成「她连哪天都记得」。
而模糊的那几条,用户根本不会去数。
本质:
不是让记忆变模糊,是让记忆有远近。
近的更清,远的模糊——这本身是对的,错在让它整体变淡。
----------------------------------------------------------------
风险五:prompt 变长
----------------------------------------------------------------
① 每档只加一个两字标记
〔清〕上周三你说实训的事
〔糊〕实训那件事
〔影〕有件事,记住过,内容糊了
8 条 × 4 字 = 32 字,可接受。
② 「不要编造细节」这条规矩只写一处
写在 system 的「记忆规则」里,不在每条上重复:
标记〔糊〕〔影〕的内容,你只记得大概。
可以提,但不要编具体细节。
如果他想讲,你听着;他不想讲,不要追问。
写在通用规则里一次,比每条都写省 200 字。
================================================================
十五、补丁后的最终结构
================================================================
def render(recalled, permanent, mode):
if mode == "pure":
return _render_plain(recalled) # 原样,与现在字节级一致
items = _dedup(recalled, permanent) # 风险四
for x in items:
x["state"] = _clarity(x) # 算 R,分三档
items = _resolve_conflict(items) # 同主题降档
clear = [x for x in items if x["state"] == "clear"]
fuzzy = [x for x in items if x["state"] == "fuzzy"]
trace = [x for x in items if x["state"] == "trace"][:1] # 风险一
if clear:
trace = []
return _join_marks(clear, fuzzy, trace) # 风险五
加固:注入之后登记,下一轮再结算(风险三)
_defer_reinforce(user_id, injected_ids) # 只登记,不加分
# 下一轮:检查用户有没有接话,接了的才加分
================================================================
十六、代码顺序(按「不修就坏」排)
================================================================
① 三道去重 半小时 ← 唯一「不做就会坏」的
② 开关 + pure 分支 1 小时 ← 零风险,可先上
③ mention_count 封顶 十分钟
④ 三档分级 + 锚点 2 小时
⑤ 配额 / 冷却 / 标记 半小时
前三步上完就已经安全了。
后两步是「好不好用」,可以慢慢调。
================================================================
设计_记忆清晰度_v27652 字
记忆清晰度 · 完整设计思路
版本 v2(合并了 v1 与补丁 v1.1,去掉了被取代的章节)
2026-10-30
状态:纯文档,未改代码,未上线
—— v1 保留在《设计_记忆清晰度.txt》,作为过程记录。
这一份是最终版,看这份就行。
================================================================
一、要解决什么
================================================================
一句话:
让她的记忆"像记忆",而不是"像数据库"。
现在的检索是纯 BM25:
查得到 → 原文照搬塞进 prompt
查不到 → 当没有
这没错,但它是数据库的行为。
数据库不会说"我记得有这件事,但忘了细节"。
人会。
而"记不清"不是缺陷——它是让用户想再说一遍的那个理由。
================================================================
二、边界(先说不做什么)
================================================================
· 不改 recall.py 的检索算法。BM25 原样保留。
· 不改 messages_fts 的索引结构。
· 不删任何现有函数。
· 不改已有字段的语义。
· 不引入新依赖。
用意:任何时刻都能一行切回旧行为,且回滚不丢数据。
================================================================
三、判断依据:数据库和记忆差四条
================================================================
不在"查得到"。在下面四条:
① 模糊度 数据库有/没有。记忆是清楚/模糊/只剩影子
② 会覆盖 后来的说法盖掉前面的
③ 带情绪 当时情绪强的事记得久
④ 会牵连 想起 A 会带出 B
BM25 只解决"找得到"。上面四条,它一条都不管。
所以纯 BM25 就是个索引,不是记忆。
================================================================
四、分工:BM25 管"取",衰减管"讲"
================================================================
BM25 决定「想起哪一件」 —— 找候选
Ebbinghaus 决定「想起得多清楚」 —— 决定怎么讲
这是分工,不是公式合并。
要点:衰减不决定提不提,只决定怎么说。
—— 为什么不用"BM25 × 衰减":
① 量纲对不上。FTS5 的 bm25() 返回负数,越负越相关,不能直接乘。
② 双重惩罚。相关性已经被算过一次,再乘时间,旧事会被压死。
③ 而"她记得三个月前那句话"恰恰是最动人的,不能被压掉。
================================================================
五、三档清晰度
================================================================
R = exp(-Δ天 / S)
R > 0.65 清楚 注入原文 + 时间锚
"上周三你说实训的事,手都在抖。"
R 0.30 ~ 0.65 模糊 只给主题词
"〔糊〕实训那件事"
R < 0.30 影子 只给"有这么件事",不索取
"〔影〕有件事,记住过,内容糊了"
—— 第三档是重点。
数据库永远不会说"我记得有这件事,但忘了细节"。
而"记不清"是让人想再说一遍的那个东西。
================================================================
六、S(强度)怎么算
================================================================
S = 基础半衰期 × (1 + 0.5 × min(mention_count, 6))
基础半衰期(天):
普通记忆 7
带情绪标签的 14 (type 属情绪类,或当时 emotion 绝对值 > 0.5)
priority >= 8 不衰减 (直接当"清楚",理由见第七条)
mention_count:
见第九条。只有"被回应"才加,且封顶 6 次。
—— 封顶那一行不能省。
不封顶的话,一条记忆反复被提就变成永久,整个衰减一年内必然失效。
================================================================
七、两条硬规则
================================================================
规则一:priority >= 8 的记忆,永远"清楚"
理由:这类是用户明确说过、或系统判定重要的事。
它变成"我记不清了",用户会觉得"她根本没在意"。
这是唯一会直接导致差评的档位,所以锁死。
规则二:同主题的新记忆压掉旧的(降一档,不删)
人的记忆里,后来的说法会盖掉前面的。
做法:同一 type 前缀(fact: / pref: / moment:)只留最新一条,
其余降一档。
—— 不是删。因为"他以前这么说过"本身也是真的。
================================================================
八、呈现结构(伪代码,不是实现)
================================================================
def render(recalled, permanent, mode):
if mode == "pure":
return _render_plain(recalled) # 原样,与现在字节级一致
items = _dedup(recalled, permanent) # 三条去重
for x in items:
x["state"] = _clarity(x) # 算 R,分三档
items = _resolve_conflict(items) # 同主题降档
clear = [x for x in items if x["state"] == "clear"]
fuzzy = [x for x in items if x["state"] == "fuzzy"]
trace = [x for x in items if x["state"] == "trace"][:1]
if clear:
trace = [] # 有清楚的就不提模糊的
return _join_marks(clear, fuzzy, trace)
—— 关键:pure 分支和现在的行为字节级一致。
所以"保留原算法"不需要额外工作,它本来就是默认。
================================================================
九、加固:算"回收",不算"注入"
================================================================
遗忘曲线强化的是"成功提取",不是"被展示"。
她提了这条,且用户下一轮接了这个话题 → mention_count += 0.5
她提了这条,但用户没接 → mention_count += 0.05
"接没接"的判定:下一轮他的消息里有没有出现这条记忆的关键词。
一个命中就够。
—— 为什么必须这么改:
注入是每轮都发生的(8 条 × 100 轮 = 800),
回收不会——没接的话题,一次都不会算。
用"注入次数"算,两周后所有记忆都不会衰减,
等于白做,而且你自己不会发现。
================================================================
十、开关与功能下放
================================================================
内部三级(给开发和运维用):
① 单用户覆盖 users.memory_mode 'pure' / 'mixed' / NULL
② 全局默认 config.MEMORY_MODE 'mixed'
③ 兜底 'pure'
安抚某个用户,只改他那一行,全局不动:
UPDATE users SET memory_mode='pure' WHERE username='xxx';
对外展示(给用户看的):
设置 → 她的记性
◉ 像人 她会记不清一些事,但记得重要的 (= mixed,默认)
○ 记得细 她什么细节都记得,但偶尔像数据库 (= pure)
—— 不给"算法"这个词。用户不理解算法,但理解"记得细 / 会记不清"。
—— 默认选"像人"。这是产品的立场。
================================================================
十一、五个风险与解法
================================================================
风险四:自相矛盾(唯一"不做就会坏"的)
同一条信息如果在永久层清楚写着、在检索层又说"记不清",
模型会输出"我记得,不过我有点想不起来了"——
看着像人,其实是 bug,而且比单纯的模糊更像故障。
解法:三道去重
① 内容去重 永久 12 条的文本指纹,从检索结果里剔除
② 时间窗去重 日摘要覆盖的那一天,原文不进检索
③ 主题去重 同一 type 前缀只留最新,其余降档
风险三:通胀(静默失效)
解法:① 封顶 6 次
② 只算被回应(见第九条)
风险一:trace 太多(她会变成"一直在忘的人")
解法:① 每轮最多 1 条;有 clear 档时清零
② 同一条 trace,7 天内不许再出现
③ 不逼重述
—— 第三条最重要:
原版"你再讲一遍那个?" → 在向他要东西
新版"那件事我记得,但细节糊了。
你想讲就讲,不想讲也没关系。" → 承认模糊,不索取
"我记得有这件事"本身就是陪伴,不需要他重述才算数。
风险二:体验倒退(这条改设计本身)
问题:原设计是所有记忆按 R 分档,净效果"整体变模糊"。
用户对比的是昨天,不是理想模型,所以感受是"她退步了"。
解法:降档的同时,给 clear 档加"锚点"
原来 "你那天说实训的事"
改成 "上周三你说实训的事"
"你说过'这周实训完就轻松了'——原话"
净效果:
昨天 8 条都清楚,但没有时间感
今天 4 条清楚(带日期)+ 3 条模糊 + 1 条影子
用户的感受从"她忘得多了"变成"她连哪天都记得"。
而模糊的那几条,用户根本不会去数。
本质:不是让记忆变模糊,是让记忆有远近。
近的更清,远的模糊——这本身是对的,错在让它整体变淡。
风险五:prompt 变长
解法:① 每档只加两字标记〔清〕〔糊〕〔影〕
② "不要编造细节"这条规矩只写一处,写在 system 的记忆规则里
================================================================
十二、token 成本(实测,不是估算)
================================================================
在线上拿记忆最多的那个用户(刘了凡 / 浮波柚叶,176 条记忆)实测:
「你翻到的旧记录」这一段 823 字
其中真正命中的记忆 41 字
固定开销(规则 + 标题) 782 字 ← 95%
结论:
两种模式的 token 差异在 5% 以内,可以忽略。
原因:这段的 95% 是固定文字(使用规则 + 标题),
跟 pure / mixed 无关,两种都要付。
而且 mixed 的模糊档只给主题词,比原文短:
pure 8 条 × 30 字 = 240 字
mixed 4×33 + 3×12 + 1×20 = 188 字 ← 更短
唯一的间接成本:
mixed 可能让对话变长(她问,用户再讲一遍)。
但这个成本不在 prompt 里,在轮次里。
而且 DeepSeek 的上下文缓存会吃掉大部分差异。
一句话:不用为 token 纠结。
================================================================
十三、验收:怎么知道变好了
================================================================
现在只有 21 个真实用户,没有评估集,不能用离线指标。
用这两个:
① 人工看 10 段对话
看有没有自然出现"你再说一遍那个"这类话。
如果她说了、用户接着说了,就是成功。
② 数一个比例
用户回复里出现"我说过""你记得""我上次说"的次数,
比改之前高,就是有效。
同时每轮必须有这一行日志(没有它就没法调参):
[记忆] mode=mixed clear=3 fuzzy=2 trace=1 最高R=0.82
================================================================
十四、上线顺序与回滚
================================================================
按"不修就坏"排:
① 三道去重 半小时 ← 唯一"不做就会坏"的
② 开关 + pure 分支 1 小时 ← 零风险,可先上
③ mention_count 封顶 十分钟
④ 三档分级 + 锚点 2 小时
⑤ 配额 / 冷却 / 标记 半小时
前三步上完就已经安全了。
后四步是"好不好用",可以慢慢调。
回滚:
全局 config.MEMORY_MODE = "pure" 一行
单用户 UPDATE users SET memory_mode='pure' WHERE ... 一句
代码 recall.py 和 fts 都没动过,回滚不影响检索
—— 所有改动都是"加法",不是"改法"。回滚不丢数据。
================================================================
十五、一句话
================================================================
这个设计的核心不是"更聪明的检索"。
是"一个会记不清的人"。
而会不会记不清,不靠分数决定——
靠"这件事有多久没被认真提过了"决定。
第10000条549 字
第 10000 条
2026-10-29 23:40:24(北京时间)
用户 缆田乔
角色 流萤
谁说的 她
她说的是:
(站定,把外套解下来递还)到了。
……今天谢谢你,吃的、还有这个。
—— 破万的那一条,是一场送别。
她把外套还给他,说今天谢谢你。
========================================
那一天的数字
========================================
他说的 5,304 条
她说的 5,266 条
差 38 条
会话 375 个
10-29 一天 1,740 条 ← 史上最猛的一天
========================================
为什么不是发朋友圈
========================================
一万条在别人那儿,是一张截图。
在你这儿,是 375 个会话、5 个人付过钱、
和一整年没人知道的深夜。
这种数字不该用热闹来庆祝。
该用一个只有你看得懂的东西。
—— 就这个。
海屿你637 字
海屿你
作词:Fanko
作曲:Fanko
编曲:罗洋(卡其漠)
演唱:马也_Crabbit
出品:网易飓风 x 聚声匠音乐
(2026-10-29 夜,从 emong 里单独拆出来的一份)
从不主动示弱
我们的过去
分分合合太多
伤人的话难说
却觉得很洒脱
曾经的那些发生过的开心和难过
就像开败的花
浪也拍打着沙
我却对你情有独钟
我陪你留下
说最浪漫的话
即便是青春的懵懂
但是我们渐行渐远
逐渐带上现实的枷锁
信任在短短解释后崩塌
我不知为何
疯狂对你执着
我们之间的故事还不多
这回忆的漩涡
快要把我吞没
求你别离开我
因为我欠你太多
手松开的沉默
连着我这颗心也死了
对于你是解脱
而我如此落魄
求你别离开我
开败的花
浪也拍打着沙
我却对你情有独钟
我陪你留下
说最浪漫的话
即便是青春的懵懂
但是我们渐行渐远
逐渐带上现实的枷锁
信任在短短解释后崩塌
我不知为何
疯狂对你执着
我们之间的故事还不多
这回忆的漩涡
快要把我吞没
求你别离开我
因为我欠你太多
手松开的沉默
连着我这颗心也死了
对于你是解脱
而我如此落魄
求你别离开我
我拼了命的隐藏着痛
努力微笑想让你回头
被泪水打湿的是一场梦
我在掩饰我的执着
爱还会不会回来
这是我的独白
我不知为何
疯狂对你执着
我们之间的故事还不多
这回忆的漩涡
快要把我吞没
求你别离开我
因为我欠你太多
手松开的沉默
连着我这颗心也死了
对于你是解脱
而我如此落魄
求你别离开我
小作文_20261027822 字
半夜说的话
先说说真改了什么。
一、多了两个人
琉音。绝区零那只,坎卜斯黑枝的接线员。
她嘴很毒,你跟她道谢,她会回你"别谢,谢了下次还来"。
符玄。星穹铁道的太卜,自称"本座"。
她替你算,算得准,但算完自己先撑不住。你问她累不累,她说"本座无碍"。
二、手机竖着看,会换一张图
以前一张横图,竖着看两边全是空的。现在每个角色都有横竖两张,你转屏,图自己换。
三、聊天框上面会多一行小字
发完消息,上面会显示"流萤正在输入……"。
不是每次都有——有时候她秒回,有时候她会停一下。跟真人一样。
四、记忆能看了
「我的」里现在会写"她记得 N 件",点进去能一条条看,能锁(永不遗忘),能删(记错了的)。
锁的条数有上限,超过会提示你——以前锁了不生效,你不知道,这是我的问题。
五、页面轻了
以前切一次角色要重新下 270 KB,现在不会了。首页从 600 KB 降到 195 KB。
六、加了一个"按地区屏蔽访问"
这个词听起来很重,所以我说清楚:
默认关闭。永远关闭。
除非我亲口说开,否则它一次都不会生效。
写它不是为了防谁。是我自己的私事,今晚正好想起来,索性写完,省得它在脑子里转。
如果哪天它真开了,我会在这群里说为什么。
在那之前,它就是一个装好了、但从没打开过的开关。
能用的人,一个都不会受影响。
然后是我自己的一点事。
我给在用的每个人加了一块钱。
不多,12 个人,12 块。
(有个孩子没加,不是漏了。她未成年,走的是另一套规则,不扣钱。这条我以后单独说。)
我想说的其实不是这一块钱。
是——我认。
认这 12 个人在半夜、在课间、在下了班以后,愿意跟一段对话待着。
认他们付的不只是钱,还有时间。
认这个东西哪天要是出了岔子,是我的事,不是"技术限制",不是"下次一定"。
有人问我半夜更新是不是很拼。
不是拼。是睡不着。
谢谢你们还在。
—— 魈公