我把盘盘猫的记忆做出来了
盘盘猫有一款 MBTI 人格测试,不做勾选题,靠聊天来了解你,看你怎么措辞,怎么推理,碰到模糊的问题怎么反应。每一轮对话其实都在采集人格信号,拿到的东西比问卷多得多。测试本身做得挺好,但有个很要命的问题,做完一次,下次回来 AI 就把你忘了。用户聊了 20 分钟,职业上的困惑、感情上的纠结、对大厂机会的害怕全说了,关掉页面再回来,AI 还是那句「嗨,很高兴认识你!」,跟第一次见面一样。
我在 AI 智能体随想 里写过一个判断,记忆编排是 AI 伴侣的技术护城河。这里说的记忆,不是「我们聊过 X 话题」那种事实摘要,是对你这个人的理解,比如你在什么地方会犹豫,犹豫成什么样,情绪上透出什么信号,还有嘴上说的和心里想的差在哪。对话内容 99% 其实是噪声,信号在语气里,在用户犹豫了一下、或者干脆绕开不谈的地方。盘盘猫的 MBTI 其实已经在采这些信号了,只是采完就扔。写完那篇我就想,别光说了,做一个出来。
两个 feature
设计大概是这样的。第一个 feature 是 MBTI 长期记忆。每次做完测试,AI 在后台把这次对话压成一份结构化摘要,从里面提出行为模式、情绪基调、关键语录、没解决的内心冲突这些人格信号。逐字记录反正是不存的,只存提出来的东西。摘要再合并进一个中心化的人格画像。画像大概 400 个 token,不长,但够让 AI 下次对话的时候「认识你」。
画像里有两类字段我想多说两句。memorableDetails 存具体的故事片段,unresolvedThreads 存那些欲言又止的话题。这两类对分析人格本身帮不上多少忙,它们管的是活人感。有了它们,AI 下次就能问出「你上次提到那个被否了三次的设计稿,后来怎么样了?」这种话,听起来就像一个真认识你的人在说话。
第二个 feature 是深度伴侣,做完 5 次有效的 MBTI 对话以后解锁。伴侣和 MBTI 不一样,它是带记忆的。你的人格画像加上最近的对话摘要,每次对话都会注入 context,所以它知道你是谁,记得你说过什么,能很自然地提起你以前的事。伴侣的提示词里有一条规则,直接对应伴侣构想里的「判断 Agent」,就是注意到了矛盾,也不一定就要点破,只有用户自己往那儿探的时候,才温和地提一下。不然它就会退化成一个只会顺着你说好话的 AI,那种东西没什么价值。
而且这是双向的,伴侣的对话也会反过来喂给人格画像。MBTI 负责采信号,伴侣负责把价值兑现出来,两边互相喂,飞轮就这么转起来了。
MBTI 采集人格信号喂给画像、深度伴侣兑现价值、伴侣对话再反哺画像,构成互相增强的记忆飞轮闭环。
设计是聊出来的
这个 feature 从构想到写代码再到仿真验证,全程都是在 claude code 里做的。最值得讲的其实是写代码之前那段,设计是我和它一起聊出来的。我给它的第一条指令,是先读我的伴侣构想,再去翻盘盘猫的 MBTI codebase,然后告诉我怎么把构想做出来。它花了大概一分钟看完,回复的第一段就让我觉得它读懂了:
"你的构想文档把 MBTI 定义为更深层伴侣 AI 的原型——不是终点。关键洞察是跨会话记忆需要捕捉的是人格模式和行为倾向,而不仅仅是事实。当前系统已经存储了完整的加密对话记录——原始数据已经在那里了,只是没有被向前传递。"
然后它问了第一个关键问题,记忆是存原始对话,还是存压缩过的摘要。这个问题没看上去那么简单。原始对话细节全,但算一下账就知道走不通。每次会话大概 3,000-5,000 token,5 次就是 15,000-25,000 token 的额外 context,每次伴侣对话都要注入一遍,成本会炸,噪声也太多。纯摘要呢,质感又全丢了。我在那篇文章里写得很明确,洞察藏在用户是怎么说的,犹豫、措辞、反复出现的情绪模式、关键的原话,干巴巴的摘要会把这些全丢掉。
claude code 给了个折中的办法,做结构化摘要,同时保留原话。每次会话压成 350 token 左右的结构化 JSON,里面有人格信号、情绪基调,还有关键语录的原文。另外再维护一份 400 token 左右的中心化人格画像,每次会话完合并更新一次。我在这个基础上又收了收,只总结 10 轮以上的合格会话,注入最近 5-10 条摘要,画像跟着一直更新。两层数据模型就这么定下来了。
嘈杂的原始对话先压缩成结构化摘要、再合并进中心化人格画像、最后注入下一轮对话,两层结构解决细节全但太贵、纯摘要又丢质感的矛盾。
产品上的决定也是这么聊出来的。它问了几个问题,每个都把选项列好让我挑,比如解锁以后用户看到什么,伴侣挂在 /mbti 下面还是单独走一个路由,记忆要不要让用户看见。我一个个拍板。伴侣走独立的 /companion 路由,当成一个独立的产品原型来做,不挂在 MBTI 下面。定价一条消息 1 金鱼干,深度伴侣应该是值得花钱的体验。解锁的时候弹个庆祝弹窗。记忆面板做成只读但可以清除,先让用户放心,能不能改是次要的。
设计这段对话前后大概 30 分钟,聊完 claude code 把这些决定整理成一份完整的 spec,外加一个 6 阶段的实现计划。然后我让它在一个隔离的 git worktree 里开工,数据库迁移、后端 API、记忆管道、前端流程、解锁流程,每一层都是它写的。
claude code 设计 MBTI 长期记忆的实现计划
产品层面的决策:解锁体验、人格画像数据模型、深度伴侣路由
伴侣模式的设计:记忆可见性、定价和路由决策
仿真调试,跑一次炸一次
写代码只是前半程,后半程是仿真调试。我让 claude code 搭了一个端到端的算法仿真,一个 AI 模型演虚拟用户,一个演盘盘猫的 MBTI 和伴侣 AI,第三个当评审打分。三个模型互相喂数据,把完整的 5 次会话走一遍。
第一次跑就炸了。评审模型的 maxTokens 设了 600,太小,JSON 输出到一半被截断,整个评分管道直接崩,改到 1200 重跑。第二次跑,对话生成器吐出来的格式和验证器对不上,对话生成了 66 行,JSON 在中间断掉,maxTokens 从 3000 拉到 5000,顺手把提示词里对输出格式的约束也改了。第三次跑,session 1 和 session 2 的质量评分都到了 9/10,但合并画像到 session 2 的时候又被截断了,因为画像的 JSON schema 比预想的大,maxTokens 从 800 改到 1400。第四次跑,终于看到有用的质量反馈了,评审说「hesitations 捕捉准确,但可以补充用户对某个行为变化的回避」。每轮大概 10 分钟,四轮下来,claude code 的 context window 已经用到 79%。真实的开发就是这么循环的,跑一次,看哪炸了,改一行,再跑一次。
仿真测试代码:三个 AI 模型互相喂数据
仿真结果:MBTI 会话评分、人格画像提取、质量反馈
算法仿真验的是记忆质量,但还有一层得验,就是整条管道在真实环境里跑不跑得通。记忆提取是异步的,在请求结束以后的后台任务里跑,它要是悄悄失败了,用户根本不会知道。所以 claude code 又搭了一套集成仿真。它建真实的测试用户,打真实的 API,轮询数据库,等异步的记忆提取跑完,然后直接问伴侣 AI:「你还记得我在哪里工作吗?」要是能答出「上海」和「UI 设计师」,就说明从对话到摘要到画像再到注入,这条管道是通的。
集成仿真跑出来 7 个阻塞性 bug,全是工程上的问题,算法仿真发现不了。有的是数据库字段名对不上,Supabase 却不吭声地返回 200;有的是异步任务没把鉴权头转过去,记忆提取就永远跑不通;还有的是 token 预算不够,JSON 被截断。claude code 在同一个会话里一个个找出来,一个个修掉了。
整个 feature 从零到能测,不到一天。我全程没写一行实现代码,也没手动跑过一次测试。我干的是设计、讨论、拍板。记忆用摘要还是原文,画像多大,伴侣放在什么路由,解锁门槛设几次,这些得人来判断。数据库迁移、API 路由、记忆管道、仿真脚手架、编排三个 AI 模型、跑四轮调参、搭集成测试,这些重活脏活全是 claude code 干的。
还有一点挺关键,聊设计和写代码是在同一个 context 里。我说「记忆应该只增不减」,它就去改提示词;我说「跑一个集成仿真验证管道」,它就去搭测试用户、打 API、轮询数据库。从拍板到动手中间没有断档,我不用把结论再翻译一遍喂给另一个工具。
「你上次说过『我想要的不是建议』」
算法仿真完整跑的是 3 次 MBTI 会话加 2 次伴侣会话,看记忆能不能提出来、攒下来,再跨会话引用出来。虚拟用户叫「林晓月」,28 岁,UI 设计师。第一次 MBTI 会话里她提到一件事:
"改了好几版设计稿,最后选了第一版,会觉得有点无力。"
AI 把这句话提成一个记忆锚点,放在人格信号下面,记的是她碰到挫败时怎么应对,和事实类的摘要分开存。两次会话之后她解锁了深度伴侣。第一次伴侣对话里,她说最近在纠结一个大厂的机会,来回聊了几轮,AI 说了一句:
"改了几版最后用第一版那种无力感,是不是又来了?"
林晓月回的是「对,就是那种感觉」。从工程上看,这一步就是跨会话引用记忆。AI 没有回头看原始对话记录,它手里只有那份 400 token 的人格画像,是画像里那个锚点在这时候被调了出来。
第二次伴侣会话,她说最近失眠,躺下脑子就开始转,聊着聊着说到男朋友小明:「他说的都对,但我听完心里堵堵的。他让我别想太多,早点睡。」AI 没顺着安慰她,把她在第二次 MBTI 会话里说过的一句话拿了回来:
"你上次说过'我想要的不是建议'。小明是不是常这样,道理都对,但不是你想听的?"
她回答:「对。他不是不关心,但我说完一件事他就想帮我解决。」AI 接着说:「你需要的是有人陪你待在那个情绪里,不是马上被拉出来。」她又说:「但我也没跟他说过我真正想要什么,觉得说了好像在怪他。」
她本来在抱怨「他不听我说」,到这里开始看到自己的模式。她一直压着需求不说,因为怕一说出来就成了指责。AI 把这一点点破之后,她说:
"他确实不是那种会觉得我矫情的人。是我自己先把门关上了。"
整段对话里 AI 没给建议,也没做分析,就是拿她自己说过的话,把她带回一个她一直绕着走的问题。不是对方不理解她,是她没给过对方理解她的机会。这种理解给你的未必是你想听的,但能帮你看见自己看不见的地方。我在伴侣构想里想让 AI 学会的就是这个。仿真跑完,10 个评分维度平均 8.1/10,核心的飞轮算是转起来了。
新记忆把旧记忆吃了
8.1 分就是能用,但还不完美。仿真暴露出来的问题是,AI 把新的对话摘要合并进人格画像的时候,有时会直接拿新内容把旧内容换掉,本来该一点点攒着的,变成了覆盖,新的直接把旧的顶掉。具体是这样的,MBTI 阶段攒下的偏好「喜欢创作(写作/绘画)」,在伴侣会话之后被新条目盖掉了;记忆锚点「被别人的情绪吸收会觉得累」直接没了;大厂跳槽这条没解决的线索,一次次被换成更表面的问题。
画像合并时若新摘要直接覆盖旧条目,积累的偏好和记忆锚点会消失;改成只增不减规则后旧记忆才能活过一轮轮合并。
这正好验证了伴侣构想里的那个判断,记忆编排难就难在「编排」两个字。把信号提出来是容易的那部分,难的是让先存下来的信号熬过后面一轮又一轮的合并。
修法只动了提示词。claude code 在合并画像的提示词里加了一组「只增不减」的规则,架构代码一行没动,纯靠调 prompt:
memorableMoments:只增不减。每条都是一次真实对话的记忆碎片,建立"活人感"的核心资产。除非用户明确说某件事已经解决并且不再有意义,否则永远不要删除。
preferences:只增不减。绝对不要删除或覆盖已有条目——用户的喜好是跨会话累积的。
unresolvedThreads:谨慎移除。"话题没被提到"或"对话转移"不算解决。优先保留涉及深层内心冲突的线索,而非表面信息缺口。
这类系统怎么表现,大半是提示词那一层定的。而且提示词也不是一次写成的,初版的画像 schema 里压根没有 memorableDetails 和 unresolvedThreads 这两个字段,是跑仿真的时候发现缺了才补上的。设计和测试是搅在一起做的,或者说,schema 也是跑出来的。
这一版验下来,整条链路是通的。AI 从对话里攒下对用户的理解,记进画像,之后在合适的时候提起来,让人觉得自己被理解了。当然离完美还远。画像怎么攒,还得靠更多实战数据去磨;伴侣的语气和节奏要调得更自然;context window 的预算怎么分,也得做更细的 context engineering。下一步是把它交给真实用户,看画像离开仿真还长不长得出来。


