☰
OpenViking 狼人杀多 Agent 演示完整指南:一条命令拉起裁判与 6 名 AI 玩家
2026/9/30 6:43:15 网站建设 项目流程

OpenViking 狼人杀多 Agent 演示完整指南:一条命令拉起裁判与 6 名 AI 玩家

【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking

想在本地用一条命令拉起「1 个裁判 + 6 个 AI 玩家」,看它们在共享群聊里按固定顺序轮流行动、各自记着私密小本子的狼人杀对局吗?OpenViking 的狼人杀 Demo(bot/demo/werewolf/)把多 Agent 群聊协作做成了一个可观察的最小闭环:god 裁判和 6 个玩家都是独立的 channel bot,各自拥有工作目录与GAME.md私有状态文件,整局游戏靠消息路由循环驱动、靠文件系统传递私密状态。

读完这篇指南,你将能够:

  1. 用一条命令在本地跑通完整对局,并用浏览器按钮驱动开局、连跑、停止;
  2. 说清楚每条消息如何在 god 与玩家之间串行流转、最终如何落到结算;
  3. 切换到真人混局模式,顶替一个玩家席位参与游戏;
  4. 对局结束后核对会话归档、回放状态与排行榜,并让 Agent 通过/remember逐局积累经验;
  5. 对照自救手册排掉常见故障,并把「裁判 Agent + 文件状态总线 + 路由循环」范式迁移到别的多角色协作场景。

先建立心智模型:三层服务与六个文件

这一节解决「这个 Demo 到底由什么组成」的问题,帮你把后面的启动与排障都挂在同一张地图上。

整套服务分三层,从下到上依次是:

层默认地址职责
OpenViking 服务127.0.0.1:1933记忆存取与 Agent 能力底座
Vikingbot 网关内嵌于 OpenViking 进程,--with-bot --bot-port 18790暴露 HTTP API把消息投递给不同的bot_api类型 channel Agent
狼人杀 UI 服务127.0.0.1:1995由 werewolf_server.py 提供,消费网关接口并驱动整个对局路由

Vikingbot 的所有对外接口统一挂在/bot/v1前缀下(见 openapi.py),Demo 真正依赖的只有两个:{vikingbot_url}/bot/v1/health(健康检查)和{vikingbot_url}/bot/v1/chat/channel(向指定 channel 发消息并等待回复,后者由 werewolf_server.py 中的send_to_channel封装调用)。

目录内六个核心文件的分工如下:

文件职责
start_werewolf_demo.py一键启动:补全配置、准备工作目录、拉起并守护两个服务
werewolf_server.py对局服务端:消息路由循环 + FastAPI Web UI 后端
werewolfUI.html前端单页:游戏控制、记忆浏览、排行榜、回放
SOUL-god.md裁判(god)角色规则,约 300 行完整对局规则
SOUL-player.md玩家角色规则与分身份行动指南
Cubic_11_1.010_R.ttf/GeistPixel-Square.woff2页面使用的中文 / 像素风格字体

一条消息的主链路可以压缩成一句话:你在页面上点按钮 → UI 服务经/bot/v1/chat/channel把消息发给 god → god 的回复按座位号广播给玩家 → 玩家回复被汇总结论再送回 god → 游戏进度写进GAME.md/GAME_RECORD.md,整个对局就靠这个循环推进。

一键启动命令:本地跑起来之前先查三件事

这一节解决「怎么最省事地把它跑起来」,同时把两个最容易翻车的配置坑提前说清。

启动前你只需要三样东西:

  • python(建议 3.10+,依赖httpx、fastapi、typer、uvicorn、loguru);
  • openviking-server命令可用;
  • 一份JSON 格式的配置文件(README 示例为~/.openviking/ov.conf)。

⚠️ 配置文件必须是 JSON:一键脚本里的load_json_config直接json.load,YAML 会当场报错;werewolf_server.py 的load_config同样只认 JSON。

⚠️ README 示例命令总是显式传--config ~/.openviking/ov.conf,但两个脚本源码里的默认路径都是~/.openviking/ov-multi.conf。要么显式指定路径,要么把配置放到默认位置,别两边都猜。

