Skip to content

谁是卧底游戏#70

Open
zqc9527 wants to merge 1 commit into
datawhalechina:mainfrom
zqc9527:main
Open

谁是卧底游戏#70
zqc9527 wants to merge 1 commit into
datawhalechina:mainfrom
zqc9527:main

Conversation

@zqc9527

@zqc9527 zqc9527 commented Apr 29, 2026

Copy link
Copy Markdown

🎮 8.1 项目需求拆解:“谁是卧底”游戏智能体引擎

当前场景:2026年4月28日,江西赣州

1. 项目设计评价

这个项目设计巧妙,精准抓住了 LangGraph 在“多智能体协助与状态流转”方面的优势,实现了从线性流水线到循环博弈的质变。

  • 难度分层合理(教学视角)
    • 上帝视角(默认):用户作为旁观者,聚焦于 LangGraph 的核心逻辑(状态流转、循环终止),无需处理前端交互。
    • 玩家视角(进阶):引入人类玩家,处理人机混合交互和异步等待。
  • 技术深度(技术视角)
    • 信息隔离与共享:严格隔离平民词和卧底词,但共享发言内容。
    • 记忆与推理:智能体需基于历史发言进行逻辑推理。
    • 循环图(Cyclic Graph):处理“发言 -> 投票 -> 判断 -> (循环)”的复杂流程。
  • 可扩展性(工程视角)
    • 可增加角色(如白板)、增加自由辩论环节或更换不同性格的模型。

📜 8.1.1 游戏规则简化

核心设定对比

维度 上帝视角 (默认) 玩家视角 (可选)
用户角色 旁观者 参与者 (1名用户 + 3个智能体)
参与方 4个智能体 (1卧底, 3平民) 1用户 + 3智能体
流程控制 全程由智能体自主完成 用户需输入发言和投票
胜负逻辑 淘汰卧底则平民胜;剩余1平民1卧底则卧底胜 同左

🧩 8.1.2 智能体引擎核心模块

要实现上述游戏,引擎包含以下 6 个核心模块:

  1. 词语生成模块:生成相关的平民词和卧底词。
  2. 角色分配模块:随机分配卧底和平民。
  3. 发言生成模块:智能体根据角色生成描述。
  4. 投票模块:分析发言并投票。
  5. 游戏控制模块:串联流程,判断胜负。
  6. 结果展示模块:输出游戏复盘。

💻 8.3 完整运行代码

以下代码基于 LangGraph 实现了完整的“谁是卧底”游戏逻辑。

1. 导入依赖与模型初始化

import random
import os
import json
import textwrap
from typing import TypedDict, List, Dict
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langgraph.graph import StateGraph, END

# 加载环境变量并初始化大模型
load_dotenv()
llm = ChatOpenAI(
    api_key=os.getenv("API_KEY"),
    base_url="https://qianfan.baidubce.com/v2",
    model="deepseek-r1-distill-qwen-32b",
    temperature=0.7,
    max_tokens=500
)
parser = StrOutputParser()

2. 定义游戏状态 (GameState)

class GameState(TypedDict):
    """全局游戏状态容器"""
    civilian_word: str          # 平民词
    undercover_word: str        # 卧底词
    role_assignment: dict       # 角色分配
    speeches: dict              # 当前轮发言
    history_speeches: List[Dict[str, str]] # 历史发言记录
    speech_reasoning: dict      # 发言策略
    votes: dict                 # 当前轮投票
    vote_reasoning: dict        # 投票理由
    game_status: str            # running/end
    winner: str                 # 获胜方
    eliminated: List[str]       # 已淘汰玩家
    round: int                  # 当前轮次

def init_game_state() -> GameState:
    return {
        "civilian_word": "",
        "undercover_word": "",
        "role_assignment": {},
        "speeches": {},
        "history_speeches": [],
        "speech_reasoning": {},
        "votes": {},
        "vote_reasoning": {},
        "game_status": "running",
        "winner": "",
        "eliminated": [],
        "round": 1
    }

3. 核心节点逻辑

节点1:词语生成

def generate_words(state: GameState) -> GameState:
    # ... (Prompt逻辑:生成形似神不似的词语对)
    # 包含兜底词库逻辑
    fallback_pairs = [("脐橙", "橘子"), ("米粉", "面条"), ("赣州塔", "电视塔")]
    # 返回包含新词语的状态

节点2:角色分配

def assign_roles(state: GameState) -> GameState:
    agents = ["agent1", "agent2", "agent3", "agent4"]
    undercover = random.choice(agents)
    for agent in agents:
        if agent == undercover:
            state["role_assignment"][agent] = ("卧底", state["undercover_word"])
        else:
            state["role_assignment"][agent] = ("平民", state["civilian_word"])
    return state

节点3:发言生成 (核心博弈)

def generate_speeches(state: GameState) -> GameState:
    # 包含历史记忆上下文构建
    # 区分平民(具体特征)和卧底(模糊描述)的策略
    # 处理JSON解析失败的容错

节点4:投票决策

def vote_undercover(state: GameState) -> GameState:
    # 分析当前发言与历史记录的矛盾点
    # 实现防自投、防投已淘汰玩家的校验

节点5:胜负判定

def judge_result(state: GameState) -> GameState:
    # 统计票数,淘汰最高票者
    # 判定逻辑:淘汰卧底->平民胜;剩1人vs1人->卧底胜

节点6:结果展示

def show_final_result(state: GameState) -> GameState:
    # 使用 textwrap.fill 进行文本自动换行美化
    # 输出复盘报告

4. 构建 LangGraph 图结构

def build_game_graph():
    graph = StateGraph(GameState)
    
    # 注册节点
    graph.add_node("generate_words", generate_words)
    graph.add_node("assign_roles", assign_roles)
    graph.add_node("generate_speeches", generate_speeches)
    graph.add_node("vote_undercover", vote_undercover)
    graph.add_node("judge_result", judge_result)
    graph.add_node("show_final_result", show_final_result)

    # 定义流程边
    graph.set_entry_point("generate_words")
    graph.add_edge("generate_words", "assign_roles")
    graph.add_edge("assign_roles", "generate_speeches")
    graph.add_edge("generate_speeches", "vote_undercover")
    graph.add_edge("vote_undercover", "judge_result")
    
    # 条件边:根据游戏状态决定继续循环还是结束
    def should_continue(state: GameState):
        return "generate_speeches" if state["game_status"] == "running" else "show_final_result"
    
    graph.add_conditional_edges("judge_result", should_continue)
    graph.add_edge("show_final_result", END)
    
    return graph

5. 运行入口

if __name__ == "__main__":
    game_graph = build_game_graph()
    game = game_graph.compile()
    
    print("🎮 **谁是卧底** · 多智能体推理版")
    print("📍 当前场景:江西赣州 · 2026-04-28")
    
    game.invoke(init_game_state())

📝 运行结果示例

游戏复盘报告

  • 词语:平民词『赣州塔』| 卧底词『电视塔』
  • 过程:第1轮 agent2 (平民) 淘汰 -> 第2轮 agent1 (平民) 淘汰
  • 结局卧底胜利 (最后的幸存者)
  • 淘汰顺序:agent2 -> agent1

总结:该代码实现了一个完整的循环博弈系统,展示了如何利用 LangGraph 管理复杂的多智能体交互状态。

@muxiaoxiong

Copy link
Copy Markdown
Member

代码建议优化

@muxiaoxiong muxiaoxiong added the invalid This doesn't seem right label May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

invalid This doesn't seem right

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants