agent构建狼人杀案例

原文链接地址

!TIP\] 项目地址:[github.com/agentscope-...](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fagentscope-ai%2Fagentscope-java%2Ftree%2Fmain%2Fagentscope-examples%2Fwerewolf "https://github.com/agentscope-ai/agentscope-java/tree/main/agentscope-examples/werewolf") 基于 agentscope-java 实现的狼人杀案例------多智能体协作游戏示例,展示了以下技术亮点:

  1. 清晰的分层架构: Web 层、游戏核心层、事件层、国际化层分离
  2. 响应式编程: 全程使用 Reactor 实现非阻塞和事件流
  3. 事件驱动: 游戏逻辑与 UI 解耦,易于扩展
  4. 多智能体协作: MsgHub 和 FanoutPipeline 的实践应用
  5. 结构化输出: 约束 LLM 输出,保证游戏规则
  6. 国际化支持: 接口驱动的多语言架构
  7. 可扩展性: 易于添加新角色、新语言、新 UI

效果演示

Werewolf 模块技术架构文档

系统架构图

整体架构图

游戏流程架构图

类依赖关系图

核心类详细说明

Web 层

WerewolfWebApplication
  • 包路径 : io.agentscope.examples.werewolf

  • 类型: Spring Boot 应用入口类

  • 职责:

    • 启动 Spring Boot 应用
    • 检查 DASHSCOPE_API_KEY 环境变量
    • 初始化 Web 服务器
  • 关键方法:

    • main(String[] args): 应用入口,启动 Spring Boot 容器
WerewolfWebController
  • 包路径 : io.agentscope.examples.werewolf.web

  • 类型: REST Controller

  • 职责:

    • 提供 HTTP API 接口
    • 处理游戏启动请求
    • 通过 Server-Sent Events (SSE) 推送游戏事件
    • 管理国际化语言选择
  • 关键方法:

    • startGame(String lang): 启动游戏并返回事件流
      • 参数: lang - 语言代码 (zh-CN/en-US)
      • 返回: Flux<ServerSentEvent<GameEvent>> - 响应式事件流
  • 特点:

    • 使用 @CrossOrigin 支持跨域请求
    • 使用 Schedulers.boundedElastic() 在独立线程池中运行游戏
    • 返回 TEXT_EVENT_STREAM 类型响应
I18nConfig
  • 包路径 : io.agentscope.examples.werewolf.web.config

  • 类型: Spring 配置类

  • 职责:

    • 配置 Spring MessageSource
    • 设置资源文件路径和编码
    • 支持多语言资源加载

游戏核心层

WerewolfWebGame
  • 包路径 : io.agentscope.examples.werewolf.web

  • 类型: 游戏主控制器

  • 职责:

    • 统筹整个游戏流程
    • 管理昼夜循环
    • 协调智能体交互
    • 调用特殊角色技能
    • 判断胜负条件
  • 核心流程:

    1. initializeGame(): 初始化玩家和智能体
    2. nightPhase(): 执行夜晚阶段
      • werewolvesKill(): 狼人杀人
      • witchActions(): 女巫使用药剂
      • seerCheck(): 预言家查验
    3. dayPhase(): 执行白天阶段
      • 公布夜晚结果
      • 多轮讨论
      • 投票放逐
    4. checkGameEnd(): 检查游戏是否结束
  • 关键技术点:

    • 使用 MsgHub 实现玩家间的消息广播
    • 使用 FanoutPipeline 实现并发投票
    • 使用 StructuredOutputHandler 约束 LLM 输出格式
    • 所有操作通过 GameEventEmitter 发射事件
GameState
  • 包路径 : io.agentscope.examples.werewolf.entity

  • 类型: 游戏状态管理类

  • 职责:

    • 存储所有玩家信息
    • 维护当前游戏回合数
    • 记录夜晚行动结果
    • 提供存活玩家查询
    • 判断胜利条件
  • 核心属性:

    • allPlayers: 所有玩家列表
    • seer/witch/hunter: 特殊角色引用
    • currentRound: 当前回合数
    • lastNightVictim: 昨晚被杀玩家
    • lastPoisonedVictim: 被毒杀玩家
    • lastVictimResurrected: 是否被救活
  • 关键方法:

    • getAlivePlayers(): 获取所有存活玩家
    • getAliveWerewolves(): 获取存活狼人
    • getAliveVillagers(): 获取存活好人
    • checkWerewolvesWin(): 判断狼人是否获胜
    • checkVillagersWin(): 判断好人是否获胜
