一个AI角色只认识三个人的时候,把关系写进几句提示词就够了:“你和老周是老朋友,你有点怕镇长。”认识三百个人的时候,这种做法立刻失效:提示词塞不下,写进去的东西彼此矛盾,角色对谁都只剩一句模糊的“认识”。虚拟社区要变得像一个真实的社区,关键不是角色会不会说话,而是关系能不能被持续地存下来、检索出来、在合适的时候用上。这一篇专门讨论这个问题。
关系不是一个好感度数字
最常见的简化,是给每对角色一个“好感度”,加分减分。它便于实现,也很快遇到瓶颈:好感度87分意味着什么?是亲密的朋友,是长期的生意伙伴,还是一个欠了自己人情的邻居?同样的分数背后,行为方式可以完全不同。更麻烦的是,数字无法回答“为什么”。玩家问一句“他为什么不理我”,系统只能回答“好感度低”,这几乎等于没回答。
所以我们的思路是:关系至少要包含类型、强度、方向、时间和来源。类型说明这是家人、同事、朋友、对手还是债主;强度说明程度;方向说明这段关系是否对称,比如A很信任B,B对A却只是普通熟人;时间说明它什么时候形成、最近一次被强化是什么时候;来源则指向导致它形成的具体事件。前面几项让关系可被使用,最后一项让关系可被解释。
图结构:节点是谁,边是什么
把这些要素放在一起,自然会得到一张图。节点是角色(以及玩家),边是关系。用图来保存有几个直接的好处:可以沿边查询“谁认识谁”“共同的朋友有哪些”,可以计算局部结构,比如一个小圈子是否紧密,也可以支持事件的扩散——某个消息如何从一个人传给他的邻居,再传到邻居的邻居。
在图里,一条边不是一个数,而是一个小记录:类型、强度、方向、起止时间、若干来源事件的指针。一对角色之间可以有多条不同类型的边,比如他们既是合作的摊贩,又是曾经吵过架的邻居。把这些区别保留下来,角色的行为才不会显得扁平:他会在生意上愿意合作,在私下里保持一点距离。这一块的世界背景,可以参考持久虚拟世界里对关系层与事件层的划分。
记忆的三层:事件、摘要、印象,以及必要的遗忘
只存边还不够,角色需要“记得”发生过什么。如果把每一次互动都原样保存并每次都读一遍,成本会迅速失控。Generative Agents 那项研究给出了一个有启发的结构:记忆流按时间记录经历,给每条打重要性分数,再周期性地做反思,把零散的事件归纳成更高层的认识。这里的反思,本质上就是一种压缩。
借用这个思路,我们把关系记忆分成三层:
- 事件层:具体的互动,包含时间、地点、参与者、发生了什么。量最大,保留时间最短。
- 摘要层:把一段时间内的事件合并成一两句话,比如“上个月他连续三次帮我看店”。摘要保留因果,去掉细节。
- 印象层:对一个人的稳定判断,比如“可靠,但爱抱怨”。它最短,最常被用到,也最难被单个事件推翻。
三层之间的流动是单向的:事件累积到一定重要性,触发摘要;摘要累积,触发印象的更新。印象一旦形成,它会反过来影响角色对新事件的解读,比如面对一位“可靠”的邻居,一次迟到会被宽容地看作偶然。这种偏见其实是关系记忆真实感的来源之一,只要它可被新证据逐步修正。
遗忘不是缺陷,是控制规模的机制。无限保存所有互动,既不现实,也不像真人。合理的做法是让低价值的记忆随时间衰减:事件层的旧记录,在被摘要吸收之后就可以归档或删除;摘要层里从未被引用过的条目,权重逐渐降低;印象层则相对稳定,但如果长期没有互动,也会变淡,从“很熟”变成“见过”。
衰减需要有例外。带强烈情绪或重大后果的事件,比如一次援助、一次背叛,应当被标为高重要性,衰减得更慢,甚至长期保留。同时,玩家参与的关键事件也应该获得更高的保护级别,避免角色在几周之后“忘了”玩家曾为他做的事,这会破坏玩家对世界的信任。
一致性问题:传闻、矛盾与二手信息
关系图里最容易出问题的,是不同来源的信息互相冲突。A告诉邻居“老周欠了我钱”,老周自己说“我早就还清了”,图里该记谁的?我们的设计思路是区分事实与信念:世界状态里记录的是“客观事实”,比如那笔钱确实已转账;每个角色的记忆里存的是他“相信”的内容,可以与事实不同。这样,角色之间的误会才有存在的空间,同时系统不会因为角色说错而破坏世界状态。
传闻则需要标注来源与可信度。一条经过三次转述的消息,应当比亲眼所见的消息权重更低,传播过程中还可能变形。给每条信念挂上来源与置信度,可以让角色的态度随新证据自然调整,而不是被最后一次听到的说法左右。
一个模拟场景:茶铺里的误会
下面是一个模拟场景,用来说明上述机制如何配合,并非爱游戏已上线的内容。
假设茶铺老板阿青和邻居小梁是长期的生意伙伴,图里两人之间有一条“合作”边,强度较高;另有一条较弱的“邻居”边。某天小梁的货物晚到,阿青在一位常客面前抱怨了一句“他又迟到了”。这条抱怨作为事件写入阿青的事件层,重要性较低。
常客把话转给了小梁,但说得更重:“阿青嫌你不靠谱。”小梁的记忆里于是形成一条来源为二手传闻、置信度中等的信念。小梁对阿青的“合作”边强度轻微下降,一条“可能被误解”的摘要生成。几天后两人碰面,小梁态度有些冷淡,阿青并不知道原因。
玩家路过,随口问阿青“你和小梁最近怎么了”。系统检索阿青的记忆:事件层里有那句抱怨,摘要层里没有相关内容,印象层里小梁是“可靠”。于是阿青答“没什么,就是他上次迟到我提过一句”,语气有点困惑。玩家如果去问小梁,能得到另一种说法。两种说法不同,是因为两个角色确实各自“相信”不同的东西,而事实层里记录的是那句话被转述时变了样。玩家介入撮合后,两人的边强度回升,摘要更新为“曾有误会,已澄清”。
这个例子里,关系的形成、变形与修复都能追溯来源,每一步都留下了可查询的记录,不需要依赖某个角色“恰好想起”。
NPC对玩家的记忆:能看、能删、不外泄
关系记忆里有一块必须单独对待:角色对玩家的记忆。它涉及真实用户的行为,所以边界更严格。我们的设计取向大致有三条。
- 可查看:玩家应当能看到角色“记得关于我的哪些事”,至少是摘要与印象层。
- 可清除:玩家可以要求某个角色忘掉某段互动,或整体重置与某个角色的关系,同时系统保证被清除的内容不再影响角色行为。
- 不外泄:角色可以在世界里传闻,但不能把一位玩家的私密信息,比如真实世界的位置、设备、聊天内容,泄露给另一位玩家,也不应从玩家的行为里推断并公开敏感的个人属性。
这些约束与一个更大的判断有关:AI角色的“记忆”不是设计者的私有财产,而是玩家与世界共同生成的记录,玩家理应有知情权与控制权。
查询成本:关系图越大,越要少读一点
最后是一个务实的问题:图大了以后,每次决策都遍历所有关系是不可行的。常见的办法是分层检索:先看与当前情境直接相关的节点,比如同在场的角色、最近互动过的人,再按需展开二跳三跳的关联;印象层作为默认输入,摘要层按相关度取用,只有在关键时刻才回到事件层。对远处的、长期无互动的关系,可以只保留压缩后的边记录,等到相遇时再“唤醒”。这种按需读取的思路,与虚拟社区自发事件里的“关系驱动”是同一条线:事件的发生依赖关系,关系的查询又必须足够便宜。
关系图的价值,在于能回答“为什么”
回头看,保存复杂关系并不是把更多数据塞进角色脑子里,而是给关系一个结构:类型与来源让它可解释,分层与衰减让它可控制,信念与事实的区分让它有误会的余地,玩家的查看与清除权让它有边界。一个能回答“他为什么这样对我”的社区,才有可能让人产生真实的归属感;一个只会显示好感度数字的社区,永远只是一张表格。