我把盘盘猫的记忆做出来了
盘盘猫有一款 MBTI 人格测试,不是勾选题那种,是用对话来理解你:你的措辞、你的推理方式、碰到模糊问题时的反应。每一轮对话其实都在采集人格信号,拿到的东西比问卷多得多。测试本身做得挺好,但有个很要命的问题:做完一次,下次回来 AI 就把你忘了。用户聊了 20 分钟,把职业困惑、感情纠结、对大厂机会的恐惧全说了,关掉页面再回来,还是那句「嗨,很高兴认识你!」,跟初次见面一样。
我在 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。下一步是把它交给真实用户,看画像在仿真之外长不长得出来。


