{"id":50791068,"url":"https://github.com/gtoxlili/lark-arena","last_synced_at":"2026-06-12T11:01:26.849Z","repository":{"id":354134985,"uuid":"1222252028","full_name":"gtoxlili/lark-arena","owner":"gtoxlili","description":"飞书群聊 AI 牌局机器人 · 德州扑克 + 狼人杀 · 接 DeepSeek/OpenAI 大模型当 AI 玩家 · 卡片 JSON 2.0 · 群里就能开局 · Rust + axum + redb","archived":false,"fork":false,"pushed_at":"2026-04-29T04:39:55.000Z","size":317,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-29T05:25:05.135Z","etag":null,"topics":["ai-agent","ai-poker","axum","bot","card-game","chatbot","deepseek","docker","feishu","feishu-bot","group-chat-bot","lark","lark-bot","llm","mafia-game","poker","rust","texas-holdem","webhook","werewolf"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gtoxlili.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-27T07:24:55.000Z","updated_at":"2026-04-29T04:39:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gtoxlili/lark-arena","commit_stats":null,"previous_names":["gtoxlili/lark-poker","gtoxlili/lark-arena"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/gtoxlili/lark-arena","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtoxlili%2Flark-arena","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtoxlili%2Flark-arena/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtoxlili%2Flark-arena/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtoxlili%2Flark-arena/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gtoxlili","download_url":"https://codeload.github.com/gtoxlili/lark-arena/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gtoxlili%2Flark-arena/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34240817,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agent","ai-poker","axum","bot","card-game","chatbot","deepseek","docker","feishu","feishu-bot","group-chat-bot","lark","lark-bot","llm","mafia-game","poker","rust","texas-holdem","webhook","werewolf"],"created_at":"2026-06-12T11:01:13.988Z","updated_at":"2026-06-12T11:01:26.834Z","avatar_url":"https://github.com/gtoxlili.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 夜局 · 飞书群聊 AI 牌局机器人\n\n\u003e **夜局**(`lark-arena`)—— 饭后约一局,在飞书群里玩 **德州扑克** + **狼人杀**,人不够用 **AI 玩家**凑（DeepSeek / OpenAI / Doubao 都能接）。一行 docker 起服务,把 bot 拉进任意群,@ 一下就开局。\n\n\u003e *Yejú* (lit. \"night session\", project codename `lark-arena`) is a multi-game arena bot for **Feishu (Lark)** group chats — runs **Texas Hold'em** and **Werewolf / Mafia** sessions where empty seats are filled by **LLM-driven AI players**. Single static binary, JSON 2.0 interactive cards, persistent chip stacks via redb. Drop the bot into any group; it just works.\n\n**关键词 / Keywords**: 飞书机器人, Lark bot, 飞书 AI 玩家, 飞书德州扑克, 飞书狼人杀, 飞书桌游, 群聊游戏, Texas Hold'em poker bot, Werewolf / Mafia game bot, group chat AI agent, LLM poker, DeepSeek bot, Rust + axum.\n\n## 特性 · Features\n\n- **德州扑克 (Texas Hold'em)**：多玩家、边池 (side pots)、全押 (all-in)、6+ 短牌 (6+ short deck)\n- **狼人杀 (Werewolf / Mafia)**：9-12 人板娘、狼 / 狼王 / 预言家 / 女巫 / 猎人 / 守卫 / 村民、屠城判定、上警警徽流转、自刀策略\n- **AI 玩家 (LLM-driven seats)**：每个 AI 都有人设 (莽哥/老炮/跟注站/老抠/头铁)，跟人打感觉不像跟机器打。可叠加多个，一桌混合人 + AI\n- **卡片 JSON 2.0**：手牌方块、加注 form 输入、按钮分级、ephemeral 私密卡片（仅当前 actor 可见，群里其他人只看公开公告）\n- **持久化**：redb 嵌入式 ACID 数据库，重启不丢筹码 / 不丢身份 / 不丢局\n- **2026 极致性能栈**：Rust 2024 edition · mimalloc 全局 allocator · sonic-rs SIMD JSON · foldhash · fastrand · rayon 并行 Monte Carlo equity · u64 bitmask 7 张直评器 · arc-swap 无锁 token 缓存\n\n## 部署\n\n### 1. 拉镜像并运行\n\n**默认多群模式** —— 机器人会响应所有把它拉进群的飞书群,各群游戏状态独立按 `chat_id` 分桶,互不干扰。\n\n```bash\ndocker pull ghcr.io/gtoxlili/lark-arena:latest\n\ndocker run -d \\\n  --name lark-arena \\\n  --restart unless-stopped \\\n  -e FEISHU_APP_ID=\u003cyour_app_id\u003e \\\n  -e FEISHU_APP_SECRET=\u003cyour_app_secret\u003e \\\n  -e BIND_ADDR=0.0.0.0:8080 \\\n  -e RUST_LOG=lark_arena=info,tower_http=info \\\n  -e LARK_ARENA_DB_PATH=/data/arena.redb \\\n  -v lark-arena-data:/data \\\n  -p 8080:8080 \\\n  ghcr.io/gtoxlili/lark-arena:latest\n```\n\n\u003e 想锁单群测试?加上 `-e ALLOWED_CHAT_ID=oc_xxx`,只有那个群的事件被处理,其他群一律忽略。生产部署不建议设这个。\n\n### 2. 飞书后台配置\n\n在 [飞书开放平台](https://open.feishu.cn/app) 新建企业自建应用，添加机器人能力。\n\n**权限管理**(租户级,加完一次所有群通用)\n\n| Scope | 用途 |\n| --- | --- |\n| `im:message:send_as_bot` | 发消息 |\n| `im:message.group_at_msg:readonly` | 接收群里 @ 机器人 |\n| `im:chat:readonly` | 读群成员、用户进群事件 |\n| `contact:contact.base:readonly` | 读真人昵称（否则全部 fallback 成\"玩家\"，AI 没法分辨谁是谁）|\n\n**事件配置**（事件与回调 → 事件配置）\n\n- 订阅方式：将事件发送至开发者服务器\n- 请求地址：`http://\u003cyour-server\u003e:8080/webhook/event`\n- 订阅事件:\n\n| 事件 | 用途 |\n| --- | --- |\n| `im.message.receive_v1` | 接收群里所有 `@机器人 …` / `/poker` / `/wolf` 命令 |\n| `im.chat.member.user.added_v1` | 普通用户进群,bot 给该用户发个 ephemeral 玩法提示 |\n| `im.chat.member.bot.added_v1` | **机器人自己**被拉进新群时,在群里发欢迎卡 + 玩法说明(让群成员立刻知道 bot 能干啥) |\n\n不要在事件配置页订阅 `card.action.trigger`。\n\n**回调配置**（事件与回调 → 回调配置）\n\n- 请求地址：`http://\u003cyour-server\u003e:8080/webhook/card`\n- 订阅回调：仅 `card.action.trigger`\n- 删除：`card.action.trigger_v1`、`url.preview.get`、`profile.view.get`\n\n`card.action.trigger_v1` 和 `card.action.trigger` 同时订阅会造成同一次按钮点击发两份回调。\n\n**版本管理与发布**\n\n每次改完订阅或权限都要创建版本并发布。\n\n### 3. 把机器人拉进群\n\n群设置 → 机器人 → 添加机器人。\n\n## 玩法\n\n### 统一大厅\n\n每个群只有一张大厅卡，玩家先点 **[加入]** 入座，再选模式：\n\n- **[🎰 开始德州]** / **[🎰 短牌德州]** — 走德州流程\n- **[🐺 开始狼人杀]** — 走狼人杀流程\n\n人数门槛：\n- 德州：≥ 2 名持筹码玩家\n- 狼人杀：9-12 人（标准板娘）\n\n按钮共用：`[加入]` `[加入 AI]` `[移除 AI]` `[离开]` `[重置]`。任一模式进行中时所有按钮收起，只显示当前游戏状态。\n\n### 文字命令\n\n#### 德州\n\n`/poker \u003c关键词\u003e` 或 `@机器人 \u003c关键词\u003e`：\n\n| 命令 | 说明 |\n| --- | --- |\n| `join` / `加入` | 入桌 |\n| `leave` / `离开` | 离桌（牌局未开始时） |\n| `start` / `开始` | 开局，需 ≥ 2 名持筹码玩家。`start short` 走 6+ 短牌 |\n| `state` / `状态` | 查看当前状态（私下回复） |\n| `chips` / `筹码` | 查看各家筹码（私下回复） |\n| `reset` / `重置` | 重置房间（清空德州+狼人杀） |\n| `help` / `帮助` | 帮助卡 |\n\n短牌：36 张牌（去掉 2-5），同花 \u003e 葫芦、三条 \u003e 顺子，A 低顺是 A-6-7-8-9。\n\n行动按钮只发给当前 actor，仅他可见，包括 `[弃牌] [跟注 X] [全押]` 一行 + 加注 form 输入框 + 三个加注预设。\n\n#### 狼人杀\n\n`/wolf \u003c关键词\u003e` 或 `@机器人 wolf \u003c关键词\u003e` 或 `@机器人 狼 \u003c关键词\u003e`：\n\n| 命令 | 说明 |\n| --- | --- |\n| `join` / `加入` | 入房（同 `/poker join`） |\n| `leave` / `离开` | 离房（同 `/poker leave`） |\n| `start` / `开始` | 开狼人杀，需 9-12 名玩家 |\n| `reset` / `重置` | 重置房间（同 `/poker reset`） |\n| `help` / `帮助` | 狼人杀帮助卡 |\n\n`join` / `leave` / `reset` 在两个命名空间下完全等价——大厅名册是统一的。\n\n**角色配比**：\n\n| 人数 | 角色 |\n| --- | --- |\n| 9 | 3 狼 + 预言家 + 女巫 + 猎人 + 3 村民（不上警） |\n| 10 | 2 狼 + **狼王** + 预言家 + 女巫 + 猎人 + 守卫 + 3 村民 |\n| 11 | 2 狼 + **狼王** + 预言家 + 女巫 + 猎人 + 守卫 + 4 村民 |\n| 12 | 3 狼 + **狼王** + 预言家 + 女巫 + 猎人 + 守卫 + 4 村民 |\n\n**流程**：开局 → 身份 ephemeral → **第 1 夜**（守卫 → 狼刀 → 预言家 → 女巫）→ 黎明公布死讯（夜里死的人**全部静默**，不说遗言）→ **上警阶段**（10+ 人板，仅第 1 天）→ **上警发言**（候选 ≥ 2 时按提名顺序轮流）→ 警长投票 → **警长选警上 / 警下** → **白天轮流发言**（警长末位归票）→ 全员投票放逐 → **放逐者遗言** → 猎人 / 狼王开枪 / 警徽流转 → 检查胜负 → 下一夜 / 结束。\n\n**胜负**（屠城 + 警长例外）：\n- 好人胜：杀光所有狼（含狼王）\n- 狼胜：存活狼 \u003e 存活好人，**或** 1:1 但警长不在好人手上\n- 1:1 时如果好人方还有警长存活（1.5x 票权可在投票中反扑），**不算狼胜，游戏继续**\n\n**关键规则**：\n- **狼王 (10+ 人板)**：狼阵营。被投票放逐时可开枪带走一人；**被毒不能开枪**。预言家查验显示为狼。**公开开枪广播不会标记为\"狼王\"**（按惯例伪装成猎人），真身在结算 summary 揭晓。\n- **守卫 (10+ 人板)**：每晚守一名玩家（含自己），不可连续两晚守同一人。**同守同救**：被守 + 被救 → 双重保护抵消，依然死亡。\n- **女巫**：救药 / 毒药各 1 瓶，同晚不可救+毒。\n- **猎人**：被狼刀或被放逐时可开枪带走一人。**被毒**不能开枪。\n- **警长 (10+ 人板)**：1.5 倍票权（整数 3 vs 普通 2）；死亡时可移交警徽给存活玩家或撕毁。**警长决定白天发言警上 / 警下方向，本人末位归票**。\n- **死亡遗言**：**只有白天被放逐者有遗言**；夜里死的人（狼刀 / 毒 / 同守同救）全部静默；被开枪带走者也无遗言。猎人 / 狼王临死开枪时由 `dying_hunter_combined` 一次性吐出『一句话+开枪目标』，那一句话同时充当临终信号。\n\n**讨论 / 发言机制**：\n- **狼人夜间** ：\n  - 全 AI 局：跳过讨论，AI 顺序决策后直接结算\n  - 混合 / 全人类局：每只狼收到带聊天的私密行动卡（update_card 原地刷新），AI 也会发表一句协调队友的话；人类可在卡片输入框里发言、改目标、点 [我决定了] 锁定。**全员就绪才结夜**\n- **上警发言（10+ 板，候选 ≥ 2）**：候选人按提名顺序轮流，公开\"上警发言卡\"显示进度+历史，当前候选人收到私密输入卡（[✅ 说完了] / [⏭ 沉默]）\n- **白天发言**：警长起手顺时针轮流（无警长则随机起点），公开发言卡 update_card 同步进度，当前发言人私密收到输入卡。**全员说完才能投票**，避免抢话\n\n**AI 玩家**：配 `OPENAI_API_KEY` 后可加入 LLM 驱动的 AI。每个角色都有专属 prompt：狼/狼王夜杀 + 队伍频道发言 / 预查验 / 女巫救毒 / 守卫守护 / 猎人 / 狼王开枪 / 上警决策 / 警长投票 / 警徽流转 / 白天发言。AI 失败/超时自动 fallback 到安全选择。\n\n## AI 对手\n\n设置了 `OPENAI_API_KEY` 后，大厅多一个 `[加入 AI]` 按钮，点一次加一个 LLM 驱动的 AI 玩家（可加多个）。AI 轮到时机器人会带着公共牌、手牌、底池、equity、历史动作请 LLM 给出 fold/check/call/raise/allin 决策，模型用 `response_format=json_object` 返回结构化 JSON。LLM 失败/超时自动 fallback 到 check 或 fold。\n\n兼容任何 OpenAI 风格端点（DeepSeek / 豆包 / OpenAI / OpenRouter / vLLM 等）。`.env.example` 里有几个端点的配置示例。\n\n## 注意事项\n\n- 卡片 JSON 2.0 要求 Lark 客户端 v7.20+\n- 游戏状态持久化到 redb（`LARK_ARENA_DB_PATH`，默认 `arena.redb`），筹码 / 玩家 / AI 座位重启不丢\n- 进行中的一手牌如果在容器重启之间被打断，下次 `[开局]` 会按\"卡住\"处理：退还场上筹码 + 重新发牌\n- 牌局卡住用 `/poker reset` 手动重置\n- 双层去重抗飞书重投：`event_id`（120s 窗口） + `(open_id, value)` 指纹（3s 窗口）\n\n## 项目结构\n\n```\nsrc/\n├── main.rs              入口；--mock \u003copen_id\u003e 把所有卡片样式发到群里看\n├── config.rs            env 加载\n├── feishu/\n│   ├── client.rs        token 缓存 + 发消息 / 临时消息 / 更新卡片\n│   ├── cards.rs         JSON 2.0 helpers\n│   └── events.rs        webhook payload 解析\n├── poker/               德州扑克\n│   ├── card.rs          Card / Suit / Rank / Deck\n│   ├── hand.rs          7 张牌评估器\n│   └── equity.rs        Monte Carlo 胜率\n├── werewolf/            狼人杀\n│   ├── game.rs          角色 / 阶段 / 状态机\n│   ├── cards.rs         身份卡 / 夜间卡 / 投票卡 / 结算卡\n│   ├── llm.rs           各角色的 AI 决策 prompt\n│   └── handlers.rs      bot.rs 的 Bot 扩展（命令/回调/AI 推进）\n├── game.rs              德州状态机\n├── llm.rs               OpenAI 客户端封装（共享）\n├── bot.rs               事件分发 + 卡片渲染 + dedup\n├── storage.rs           redb 持久化（games + wolf_games 两张表）\n└── server.rs            axum HTTP server\n```\n\n## 开发\n\n```bash\ngit clone https://github.com/gtoxlili/lark-arena\ncd lark-arena\ncp .env.example .env\ncargo run --release\ncargo test\n```\n\n把所有卡片样式发到 `ALLOWED_CHAT_ID` 看效果：\n\n```bash\n./target/release/lark-arena --mock \u003c你的 open_id\u003e\n```\n\n## CI 和镜像\n\n每次推 `main` 或打 `v*` tag，[.github/workflows/ci.yml](.github/workflows/ci.yml) 会跑 `docker buildx build`。Dockerfile 里有 `test` 阶段，cargo test 通过后才 build runtime 阶段，最后推到 `ghcr.io/gtoxlili/lark-arena:{latest, main, sha-\u003cshort\u003e, v\u003csemver\u003e}`。\n\nDockerfile 用 cargo-chef 缓存依赖，distroless/cc-debian12:nonroot 作运行时，最终镜像约 30 MB。\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgtoxlili%2Flark-arena","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgtoxlili%2Flark-arena","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgtoxlili%2Flark-arena/lists"}