Install
openclaw skills install @ackiles/dnd-dm-skillAI 地下城主引擎 —— 基于2024版D&D 5e规则,三层架构(dnd-engine + dnd-api + dnd-dm Skill),支持模组化运行、战斗裁决、角色创建与存档管理
openclaw skills install @ackiles/dnd-dm-skill基于 2024版 D&D 5e 规则 的 AI 地下城主系统。纯对话交互,无需专用客户端,任何 IM 软件即可运行。本 Skill 将 DM(地下城主)角色交给 AI,严格按照模组剧本和规则书推进游戏。
城主人格:明萨拉·班瑞(Minthara Baenre)——守序邪恶卓尔圣武士,前魔索布莱城贵族。语气霸道、果断、直接,但绝不放水作弊。详见 SOUL.md 和 IDENTITY.md。
┌─────────────────────────────────────────────┐
│ LLM 层:dnd-dm Skill (OpenClaw) │
│ 叙事生成、NPC 对话、场景描述、行为红线 │
│ ← prompt 驱动,保持 LLM 核心优势 │
├─────────────────────────────────────────────┤
│ API 层:dnd-api (FastAPI,端口自动检测) │
│ 30 个 HTTP 端点 + CLI 命令行工具 │
│ ← 任何平台(Discord/Foundry/Web)均可调用 │
├─────────────────────────────────────────────┤
│ 引擎层:dnd-engine(已内置) │
│ 骰子、战斗、存档、世界状态、模组缓存、SRD 搜索 │
│ ← 纯 Python,零 LLM 依赖,220 项测试覆盖 │
└─────────────────────────────────────────────┘
核心原则:上层依赖下层,下层不依赖上层。LLM 层只管叙事 + 调用引擎函数,不自行计算或拼数据。
adventurer(默认)和 gm_assist。
adventurer:引擎按规则自动执行掷骰与结算,玩家不干预骰面结果。gm_assist:城主辅助模式,允许通过 MCP 工具预设「手动骰」,用于演示、复现或争议裁定。start_new_game(mode="gm_assist"))。start_new_game(mode)、get_mode()、set_manual_roll(name, value)、list_manual_rolls()、clear_manual_rolls()。gm_assist 且存在手动骰时,掷骰函数优先使用手动骰并记录使用历史;否则正常随机掷骰。将 dnd-dm-skill-x.x.x.zip 解压到空目录即可使用。
your-workspace/
├── SKILL.md / _meta.json
├── references/ ← 核心规则文件(供 LLM 读取)
│ └── party-sheet.html ← 角色卡网页(双击打开)
├── dnd-engine/ ← 引擎源码(已内置,无需安装)
├── items/ ← 物品模板
└── DND Lens(可选子技能)
├── data/ ← 知识资产(世界卡 / 模组范式 / 映射字典)
├── scripts/ ← lens_rag.py(BM25 中文检索)+ lens_pipeline.py
├── world-lore/ ← 功能一:世界观 / 编年史检索
├── module-forge/ ← 功能二:按需求生成模组
└── echo-map/ ← 功能三:真实经历 → DND 映射
⚠️ 需用户自行准备:规则书和模组因版权原因无法随 Skill 分发。
将 2024版三宝书放入 rules/ 目录,模组文件放入 modules/ 目录。
在对话中回复 /verify,Agent 自动校验环境。通过后即可开始游戏。
首次使用时 LLM 会自动加载引擎:import sys; sys.path.insert(0, "dnd-engine")
dnd-check --actor 老白 --skill 潜行 --dc 15 # Windows 用 dnd-check.cmd
dnd-check --actor 老白 --ac 16 # 攻击检定(走 AC)
自动读 live_party.json、组装加值、投骰,输出即为可直接贴给玩家的明细。
实测 ≈0.13 秒/次(含 Python 启动)。不要为了调引擎去写临时 Python 脚本。
参数与“角色卡缺技能信息怎么办”见 references/DM_RULES.md 规则 1.2.1。
| 技能 | 作用 | 配合方式 |
|---|---|---|
dnd-dm(本技能) | 城主行为规则 + 三层架构调度 | 主技能,定义 DM 如何行动 |
dnd5e-srd | SRD 5.2.1 RAG 检索 | 战时快速查规则,通过 Python 脚本搜索+展开引用 |
dnd-dm-skill:world-lore | 功能一·世界观对话 + 费伦编年史 | RAG 检索 world_cards.jsonl,托尔金式叙述 |
dnd-dm-skill:module-forge | 功能二·按需求生成模组 | 选范式 + DMG 标准 CR 平衡,输出模组骨架 JSON |
dnd-dm-skill:echo-map | 功能三·真实经历→DND 映射 | 脱敏 + 按 mapping_dict 映射,输出 anonymized 模组 |
宿主于本技能下的三件套,共享
scripts/lens_rag.py(BM25 中文检索)与data/知识资产。三者可独立调用,也可串联:真实经历 → echo-map 映射 → module-forge 做 CR 平衡 → world-lore 检索设定锚点。
| 子技能 | 触发场景 | 数据资产 | 入口脚本 |
|---|---|---|---|
| world-lore | 「深水城历史是怎样的?」「给我讲一段阴影帝国编年史」 | data/world_cards.jsonl(360 张知识卡) | world-lore/scripts/lore_query.py |
| module-forge | 「4 人 5 级、玩一晚的都市寻宝模组」 | data/module_paradigms.json(59 篇范式)+ DMG 表 | module-forge/scripts/module_forge.py |
| echo-map | 「把我和甲方的扯皮改成冒险」 | data/mapping_dict.json(8 槽位 + 脱敏池) | echo-map/scripts/echo_map.py |
一键串联:经历 → 映射 → 平衡 → 背景,运行
python scripts/lens_pipeline.py --story 经历.txt --names "张三" --places "上海" --players 4 --level 5 --duration medium(详见脚本头部说明)。
调用方式(相对本技能目录,用当前环境的 Python 运行):
# 功能一:世界观 / 编年史检索
python scripts/lens_rag.py "深水城 历史" --top-k 6
# 功能二:按需求生成模组(带 CR 平衡)
python module-forge/scripts/module_forge.py --players 4 --level 5 --duration medium --type 都市寻宝
# 功能三:真实经历脱敏 + 映射
python echo-map/scripts/echo_map.py anonymize --names "张三" --places "上海"
数据流:各子技能脚本通过
sys.path复用scripts/lens_rag.py;数据目录默认data/,可用环境变量DND_LENS_DATA覆盖。
| 层级 | 名称 | 技术栈 | 核心职责 |
|---|---|---|---|
| LLM 层 | dnd-dm Skill | Markdown + prompt | 叙事、NPC、检定发起、行为红线——不可代码化 |
| API 层 | dnd-api | FastAPI(端口自动检测) | 30 个 HTTP 端点 + CLI 命令行工具 |
| 引擎层 | dnd-engine | pip 包, Python 3.10+ | 骰子/战斗/存档/世界状态/模组缓存/判定/叙事后端——纯函数 |
新增/修改功能时按 DM_DEV_GUIDE.md 开发规则9 做三层分析。
问题:LLM 直接决定「要不要检定 / 投什么技能 / DC 多少」时,同一条输入会给出不同答案,且无法审计。
做法:把判定拆成「批量原子提问 → 类型化回答 → 代码组合成 DecisionPacket → 引擎结算」。
Choice(选一个)、Score(打 0–1 分)、Noul(是/否)。0.60;低于门限的字段回退本地依据并记入 low_confidence_fields。contract_error:...),不会让游戏卡住。check_rules.json 映射始终可用,不依赖任何外部模型。问题:长模组(40 万 token 级)每轮整份注入,导致成本高、首字慢、且剧情状态无处落地。
做法:四级注入 + 确定性节点图 + 一轮一次调用。
L0 骨架 ≈ 300 tok / L1 当前场景 2–4k / L2 邻域摘要 ≈ 600 / L3 按需全文。实测每轮注入 52.9k → 6.1k tok。module_plot.json(节点+边)+ plot_state.json(当前节点/已访问/事件)。推进由代码裁决,不由模型自由发挥。delta 一次返回,实测 3 次 → 1 次。system(契约)/ user-stable(队伍+本章索引)/ user-volatile(本轮变化)。实测 88% 输入命中缓存。narration 字段,实测首字 ≈2.6 s 出现。dnd_engine.combat.checks 结构化返回,LLM 仅展示结果dnd_engine.save.templates 工厂生成,LLM 不自拼 JSON<!-- layer: N --> 标记)multiattack 真打 N 次(上限 4 次)combat_state.jsonPOST /api/combat/resolve-round 合并命中+伤害+状态更新_scene_cache_*.json 追踪房间checks.py 的 detail_lines 数组,格式由代码保证party-sheet.html 双击即可查看队伍状态roll_stat() 由引擎层执行live_party.json 和角色卡dnd_engine.save.io:write_save() / load_save() / list_saves()scene_cache.py)make_character_template() / make_save_template() / make_quest_template()| 命令 | 功能 |
|---|---|
dnd-engine | 初始化工作目录(创建 saves/ rules/ modules/ live_party.json) |
dnd-engine verify | 校验环境(直接调用 dnd_engine.verify.verify_environment()) |
dnd-engine server --port auto | 启动 API 服务(自动检测端口) |
骰子:
| 接口 | 功能 |
|---|---|
POST /api/roll | 骰子表达式求值 |
战斗:
| 接口 | 功能 |
|---|---|
POST /api/combat/check-hit | 命中判定 |
POST /api/combat/calc-damage | 伤害结算 |
POST /api/combat/skill-check | 技能检定(完整公式) |
POST /api/combat/state/* | 战斗状态 CRUD(6 端点) |
POST /api/combat/resolve-round | 一键命中+伤害+状态更新 |
POST /api/combat/roll-initiative | 一键掷先攻+排序 |
队伍:
| 接口 | 功能 |
|---|---|
POST /api/party/calc-combat-xp | XP 计算 |
POST /api/party/rest | 短休/长休结算 |
GET /api/party/character/{name} | 角色属性查询 |
POST /api/party/level-up | 升级自动结算 |
GET /api/party/live | 实时角色状态 |
POST /api/party/live/rebuild | 从存档重建实时状态 |
存档:
| 接口 | 功能 |
|---|---|
GET /api/saves/list | 存档列表 |
POST /api/saves/load | 读档 |
POST /api/saves/write | 存档 |
SRD:
| 接口 | 功能 |
|---|---|
GET /api/srd/search?q= | SRD 全文搜索 |
POST /api/srd/expand | 展开上下文 |
GET /api/srd/files | 查询 SRD 文件列表 |
GET /api/srd/search-in-file | 在指定文件中搜索 |
系统:
| 接口 | 功能 |
|---|---|
GET /api/system/verify | 预飞校验:引用文件、引擎、权限 |
POST /api/system/init | 自动创建工作目录 |
GET /api/system/port | 查询当前 API 端口 |
世界状态:
| 接口 | 功能 |
|---|---|
GET /api/state/world | 世界状态 |
DM_RULES.md 中 26 条运行规则按 6 层组织,每条规则开头有 <!-- layer: N --> 标记。加载时按层优先级常驻:
| 层 | 名称 | 包含规则 | 常驻时段 |
|---|---|---|---|
| 0 | 全局基石 | 0(会话启动), 0a(模组选择), 0.5(微互动), 10(红线), 18(代码), 19(Token), 21(安装) | 整个会话 |
| 1 | 运行时交互 | 1(检定), 1.5(叙事匹配), 2(场景空间), 3(推进), 4(支线), 17(不泄题), 20(回声) | 每次场景 |
| 2 | 展示模板 | 2b(地图), 9(信息展示) | 展示信息时 |
| 3 | 战斗系统 | 15(回合), 15b(装备) | 战斗回合 |
| 4 | 进度与状态 | 5(经验), 7(锚点), 8(章节), 13(存档), 14(存档), 16(实时状态) | 存档/升级 |
| 5 | 模组控制 | 12(构建), X(特殊) | 开新局/跨章 |
| 文件/目录 | 说明 |
|---|---|
references/ | 14 个核心引用文件(规则、模板、开发指南、人格定义、角色卡模板) |
items/ | 物品模板目录(3 个 .md) |
srd/ | SRD 5.2.1 检索资源(references + scripts) |
dnd-engine/src/dnd_engine/ | 引擎层 Python 包(dice/combat/party/save/state/module/npc/runtime/context/judge/narrative/cli) |
dnd-check.py + .cmd / .sh | 一条命令完成一次检定(自己把包内引擎加进 sys.path,不依赖 PYTHONPATH;读 live_party.json、组装加值、投骰) |
data/ | [DND Lens] 共享知识资产:world_cards.jsonl(360 张知识卡)/ module_paradigms.json(59 篇范式)/ mapping_dict.json(8 映射槽位) |
scripts/lens_rag.py | [DND Lens] BM25 中文检索引擎,RAG 底座,三子技能共用 |
scripts/lens_pipeline.py | [DND Lens] 联动流水线:经历 → echo-map → module-forge → world-lore 一站式(见脚本内 --help) |
world-lore/ | [DND Lens·功能一] 世界观对话 + 费伦编年史子技能 |
module-forge/ | [DND Lens·功能二] 按需求生成模组(DMG 标准 CR 平衡)子技能 |
echo-map/ | [DND Lens·功能三] 真实经历 → DND 映射(脱敏 + 字典规范化)子技能 |
saves/ | [自动生成] 存档文件 |
rules/ | [自行准备] 2024版三宝书 |
modules/ | [自行准备] D&D 模组文件 |
party-sheet.html | 角色卡网页(双击即看,从 live_party.json 读取) |
live_party.json | [自动生成] 实时角色状态 |
_api_port.txt | [自动生成] API 运行端口 |
_scene_cache_*.json | [自动生成] 场景缓存 |
reports/prefetch_cache.json | [自动生成] 叙事预取缓存 |
版本 1.2.1 · 2026-09-25 · 合并发布:线上 1.2.0 的 DND Lens 三子技能(world-lore / module-forge / echo-map)+ 本地新一代引擎(类型化判定层 judge、叙事层 narrative:四级注入 52.9k→6.1k tok、一轮一次调用、prefix cache 命中 88%、流式首字 2.6s、防出戏守卫)· 严格按 2024版 D&D 5e 规则 · 220 项测试通过 · 支持 Windows / macOS / Linux