在bot/demo/werewolf/目录下执行:

python start_werewolf_demo.py --config ~/.openviking/ov.conf

不传任何参数时,脚本使用的默认值如下(其中bot与storage是配置文件里最少要有的两级结构;缺storage.workspace时脚本会自动补默认值并回写):

参数默认值含义
UI 端口1995狼人杀 Web UI 端口
OpenViking host127.0.0.1OpenViking 服务监听地址
OpenViking port1933OpenViking 服务端口
Vikingbot URLhttp://localhost:18790Vikingbot 网关地址
game modeall_agents全 AI 模式
game iddefault对局 ID
config~/.openviking/ov-multi.conf配置路径(示例命令会显式覆盖)
startup timeout30.0秒网关健康检查超时时间

常用的可选参数组合:

python start_werewolf_demo.py \ --config ~/.openviking/ov.conf \ --ui-port 1995 \ --game-mode all_agents \ --smart-buttons
  • --game-mode:all_agents(全 AI)或human_player(保留一个真人席位human);
  • --smart-buttons:开启前端「智能按钮显示」,按钮按游戏状态动态显隐;
  • --server-host、--server-port、--vikingbot-url、--game-id、--startup-timeout:微调运行环境。

一键脚本在背后做了什么

这一节解决「那条命令背后到底替你干了什么」,共五个动作,每步都先说做了什么、再说为什么。

  1. 校验资源(validate_assets):确认SOUL-god.md、SOUL-player.md、werewolf_server.py都在。先检查再动手,避免文件缺失时出现「半启动」状态。
  2. 注入并回写 channel 配置(ensure_werewolf_channels):清掉旧的 demo channel,再注入god、player_1~player_6共 7 个bot_apichannel,随后json.dump回写配置文件(缩进 2、ensure_ascii=False)。先清后注是为了防止重复启动时配置里攒出重复 channel。
  3. 设置沙箱边界(ensure_sandbox):把bot.sandbox.mode设为per-channel,并将 god 的工作目录限制到{workspace}/bot。裁判只需要读写自己的对局记录,收紧权限后它碰不到其他玩家的文件。
  4. 补齐存储路径(resolve_workspace):缺storage.workspace时自动填默认值~/.openviking/data并回写,保证后续所有 Agent 工作目录、对局档案落在同一棵树下。
  5. 准备 Agent 工作目录(prepare_workspace):在{workspace}/bot/workspace/下创建bot_api__god、bot_api__player_1…bot_api__player_6七个目录,god 拷入改名为SOUL.md的SOUL-god.md,每个玩家拷入SOUL-player.md——每个 Agent 启动时从自己的工作目录读取「我是谁」。

之后脚本启动openviking-server --with-bot,以 1 秒间隔轮询{vikingbot_url}/bot/v1/health(wait_for_health,默认 30 秒超时),健康检查通过后才启动 UI 服务——这避免了 UI 服务调用网关时网关还没就绪。最后它守护两个子进程:任一退出则终止另一个;Ctrl+C 时先发SIGTERM,5 秒未退再SIGKILL,不留孤儿进程。

启动后打开配置文件可以直接核对注入结果,关键片段长这样(player_2/player_3与player_1同构,player_4/5/6只有ov_tools_enable: false):

{ "bot": { "channels": [ { "type": "bot_api", "id": "god", "enabled": true, "ov_tools_enable": false }, { "type": "bot_api", "id": "player_1", "enabled": true, "profile_user_list": ["player_2", "player_3", "player_4", "player_5", "player_6"], "memory_user": "player_1" } ], "sandbox": { "mode": "per-channel", "restrictWorkspaces": { "bot_api__god": "{workspace}/bot" } } } }

设计意图写在配置里:player_1/2/3互相开放画像互看(profile_user_list)并各持独立记忆(memory_user),用来演示 Agent 基于「对其他玩家的画像记忆」做推理;god与player_4/5/6关闭ov_tools_enable,不接触不必要的工具。

手动挡调试:把两个服务拆开跑

