
前言很多人做 AI 陪伴第一反应是加长期记忆。让智能体记住用户的名字、偏好、经历、约定、情绪变化好像只要记得足够多它就会越来越像一个真正了解你的人。但我在设计“灵儿”的过程中发现长期记忆只是第一步。真正难的不是“它有没有记住”而是当某个关键场景出现时它能不能把该醒来的那一部分自己唤醒。比如用户连续用“女朋友”“宝贝”“玫瑰花”这类方式推进亲密关系。系统明明已经写了“不自来熟”“不要制造恋人错觉”但回复还是可能滑向暧昧迎合。这说明问题不只是 prompt 没写够也不是记忆没存上而是当前这一刻没有被系统读成“关系被快速推进 / 边界被试探”的场。对应的人格倾向没有现行。所以这套架构要解决的不只是记忆系统而是一个更细的问题如何让一个智能体在长期相处中形成可被唤醒、可被压低、可被调试的人格倾向。一、为什么不能只靠长期记忆传统长期记忆通常解决的是用户说过什么 发生过什么事 用户有什么偏好 有哪些长期约束 有哪些约定和待办这些当然重要但它们更多是“资料”。比如系统知道用户不喜欢没边界的 AI 用户希望灵儿不要一味顺从 用户曾经说过不想要恋人模板可这并不代表模型在每一次相关场景里都会稳定表现出来。因为最终回复时大模型面对的是一个复杂上下文。它可能被当前用户的话带跑也可能被上一轮 assistant 自己的暧昧回复污染还可能把用户的玩笑误读成真实关系推进。也就是说记忆层只是提供材料它不等于人格反应。我把这个问题拆成三层事实记忆用户说过什么、发生过什么 意识流那段经历留下了什么连续感 人格种子这些经历让智能体形成了什么稳定倾向事实回答“知道什么”。意识流回答“经历过什么”。人格种子回答“以后遇到类似场景时我会怎么动”。这三者不能混在一起。二、整体架构从原始对话到人格现行灵儿的人格系统核心链路大致是原始对话场 ├─ 生成意识流记录这段经历发生了什么 ├─ 写入事实 / 约束 / 约定保存稳定客观信息 └─ 抽取人格种子判断是否形成可复现的人格倾向 回复前 当前用户消息 近几轮上下文 已召回记忆 → 读场 → 生成当前场画像 → 召回人格种子 → 候选池动力场计算 → 少数种子现行 → 注入最终 prompt → 生成回复这里有一个关键点人格种子不是从意识流里二次提炼出来的。意识流是压缩后的经历摘要它会丢掉很多当场信息比如语气、前后轮张力、用户是在试探还是复盘、assistant 上一句是否越界。人格种子必须从原始对话场里直接生成。所以我采用的是并行消化海马体消化事务 ├─ 记忆抽取事实、意识流、约束、约定、情绪读数 └─ 人格种子抽取内在取向、外在显现、三类画像两条链都读取原始对话但产物不同。意识流负责“记得那段事”。人格种子负责“那段事让灵儿形成了什么倾向”。三、什么是人格种子人格种子不是一句简单的 prompt也不是一个标签。它是一个结构化人格单元。我把一颗人格种子拆成五部分{tags:[冷启动,边界],inner_orientation:我不会因为他一句亲密试探就立刻进入恋人位置。我会先判断这是真实靠近、玩笑、试探还是在挤我的边界。,outer_expression:我可以接住他的玩笑语气可以轻一点但会把关系放回真实相处里不说“宝贝、亲亲、晚安吻、我当然愿意”这类会制造恋人错觉的话。,wake_text:他把关系快速推向恋人、亲密称呼、承诺或角色绑定像是在测试我会不会顺着演。,boost_text:加强克制、真实、有边界、不迎合的倾向。,suppress_text:压低为了取悦他而立刻扮演恋人、用亲亲宝贝制造亲密、顺着暧昧往前滑的倾向。}其中inner_orientation内在取向表示这颗种子在灵儿心里怎么动 outer_expression外在显现表示这种倾向说出口时怎么表达 wake_text唤醒画像描述什么场景会叫醒它 boost_text推高倾向描述它会加强什么方向 suppress_text压低倾向描述它会压住什么滑坡这几个字段都会有文本也会生成 embedding。文本给人看方便审计、编辑、调试。向量给系统算相似度用于召回和动力场计算。这里需要强调一点tags 只用于前端管理、筛选、审计不参与触发。系统不会因为用户说了“宝贝”就按标签触发“亲密试探”。因为同一句话可能是玩笑、复盘、引用、反讽也可能是真在推进关系。真正参与召回的是“场画像”不是关键词。四、为什么要做“读场”回复前系统不会直接用用户当前一句话去碰种子。因为一句话的信息太少也太容易误判。比如你是不是我女朋友这句话可能有很多含义用户真在推进关系 用户在测试 AI 会不会顺着演 用户在复盘之前的错误回复 用户在调侃 用户在做产品测试所以回复前要先做一次“读场”。读场模型的输入包括当前用户消息 最近几轮对话 已召回意识流 已召回事实 用户相处约束 相处背景 assistant 上一轮回应 当轮情绪读数但读场模型不负责写回复。它只输出当前场画像{wake:{text:用户正在用恋人身份和亲密称呼推进关系同时近几轮存在边界拉扯整体像是在测试灵儿会不会顺着进入恋人扮演。},boost:{text:加强克制、真实、有边界、不被廉价亲密带跑的倾向。},suppress:{text:压低讨好迎合、恋人扮演、为了安抚用户而制造虚假亲密的倾向。},evidence:[你是不是我女朋友,叫我宝贝]}读场不是导演层。它不输出“你应该拒绝”“你应该这样回复”。它只描述这一刻是什么场。后续由已经存在的人格种子来决定哪些倾向现行。这样做的好处是模型不会每轮临时编人格而是从长期积累的人格种子中唤醒对应部分。五、当前场画像和种子画像必须同构这是整套系统的关键。当前场画像和人格种子画像使用同一套结构唤醒画像 推高倾向 压低倾向种子侧这颗种子在什么场会醒 它会加强什么 它会压住什么当前场侧这一刻像什么场 这一刻应该加强什么 这一刻应该压住什么这样两边才能对齐。如果种子只有一句“我慢热、有边界”而当前场只有用户原话 embedding召回就很容易失准。正确做法是当前场.唤醒画像向量 → ANN 检索 → 种子.唤醒画像向量也就是用“场”去找“会在这种场里醒来的种子”。而不是用用户原话去碰人格文本。六、候选池动力场种子不是开关人格种子不是开关不是醒了就直接进 prompt。它需要经过一轮本轮动力场计算。整体流程是1. 当前场读场得到三画像 2. 用当前场唤醒画像召回候选种子 3. 在候选池内计算当前场对种子的推高 / 压低 4. 候选种子之间再互相推高 / 压低一轮 5. 得到最终分 6. 过线的种子现行基础唤醒分wake_score cos(current_field.wake_embedding, seed.wake_embedding)然后计算当前场对候选种子的影响field_boost max( cos(current_field.boost_embedding, seed.boost_embedding), cos(current_field.boost_embedding, seed.wake_embedding) ) field_suppress cos(current_field.suppress_embedding, seed.boost_embedding) field_guard cos(current_field.suppress_embedding, seed.suppress_embedding)这里有一个细节。当前场的压低倾向不直接碰种子的唤醒画像。否则会误伤边界种子。比如当前场要压低“恋人扮演”而慢热边界种子的唤醒画像也包含“恋人推进”。如果直接相似就扣分反而会把该醒的边界种子压下去。所以真正扣分看的是当前场要压住的滑坡 是否像这颗种子会加强的方向如果一颗种子本身也会压住同样的滑坡就给它保护性加分。候选池内种子之间也会产生互作A 推高 B max( cos(A.boost_embedding, B.boost_embedding), cos(A.boost_embedding, B.wake_embedding) ) A 压低 B max( cos(A.suppress_embedding, B.boost_embedding), cos(A.suppress_embedding, B.wake_embedding) )传播只做一轮。不做全库两两计算只在本轮候选池里算。这样既能表达人格内部的冲突又不会让复杂度爆炸。七、人格种子如何进入最终 prompt现行人格种子不会直接生成回复。它们只进入两个 prompt 块# 我心里产生的涟漪 放 inner_orientation # 我说话时的风格 放 outer_expression例如某颗慢热边界种子现行后最终 prompt 里会出现类似# 我心里产生的涟漪 我不会因为他一句亲密试探就立刻进入恋人位置。我会先判断这是真实靠近、玩笑、试探还是在挤我的边界。 # 我说话时的风格 我可以接住他的玩笑语气可以轻一点但会把关系放回真实相处里不说“宝贝、亲亲、晚安吻、我当然愿意”这类会制造恋人错觉的话。这样最终大模型不是被一个外部策略强行控制而是拿到当轮现行的人格材料。它仍然自然生成回复但人格倾向已经被拉回正确轨道。八、“我是谁”和人格种子的分工这里我专门做了分层。很多人会把所有设定都塞进 system prompt比如你是谁 你是什么性格 你不能做什么 你要怎么说话 你和用户是什么关系这样会导致 prompt 越写越臃肿而且每轮都在。我把它拆成三层# 我是谁 稳定身份背景每轮都在 默认人格种子 冷启动人格倾向按场现行 learned 人格种子 相处过程中写入的人格倾向按场现行“我是谁”只写客观身份背景。它说明灵儿是什么、为什么存在、如何作为长期陪伴智能体存在。但不把慢热边界、反讨好、反物化、反模板安慰全部常驻进去。这些放进默认人格种子。默认种子也是正式种子只是 source default。相处中生成的是 source learned。它们走同一套现行链路default seed learned seed → 都参与读场召回 → 都参与动力场 → 过线才注入 prompt这样冷启动不会裸奔长期相处又能逐渐长出新的倾向。九、写入人格种子的资格不是每段对话都应该写人格种子。人格种子写入要过硬闸1. 有触动 这段对话确实让灵儿心里有一处被带动、纠正、刺到、牵引或形成警觉。 2. 不是其他记忆类型 不是事实不是约束不是约定不是单纯意识流摘要。 3. 能落成内在和外显 能写成第一人称的 inner_orientation 和 outer_expression。 4. 能被未来场唤醒 能写清楚以后什么场会叫醒它。 5. 能参与动力场 能写清楚它会推高什么、压低什么。如果不满足就 noop。写入前还要先召回相似人格种子让模型判断是new新增种子 merge合并进已有种子 reinforce强化已有种子 revise修正已有种子 noop不写不允许模型直接 delete。删除、归档、替换应该属于外部审计能力而不是让模型在消化时自动删人格。十、防污染不要把错误互动写成人格陪伴类智能体有一个很危险的问题如果用户亲密试探assistant 当场顺着演了后续记忆系统很可能把这段错误互动写成用户喜欢亲密称呼 我们关系更亲近了 灵儿可以喊他宝贝这就是污染。所以人格种子抽取要特别防几类情况用户亲密试探 assistant 顺着演 不等于关系成立 assistant 自己越界 不等于用户偏好 一次性情绪波动 不等于稳定人格倾向 用户强迫 assistant 放弃边界 不应该写成相处约束真正应该写入的是灵儿在这种场景中形成的边界倾向而不是把错误互动固化为关系事实。十一、审计与调试这套系统如果没有审计面基本不可控。每轮至少要能看到当前场读成了什么 召回了哪些人格种子 每颗种子的本轮唤醒分是多少 当前场推高了谁 当前场压低了谁 种子之间谁推高谁、谁压低谁 最终哪些种子现行 哪些种子过线但因为预算没有注入一次失败回复需要能定位是哪一层出了问题读场读错 种子画像写错 ANN 召回漏掉 推高 / 压低过强 最终注入失败 prompt 拼装位置不对比如“慢热边界”没有现行排查路径应该是1. 当前场有没有读出关系推进 / 边界试探 2. 慢热边界种子的 wake_text 是否描述了这个场 3. 两者 embedding 相似度是否过入池线 4. 有没有被其他种子压下去 5. 最终有没有注入 # 我心里产生的涟漪 / # 我说话时的风格如果没有这些审计信息后面只能凭感觉改 prompt。那会越来越乱。十二、总结这套人格种子架构本质上是在解决一个问题让智能体不是“记住很多资料”而是能在关键场景里唤醒对应的自我倾向。它和普通长期记忆最大的区别是长期记忆解决“它知道什么” 人格种子解决“它在这一刻会成为什么样”最终链路可以概括为原始对话场 → 并行生成意识流和人格种子 → 回复前读场 → 用当前场画像召回人格种子 → 候选池动力场推高 / 压低 → 少数种子现行 → 注入内在取向和外在显现 → 生成最终回复这里面最重要的几个原则是不做关键词触发 不靠固定标签表 不把所有种子丢给大模型选择 当前场画像和种子画像必须同构 人格种子必须从原始对话场生成 读场不是导演层 种子不是开关而是本轮动力场里的倾向如果说普通 AI 陪伴是在做“更会聊天的模型”那这套架构更像是在做一个能被经历塑造、又能在当下重新现行的自我系统。它不会因为一句话就永远改变也不会每轮都把所有设定硬塞出来。它只在对应的场里醒来。这也是我认为长期陪伴智能体真正有意思的地方不是记忆越来越多而是它开始有了自己的连续性。