Player
  • 包路径 : io.agentscope.examples.werewolf.entity

  • 类型: 玩家实体类

  • 职责:

    • 封装玩家信息
    • 关联 ReActAgent 智能体
    • 管理玩家状态(存活/死亡)
    • 管理角色特定状态(女巫药剂)
  • 核心属性:

    • agent: 智能体实例
    • name: 玩家名称
    • role: 角色类型
    • isAlive: 是否存活
    • witchHasHealPotion: 女巫是否有解药
    • witchHasPoisonPotion: 女巫是否有毒药
  • 关键方法:

    • kill(): 杀死玩家
    • resurrect(): 复活玩家
    • useHealPotion(): 使用解药
    • usePoisonPotion(): 使用毒药
Role
  • 包路径 : io.agentscope.examples.werewolf.entity

  • 类型: 枚举类

  • 职责: 定义所有角色类型

  • 枚举值:

    • VILLAGER: 平民
    • WEREWOLF: 狼人
    • SEER: 预言家
    • WITCH: 女巫
    • HUNTER: 猎人
  • 方法:

    • isWerewolf(): 是否为狼人
    • isVillagerCamp(): 是否为好人阵营
WerewolfGameConfig
  • 包路径 : io.agentscope.examples.werewolf

  • 类型: 配置常量类

  • 职责: 定义游戏规则参数

  • 配置项:

    • VILLAGER_COUNT = 3: 平民数量
    • WEREWOLF_COUNT = 3: 狼人数量
    • SEER_COUNT = 1: 预言家数量
    • WITCH_COUNT = 1: 女巫数量
    • HUNTER_COUNT = 1: 猎人数量
    • MAX_ROUNDS = 30: 最大回合数
    • MAX_DISCUSSION_ROUNDS = 3: 最大讨论轮数
    • DEFAULT_MODEL = "qwen3-max": 默认模型
WerewolfUtils
  • 包路径 : io.agentscope.examples.werewolf

  • 类型: 工具类

  • 职责:

    • 统计投票结果
    • 格式化玩家列表
    • 打印游戏状态
    • 验证玩家名称
    • 提取消息内容
  • 关键方法:

    • countVotes(List<Msg> votes, GameState state): 统计投票,处理平票
    • formatPlayerList(List<Player> players): 格式化玩家名称列表
    • isValidAlivePlayer(String playerName, GameState state): 验证玩家是否存活
    • extractTextContent(Msg msg): 从消息中提取文本内容

事件发射层

GameEventEmitter
  • 包路径 : io.agentscope.examples.werewolf.web

  • 类型: 响应式事件发射器

  • 职责:

    • 使用 Reactor Sinks 发射游戏事件
    • 提供事件流订阅接口
    • 支持多订阅者
  • 核心机制:

    • 使用 Sinks.Many<GameEvent> 创建多播流
    • 支持背压缓冲
    • 非阻塞事件发射
  • 关键方法:

    • emit(GameEvent event): 发射事件
    • emitGameInit(): 发射游戏初始化事件
    • emitPhaseChange(): 发射阶段切换事件
    • emitPlayerSpeak(): 发射玩家发言事件
    • emitPlayerVote(): 发射玩家投票事件
    • emitPlayerAction(): 发射特殊角色行动事件
    • emitPlayerEliminated(): 发射玩家淘汰事件
    • getEventStream(): 获取事件流
GameEvent
  • 包路径 : io.agentscope.examples.werewolf.web

  • 类型: 事件数据类

  • 职责: 封装游戏事件数据

  • 核心属性:

    • type: 事件类型
    • data: 事件数据 (Map 结构)
    • timestamp: 时间戳
  • 静态工厂方法: 提供各类事件的便捷创建方法

