Skip to content

日记

模拟最直观的输出。每个 NPC 每天写一篇。

为什么是日记?

日记是玩家窥探 NPC 内心世界的窗口。它是:

  • 📖 玩家阅读的主要内容
  • 🪞 表达情感和反思的最自然方式
  • 🎭 观察性格和记忆发挥作用的最佳场所

如果日记写得好,模拟就是好的。如果日记写得差,底层再精妙的 AI 也无济于事。


什么时候写?

每个游戏日的 22:00

此时刚过晚餐,还未入睡。NPC 独自在家,准备休息。这是一个自然的反思时刻。


日记的内容

输入

Prompt 结构

ts
const prompt = `
You are ${npc.name}, a ${npc.age}-year-old ${npc.profession}.
Your personality: ${formatPersonality(npc.personality)}.
Your home: ${npc.home}.
Your family: ${formatFamily(npc.family)}.

Today is Day ${worldTime.day} (${worldTime.season}).
The weather today was: ${todayWeather}.
Your mood today was mostly: ${avgMood}.

Today's events (compressed):
${todayEvents}

Recent memories worth noting:
${recentMemories}

You are writing tonight's diary entry. It should be:
- 2-4 paragraphs
- Written in first person
- In your voice (${npc.styleHints})
- Reflecting on the day honestly
- Mentioning any people you interacted with
- Ending with a brief thought about tomorrow

Important:
- Do NOT invent events that didn't happen.
- Do NOT be overly dramatic. Ordinary days are fine.
- Be true to your personality.
- Keep it under 400 words.

Begin:
`;

风格提示

每个 NPC 有自己的风格提示,偏置 LLM 的输出:

NPC风格提示
Margaret"冷幽默、善于观察、略带忧伤"
Tom"务实、话少、偶尔冷笑话"
Eleanor"温暖、有点八卦、母亲般的"
Sam"豪爽、爱提喝酒的事"

这些提示来自 NPC 的性格 + 自定义特质。


长度

  • 目标: 200-400 字
  • 硬上限: 500 字(由 prompt + 后处理强制执行)
  • 最低: 100 字(不允许"今天还行。"这种一行了事)

如果 LLM 生成的日记太短或太长,系统会调整 prompt 指令后重试。


基调校准

为了防止"AI 戏剧化"问题(每篇日记都像过山车),我们对基调进行校准:

ts
const toneCalibration = {
  baseline: 'ordinary day, modest reflection',
  overrides: {
    if (avgMood === 'happy' && intensity < 0.6) return 'quietly content';
    if (avgMood === 'sad' && intensity < 0.6) return 'slightly subdued';
    if (avgMood === 'angry' && intensity < 0.6) return 'mildly irritated';
  }
};

在 prompt 中这样使用:

"Tone: ${toneCalibration}"


校验

生成后,每篇日记都会被校验:

ts
function validateDiary(entry: string, todayEvents: Event[]): ValidationResult {
  // 1. Length check
  if (entry.length < 100) return { ok: false, reason: 'too short' };
  if (entry.length > 2500) return { ok: false, reason: 'too long' };

  // 2. No fabricated events
  // (LLM-based check: does the diary mention anyone who wasn't actually present?)

  // 3. No clichés
  const bannedPhrases = ['and so it was', 'as the sun set', 'another day in paradise'];
  for (const phrase of bannedPhrases) {
    if (entry.includes(phrase)) return { ok: false, reason: 'cliché' };
  }

  // 4. Style check
  // (LLM-based: does this match the NPC's style hints?)

  return { ok: true };
}

校验失败的日记会重新生成,最多重试 2 次。


存储

ts
interface DiaryEntry {
  id: string;
  npcId: string;
  worldTime: { day: number, hour: number };
  text: string;
  mood: Emotion;
  promptHash: string;       // for reproducibility
  generatedAt: ISO8601;
  generationCost: number;   // LLM tokens used
}

存储在 D1 表 npc_diary 中。按 (npcId, day) 索引以便快速检索。


玩家看到什么

  • 世界地图上每个 NPC 最新一篇日记。
  • 可滚动浏览的历史日记时间线。
  • 跨所有 NPC 的日记全文搜索。

日记是 AI World Sim 的内容核心。其他一切都是为生产日记而存在的基础设施。


示例

一篇好日记(Margaret,第 47 天)

"上午下了大半天的雨,正好待在家里看书。我读完了那本勃朗特的小说——下雨天读太伤感了,但就是放不下。下午雨停了,走去市场。Maria 在那,看起来很疲惫。她说最近生意不好。我买了韭葱,聊了聊她儿子,听说在学校表现不错。晚上差点不想去酒馆,但还是去了。Eleanor 在那。我们没聊什么特别的,挺好的。有时候,最好的聊天就是这样。"

一篇差日记(被校验拒绝)

"今天是我人生中最最最最棒的一天!!!一切都很完美,每个人都太好了,我太感恩能活着了!!!"

拒绝原因:

  • 感叹号过度使用
  • 不符合 Margaret 的性格(内敛)
  • 没有提及具体事件
  • 违反基调校准

Released under the MIT License.