open-tabletop-gm 静态分析:模块设计与工作原理
对象:Bobby-Gray/open-tabletop-gm · 方法:纯静态分析
1. 总体架构
open-tabletop-gm 是一个「LLM 无关」的 TTRPG GM 框架:核心是一个提示词技能包(Markdown 驱动)加一套纯 Python 工具链。它的关键设计是把「叙述与判断」留给 LLM,把「一切机械计算」交给 Python,从而让小模型也能跑长线战役(README.md:7-25)。
┌────────────────────────────────────────────────────────────────┐
│ 宿主 LLM 运行时(OpenCode / LM Studio / 任意 OpenAI 兼容端点) │
│ README.md:7, 60-118;docs/LLM-GUIDE.md │
└──────────────────────────────┬─────────────────────────────────┘
│ 读指令 / 调 bash 工具 / 读写文件
┌──────────────────────────────▼─────────────────────────────────┐
│ SKILL 层(提示词,纯 Markdown,LLM 无关) │
│ SKILL.md GM 人格与技艺(会话加载时读入,非启动常驻) │
│ SKILL-branches.md 分支路由器(每个命令→步骤序列,常驻 ~2300 token) │
│ SKILL-commands.md 命令签名参考;SKILL-scripts.md 脚本语法(已废弃) │
└──────────────────────────────┬─────────────────────────────────┘
│ 命令 → 调用脚本
┌──────────────────────────────▼─────────────────────────────────┐
│ Python 工具链(确定性,零 LLM 依赖) │
│ scripts/ dice·combat·tracker·calendar·campaign_search· │
│ paths·gm_graph·graph_extract_deterministic· │
│ import_campaign·name_registry·migrate_system_version│
│ systems/<sys>/ 系统模块:system.md + 可选脚本 + 数据 │
│ display/ Flask 电影化展示伴随程序(可选) │
└──────────────────────────────┬─────────────────────────────────┘
│ 读写
┌──────────────────────────────▼─────────────────────────────────┐
│ 持久化(纯文本 Markdown + JSON,游戏无关) │
│ <campaigns-dir>/<name>/ state.md·world.md·npcs.md·npcs-full.md·│
│ session-log.md·session-log-archive.md·characters/*.md· │
│ tracker.json·calendar.json·graph.json·session_tail.json │
│ <root>/ .name_registry.json·characters/(全局角色名册) │
└────────────────────────────────────────────────────────────────┘
架构分两层(README.md:29-46、SYSTEM-PORTING.md:7-16):SKILL.md 永不随游戏变化(GM 技艺),systems//gm load 时一起读入。
2. 核心工作流
链路一:会话加载 /gm load(最重要的链路)
由 SKILL-branches.md:7-106 定义,七步顺序执行,是「路由架构」的典型体现:
- 检查 display 状态(
SKILL-branches.md:11-15):读display/app.pid判断展示程序是否在跑。 - 同步战役 + 重放上一会话尾巴(
:17-34):send.py --set-campaign注册战役,读session_tail.json逐条回放。 - 系统版本迁移检查(
:36-52):跑migrate_system_version.py --check(exit 0/1/2),旧战役提示补盖**System Version:**。 - 读三文件(
:54-63):state.md、world.md、npcs.md,并检查roll_mode、读## Pinned Facts。 - 拉取场景子图(
:65-102):gm_graph.py scene-context --place ... --present ...用 BFS 取 2 跳子图;未初始化则强制走 graph init。 - 输出开场叙述(
:104):纯文本,不调任何命令。 - 进入 GM 模式(
:106):此后玩家输入不需/gm前缀。
对应 SKILL.md:373-380 给出高层步骤。这一链路的目的是用最小 tool-call 深度完成加载——README.md:428 明确 70B 以下模型在 4-5 次连续 tool-call 后会漂移。
链路二:战斗回合(每回合确定性判定)
SKILL.md:287-297 给出「每回合战斗序列」,SKILL-branches.md:156-178 定义状态机(COMBAT 开始/回合/结束):
a. send.py --player ← 玩家动作
b. combat.py / dice.py 掷骰 ← 所有判定
c. send.py --dice ← 带上下文回传结果
d. tracker.py effect tick ← 扣减计时效果,打印过期告警
e. 写完整叙述
f. send.py [--stat-*] ← 叙述 + 全部状态变更(HP/条件/资源)
g. push_stats.py --turn-current ← 推进回合指针
combat.py init 掷先攻并输出 STATE_JSON 存入 state.md → ## Active Combat(combat.py:126-137、SKILL-branches.md:160)。判定本身由 dice.py(d20+mod、优劣势、暴击/大失败标记,dice.py:64-112)与 combat.py attack(命中判定,combat.py:70-97)完成,全程不经过 LLM。
3. 模块逐一分析
3.1 SKILL.md(265 行)— GM 核心人格
| 职责 | 关键内容(文件:行号) |
|---|---|
| GM 人格 | 「有氛围感、描述性、yes-and 取向」的 GM(SKILL.md:1-6) |
| 12 条 GM 标准 | 即兴不写剧本、倾听校准、后果可见、生动高效、NPC 难忘、控节奏、公平一致、热情、读玩家、结构化情境、世界自行运转、奖励大胆(:9-76) |
| Table Dials | difficulty/spotlight/pacing 三档可调(:78-84) |
| Script-First 规则 | 任何机械计算先查脚本,再做(:118-127) |
| 骰子约定 | roll_mode players/auto + 每角色覆盖(:217-231) |
| Display 同步 | 每个响应的 send.py 调用顺序与 stat 标志表(:235-298) |
| 启动命令 | /gm new 与 /gm load 的完整流程(:355-380) |
工作原理:这是写给 LLM 的行为约束,本身无代码逻辑;它对「何时读哪个脚本、何时停止、何时读哪一节文件」做了极细的编排,把 GM 的隐性知识显式化成可执行的提示词。
3.2 SKILL-branches.md(293 行)— 分支路由器
常驻上下文(~2,300 token,README.md:97,428)。把每个命令映射到「先读哪个脚本文件 → 执行哪个终态动作」的线性步骤。覆盖 /gm load、/gm display、/gm path、/gm update、ACTIVE 叙述回合、/gm combat、/gm rest、/gm roll、/gm character new、/gm save、/gm end、/gm list、过去事件查找。这是项目对抗「小模型工具调用漂移」的核心手段(docs/LLM-GUIDE.md:36-42)。
3.3 SKILL-commands.md(261 行)— 命令参考
命令签名表 + 详细流程:/gm new 世界生成(:46-74)、/gm save 会话保存与归档(:78-99)、/gm pin(:102-112)、/gm import(:115-159)、/gm arc(:162-200)、/gm graph(:204-261)。
3.4 SYSTEM-PORTING.md(194 行)+ systems/ — 系统移植层
| 职责 | 关键内容(文件:行号) |
|---|---|
| 两层架构 | SKILL.md(不变)vs system.md(随游戏变)(SYSTEM-PORTING.md:7-16) |
| 无需改动部分 | dice/combat/tracker/calendar/campaign 文件/display/12 原则/arc/import/Live State Flags(:19-34) |
| 每系统需配置 | 骰子判定、属性、主资源、HP、条件、休息、失能/死亡(:38-123) |
| 移植步骤 | 复制 TEMPLATE.md → 填 system.md →(可选)改 tracker 条件色 → 建战役 → 迭代(:141-165) |
| 兼容预期 | d20 最高、骰池中高、百分位中、无骰低(:169-179) |
systems/TEMPLATE.md(244 行)是脚手架;systems/brp/system.md(254 行)是纯 system.md 即够用的最小移植范例(BRP 百分位系统,无系统脚本,见其 :254)。5e 是完整参考实现。核心机制:system.md 声明 ## System Versions(如 2014/2024),paths.campaign_system_version()/campaign_system() 从 state.md 头部正则解析 **System Version:**/**System Module:**(paths.py:98-151),数据文件按版本落到 systems/<sys>/data/(paths.py:154-168)。
3.5 scripts/ — 通用确定性工具链
| 脚本 | 职责 | 关键函数(文件:行号) |
|---|---|---|
dice.py |
XdY+Z 掷骰,优劣势,kh/kl,暴击/大失败 | parse_notation:30-51、run:64-112 |
combat.py |
先攻排序、攻击判定(命中/暴击/伤害翻倍) | initiative_order:45-53、resolve_attack:70-97 |
tracker.py |
条件/专注/计时效果/死亡豁免,持久化 tracker.json | CONDITION_COLOURS:60-76、cmd_effect:189-295、cmd_saves:360-394 |
calendar.py |
战役内历法(自定义月/日/月长),时间推进、休息 | _advance_hours:136-159、cmd_rest:233-248 |
campaign_search.py |
跨战役文件关键词 AND 检索 | search_file:49-89 |
paths.py |
路径解析 + 系统版本/模块解析(GM_CAMPAIGN_ROOT) | find_campaign:48-81、campaign_system:128-151 |
gm_graph.py |
带类型边的战役关系图(graph.json) | _edge_active_at:173-189、_expand(BFS):457-483、_emit_subgraph:486-526 |
graph_extract_deterministic.py |
无 LLM 的关系抽取(动词表模式匹配) | build_alias_index:132-182、extract_proposals:296-418 |
import_campaign.py |
从 PDF/DOCX/MD/TXT 抽取文本 | extract_pdf:28-48、extract:71-88 |
name_registry.py |
跨战役角色名去重注册表 | rebuild:184-222、check:275-316 |
migrate_system_version.py |
旧战役补 **System Version:** 字段(幂等+备份) |
cmd_check:102-117、cmd_migrate:120-173 |
npc_rename.py |
跨所有战役文件安全改名(含 graph 节点/边保留) | 未逐行读,见 SKILL-commands.md:36 |
tracker.py 与 calendar.py 都通过 subprocess 把状态推给 display,且display 未运行时静默失败(tracker.py:162-184、calendar.py:162-172)——这是「展示层可插拔」的体现。
3.6 systems/dnd5e/ — 5e 参考实现(规则数据组织)
| 文件 | 职责 | 关键内容(文件:行号) |
|---|---|---|
system.md |
5e 规则上下文(版本/骰子/属性/角色/XP/死亡豁免/条件/灵感) | 版本:7-23、SRD 查询:145-164、大胆奖励硬触发(自然 20 必给灵感):167-170 |
lookup.py |
查询 dnd5e_srd.json(1453 条:法术/装备/魔法物品/条件/怪物/职业特性) | CATEGORY_MAP:35-53、_load:63-100、lookup:310-339、suggest(纠错提示):399-451 |
character.py |
角色属性计算(熟练加值/生命骰/豁免/技能/XP) | PROF_BONUS:25-27、HIT_DICE:38-42、SAVE_PROFS:45-58、do_calc:104-149 |
ability-scores.py |
属性生成(4d6kh3/购点校验 27 点) | POINT_BUY_COST:24、do_pointbuy_check:75-102 |
xp.py |
完整 5e 遭遇 XP 表(难度阈值/CR→XP/数量倍率/升级) | XP_THRESHOLDS:38-59、CR_XP:62-72、cmd_award:253-309 |
build_srd.py |
从 5e-bits/5e-database + FoundryVTT 拉取并构建 SRD 数据集 | 来源:5-14、BITS_FILES:43-49、HTML 清洗 _strip_html:76-120 |
sync_srd.py/build_supplemental.py |
数据集同步/非 SRD 补充(wikidot 缓存) | 未逐行读,见 SYSTEM-PORTING.md:135 |
5e 规则数据以代码内硬编码表 + 外部 JSON 数据集两种方式组织:表格型规则(熟练加值、XP、生命骰、CR)直接写在 character.py/xp.py 字典里;开放授权内容(SRD)经 build_srd.py 打包成 dnd5e_srd.json,由 lookup.py 提供模糊匹配与格式化输出。
3.7 templates/ — 战役数据模型(文件模板)
| 模板 | 定义的数据结构(文件:行号) |
|---|---|
state.md |
头部(创建/会话数/系统模块/系统版本):2、## Pinned Facts:10-12、## Live State Flags(抗压缩关键值):37-47、## Campaign Arc(dynamic/structured YAML):49-146、## Session Flags:152-154、## GM Style Notes:156-158 |
world.md |
基调:4-9、世界基础(地理/魔法/神系/历法):13-40、Three Truths:47-50、威胁升级弧(5 阶段):71-82、谜团线索链:95-101、阵营:105-129、冒险节点:133-153、任务种子:157-161 |
npcs.md / character-sheet.md / session-log.md |
NPC 索引、角色卡字段、会话日志骨架 |
3.8 display/ — 电影化展示伴随程序(可选 Flask)
gm-display-app.py(2609 行)是核心:SSE 流式推送到浏览器,端点见其 :7-21(/chunk、/stats、/stream、/player-input/*、/srd-lookup)。场景检测按关键词切背景(README.md:304-322)、动态天空画布按 world_time 渲染(README.md:324-340)、SFX 需 numpy 否则静默降级(README.md:350)。它完全独立于 LLM,未运行时所有脚本静默失败(README.md:253)。子模块拆解:
| 子模块 | 职责 | 关键点(文件:行号) |
|---|---|---|
send.py |
发送叙述/骰子/NPC 对话/玩家动作 + stat 标志,段落分块 | stat 标志表 send.py:42-55、CHUNK_LIMIT:78 |
push_stats.py |
推侧栏统计(HP/资源/条件/先攻/任务/阵营/世界时间),按名字合并 | 用法 doc:1-69 |
check_input.py |
每回合开始非阻塞排空玩家输入队列 | HTTP drain + 文件回退:86-107、叙述长度/掷骰指令:47-70 |
wrapper.py |
(遗留)PTY 包裹 agent,安全注入玩家输入 | 安全模型(字符白名单/元字符剥离/审计):27-37 |
dm_help.py / audio.py / tts.py |
情境化 GM 提示 / Web Audio 合成 SFX / 旁白 TTS | 未逐行读 |
setup_tls.py / verify_tail.sh |
自签证书 / 会话尾巴健康检查 | 未逐行读 |
玩家输入走「stage→ready→skip」队列(gm-display-app.py:16-19),设备首次出现需 GM 批准(README.md:294-302);会话缓冲把最近 60 块叙述落盘到 text_log.json,断线重连自动重放(README.md:374-376)。
3.9 probe/ — 模型评测工具
probe.py(421 行)对任意 OpenAI 兼容端点跑 5 个测试用例;narrative_probe.py(890 行)做叙事质量评测;model_sweep.py(302 行)批量扫模型;results/narrative/ 存几十个模型的评测 JSON。docs/LLM-GUIDE.md 汇总结论(如 24B 在 4-5 次 tool-call 后漂移、gguf 需 eval_batch_size:4096,:36-88)。
4. 数据模型与持久化
- 战役数据(游戏无关,纯 Markdown + JSON):
state.md(世界状态/阵营移动/活跃任务/Live State Flags/战役弧/会话旗标/GM 风格笔记)、world.md、npcs.md(一行索引)+npcs-full.md(完整 NPC:性格轴/关系/隐藏目标/说话怪癖,SKILL.md:163-164)、session-log.md+session-log-archive.md(>3 次会话后归档,SKILL-commands.md:93)、characters/<name>.md、tracker.json、calendar.json、graph.json、session_tail.json。 - NPC 结构化档案(
templates/npcs.md):表面索引表(Name/Role/Faction/Location/Attitude/Notes):3-5 + 深度字段(Demeanor/Motivation/Secret/Speech quirk/Attitude 五级刻度/Current goal/Schedule):9-17 + 四组人格轴(Trustworthy↔Deceptive、Ambitious↔Content、Loyal↔Opportunistic、Brave↔Cowardly):19-23 + 关系清单(Knows/Owes/Hates/Fears/Allied with,每 NPC 至少 2 条):25-31。这是本项目最接近「NPC 情绪记忆」的结构——但存的是倾向与关系,非逐回合情绪状态。 - 角色卡(
templates/character-sheet.md):身份/人物支柱(玩家一句话 + 派生 Bond/Flaw/Ideal/Goal + 活跃钩子):8-13、属性/战斗/豁免/技能表:19-59、攻击/法术位/装备/背景:61-96。XP 字段由xp.py正则读写**XP:**行(xp.py:186-209)。 - 系统移植层:
system.md(规则上下文)+system_data_path()定位systems/<sys>/data/下的版本化数据;核心对版本值「不透明」,由系统模块自解释(paths.py:84-94)。 - 全局名册:
<root>/.name_registry.json(跨战役角色名去重,含 slug/首次出现/活跃战役/退役记录)+characters/全局角色镜像(SKILL.md:110-112、name_registry.py:15-28)。 - 路径可迁移:
GM_CAMPAIGN_ROOT环境变量重定位,find_campaign()带旧路径回退 + 按访问复制(paths.py:48-81)。
4.1 工程与安全实践
- 测试(
tests/,7 个文件):test_gm_graph.py(368 行)、test_deterministic_extract.py(313 行)、test_display_robustness.py、test_lookup_suggest.py、test_milestone_counter.py、test_verb_table.py覆盖图、确定性抽取、display 鲁棒性、lookup 纠错等核心路径。 - 安全:
wrapper.py:27-37对注入的玩家输入做多层防御(会话门、[角色]: 文本结构校验、角色白名单、仅可打印 ASCII、shell 元字符剥离、行长/总量上限、审计日志、拒绝时静默丢弃);display 用 token + 自签 TLS 认证(send.py:69-89)。 - 版本与迁移:语义化版本 +
VERSION+CHANGELOG.md;/gm update --check只做 fast-forward、拒绝脏工作树(SKILL-branches.md:131-138、update_skill.py);migrate_system_version.py幂等补字段并先备份(migrate_system_version.py:95-99)。
5. 与 Z.R.I.C 功能对照表
| Z.R.I.C 功能 | 本项目状态 | 依据 |
|---|---|---|
| 剧本解析 | ✅ 部分 | /gm import + import_campaign.py 抽取 PDF/DOCX/MD/TXT 文本,但结构提取(act/chapter/beat)由 LLM 完成而非代码(import_campaign.py:71-88、SKILL-commands.md:115-159) |
| 推演分支 | ✅ 部分 | dynamic 弧以 what_changes(后果而非事件)承载分支,/gm arc revise 三条修正路径(SKILL.md:192-215、SKILL-commands.md:162-200);分支路由靠 SKILL-branches.md,非代码引擎 |
| 自动判定 | ✅ 强 | 骰子/命中/HP/条件/计时效果/死亡豁免/XP 全部确定性脚本,零 LLM(dice.py、combat.py、tracker.py、xp.py) |
| 世界状态 | ✅ 强 | state.md+world.md+calendar.py,## Live State Flags 抗压缩(templates/state.md:37-47) |
| NPC 情绪记忆 | ⚠️ 部分 | NPC 性格轴/关系/隐藏目标在 npcs-full.md;阵营/立场在 Live State Flags + graph set-disposition(gm_graph.py:94-101);无显式「情绪」字段,是立场而非情绪 |
| 地图 | ⚠️ 弱 | 无地图模块;只有 display 关键词场景检测(README.md:304-322)、world.md 冒险节点、graph place 节点 |
| 触发器 | ⚠️ 部分 | 威胁升级弧 5 阶段触发表(templates/world.md:71-82)、world_pressure、## Faction Moves;无事件引擎/自动触发 |
| 时间线 | ✅ 强 | calendar.py 历法推进 + session-log/Continuity Archive 归档 + graph 边 since_session/until_session(gm_graph.py:173-189) |
| 记忆系统 | ✅ 强 | 分层记忆:Pinned Facts(稳定软正典)+ Live State Flags(抗压缩)+ Continuity Archive + GM Style Notes(玩家校准)+ 会话日志归档(SKILL.md:166-174、templates/state.md) |
| 本地模型 | ✅ 强 | 纯提示词+Python,OpenCode/LM Studio 适配(README.md:60-118);probe/ 评测 + docs/LLM-GUIDE.md 硬件/参数指南;确定性抽取替代上游 Haiku 依赖(gm_graph.py:8-13) |
| 许可 | ✅ 已落实 | AGPL-3.0-or-later(README.md:457、LICENSE);systems/brp/NOTICE 标注 ORC 许可来源(brp/system.md:5) |
6. 三个重点问题的答案
SKILL.md 如何驱动 GM:SKILL.md 是「GM 技艺的行为约束提示词」,不参与启动常驻(README.md:97)。它用「Script-First 规则」(:118-127)+「每回合 Display 同步序列」(:287-297)+「压缩后重读最小源节」(:166-174)等显式约束,把 GM 经验写成 LLM 可执行的编排步骤;SKILL-branches.md 再把命令映射成最短 tool-call 序列。
SYSTEM-PORTING.md 的移植机制:两层分离——SKILL.md 恒定、system.md 承载规则。移植 = 复制 TEMPLATE.md 填 system.md,最小可用集只需「骰子判定/属性/HP/资源/条件」(SYSTEM-PORTING.md:149-156)。通用脚本不依赖具体系统;系统特定数据经
paths.py版本化落到systems/<sys>/data/;brp/system.md证明「纯文档即可跑」的底线。LLM 无关性如何实现:三层——(a) 宿主层无绑定,README 给 OpenCode 与 LM Studio 两份配置(README.md:84-118);(b) 所有机械操作移出模型,LLM 只做叙述与判断(docs/LLM-GUIDE.md:7-20);(c) 上游 claude-dnd-skill 中依赖 Claude API/Haiku 的部分,此 fork 用确定性等价物替代或暂缓——关系图是「manual + query-only」,抽取用
graph_extract_deterministic.py动词表模式匹配(gm_graph.py:8-13、graph_extract_deterministic.py:1-16)。
7. 设计评价
优点
- 机械/叙述严格分离:所有算术(骰子、HP、先攻、计时效果、XP 表)都在 Python 里确定性完成,模型不碰数字——直接降低对小模型的能力门槛(docs/LLM-GUIDE.md:7-20、README.md:424-426)。
- 提示词工程精良:SKILL-branches.md 把系统提示从 ~18,000 压到 ~2,300 token,并逐命令定义线性步骤以对抗小模型工具调用漂移(README.md:97,428;docs/LLM-GUIDE.md:36-42)。
- 持久化选型务实:战役数据全用可读可改的 Markdown + JSON,配合「最小源节重读」「Live State Flags」等抗压缩策略,明确针对长线战役的上下文压缩问题(templates/state.md:37-47、SKILL.md:166-174)。
- 系统可移植性设计干净:SKILL/system 两层分离 + TEMPLATE.md 脚手架 + 通用脚本不耦合具体系统,brp 模块证明最小移植成本极低(SYSTEM-PORTING.md:149-156)。
- 防御性降级做得好:display 未运行、numpy 缺失、PyYAML 缺失、SRD 未构建时均静默降级不中断会话(tracker.py:162-184、build_srd.py:27-32、gm-display-app.py:44-76)。
缺陷
- 对 LLM 上下文窗口高度依赖:核心状态(state.md/world.md/npcs.md + 全部角色卡 + system.md)每次
/gm load全量读入(SKILL.md:378),战役变长后上下文压力线性上升,虽有用归档/图缓解但仍靠模型自己按提示词「只读最小节」,无硬约束。 - 触发器/事件是「人肉」而非引擎:威胁升级弧、
world_pressure、Faction Moves 都是「提示词让 GM 记着做」的约定,没有代码自动触发(templates/world.md:71-82、SKILL.md:63-64);tracker.py计时效果需手动tick(tracker.py:243)。 - 图是「手工+查询」而非自动维护:graph 边靠 GM 在会话中手动
add-edge,save 时的关系变化扫描也靠 LLM 事后提出、GM 审批(SKILL-branches.md:254-268);确定性抽取器明确标 recall ~50%(graph_extract_deterministic.py:12)。 - 规则数据硬编码在代码里:XP/CR/生命骰/豁免熟练等 5e 表直接写死在
character.py/xp.py字典,改版本(2014/2024)或换系统时需改代码而非数据(character.py:25-68、xp.py:38-92),与「system.md 即规则」的移植理念部分冲突。 - display 状态与战役状态双写易失同步:tracker.json/calendar.json/display 侧 stats.json 与 state.md 里的人工字段(HP/资源/条件)多处并存,靠 GM 逐回合同步(SKILL.md:268-297),无单一权威源,存在漂移风险。
8. 结论
open-tabletop-gm 是一个**「提示词技能包 + 确定性 Python 工具链」的 GM 框架,其真正价值不在某个模型能力,而在工程化的职责分离**:把 TTRPG GM 工作拆成「叙述判断(LLM)」「机械判定(脚本)」「世界记忆(Markdown/JSON 分层)」「展示(可选 Flask)」四层,并针对小模型/本地模型的工具调用深度做专门优化。它已是一个成熟可运行的开源项目(非文档占位),5e 全支持、BRP 作移植范例,LLM 无关性落实到位。其短板集中在「剧情/世界自动推演仍是提示词约定而非代码引擎」——推演分支、触发器、NPC 情绪等 Z.R.I.C 维度目前靠 GM 模型的自觉与 SKILL 编排维持,而非确定性状态机。对后续 Z.R.I.C 设计的直接借鉴点:**分层记忆(Pinned Facts / Live State Flags / Continuity Archive)与「把可计算部分移出模型」**这两条路线,是本地小模型跑长线战役最可复用的两个经验。
9. 关键代码位置速查
| 关注点 | 定位 |
|---|---|
| GM 行为约束(SKILL 驱动核心) | SKILL.md:9-76(12 标准)、:118-127(Script-First)、:217-231(骰子约定) |
| 会话加载七步链路 | SKILL-branches.md:7-106 |
| 战斗回合状态机 | SKILL-branches.md:156-178、SKILL.md:287-297 |
| 会话保存/归档/关系扫掠 | SKILL-branches.md:228-269、SKILL-commands.md:78-99 |
| 系统移植机制 | SYSTEM-PORTING.md:38-123、paths.py:98-168 |
| 5e 规则表(硬编码) | systems/dnd5e/character.py:25-68、xp.py:38-92 |
| 5e SRD 数据集构建/查询 | build_srd.py:5-49、lookup.py:63-100、:310-339 |
| 确定性关系抽取 | graph_extract_deterministic.py:296-418、data/graph/verb_table_seed.yaml |
| 战役数据模型模板 | templates/state.md:37-47(Live State Flags)、templates/world.md:71-82(威胁弧) |
| LLM 无关性与本地模型 | README.md:84-118、docs/LLM-GUIDE.md:7-20、gm_graph.py:8-13 |