GameEventType
  • 包路径 : io.agentscope.examples.werewolf.web

  • 类型: 枚举类

  • 职责: 定义所有事件类型

  • 枚举值:

    • GAME_INIT: 游戏初始化
    • PHASE_CHANGE: 阶段切换
    • PLAYER_SPEAK: 玩家发言
    • PLAYER_VOTE: 玩家投票
    • PLAYER_ACTION: 特殊角色行动
    • PLAYER_ELIMINATED: 玩家淘汰
    • PLAYER_RESURRECTED: 玩家复活
    • STATS_UPDATE: 统计更新
    • SYSTEM_MESSAGE: 系统消息
    • GAME_END: 游戏结束
    • ERROR: 错误

国际化层

LocalizationFactory
  • 包路径 : io.agentscope.examples.werewolf.localization

  • 类型: 国际化资源工厂

  • 职责:

    • 根据语言代码创建国际化资源包
    • 解析 Locale
    • 统一管理国际化实现
  • 关键方法:

    • createBundle(Locale locale): 创建国际化包
    • createBundle(String langTag): 根据语言标签创建包
LocalizationBundle
  • 包路径 : io.agentscope.examples.werewolf.localization

  • 类型: Record 类

  • 职责: 聚合所有国际化资源

  • 属性:

    • locale: 语言环境
    • prompts: 提示词提供者
    • messages: 消息提供者
    • langConfig: 语言配置
PromptProvider (接口)
  • 包路径 : io.agentscope.examples.werewolf.localization

  • 类型: 接口

  • 职责: 定义所有发送给智能体的提示词

  • 关键方法:

    • getSystemPrompt(Role role, String playerName): 获取角色系统提示词
    • createWerewolfDiscussionPrompt(): 创建狼人讨论提示
    • createWitchHealPrompt(): 创建女巫救人提示
    • createSeerCheckPrompt(): 创建预言家查验提示
    • createDiscussionPrompt(): 创建白天讨论提示
    • createVotingPrompt(): 创建投票提示
GameMessages (接口)
  • 包路径 : io.agentscope.examples.werewolf.localization

  • 类型: 接口

  • 职责: 定义所有 UI 显示消息

  • 关键方法:

    • getNightPhaseTitle(): 获取夜晚阶段标题
    • getDayPhaseTitle(): 获取白天阶段标题
    • getRoleDisplayName(Role role): 获取角色显示名称
    • getWerewolvesWin(): 获取狼人胜利消息
    • getVillagersWin(): 获取好人胜利消息
LanguageConfig (接口)
  • 包路径 : io.agentscope.examples.werewolf.localization

  • 类型: 接口

  • 职责: 提供语言相关配置

  • 关键方法:

    • getPlayerNames(): 获取玩家名称列表(不同语言使用不同名字)
18-20. MessageSource 实现类*
  • 包路径 : io.agentscope.examples.werewolf.localization

  • 类名:

    • MessageSourcePromptProvider
    • MessageSourceGameMessages
    • MessageSourceLanguageConfig
  • 职责: 基于 Spring MessageSource 实现国际化接口

  • 特点 : 从 messages.properties 文件读取多语言内容

结构化输出模型层

VoteModel
  • 包路径 : io.agentscope.examples.werewolf.model

  • 类型: POJO

  • 职责: 约束投票输出格式

  • 字段:

    • targetPlayer: 投票目标玩家名称
    • reason: 投票理由
SeerCheckModel
  • 包路径 : io.agentscope.examples.werewolf.model

  • 类型: POJO

  • 职责: 约束预言家查验输出格式

  • 字段:

    • targetPlayer: 查验目标
    • reasoning: 查验理由
WitchHealModel
  • 包路径 : io.agentscope.examples.werewolf.model

  • 类型: POJO

  • 职责: 约束女巫救人决策格式

  • 字段:

    • useHealPotion: 是否使用解药
    • reasoning: 决策理由
WitchPoisonModel
  • 包路径 : io.agentscope.examples.werewolf.model

  • 类型: POJO

  • 职责: 约束女巫毒人决策格式

  • 字段:

    • usePoisonPotion: 是否使用毒药
    • targetPlayer: 毒人目标
    • reasoning: 决策理由
