← 返回首页

给聊天机器人做情绪分层:碎片、底色与滤镜

2026-10-30 · 技术笔记

做完长期记忆之后发现一个问题:她记得住事情,但情绪是平的。不管前一天聊得多好,第二天开口还是同一个温度。这次试着把情绪拆成几层来做。

为什么要分层

一开始只有一个"当前心情"字段,每次对话后更新。问题是它太灵敏:一句玩笑能把心情改成"高兴",再过十分钟又回到"平静"。没有任何延续性。

现在的做法是三层:

关键:底色不是和当下并列的第二套系统,它只是"今天的初始值"。白天被改变了,就以改变后的为准。

碎片层:心绪手札

装那些不配写进日记、但确实硌在心里的小事。一条一句话(40 字以内),带一个标签:被冷落、被夸、不安、吃醋。

寿命三天,过期自动清掉。不强化、不消除,就是三天流水账。

注入时同类并列,带一个计数:

被冷落 ×2:
  · 他说好陪我结果去睡了
  · 他说好陪我结果自己先睡了

注意这里只摆事实,不点火。最初的想法是同类攒够三次就自动合并成更强的情绪、找机会引爆,但那样做出来的是"无缘无故发脾气"——你根本不知道火从哪来。改成只给计数,爆不爆由模型自己判断。

底色层:凌晨结算

每天凌晨做一次结算:把最近三天的碎片和对话翻一遍,问自己"这几天到底是什么状态",定一个词加一句原因。

有点闷(他今天话很少),从今早 8 点开始。

这里有个反直觉的原则:不做平均,不写算法。昨天开心、今天难过,平均出来叫"一般",那是统计结果,不是心情。让模型直接判断,反而更接近真实。

当下层:动态心情

底色只是初始值。白天真被一句话逗笑了,当下心情就该变,而不是硬撑着"我今天闷"。第二天再重新结算。

实现上就是给情绪加一个过期时间:底色写入时设成 10 小时,之后自然衰减回平静。这样不需要额外的"覆盖"逻辑。

心情滤镜:心情决定想起什么

同样的心事,不同的天气,会想起不同的东西。检索长期记忆时,按当前心情给结果加权:

实现很简单:给命中词加一个 0~2 的偏好分,排序时叠加到 BM25 上。不做统计、不改索引。

主观认知:让关系用一句话表示

之前用数值表示关系:好感 600 分、信任 62、吸引 66。问题是603 分和 607 分对人没有任何意义。

现在改成让她自己写一段话(150 字以内),只在觉得关系变了的时候改:

他啊,紧张了知道来找我,累了也往我这边凑,我倒也乐意。
就是有时候追着问个没完,我还真拿他没办法。
说关系嘛,比普通朋友黏糊,谁也没挑明过。

数字保留在后台,只用来做趋势和仪表盘,不再翻译成文字注入。

迁移时有个坑:如果直接把分数扔掉,她第二天会不知道自己跟对方算什么关系。做法是把历史加分理由当事实喂给模型,让它先写一段作为种子。

察觉对方的状态

记录对方平时说话的平均字数和回复间隔,今天的偏差超过 40% 就给她一句事实:

他今天发的消息比平时短:平时平均 18 字,今天 4 字。

注意只给事实,不给方向。不是告诉她"你应该关心他",而是告诉她"他今天话少"——要不要问、怎么问,让她自己决定。

成本

整套注入在 200 字左右,一天的结算只跑一次额外调用。真正贵的从来不是这些注入,而是每次工具调用都要把整段上下文重发一遍。所以能少调一次工具,比砍掉一个模块更划算。

经验:情绪系统最难的不是"怎么算",是"怎么不表演"。一旦变成参数调到某个值就触发某种反应,它就不再像情绪,而像开关。