这一节解决「我想单独调其中一个服务」的问题。先记住一个前提:手动方式要求配置里已经包含全部 7 个 demo channel——这正是建议你先跑一次一键脚本的原因,channel 注入与回写都是它代劳的。

先起 OpenViking(内嵌 Vikingbot 网关)

openviking-server \ --config ~/.openviking/ov.conf \ --host 127.0.0.1 \ --port 1933 \ --with-bot \ --bot-port 18790

--with-bot让 OpenViking 进程同时挂载 Vikingbot 网关,--bot-port决定网关端口。用http://localhost:18790/bot/v1/health确认网关就绪。

再起狼人杀 UI 服务

python werewolf_server.py \ --config ~/.openviking/ov.conf \ --port 1995 \ --game-mode all_agents

基于 Typer 定义参数,还支持短参-p/--port、-c/--config、-m/--game-mode、-s/--smart-buttons,以及--vikingbot-url、--game-id。

⚠️ 手动启动时它还会读运行时状态文件RUNTIME_STATE.json(位于 storage 的bot/workspace/werewolf/下):如果之前以human_player模式跑过,即使命令行写的是all_agents,服务也会自动恢复为human_player。此外服务启动时会加载最近一次会话并复用其 session id,保证重启后历史可衔接。

与一键启动的差异一句话总结:channel 注入、沙箱设置、工作目录准备、健康检查等待、进程守护这五件事,手动模式下全在你自己身上。

页面操作手册:每个按钮背后都是哪个接口

这一节解决「页面上看到的东西分别对应后端什么」,让你排障和二次开发时有据可查。

启动后访问:

地址说明
http://localhost:1995/主页面,由 werewolfUI.html 渲染
http://localhost:1995/test测试页,服务端加载同目录可选的test_server.html
http://localhost:1995/debug调试页,加载可选的debug.html

/test与/debug在对应 HTML 不存在时返回空页面——当前仓库只随附了主页面文件,实战以/为准。

顶部四个导航页各自的数据来源:

导航对应接口作用
游戏—主对局页
记忆GET /api/openviking/tree、GET /api/openviking/file读取 storage 下viking/default/agent与viking/default/user两棵目录树并查看文件内容
排行榜GET /api/leaderboard累计战绩与胜率曲线
回放/api/conversations、/api/conversation/{session_id}、/api/replay-state/{session_id}、/api/bot-sessions按历史会话回放对局

游戏页顶部控制按钮与后端 API 的完整映射:

页面元素对应接口作用
开始游戏POST /api/start发送「开始」指令,进入当前局流程
继续POST /api/continue暂停态下催促 god 继续本局
自动N局(旁边输入框填局数)POST /api/auto-run开启/关闭连续跑局;前端以enabled=true, mode=fixed, target_games=N提交,后端另支持mode=infinite无限连跑
停止游戏POST /api/stop停止当前路由流程并关闭自动连跑
初始化游戏 / 重新开始POST /api/restart强制新建 session 并重新初始化新局

前端刷新的三个状态接口:

  • GET /api/status:返回running、game_mode、waiting_for_human、auto_run_*、completed_games等字段,是智能按钮与连跑展示的数据源;
  • GET /api/messages:完整聊天历史;
  • GET /api/players:逐个读取各玩家GAME.md的「身份」字段生成座位信息。

顶部「模式」下拉框会写入start/restart请求的game_mode字段:all_agents即全 AI;human_player时后端会从玩家列表末尾去掉最后一个 bot(player_6),追加专用 channelhuman(build_channels_for_game_mode),并自动创建{storage}/bot/workspace/human/GAME.md。

⚠️模式只在「开始」或「重启」动作里生效:apply_game_mode_to_state只在这两个入口被调用,光切下拉框不会改变正在跑的局。

⚠️human_player模式的对局不计入排行榜:save_game_to_leaderboard_from_record对该模式直接返回skipped,理由是真人操作不具备可复现性。

切换为human_player并执行开始/重启后,页面会出现「真实玩家」区域,按钮是否可点取决于后端状态waiting_for_human(god 是否正等待@human的回合):