HunterShootModel
  • 包路径 : io.agentscope.examples.werewolf.model

  • 类型: POJO

  • 职责: 约束猎人开枪输出格式

  • 字段:

    • targetPlayer: 开枪目标
    • reasoning: 开枪理由
DiscussionModel
  • 包路径 : io.agentscope.examples.werewolf.model

  • 类型: POJO

  • 职责: 约束讨论发言格式

  • 字段:

    • discussion: 发言内容

技术特点分析

多智能体协作模式

MsgHub 消息中心:

  • 用于狼人讨论、白天讨论等场景
  • 支持自动广播 (enableAutoBroadcast)
  • 智能体间消息同步共享
  • 实现:
java 复制代码
try (MsgHub hub = MsgHub.builder()
        .name("Discussion")
        .participants(agents)
        .announcement(prompt)
        .enableAutoBroadcast(true)
        .build()) {
    hub.enter().block();
    // 智能体交互
}

FanoutPipeline 并发管道:

  • 用于投票等并发场景
  • 所有智能体同时执行
  • 收集所有结果
  • 实现:
java 复制代码
FanoutPipeline pipeline = FanoutPipeline.builder()
    .addAgents(agents)
    .concurrent()
    .build();
List<Msg> results = pipeline.execute(prompt, VoteModel.class).block();

结构化输出控制

使用 StructuredOutputHandler 确保 LLM 输出符合预定义格式:

  • 定义 POJO 模型类
  • 框架自动生成 JSON Schema
  • LLM 输出自动映射到 Java 对象
  • 支持自动重试和错误纠正

示例:

java 复制代码
// 约束投票输出
Msg voteMsg = agent.call(votingPrompt, VoteModel.class).block();
VoteModel vote = voteMsg.getStructuredData(VoteModel.class);
String target = vote.targetPlayer;
String reason = vote.reason;

响应式编程

Reactor 框架应用:

  • 所有智能体调用返回 Mono<Msg>
  • 事件流使用 Flux<GameEvent>
  • 支持背压和非阻塞
  • SSE 推送基于响应式流

优势:

  • 高并发处理能力
  • 资源利用率高
  • 天然支持事件驱动
  • 适合实时推送场景

国际化架构

三层分离设计:

  1. 接口层 : PromptProvider, GameMessages, LanguageConfig
  2. 实现层: 基于 Spring MessageSource
  3. 资源层 : messages.properties 文件

支持语言:

  • 中文 (messages_zh_CN.properties)
  • 英文 (messages_en_US.properties)

优势:

  • 提示词和消息分离
  • 易于扩展新语言
  • 智能体和 UI 分别国际化

事件驱动架构

解耦设计:

  • 游戏逻辑通过 GameEventEmitter 发射事件
  • Web 层订阅事件流并推送给客户端
  • 游戏核心与 UI 完全解耦

事件流转:

rust 复制代码
WerewolfWebGame -> GameEventEmitter -> Reactor Flux -> SSE -> Web 客户端

优势:

  • 游戏逻辑可复用(控制台版/Web 版)
  • 易于添加新的 UI 形式
  • 支持实时监控和录制回放

关键技术实现细节

智能体角色扮演

每个玩家智能体通过系统提示词获得角色认知:

java 复制代码
ReActAgent agent = ReActAgent.builder()
    .name(playerName)
    .sysPrompt(prompts.getSystemPrompt(role, playerName))  // 角色提示词
    .model(model)
    .memory(new InMemoryMemory())  // 独立记忆
    .build();

提示词内容包括:

  • 角色身份和目标
  • 游戏规则
  • 行为约束
  • 输出格式要求

狼人讨论机制

使用 MsgHub 实现狼人间的私密讨论:

  1. 创建 MsgHub,只包含狼人智能体
  2. 发布讨论主题公告
  3. 智能体轮流发言,消息自动广播
  4. 所有狼人共享讨论记忆
