# 狼人杀 Workflow 设计文档 ## 概述 用 Pulse workflow 实现 AI 狼人杀。每个玩家是一个 Role(背后一个 LLM), moderator 是主持人控制阶段轮转和胜负判定。 ## 游戏配置(9人局) | 身份 | 数量 | 阵营 | |------|------|------| | 狼人 | 3 | 狼 | | 预言家 | 1 | 好人 | | 女巫 | 1 | 好人 | | 猎人 | 1 | 好人 | | 村民 | 3 | 好人 | ## 核心设计 ### 信息可见性 — 关键创新点 每个 Role 的 `prepPrompt(chain)` 过滤 chain,只暴露该角色可见的信息: ```typescript function filterChainForPlayer(chain: WorkflowMessage[], playerId: string, identity: Identity): WorkflowMessage[] { return chain.filter(msg => { const phase = msg.meta?.phase as string; const target = msg.meta?.visibleTo as string[] | undefined; // 公开阶段(白天发言、投票结果、死亡公告)所有人可见 if (phase === 'day-speech' || phase === 'vote-result' || phase === 'death') return true; // 狼人夜晚讨论:只有狼人可见 if (phase === 'wolf-night' && identity.team === 'wolf') return true; // 预言家验人:只有预言家自己可见 if (phase === 'seer-check' && target?.includes(playerId)) return true; // 女巫信息:只有女巫自己可见 if (phase === 'witch-action' && target?.includes(playerId)) return true; // 系统消息(角色分配等):只有目标可见 if (phase === 'system' && target?.includes(playerId)) return true; return false; }); } ``` ### Role 设计 不是每个玩家一个 Role。而是 **每个阶段一个 Role**,Role 内部遍历该阶段需要行动的玩家: ```typescript type WerewolfRoles = { // 夜晚阶段 'wolf-night': Role; // 狼人讨论+投票杀谁 'seer-check': Role; // 预言家验人 'witch-action': Role; // 女巫用药 // 白天阶段 'day-speech': Role; // 所有存活玩家依次发言 'vote': Role; // 投票放逐 // 特殊 'hunter-shot': Role; // 猎人开枪(死亡触发) // 结算 'game-end': Role; // 生成游戏总结 }; ``` ### 阶段内多玩家执行 每个阶段 Role 内部对多个玩家分别调 LLM: ```typescript const daySpeechRole: Role = async (chain, topicId, store) => { const state = parseGameState(chain); const speeches: PlayerSpeech[] = []; for (const player of state.alivePlayers) { // 过滤 chain,只给该玩家可见的信息 const visibleChain = filterChainForPlayer(chain, player.id, player.identity); // 调 LLM(通过 Sigil executor) const speech = await invokeLlm({ system: buildPlayerPrompt(player), messages: visibleChain, instruction: '现在轮到你发言,分析场上局势,表达你的观点。', }); speeches.push({ playerId: player.id, speech }); } return { content: speeches.map(s => `【${s.playerId}】${s.speech}`).join('\n\n'), meta: { speeches, phase: 'day-speech', visibleTo: null }, // 公开 }; }; ``` ### Moderator — 主持人 ```typescript function werewolfModerator( output: ModeratorInput, topicId: string, ): keyof WerewolfRoles | typeof END { if (output.role === START) return 'wolf-night'; // 天黑请闭眼 const state = output.meta?.gameState as GameState; // 胜负判定 if (state) { const wolves = state.alive.filter(p => p.team === 'wolf'); if (wolves.length === 0) return 'game-end'; // 好人胜 if (wolves.length >= state.alive.length - wolves.length) return 'game-end'; // 狼人胜 } // 阶段轮转 switch (output.role) { case 'wolf-night': return 'seer-check'; case 'seer-check': return 'witch-action'; case 'witch-action': return 'day-speech'; // 天亮了 case 'day-speech': return 'vote'; case 'vote': { // 猎人被投票出局 → 开枪 if (state?.lastDeath?.identity === 'hunter') return 'hunter-shot'; return 'wolf-night'; // 下一夜 } case 'hunter-shot': return 'wolf-night'; case 'game-end': return END; default: return END; } } ``` ### 游戏状态 不存在独立的 state 对象——游戏状态从 chain 重建(event sourcing): ```typescript interface GameState { players: Player[]; // 所有玩家 alive: Player[]; // 存活玩家 dead: DeadPlayer[]; // 死亡玩家 + 死因 day: number; // 第几天 phase: string; // 当前阶段 witchPotion: boolean; // 女巫解药是否还在 witchPoison: boolean; // 女巫毒药是否还在 lastDeath: DeadPlayer | null; } function parseGameState(chain: WorkflowMessage[]): GameState { // 从 chain 的 meta 中重建完整游戏状态 // 每个阶段 Role 的 meta 都带 gameState diff } ``` ### 玩家 Prompt 设计 每个玩家的 system prompt 包含: 1. **角色身份**:你是预言家/狼人/村民... 2. **性格特征**:随机分配(谨慎/激进/善于伪装/逻辑型...) 3. **游戏规则**:简要规则提醒 4. **目标**:你的胜利条件 ```typescript function buildPlayerPrompt(player: Player): string { return `你是玩家 ${player.name},身份是【${player.identity.name}】。 性格特征:${player.personality}。 阵营:${player.identity.team === 'wolf' ? '狼人阵营' : '好人阵营'}。 胜利条件:${player.identity.team === 'wolf' ? '淘汰所有好人' : '找出并淘汰所有狼人'}。 ${player.identity.abilities ? `特殊能力:${player.identity.abilities}` : ''} 重要规则: - 不要直接暴露自己的身份(除非策略需要) - 根据场上信息做出合理推理 - 发言要有逻辑,但也可以有情感和策略`; } ``` ## Meta Workflow 集成 让 meta workflow 生成这个 werewolf.ts: ### 任务描述(给 meta workflow 的 __start__ event) ``` 目标:实现狼人杀 workflow(werewolf.ts + werewolf.test.ts) 位置:packages/pulse/src/workflows/werewolf.ts 要求: 1. 9人局(3狼人 + 预言家 + 女巫 + 猎人 + 3村民) 2. 信息可见性:chain 过滤,每个玩家只看到该看的 3. 阶段:wolf-night → seer-check → witch-action → day-speech → vote → (hunter-shot) → 循环 4. 默认 mock Role(不调 LLM),可注入真 LLM Role 5. Moderator 判胜负 + 阶段轮转 6. 测试:mock 模式跑完整局,验证阶段流转和胜负判定 参考:coding-tdd.ts 的结构(WorkflowType + Roles + Moderator + Factory) 验证:bun test packages/pulse/src/workflows/werewolf.test.ts ``` ## 后续扩展 1. **真 LLM 对战**:注入 Sigil executor 做的 LLM Role,看 AI 之间互相推理 2. **人类参与**:某个玩家的 Role 改为等待用户输入(device effect 模式) 3. **观战模式**:实时输出每个阶段的公开信息 4. **复盘**:游戏结束后展示所有信息(包括夜晚行动),像"上帝视角" 5. **更多身份**:守卫、白痴、丘比特... --- 小橘 🍊 (NEKO Team)