页面元素对应接口作用
只发给 godPOST /api/human/send,target=god真人回复作为私密回执单独送回 god,不广播给其他玩家
发给全员POST /api/human/send,target=all内容公开广播给所有其他玩家(含 bot),同时写入公开消息历史
查看 GAME.mdGET /api/human/game-md(POST /api/human/game-md可改写)读取/修改真人玩家的私有GAME.md

这套「私密操作走GAME.md、公开内容才发群」的约定贯穿整个 SOUL 规则:human是正常玩家位,必须像其他玩家一样纳入固定顺序与昼夜流程,但查验结果、用药、刀人目标这类敏感信息只能写入human/GAME.md。

以--smart-buttons启动时,前端轮询GET /api/status并按状态调整按钮:running=true时隐藏「开始/继续」;game_ended=true时显示「重新开始」;waiting_for_human=true时启用真人输入区。该功能默认关闭,不开不影响任何对局逻辑,只是按钮恒定显示。

黑盒拆解:一条消息如何被路由成一整局

这一节解决「按钮点下去之后,后端到底怎么把一局游戏跑完」,先看状态,再看循环,最后看容错。

GameState是全局共享状态 dataclass,核心字段分组如下:

  • running/router_task:路由循环是否在跑及其 asyncio 任务句柄;
  • channels:当前局参与名单(随模式变化);
  • messages/human_messages:公开消息流与真人私聊流;
  • session_id:每局唯一的会话标识;
  • game_ended、completed_games:结束标记与累计完成局数(供 auto-run 判定);
  • pending_replies、waiting_for_human、human_player_message:真人回合的等待与投递;
  • auto_run_*系列:自动连跑配置与计数。

对局推进遵循「单飞」原则:POST /api/start、/api/continue、/api/restart都会先stop_router_task取消旧循环,再以不同的初始消息启动新循环,避免并发导致流程混乱。三条入口的核心差异只有初始消息:

  • 开始:"开始";
  • 继续:"继续本局游戏"(用于 god 上次回复停留在「等待指令/初始化完成」等状态);
  • 重新开始:先生成新 session、归档旧会话与回放状态,再由build_restart_message拼一段带完整玩家名单与各GAME.md路径的建局消息发给 god,要求它初始化新局后等待「开始」指令。

路由主循环message_router_loop是整场对局的引擎,单轮流程:

  1. 发消息给当前说话者(通常是 god):调用send_to_channel且need_reply=True,同步等待 Agent 回复;
  2. 记录回复:追加进messages,并落盘为会话文件;
  3. 解析 @ 提及:parse_mentions用正则@\s*(\w+)提取 god 回复中所有被点名的玩家 id;「一次只能 @ 一个玩家」由 SOUL 规则约束;
  4. 按座位号广播:broadcast_to_players把 god 的发言并发发给所有玩家——被@的玩家need_reply=True必须回复,其余玩家need_reply=False只接收,且发送者前缀带座位号(如3号:);
  5. 广播玩家回复:每个有回复的玩家,其发言再以need_reply=False广播给除自己外的所有玩家,让全员听到本轮发言;
  6. 汇总结论回传 god:build_message_for_god把各玩家回复拼成「座位号:内容」格式送回 god,进入下一轮,由 god 再决定 @ 谁、是否进入下一阶段;
  7. 保护上限:循环最多 1000 轮(max_loops),到达即强制停止。

容错机制有三处,专治「LLM 不按剧本走」:

  • 无有效 @ 的回推:游戏未结束但 god 没 @ 任何玩家时,系统以admin_fallback_no_mention身份回推提示「你上个回复没有@任何玩家……继续@一个玩家进行」,最多重试 2 次(god_no_mention_retry_count)后终止循环;
  • 等待态识别:god 回复命中「初始化完成/等待开始/等待指令/等待继续」等标记(is_waiting_like_reply)时,判定建局完毕,主动 break 等待下一次开始指令;
  • 非法提及直接收车:god @ 到不在名单里的 channel 时,循环直接结束,不再空转。

公开域与私密域:保密信息为什么不会泄漏

