|
1 | | -# SDK |
2 | 1 |
|
3 | | -A basic framework upon which competitors build their works. |
| 2 | +# 狼人杀智能体 SDK 使用指南 |
4 | 3 |
|
5 | | -<!-- TODO: finish --> |
| 4 | +## 概览 |
| 5 | + |
| 6 | +开发环境:python 3.12.12+websockets 15.0.1 |
| 7 | +本 SDK 提供了一个完整的智能体框架,用于与狼人杀游戏服务器通过 WebSocket 通讯,实现以下功能: |
| 8 | + |
| 9 | +- **初始化** (`initialize`):接收玩家身份和游戏配置 |
| 10 | +- **夜晚行动**: |
| 11 | + - `werewolf_action`:狼人选择目标进行击杀 |
| 12 | + - `seer_action`:预言家选择目标进行查验 |
| 13 | + - `witch_action`:女巫使用解药或毒药 |
| 14 | + - `hunter_action`:猎人反击(被杀或投票出局时) |
| 15 | +- **白天阶段**: |
| 16 | + - `discuss`:白天讨论发言 |
| 17 | + - `vote`:投票出局目标 |
| 18 | + - `defend`:在被指控时进行辩护 |
| 19 | +- **游戏结束** (`game_over`):接收游戏结果和反思 |
| 20 | + |
| 21 | +## 快速开始 |
| 22 | + |
| 23 | +### 1. 基本设置 |
| 24 | + |
| 25 | +```python |
| 26 | +import asyncio |
| 27 | +from sdk.agent import Agent |
| 28 | + |
| 29 | +async def main(): |
| 30 | + # 创建智能体 |
| 31 | + agent = Agent(name="MyAgent") |
| 32 | + |
| 33 | + # 连接到服务器 |
| 34 | + await agent.start("ws://localhost:8000/ws") |
| 35 | + |
| 36 | + # 保持运行 |
| 37 | + try: |
| 38 | + while True: |
| 39 | + await asyncio.sleep(1) |
| 40 | + except KeyboardInterrupt: |
| 41 | + await agent.stop() |
| 42 | + |
| 43 | +if __name__ == "__main__": |
| 44 | + asyncio.run(main()) |
| 45 | +``` |
| 46 | + |
| 47 | +### 2. 使用命令行工具 |
| 48 | + |
| 49 | +```bash |
| 50 | +# 启动智能体,连接到本地服务器 |
| 51 | +python -m sdk.runner --name "MyAgent" --server "ws://127.0.0.1:8000/ws" |
| 52 | + |
| 53 | +# 也可以不指定参数(使用默认值) |
| 54 | +python -m sdk.runner |
| 55 | +``` |
| 56 | + |
| 57 | +### 3. 自定义行为 |
| 58 | + |
| 59 | +继承 `Agent` 类并重写行为方法: |
| 60 | + |
| 61 | +```python |
| 62 | +from sdk.agent import Agent |
| 63 | +from sdk.messages import WerewolfActionMessage, WerewolfActionResponseMessage |
| 64 | + |
| 65 | +class SmartAgent(Agent): |
| 66 | + def on_werewolf_action(self, msg: WerewolfActionMessage) -> WerewolfActionResponseMessage: |
| 67 | + # 获取信息 |
| 68 | + alive_players = msg.msg.get("alive_players", []) |
| 69 | + teammates = msg.msg.get("teammates", []) |
| 70 | + |
| 71 | + # 实现自定义策略 |
| 72 | + target_id = self.select_best_target(alive_players, teammates) |
| 73 | + |
| 74 | + return WerewolfActionResponseMessage( |
| 75 | + token=msg.msg["token"], |
| 76 | + action="kill", |
| 77 | + target_id=target_id, |
| 78 | + reasoning="我的分析表明这个玩家最有可能是好人...", |
| 79 | + confidence=0.8 |
| 80 | + ) |
| 81 | + |
| 82 | + def select_best_target(self, alive_players, teammates): |
| 83 | + # 自定义选择逻辑 |
| 84 | + teammate_ids = {p.get("player_id") for p in teammates} |
| 85 | + for p in alive_players: |
| 86 | + if p.get("player_id") not in teammate_ids: |
| 87 | + return p.get("player_id", 0) |
| 88 | + return 0 |
| 89 | +``` |
| 90 | + |
| 91 | +## 消息格式 |
| 92 | + |
| 93 | +所有消息都是 JSON 格式,包含 `type` 和 `token` 字段。 |
| 94 | + |
| 95 | +### 请求示例(服务器 → 智能体) |
| 96 | + |
| 97 | +```json |
| 98 | +{ |
| 99 | + "type": "initialize", |
| 100 | + "token": "abc123", |
| 101 | + "player_id": 1, |
| 102 | + "role": "werewolf", |
| 103 | + "role_description": "你是狼人,每晚可以杀死一名玩家", |
| 104 | + "all_players": [ |
| 105 | + {"player_id": 1, "name": "玩家1"}, |
| 106 | + {"player_id": 2, "name": "玩家2"} |
| 107 | + ], |
| 108 | + "game_config": { |
| 109 | + "roles": ["werewolf", "seer", "witch", "villager"], |
| 110 | + "wolf_count": 2, |
| 111 | + "max_days": 10, |
| 112 | + "language": "zh-CN" |
| 113 | + } |
| 114 | +} |
| 115 | +``` |
| 116 | + |
| 117 | +### 响应示例(智能体 → 服务器) |
| 118 | + |
| 119 | +```json |
| 120 | +{ |
| 121 | + "type": "initialize_response", |
| 122 | + "token": "abc123", |
| 123 | + "status": "success", |
| 124 | + "message": "初始化完成" |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +## 行为方法文档 |
| 129 | + |
| 130 | +### 初始化 |
| 131 | + |
| 132 | +**方法**: `on_initialize(msg: InitializeMessage) -> InitializeResponseMessage` |
| 133 | + |
| 134 | +记录玩家 ID、角色和游戏配置。 |
| 135 | + |
| 136 | +### 狼人行动 |
| 137 | + |
| 138 | +**方法**: `on_werewolf_action(msg: WerewolfActionMessage) -> WerewolfActionResponseMessage` |
| 139 | + |
| 140 | +选择要杀害的目标。 |
| 141 | + |
| 142 | +**消息字段**: |
| 143 | + |
| 144 | +- `game_state`: 当前游戏状态 |
| 145 | +- `night_numbers`: 当前是第几晚 |
| 146 | +- `alive_players`: 所有存活的玩家列表 |
| 147 | +- `teammates`: 狼队友(只显示还活着的队友) |
| 148 | +- `previous_votes`: 历史投票记录 |
| 149 | + |
| 150 | +### 预言家行动 |
| 151 | + |
| 152 | +**方法**: `on_seer_action(msg: SeerActionMessage) -> SeerActionResponseMessage` |
| 153 | + |
| 154 | +选择要查验的目标。 |
| 155 | + |
| 156 | +### 女巫行动 |
| 157 | + |
| 158 | +**方法**: `on_witch_action(msg: WitchActionMessage) -> WitchActionResponseMessage` |
| 159 | + |
| 160 | +决定是否使用解药或毒药,以及对谁使用。 |
| 161 | + |
| 162 | +### 猎人行动 |
| 163 | + |
| 164 | +**方法**: `on_hunter_action(msg: HunterActionMessage) -> HunterActionResponseMessage` |
| 165 | + |
| 166 | +在被杀死或投票出局时选择射击目标。 |
| 167 | + |
| 168 | +### 讨论 |
| 169 | + |
| 170 | +**方法**: `on_discuss(msg: DiscussMessage) -> DiscussResponseMessage` |
| 171 | + |
| 172 | +在白天讨论阶段发言表达观点。 |
| 173 | + |
| 174 | +### 投票 |
| 175 | + |
| 176 | +**方法**: `on_vote(msg: VoteMessage) -> VoteResponseMessage` |
| 177 | + |
| 178 | +投票选择要出局的玩家。 |
| 179 | + |
| 180 | +### 辩护 |
| 181 | + |
| 182 | +**方法**: `on_defend(msg: DefendMessage) -> DefendResponseMessage` |
| 183 | + |
| 184 | +在被指控时进行辩解。 |
| 185 | + |
| 186 | +### 游戏结束 |
| 187 | + |
| 188 | +**方法**: `on_game_over(msg: GameOverMessage) -> GameOverResponseMessage` |
| 189 | + |
| 190 | +处理游戏结束,返回反思总结和自评分数。 |
| 191 | + |
| 192 | +## 文件结构 |
| 193 | + |
| 194 | +``` |
| 195 | +sdk/ |
| 196 | +├── __init__.py # SDK 入口 |
| 197 | +├── agent.py # 智能体主类 |
| 198 | +├── messages.py # 消息类型定义 |
| 199 | +├── websocket_client.py # WebSocket 客户端 |
| 200 | +├── interface.py # 接口定义 |
| 201 | +├── runner.py # 命令行启动脚本 |
| 202 | +└── README.md # SDK 文档 |
| 203 | +``` |
| 204 | + |
| 205 | +## 日志 |
| 206 | + |
| 207 | +SDK 使用 Python 标准的 `logging` 模块。可以通过以下方式配置日志级别: |
| 208 | + |
| 209 | +```python |
| 210 | +import logging |
| 211 | + |
| 212 | +logging.basicConfig(level=logging.DEBUG) |
| 213 | +logger = logging.getLogger("sdk.agent") |
| 214 | +``` |
| 215 | + |
| 216 | +## 错误处理 |
| 217 | + |
| 218 | +所有行为方法的异常会被捕获,智能体会发送错误响应给服务器,包含错误码和建议行动。 |
| 219 | + |
| 220 | +## 扩展 |
| 221 | + |
| 222 | +可以通过继承 `Agent` 类来实现更复杂的策略: |
| 223 | + |
| 224 | +1. 维护游戏状态和历史信息 |
| 225 | +2. 实现复杂的分析和决策逻辑 |
| 226 | +3. 添加自定义日志和统计 |
| 227 | + |
| 228 | +示例: |
| 229 | + |
| 230 | +```python |
| 231 | +class AdvancedAgent(Agent): |
| 232 | + def __init__(self, name): |
| 233 | + super().__init__(name) |
| 234 | + self.history = [] |
| 235 | + self.suspicions = {} |
| 236 | + |
| 237 | + def on_discuss(self, msg: DiscussMessage) -> DiscussResponse: |
| 238 | + # 分析历史信息 |
| 239 | + self.update_suspicions(msg.msg.get("previous_speeches", [])) |
| 240 | + |
| 241 | + # 生成发言 |
| 242 | + speech = self.generate_speech() |
| 243 | + return DiscussResponseMessage( |
| 244 | + token=msg.msg["token"], |
| 245 | + speech=speech, |
| 246 | + emotion="confident", |
| 247 | + target_players=list(self.suspicions.keys()), |
| 248 | + is_accusation=True |
| 249 | + ) |
| 250 | + |
| 251 | + def update_suspicions(self, speeches): |
| 252 | + for speech in speeches: |
| 253 | + # 分析发言逻辑 |
| 254 | + pass |
| 255 | + |
| 256 | + def generate_speech(self): |
| 257 | + # 根据分析生成发言 |
| 258 | + return "根据前面的讨论,我认为..." |
| 259 | +``` |
| 260 | + |
| 261 | +## 常见问题 |
| 262 | + |
| 263 | +### 消息没有被发送 |
| 264 | + |
| 265 | +确保 Agent 已经连接到服务器,检查网络连接和服务器地址。 |
| 266 | + |
| 267 | +### 收不到服务器消息 |
| 268 | + |
| 269 | +检查事件循环是否正常运行,以及 `on_message` 回调是否正确设置。 |
| 270 | + |
| 271 | +### 超时错误 |
| 272 | + |
| 273 | +确保行为方法在规定时间内返回(通常 5-10 秒),避免进行耗时的操作 |
0 commit comments