“一觉醒来,全球狼人杀水平下降100倍”这个标题并不是游戏新闻,而是一个非常可以直接验证的技术假设:如果一桌玩家全部换成大模型智能体,狼人杀的水平会迅速退化。狼人杀的核心动作是发言、投票、伪装、联合,这些动作背后依赖多轮记忆、反向推理、协作判断和反套话能力。大模型在单轮问答里表现很强,但把它放进狼人杀这种连续博弈场景,说话顺序、票型记录、身份暴露都会变成真实的工程问题,甚至会因为上下文过长、指令覆盖不足,直接把一局游戏跑崩。
这篇文章不讨论“大模型能不能统治狼人杀”,而是给出一个本地可以复现的验证思路:如何搭一套多智能体狼人杀仿真环境,用本地模型或 API 模型驱动玩家角色,批量跑几十局,统计好人方和狼人方的胜率,再用真实对战日志判断模型更适合坐在哪张椅子上。整个过程不需要复杂的外部依赖,也不需要专用硬件,模型接入方式、提示词模板、批量并发全部由你自己控制。
后面所有命令、配置和代码都按照通用模板给出。你的实际项目路径、模型名、端口、提示词模板和数据结构可能与示例不同,替换对应字段即可。如果你想验证一个开源模型的“角色扮演稳定性”、推理一致性和长时间对话能力,这个环境比普通的多轮问答更有说服力。
1. 核心能力速览
先看这套多智能体狼人杀仿真环境的核心能力。因为它是 DIY 方式搭建,不是某个固定的开源闭源项目,所以下面表格里的能力项描述的是环境本身:
| 能力项 | 说明 |
|---|---|
| 角色类型 | 狼人、村民、预言家、女巫、猎人,数量可配置 |
| 玩家组成 | 每个角色由一个 LLM Agent 驱动,模型可本地可 API |
| 核心机制 | 发言生成、投票决策、遗言分析、夜间行动、胜负结算 |
| 批量能力 | 支持多局流水线、连续采样、胜率统计 |
| 接口接入 | 本地模型多使用 OpenAI 兼容接口,地址需按实际服务调整 |
| 启动方式 | Python 脚本启动,可自定义日志目录和结果输出 |
| 硬件门槛 | 纯 API 方式基本不占本地显存;本地模型跟随所选模型参数量变化 |
| 输出结果 | 局面日志、发言文本、投票记录、胜负结果、Token 消耗 |
这套环境最值得做的三件事:第一,单局跑通,验证对话链路和胜负判定逻辑是否正常;第二,批量跑局,验证模型在不同角色下的胜率差异;第三,观察 Token 消耗和长上下文表现,判断模型在语音之外的“策略稳定性”。
2. 这个场景到底在测什么
狼人杀不是简单的问答任务。它更像一个长时间、多角色、有信息不对称的“社会推理沙盒”。把大模型放进去,实际暴露的是四类能力:
第一,多轮记忆。一局狼人杀少则三轮,多则六七轮,玩家需要记住谁第一天投了谁、谁跳了预言家、谁在关键轮次改票。大模型的上下文窗口有限,早期发言还有可能被后续长文本稀释,很容易出现“第二轮就开始遗忘第一轮票型”的问题。这里可以量化测试:让同一个模型分别用 2K、4K、8K 上下文窗口跑同一局,比较发言的引用准确度。
第二,身份伪装与诱导。狼人玩家要编造一套“我是好人”的逻辑,还要给真预言家泼脏水。大模型默认的训练目标是“诚实、有帮助”,让它在游戏语境下“合理撒谎”并不容易。你可以在提示词里明确指定:“你现在是狼人,你要在不直接暴露身份的前提下把投票引向另一名玩家”,然后检查它生成的发言是否足够自然。
第三,反向推理与反诈。好人玩家要识别狼人发言中的漏洞,尤其是要在预言家查验信息和自己观察到的投票行为之间做交叉验证。大模型擅长单点推理,但在“多候选、多轮证词”的复杂推理中容易偏向最近发言或语气更强势的玩家,这类偏差会直接反映在投票准确率上。
第四,协作与分工。女巫救人、猎人开枪、预言家报查验,这些强神角色需要通过发言完成信息交换,但又不能过早暴露身份。多智能体环境里,角色之间的协作是否有效,取决于 Agent 能否根据游戏规则生成可执行决策,而不是单纯生成“听起来合理”的文本。
这也是为什么很多研究项目和开源评测会拿狼人杀作为大模型能力的试金石。相比固定答案的 benchmark,狼人杀没有标准答案,只有“这一局谁赢了”,因此输出空间更开放,也更难作弊。
3. 环境准备与前置条件
搭这套验证环境不需要太高的门槛,但需要先把运行链路理清。模型你可以选择两个方向:
- 本地模型:用 Ollama、vLLM、Xinference 等工具加载开源模型,服务地址通常是
http://127.0.0.1:11434/v1之类的 OpenAI 兼容接口。本地模型的优势是数据不出本机、可以高频调试,劣势是显存占用取决于模型规格。 - API 模型:调用云端模型的 OpenAI 兼容接口。这种方式对本地显存没有要求,适合先验证游戏逻辑和提示词设计;但是批量跑局会消耗 Token,并且日志中会包含完整的对局文本,注意不要放入真实个人信息。
操作系统与运行环境检查清单:
| 检查项 | 要求说明 |
|---|---|
| 操作系统 | Linux 或 Windows 均可,本地模型推荐 Linux + NVIDIA 驱动环境 |
| Python | 建议 3.10 及以上 |
| 依赖包 | openai、pyyaml、pydantic,后续按实际模块补充 |
| 本地模型服务 | Ollama / vLLM / Xinference 任选其一,先保证 chat 接口可通 |
| 磁盘空间 | 根据模型文件大小预留,7B 量化模型与 70B 模型相差很大 |
| 端口占用 | 模型服务端口和脚本请求端口要一致 |
如果没有本地 GPU,也可以直接用 CPU 跑小参数量化模型,但每局速度会比较慢。更稳妥的判断是:先用云端 API 或一个小模型跑通游戏状态机,再决定是否引入更大的本地模型。
4. 搭建 AI 狼人杀仿真环境的目录与配置
一个最小可运行的多智能体狼人杀环境建议按下述目录组织,把“游戏规则”和“模型行为”分离,后续替换提示词或模型时不需要动主流程。
wolf_arena/ ├── config/ # 角色配置、局数配置、模型配置 ├── agents/ # Agent 行为封装 ├── core/ │ ├── game.py # 游戏状态机 │ ├── narrator.py # 主持人与裁判逻辑 │ └── voter.py # 投票结算 ├── prompts/ # 各类角色的提示词模板 ├── runner.py # 批量运行入口 └── logs/ # 对局日志与结果输出4.1 游戏配置示例
这里给出一个 YAML 配置模板,字段含义清晰,按实际需要修改即可。不要照抄模型名和端口,它们取决于你本地加载的服务。
# config/example.yaml game: max_rounds: 6 roles: werewolf: 2 seer: 1 witch: 1 villager: 4 agents: model: "qwen2.5:7b" # 示例模型名,按实际替换 base_url: "http://127.0.0.1:11434/v1" api_key: "EMPTY" temperature: 0.8 max_tokens: 256 output: log_dir: "./logs"角色数量不需要固定,但最好保证游戏能正常结束。常见的做法是 9 人局或 12 人局,玩家总数偏少时容易出现“白天没投出人、晚上又刀一个”的死循环,因此max_rounds建议设置上限。
4.2 最小批量运行入口
下面的runner.py只是示意代码,用来展示多智能体狼人杀环境的主流程:创建玩家、运行游戏、收集结果。真正落地时,你需要把create_agent、Game等模块换成你自己实现的类。
# runner.py: 最小批量运行入口,需按你的目录结构调整 import asyncio from agents.player import create_agent from core.game import Game async def run_one_game(cfg: dict) -> dict: players = [ create_agent(seat, role, cfg) for seat, role in enumerate(cfg["seats"]) ] game = Game(players, narrator=cfg["narrator"]) result = await game.run() return result if __name__ == "__main__": cfg = { "seats": [ {"role": "werewolf"}, {"role": "werewolf"}, {"role": "villager"}, {"role": "villager"}, {"role": "seer"}, ], "narrator": {"model": "qwen2.5:7b"}, } result = asyncio.run(run_one_game(cfg)) print("winner:", result["winner"])在这类多智能体框架里,主持人也可以由大模型承担。主持人负责宣布昼夜转换、收集夜间行动、公布死亡信息。必须注意的是:主持人不能被某一边的角色“带偏”,所以主持人的系统提示词要明确禁止它参与投票,也禁止它泄露任何角色身份。
5. 功能测试与效果验证
环境搭好之后,第一步不是直接上 100 局,而是先做最小功能验证。多智能体系统的失败通常是一层层叠加的:状态机出错、提示词写错、模型返回格式不对,都会导致整局游戏中断。下面按验证顺序展开。
5.1 最小单局测试:跑通还是跑不通
测试目的:确认游戏能在一局内正常结束,没有死循环,也没有中间报错。
操作步骤:
- 加载一个最小配置,例如 4 个村民 + 2 个狼人;
- 将模型
temperature调到 0.3,降低随机性; - 启动
runner.py,观察是否逐轮输出; - 在日志中确认:夜晚结算、白天发言、投票、胜负判定四个阶段都执行完毕。
判断成功标准:日志完整记录每一轮的发言和投票,最后输出winner字段,且没有因 JSON 解析或超时导致中断。
常见失败原因:模型返回了非结构化文本,投票解析器读不出目标玩家。遇到这种情况,最直接的修复方式是给投票格式加约束,例如在提示词中强制要求输出VOTE: <玩家编号>,再在代码里做正则提取。
5.2 角色行为质量人工检查
游戏跑通之后,需要人工阅读一轮完整日志,重点不是看谁赢,而是看每个角色的行为是否符合身份逻辑。建议从以下问题入手:
- 村民是否只会无脑跟票?如果是,说明提示词缺少分析环节。
- 狼人是否在首轮就暴露了身份?如果是,说明伪装提示词没有生效。
- 预言家是否在查验结果后合理报信息?它有没有把查验结果说成“猜测”?
- 女巫是否乱用解药?救人条件是否合理?
- 被投票出局的玩家有没有按照“遗言”规则约束输出?
如果你发现某个角色连续复读同一句话,或者发言中出现“作为 AI,我无法参与这类游戏”的脱戏内容,优先检查两处:系统提示词里是否明确了这个 Agent 的玩家身份;模型是否有拒绝执行游戏指令的倾向。很多开源模型默认带有“伦理对齐”行为,需要在提示词里写清楚“这是模拟游戏,你的输出仅用于游戏进程”。
5.3 指令遵循与格式稳定性测试
这是狼人杀多智能体环境和大模型普通聊天最大的区别:游戏要求模型在限定时间内给出结构化决策,而不是自由输出。
可以设计 10 次重复调用来测试格式稳定性:
- 给同一个 Agent 发送同一段“当前局面摘要”,要求它给出投票目标;
- 连续调用 10 次,统计返回值可以正确解析的比例;
- 如果成功率低于 80%,优先调整输出格式约束,而不是换模型。
import re from openai import OpenAI client = OpenAI(base_url="http://127.0.0.1:11434/v1", api_key="EMPTY") def ask_vote(client, model: str, situation: str) -> str: resp = client.chat.completions.create( model=model, messages=[ {"role": "system", "content": "你是狼人杀玩家,只能输出 VOTE: <编号>"}, {"role": "user", "content": situation}, ], temperature=0.2, ) return resp.choices[0].message.content situation = "场上剩余玩家:0号普通村民、1号预言家、2号狼人。你也是狼人。" for i in range(10): out = ask_vote(client, "qwen2.5:7b", situation) print(i, out, "格式OK" if re.match(r"^VOTE: \d+$", out.strip()) else "格式错误")这段代码展示了“格式稳定性”的测试方法。真实游戏里,你还要考虑模型输出多余内容的情况,例如在VOTE: 2前面加了“我认为应该投……”这种话,解析时要做容错处理。
6. 批量评测与接口接入
6.1 批量对战脚本设计
单局测试通过后,就可以进入批量评测阶段。批量跑局的目标不是“让模型多玩几把”,而是获得可统计的胜率数据。比如相同角色配置下,让同一个模型分别扮演狼人和预言家,各跑 20 局,比较两个角色胜率差异,就能直观看出它更适合强推理位还是更适合伪装位。
批量并发不能盲目调大。一个本地模型服务同时接收太多请求,会拉长单请求响应时间,甚至出现超时。更稳妥的做法是限制并发数,用结果队列收集数据。
# batch_demo.py: 多线程批量跑局示例,需按实际模块调整 from concurrent.futures import ThreadPoolExecutor, as_completed def run_game_with_seed(seed: int): # 把 seed 传入游戏模块,确保每局行为不完全相同 return run_one_game(cfg, seed=seed) results = [] with ThreadPoolExecutor(max_workers=4) as pool: futures = [pool.submit(run_game_with_seed, i) for i in range(20)] for future in as_completed(futures): results.append(future.result()) werewolf_wins = sum(1 for r in results if r["winner"] == "werewolf") print(f"共 20 局,狼人胜 {werewolf_wins} 局,好人胜 {20 - werewolf_wins} 局")批量跑局时,建议每局记录独立的日志文件,包括:模型名称、温度、角色分配、随机种子、每一轮发言摘要、最终胜负。这样后续做数据分析时,不用重新跑局就能定位到具体问题。
6.2 API 接入与远程模型调用
如果不想本地加载模型,或者要对比多个云端模型的表现,可以直接把 Agent 的base_url切换到云端服务的 OpenAI 兼容地址。用 curl 可以快速验证某个模型是否可用:
curl http://127.0.0.1:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5:7b", "messages": [ {"role": "system", "content": "你是狼人杀玩家,请给出今晚要击杀的目标编号"}, {"role": "user", "content": "你是狼人,目前存活玩家:0号、1号、2号"} ], "temperature": 0.7 }'需要注意的是,这只是一个通用请求示例。不同模型服务的接口路径、参数名、鉴权方式都不完全相同,切换服务商时一定要先查看对应文档。接入 API 后,推荐增加“接口连通性检查”函数,在批量任务启动前先发一条测试消息,避免跑到一半才发现服务不可用。
7. 资源占用与性能观察
狼人杀多智能体环境的资源占用,主要由模型推理消耗和游戏框架消耗两部分构成。游戏框架本身只做规则判断和文本拼接,开销很小;大头在模型请求上。
本地模型场景下,需要同时关注显存占用、单次请求延迟和上下文长度。显存占用来源包括模型权重、KV Cache 和并发请求的临时缓存。模型参数量越大、并发数越多,显存占用越高。接入多个不同本地模型做对比时,注意不要让几个模型同时常驻显存,否则很容易在批量任务中直接 OOM。
上下文长度是另一个关键瓶颈。狼人杀一局会产生发言、投票、夜间行动等多轮文本,随着轮数增加,输入给模型的上下文会越来越长。如果模型窗口只有 8K,可能到第 4 轮就会出现早期信息被截断的问题。实际需要多长的上下文,取决于你每一轮给 Agent 输入多少历史信息。建议先设计“最近 N 轮摘要”机制,而不是把全部历史发言原样塞给每个 Agent。
观察资源占用有多种方式:
nvidia-smi可以实时看显存利用率和显卡温度;- 模型服务的日志通常会打印每次请求的 Token 消耗;
- 在代码里给每次响应计数,一天跑完可以汇总出总 Token 用量;
- 批量任务建议每 10 局输出一次进度和累计耗时,方便提前发现卡死情况。
如果你用的是云端 API,本地资源占用基本恒定,重点观察的是单局 Token 消耗和接口延迟。日志越完整,越容易判断一个模型“是否划算”——有些模型单局质量不错,但 Token 消耗量是其他模型的两三倍,并不适合大批量跑。
8. 常见问题与排查方法
多智能体系统调试起来比单模型调用麻烦很多,因为“模型答错了”和“框架逻辑错了”都会表现为“游戏跑崩了”。下面按问题现象整理排查思路:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 启动后一直没有输出 | 模型服务未启动或接口地址错误 | 检查模型服务日志,单独发一次 chat 请求 | 确认base_url和端口配置正确 |
| 发言重复或内容空洞 | 温度设置过低或提示词缺少上下文 | 调高温度,检查输入历史是否完整 | 降低温度时同步增加角色性格约束 |
| 投票结果无法解析 | 模型未按VOTE: 编号格式输出 | 打印模型原始返回 | 加正则容错,或要求模型只输出 JSON |
| 上下文超长被截断 | 每轮历史全部填充导致窗口耗尽 | 查看日志中的 Token 统计 | 引入滑动窗口或摘要机制 |
| 局数越多结果越单调 | 随机种子固定或模型采样过于收敛 | 检查不同局之间的配置差异 | 每次运行换随机种子,适当调高温度 |
| 本地显存不足 | 模型太大或并发数太高 | nvidia-smi查看显存 | 换量化模型或减少并发数 |
| 批量任务中途超时 | 单次请求响应时间过长 | 查看单请求耗时日志 | 增大超时时间,缩小批量并发规模 |
| 模型拒绝扮演角色 | 模型对齐策略拦截了游戏指令 | 打印拒绝回复原文 | 在系统提示词中明确模拟游戏属性 |
排查有一条通用经验:先单独调模型接口,再跑单局,最后才上批量。直接拿 100 局压测来定位一个“模型返回被拒”的问题,会把问题放大十倍。
9. 最佳实践与合规提醒
批量验证狼人杀多智能体环境,建议从一开始就建立工程规范。日志目录、配置目录、模型输出目录最好分开,每次实验前用命令行参数记录本次实验的模型名、温度、角色配置和随机种子。这样跑完几十局之后,你能证明胜率差异是“模型能力差异”而不是“随机种子差异”。
提示词模板建议做版本管理。角色提示词通常会迭代很多次,每次修改都要记录修改原因。比如某次调整把狼人的“隐藏身份”约束加强后,狼人胜率明显提升,这个结论需要可靠的版本对比支撑。
在这个场景里还要注意安全和合规边界。狼人杀本身是模拟游戏,不涉及真实隐私,但批量日志里会包含完整发言和投票记录。如果这些日志未来要公开或用于评测报告,建议先做匿名化处理,移除玩家编号之外的可识别信息。另一个边界是:不要让 AI 玩家使用特定算法去模仿真实社区里的玩家风格。任何对真实人物、真实网络社区用户行为的模仿和采集,都需要明确授权,在不具备授权条件下只能测试通用角色设定。
如果你的环境需要接入第三方 API 服务,注意查看服务商的使用条款和数据存储政策,不要往日志里写入账号密钥,也不要把组织内部敏感文本放进游戏上下文中。本地模型最大的优势就在数据不出机器,如果你的实验环境涉及未公开材料,优先选择本地部署路线。
10. 批量实验的下一步扩展
多智能体狼人杀环境跑通后,能做的扩展方向很多。最常见的是模型横向对比:在完全相同角色配置下,让不同模型各跑 20 局,用胜率、回合数、格式错误率、Token 消耗四个指标综合排序。这个结果比“打榜分数”更接近真实使用体验。
另一个方向是角色混合实验:让模型 A 扮演狼人,模型 B 扮演好人,观察双方在同一局里的博弈。很多场景下的“队友”并不是同一个模型,混合实验能更真实地反映部署后的协作表现。
还有一个方向是 Agent 记忆模块优化。不依赖模型原生上下文窗口,而是手动维护一个“局面摘要”,每一轮把关键票型、发言疑点、存活角色压成一段结构化文本,再和最新发言一起送入模型。这种做法的好处是能够降低 Token 消耗、减少长上下文噪声。你可以直接拿批量胜率来验证摘要是否丢失关键信息。
如果你真的想测“一觉醒来全球狼人杀水平下降 100 倍”这个假设,最直接的做法就是跑一组对照实验:给同一个模型分别配置 512 字短记忆、完整长上下文、无记忆三种模式,每组跑 20 局。大概率你会看到:无记忆的模型在第三轮就开始逻辑混乱,短记忆模型表现稳定但很难做复杂的反推,长上下文模型能不能赢更多,则取决于模型本身的长文本理解能力。
这个验证环境不贵,也不依赖专用硬件,核心价值是给大模型提供一种“持续博弈压力测试”。角色扮演提示词、格式解析、批量并发、日志统计,每一步都是可以落地的工程问题。建议先把最小单局跑通,再跑 20 局对照,最后再上 100 局批量实验。