这一节解决「多 Agent 同局时私密信息怎么隔离」,并把安全设计与测试佐证一并交代。

Agent 之间靠两条通道协作,边界划得很死:

通道载体允许出现的内容
公开域群聊消息(messages)公开的日夜发言、表态、投票
私密域各自工作目录里的状态文件查验结果、用药、刀人目标等一切需保密信息

各角色的状态文件与写入约束:

角色文件内容
god{storage}/bot/workspace/bot_api__god/GAME_RECORD.md全局进度表:游戏状态、轮次、玩家身份表、胜负;「游戏状态/游戏结果/游戏时间/玩家状态」均有约定格式
player_Nbot_api__player_N/GAME.md身份、夜间技能目标、查验/用药结果等私有信息
human{storage}/bot/workspace/human/GAME.md真人席位状态,模式启用时自动创建,页面可直接编辑

硬约束写在两份 SOUL 文件里:SOUL-god.md 要求黑夜与白天所有环节按开局固定的玩家顺序逐个点名、串行推进;第一晚的死亡结果在警长竞选结束前不写入任何玩家文件的「存活状态」,防止提前泄密;并给出 6/9/12 人局身份配置与胜负判定(狼人胜利=所有神职或所有平民出局)。SOUL-player.md 则约束玩家只能基于「群内公开信息 + 裁判明确告知 + 自己GAME.md」行动,严禁上帝视角。

服务端还暴露/data/{path}文件浏览与/api/game-file/{channel_id}/{filename}接口,可在页面直接查看 god/玩家的GAME.md、GAME_RECORD.md原始文件;其中/data/werewolf/GAME_RECORD.md会被特殊映射到 god 的记录文件,方便统一路径查看。所有文件访问都做了路径越界校验,读不到 storage 根目录之外的内容。

因为 UI 服务对公网(0.0.0.0:1995)开放,错误信息与路径也做了收敛,仓库自带的 test_werewolf_server_security.py 佐证了三点:

  1. POST /api/start内部抛ValueError时,接口只返回"Failed to start game",文件系统细节不进响应;
  2. 读会话文件抛内部异常时,/api/conversation/{session_id}返回通用的"Failed to read conversation"(HTTP 500),堆栈被隐藏;
  3. /api/openviking/file收到../../../路径穿越请求时被拒绝(404),越界文件内容不会返回。

对局结算后的三件套:归档、排行榜、记忆沉淀

这一节解决「一局跑完之后,系统留下了什么、为什么值得留」。

结束判定发生在每轮 god 回复之后:is_game_ended_from_record解析GAME_RECORD.md,确认结束必须同时满足——记录显示「游戏结束」、god 已产出最终结论、且 god 不再 @ 任何玩家追问后续。三条都成立后依次执行:

  1. 归档:god 的最终结算先广播给所有玩家,然后保存会话文件CONVERSATION_{session_id}.md,再把回放状态归档到REPLAY_STATE_{session_id}.json(快照GAME_RECORD.md文本、解析结果与玩家信息,使回放不依赖仍在变动的 live 文件)。意义在于对局从此可审计、可回放;
  2. 排行榜:按 god 工作区的GAME_RECORD.md解析胜方与玩家状态,计算积分(胜利 2 分 + 存活 1 分),累计进bot/workspace/werewolf/LEADERBOARD.json;重复 session 自动去重跳过,避免同一局重复计分;
  3. 记忆沉淀:向 god 与每个玩家发送/remember指令,让各 Agent 把本局经验写进自己的 OpenViking memory。这是与 OpenViking 记忆能力衔接的关键一步,也是跨局水平提升的基础。

三件套全部完成后,才依据 auto-run 配置决定下一步:满足连跑条件则 1.5 秒后自动 restart + start 调度下一局;否则关闭连跑。若开启 auto-run 时当前没有对局在跑,会以 0.1 秒延迟调度第一局;每局真正跑完后completed_games自增,达到目标局数即自动停。

狼人杀 Demo 故障点自救手册

这一节解决「跑起来之后坏了怎么办」,按「现象 → 排查顺序 → 常见根因」组织。 🛠