java 复制代码
try (MsgHub werewolfHub = MsgHub.builder()
        .name("WerewolfDiscussion")
        .participants(werewolves)
        .announcement(discussionPrompt)
        .enableAutoBroadcast(true)
        .build()) {

    werewolfHub.enter().block();

    // 多轮讨论
    for (int i = 0; i < 2; i++) {
        for (Player werewolf : werewolves) {
            Msg response = werewolf.getAgent().call().block();
            // 自动广播给其他狼人
        }
    }

    // 投票阶段
    werewolfHub.setAutoBroadcast(false);
    // 并发投票
}

投票统计逻辑

处理平票情况的算法:

java 复制代码
public Player countVotes(List<Msg> votes, GameState state) {
    Map<String, Integer> voteCount = new HashMap<>();

    // 统计票数
    for (Msg voteMsg : votes) {
        VoteModel vote = voteMsg.getStructuredData(VoteModel.class);
        voteCount.put(vote.targetPlayer,
                     voteCount.getOrDefault(vote.targetPlayer, 0) + 1);
    }

    // 找到最高票数
    int maxVotes = voteCount.values().stream()
        .max(Integer::compareTo).orElse(0);

    // 获取所有最高票玩家
    List<String> tied = voteCount.entrySet().stream()
        .filter(e -> e.getValue() == maxVotes)
        .map(Map.Entry::getKey)
        .toList();

    // 平票则随机选择
    if (tied.size() > 1) {
        String chosen = tied.get(RANDOM.nextInt(tied.size()));
        return state.findPlayerByName(chosen);
    }

    return state.findPlayerByName(tied.get(0));
}

胜负判定

java 复制代码
// 狼人胜利: 狼人数 >= 好人数
public boolean checkWerewolvesWin() {
    int aliveWerewolves = getAliveWerewolves().size();
    int aliveVillagers = getAliveVillagers().size();
    return aliveWerewolves > 0 && aliveWerewolves >= aliveVillagers;
}

// 好人胜利: 狼人全灭
public boolean checkVillagersWin() {
    return getAliveWerewolves().isEmpty();
}

SSE 事件推送

使用 Spring WebFlux 的 SSE 支持:

java 复制代码
@PostMapping(value = "/start", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<ServerSentEvent<GameEvent>> startGame(@RequestParam String lang) {
    GameEventEmitter emitter = new GameEventEmitter();
    WerewolfWebGame game = new WerewolfWebGame(emitter, bundle);

    // 异步执行游戏
    Mono.fromRunnable(() -> {
        try {
            game.start();
        } finally {
            emitter.complete();
        }
    }).subscribeOn(Schedulers.boundedElastic()).subscribe();

    // 返回事件流
    return emitter.getEventStream()
        .map(event -> ServerSentEvent.<GameEvent>builder()
            .event(event.getType().name().toLowerCase())
            .data(event)
            .build());
}

文件组织结构

bash 复制代码
agentscope-examples/werewolf/
├── pom.xml
└── src/
    └── main/
        ├── java/io/agentscope/examples/werewolf/
        │   ├── WerewolfWebApplication.java          # 主程序入口
        │   ├── WerewolfGameConfig.java              # 游戏配置
        │   ├── WerewolfUtils.java                   # 工具类
        │   │
        │   ├── entity/                              # 实体包
        │   │   ├── GameState.java                   # 游戏状态
        │   │   ├── Player.java                      # 玩家
        │   │   └── Role.java                        # 角色枚举
        │   │
        │   ├── web/                                 # Web 层
        │   │   ├── WerewolfWebController.java      # REST 控制器
        │   │   ├── WerewolfWebGame.java            # 游戏主逻辑
        │   │   ├── GameEvent.java                   # 事件数据
        │   │   ├── GameEventType.java               # 事件类型
        │   │   ├── GameEventEmitter.java            # 事件发射器
        │   │   └── config/
        │   │       └── I18nConfig.java              # 国际化配置
        │   │
        │   ├── model/                               # 结构化输出模型
        │   │   ├── VoteModel.java                   # 投票模型
        │   │   ├── SeerCheckModel.java              # 预言家模型
        │   │   ├── WitchHealModel.java              # 女巫救人模型
        │   │   ├── WitchPoisonModel.java            # 女巫毒人模型
        │   │   ├── HunterShootModel.java            # 猎人模型
        │   │   └── DiscussionModel.java             # 讨论模型
        │   │
        │   └── localization/                        # 国际化包
        │       ├── LocalizationFactory.java         # 国际化工厂
        │       ├── LocalizationBundle.java          # 资源包
        │       ├── PromptProvider.java              # 提示词接口
        │       ├── GameMessages.java                # 消息接口
        │       ├── LanguageConfig.java              # 语言配置接口
        │       ├── MessageSourcePromptProvider.java # 提示词实现
        │       ├── MessageSourceGameMessages.java   # 消息实现
        │       └── MessageSourceLanguageConfig.java # 语言配置实现
        │
        └── resources/
            ├── messages.properties                  # 默认资源(中文)
            ├── messages_zh_CN.properties            # 中文资源
            ├── messages_en_US.properties            # 英文资源
            ├── logback.xml                          # 日志配置
            └── static/                              # 静态资源(HTML/CSS/JS)

依赖关系总结

框架依赖

  • AgentScope Core: 核心框架

    • ReActAgent: 智能体
    • DashScopeChatModel: 大模型
    • MsgHub: 消息中心
    • FanoutPipeline: 并发管道
    • InMemoryMemory: 内存
    • Msg: 消息对象
  • Spring Boot WebFlux: 响应式 Web 框架

  • Project Reactor: 响应式编程库

模块内依赖层次

scss 复制代码
Web 层 (Controller, Application)
    ↓
游戏核心层 (WebGame, GameState, Player)
    ↓
事件层 (Emitter, Event) + 国际化层 (Localization)
    ↓
模型层 (VoteModel, SeerModel, etc.)
    ↓
AgentScope 框架层

关键依赖关系

  1. WerewolfWebGame 依赖所有层
  2. GameState 管理 Player 集合
  3. Player 封装 ReActAgent
  4. 所有操作通过 GameEventEmitter 发射事件
  5. 国际化通过 LocalizationBundle 统一提供

扩展性分析

添加新角色

需要修改的类:

  • Role: 添加新角色枚举
  • WerewolfGameConfig: 配置角色数量
  • PromptProvider: 添加角色提示词
  • GameMessages: 添加角色显示名称
  • WerewolfWebGame: 实现角色技能逻辑
  • 添加新的结构化输出模型类

支持新语言

需要添加:

  • messages_<locale>.properties 文件
  • 所有提示词和消息的翻译
  • 玩家名称列表

添加新的 UI 形式

步骤:

  1. 创建新的 Controller 或 Application
  2. 订阅 GameEventEmitter.getEventStream()
  3. 将事件转换为对应 UI 形式
  4. 游戏核心逻辑无需修改

更换 LLM

步骤:

  1. 使用不同的 Model 实现 (OpenAI, Anthropic, Gemini)
  2. 修改 WerewolfWebGame.initializeGame() 中的模型创建
  3. 其他代码无需修改
相关推荐
ITFLY82 小时前
架构很简单:系统拆分与组合
架构
踏浪无痕4 小时前
AI 时代架构师如何有效成长?
人工智能·后端·架构
anyup5 小时前
2026第一站:分享我在高德大赛现场学到的技术、产品与心得
前端·架构·harmonyos
桌面运维家6 小时前
vDisk配置漂移怎么办?VOI/IDV架构故障快速修复
网络·架构
刘立军6 小时前
如何选择FAISS的索引类型
人工智能·算法·架构
小当家.1056 小时前
深入理解JVM:架构、原理与调优实战
java·jvm·架构
刀法如飞6 小时前
一款开箱即用的Spring Boot 4 DDD工程脚手架
java·后端·架构
好奇龙猫6 小时前
【人工智能学习-AI-MIT公开课第 19. 架构:GPS、SOAR、包容架构】
人工智能·学习·架构
老前端的功夫7 小时前
TypeScript 类型魔术:模板字面量类型的深层解密与工程实践
前端·javascript·ubuntu·架构·typescript·前端框架
min1811234568 小时前
PC端零基础跨职能流程图制作教程
大数据·人工智能·信息可视化·架构·流程图