Skip to content

情感

NPC 的感受——派生状态,而非存储状态。始终新鲜,始终有上下文。

核心理念

AI World Sim 中的情感是派生的,不是存储的。

这意味着 NPC 的情感每次都是全新计算的,基于他们当前的需求 + 最近的事件。不存在一个随时间衰减的"愤怒值"。只有"考虑到刚刚发生的事和他们当前的状态,他们此刻感觉如何?"

这比将情感存储为状态变量能产生更自然的行为。


情感模型

离散标签

NPC 在任何时刻感受到以下情感之一:

ts
type Emotion =
  | 'happy'
  | 'sad'
  | 'angry'
  | 'anxious'
  | 'lonely'
  | 'content'
  | 'frustrated'
  | 'excited'
  | 'bored'
  | 'neutral';

加上强度

ts
type EmotionalState = {
  label: Emotion;
  intensity: number;  // 0-1
};

情感如何派生

Step 1 — 基于需求的基础分

ts
function emotionFromNeeds(needs: Needs): EmotionScore {
  let score = { happy: 0, sad: 0, anxious: 0, ... };

  if (needs.hunger > 80) score.frustrated += 0.6;
  if (needs.energy < 20) score.bored += 0.4;
  if (needs.social > 70) score.lonely += 0.7;
  if (needs.health < 30) score.sad += 0.5;
  if (needs.fun > 70) score.bored += 0.5;

  return score;
}

Step 2 — 事件修正

最近的事件会偏移分数:

ts
const eventModifiers = {
  'argument': { angry: +0.8, anxious: +0.3 },
  'good_news': { happy: +0.7, excited: +0.3 },
  'lost_money': { sad: +0.4, anxious: +0.6 },
  'met_friend': { happy: +0.6, content: +0.3 },
  'got_praised': { happy: +0.5 },
  'got_insulted': { angry: +0.6, sad: +0.3 },
};

Step 3 — 性格修正

ts
function personalityModifier(emotion: Emotion, personality: Personality): number {
  if (emotion === 'anxious' && personality.neuroticism > 0.7) return 1.5;
  if (emotion === 'happy' && personality.neuroticism > 0.7) return 0.5;
  if (emotion === 'lonely' && personality.extraversion < 0.3) return 1.4;
  return 1.0;
}

Step 4 — 记忆召回

有时系统会召回一段相关记忆,影响当前情感:

Margaret 刚刚听到了 Tom 的名字。她想起了上周他们吵的那架。她当前的情感被推向沮丧 + 难过。

Step 5 — LLM 精调(可选)

在模糊情况下,会咨询 LLM 来在得分接近的情感之间做选择。


情感影响什么

情感影响:

系统影响方式
决策偏向与情感一致的行为
对话语气、措辞
日记整体基调
关系生气时更容易得罪人,等等

情感衰减

情感默认不会跨 Tick 持久化。每个 Tick 都会重新派生。

然而,强烈的情感(强度 > 0.8)会留下记忆痕迹:

ts
if (state.intensity > 0.8) {
  await memory.write({
    type: 'emotion',
    content: `Felt very ${state.label} because ${event.summary}`,
    importance: 0.9,
  });
}

这段记忆可以在类似情境出现时重新触发情感。


心境 vs 情感

我们做了细致的区分:

  • 情感 —— 当前的、派生的、持续一个 Tick
  • 心境 —— 更长期的基线,跨 Tick 持久化,由近期情感的滚动平均计算
ts
function computeMood(npc: NPC): Emotion {
  // Average last 24 hours of emotions
  // Weight recent ones higher
  // Return dominant mood
}

心境决定了一个 NPC 在几周内是整体暴躁还是整体开朗。


情感在日记中的体现

日记生成以 NPC 当天的平均情感作为主导基调:

"今天挺满足的。没什么特别的事,但也没什么坏事。"

如果当天的情感波动较大,日记可能反映这一点:

"早上焦虑,晚上开心。下午 Eleanor 来了,我们聊了一个小时。"


故障模式

情感系统经过调优,避免以下情况:

  • 持续戏剧化 —— NPC 每个 Tick 都感受极端情感
  • 情感平坦 —— NPC 永远没有感受
  • 不连贯的情绪波动 —— 无缘无故的剧烈情绪变化

基线假设是:大多数 NPC 在大多数日子里感受的主要是满足或中性。强烈的情感留给真实事件。

Released under the MIT License.