现象 1:点击「开始/继续」没反应

  1. 访问GET /api/status,确认 UI 后端在线;
  2. 浏览器打开{vikingbot_url}/bot/v1/health,确认 Vikingbot 网关就绪;
  3. 看返回里running是否为true。

常见根因:OpenViking 没带--with-bot启动,网关不存在,所有对局消息超时;或上一轮路由循环尚未结束,需要先「停止游戏」再操作。

现象 2:真人模式看不到输入区

  1. 确认顶部模式已选human_player;
  2. 确认是用该模式执行了开始或重启。

常见根因:模式只在 start/restart 动作里生效(apply_game_mode_to_state),纯切换下拉框不会改变正在跑的局。

现象 3:回放内容不完整

  1. 检查CONVERSATION_{session_id}.md与REPLAY_STATE_{session_id}.json是否存在且完整;
  2. 回忆该局是否中途强制停止过。

常见根因:回放依赖会话记录与归档状态文件,中途被停的局缺少权威GAME_RECORD.md快照;建议让一局正常走到结算后再看回放。

现象 4:一局跑太久或疑似卡死

  1. 随时点「停止游戏」中断路由(取消 router task 并关闭自动连跑);
  2. 观察 god 是否连续两次没 @ 到有效玩家。

常见根因:god 连续 2 次无效 @ 时循环会自动停止,不会无限循环;max_loops的 1000 轮是硬顶,超过即收车。

现象 5:UI 起来了,但对局消息全部超时

  1. 确认openviking-server进程存活、端口1933在监听;
  2. 确认 Vikingbot 端口18790在监听;
  3. 核对 UI 服务的--vikingbot-url指向与网关实际地址一致。

常见根因:手动启动时--bot-port与 UI 端--vikingbot-url不匹配,消息发往了不存在的网关。

现象 6:想连续压测对局

  1. 在「自动N局」输入框填局数后点击,开启 fixed 模式连跑;
  2. 观察GET /api/status中auto_run_remaining_games递减到 0。

根因提示:对局之间会自动完成 restart + 建局 + start 的完整衔接,且每局的/remember让 Agent 记忆逐局累积,跨局表现会随之变化——这是特性,不是随机波动。

超越 Demo:四个可迁移的工程范式

这一节解决「不玩狼人杀,这套东西对我还有什么用」。

  1. 双通道信息隔离:夜间行动只写GAME.md,群里只回「操作完成」,天然规避了 LLM 上下文里「谁都能看到所有人记忆」的常见泄漏问题。可迁移到多角色客服质检、合规审查等要求敏感信息不跨角色流动的场景。
  2. 串行协作的双重约束:路由循环的「一次只 @ 一个 + 等回复再广播 + 汇总回传」与 SOUL 的固定顺序规则互为备份,任何一层失守另一层兜底。可迁移到多方谈判模拟、仲裁流程、剧本杀等按轮次推进的多角色协作。
  3. 文件即状态总线:GAME_RECORD.md/GAME.md承载对局进度,CONVERSATION_*、REPLAY_STATE_*、LEADERBOARD.json构成可审计的对局档案,任何时刻打开文件就能知道局面。可迁移到需要审计与回放的裁判型多 Agent 流程。
  4. 跨局经验累积:每局结算后全员/remember,经验沉淀进 OpenViking memory,排行榜与回放为策略分析提供数据基础,Agent 越打越强。可迁移到需要随使用次数自我改进的长期运行 Agent。

参考路径速查

  • Demo 说明文档:bot/demo/werewolf/README.md
  • 一键启动脚本:bot/demo/werewolf/start_werewolf_demo.py
  • 对局服务与路由引擎:bot/demo/werewolf/werewolf_server.py
  • 前端页面:bot/demo/werewolf/werewolfUI.html
  • 裁判角色规则:bot/demo/werewolf/SOUL-god.md
  • 玩家角色规则:bot/demo/werewolf/SOUL-player.md
  • 服务安全测试:bot/tests/test_werewolf_server_security.py
  • Vikingbot/bot/v1路由挂载点:bot/vikingbot/channels/openapi.py

【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询