Dungeon Master OS 静态分析:模块设计与工作原理
对象:DjNightmare9909/Dungeon-master-OS-WFGY · 方法:纯静态分析
一、总体架构
纯前端 SPA(Vite + TypeScript),无后端、无 Node 运行时逻辑。index.tsx 虽为 .tsx 后缀,但全文不使用 React/JSX,采用命令式 DOM 操作;framer-motion/lucide-react 在 package.json 中声明却未被 import(图标走 CDN window.lucide,ui.ts:229)。唯一实际使用的第三方库是 @google/genai(AI SDK)与 marked(Markdown 渲染,ui.ts:468)。
index.html (静态壳, 所有 id 挂载点)
└── index.tsx (入口 initApp@1750, 编排/事件/引导流程)
├── state.ts 状态 + IndexedDB 持久化
├── types.ts 数据模型(ChatSession 等)
├── utils.ts 向量数学/迁移/重试
├── rulesets.ts D&D 5e / CoC 7e 规则集定义
├── gemini.ts AI 客户端 + 巨型系统 Prompt + Persona
├── features.ts 业务逻辑(骰子/日志/记忆/WFGY/拦截/Chronicler)
└── ui.ts DOM 渲染(消息/角色卡/战斗追踪器)
二、核心工作流
链路 1:新游戏引导(程序化生成替代品)
startNewChat()(index.tsx:363)创建ChatSession,creationPhase='guided',注入第一轮欢迎语(本地硬编码)。- 引导靠标签协议状态机:模型输出
[START_GUIDED_SETUP]/[START_UPLOAD_SETUP]/[GENERATE_QUICK_START_CHARACTERS]/[CHARACTER_CREATION_COMPLETE]/[SETUP_COMPLETE],handleFormSubmit(index.tsx:665-826)逐个includes()匹配并切换creationPhase。 - Quick Start 角色由 AI 用 JSON Schema 生成(index.tsx:780-791);世界/剧情生成完全委托给 setup prompt(gemini.ts:290),代码层面无程序化生成算法。
- 选完 Persona/Tone/Narration + OOC 密码后
finalizeSetupAndStartGame()(index.tsx:551)重建主游戏 Chat 实例并请求开场白。
链路 2:主游戏回合(玩家输入 → AI DM 裁决 → 状态更新)
handleFormSubmit(index.tsx:634,非引导分支 863-1062):
- 记忆检索:
recallRelevantMemories()(features.ts:534)按余弦相似度取 topK 语义节点。 - 上下文注入:用户笔记 + 检索记忆 +
storySummary拼入 message(index.tsx:892-907)。 - 调用 AI:
createNewChatInstance()(gemini.ts:408,temperature 0.9,挂googleSearch工具)+sendMessageStream()流式输出。 - 响应后处理(多标签管道):
extractSpatialTopology(features.ts:1183)→interceptAndValidateModelResponse(features.ts:1002,解析<EXECUTE_STATE_CHANGE>并校验/应用 HP/条件变更)→processIntents(features.ts:1289)。 - 状态落地:解析
[COMBAT_STATUS]更新战斗追踪器(index.tsx:992)、[LOGBOOK_UPDATE]更新角色卡/日志(index.tsx:1007)。 - 后台任务:
runWFGYAudit(features.ts:875)、关键词触发runChroniclerTurn(index.tsx:1042-1055)、pruneAndSummarizeHistory(features.ts:788)。
三、模块逐一分析
- state.ts:模块级单例状态(
chatHistory、userContext、uiSettings等,state.ts:28-50)。IndexedDB 封装initDB/dbGet/dbSet(state.ts:98/119/138),库名DM-OS-DBv2,单 storeKeyValueStore。migrateAndValidateSession(state.ts:161)逐字段兜底迁移。traverseMemoryGraph(state.ts:389,扩散激活图遍历)为死代码,全库无调用。 - types.ts:
ChatSession(types.ts:138)为一切状态根对象;SemanticNode(types.ts:110)、Scar(types.ts:122)、ActiveEncounters(types.ts:129)等支撑 WFGY 记忆/战斗。 - utils.ts:
calculateCosineSimilarity(:129)、calculateSemanticTension(:150)、calculateScarPotential(:173)、updateVectorBBPF(:189,BBPF 排斥更新)、retryOperation(:242,429 指数退避)。注意migrateAndValidateSession在此重复实现(utils.ts:15),与 state.ts 版本不一致(utils 版缺activeEncounters/rulesetId/latentStateEmbedding迁移)。 - rulesets.ts:
DND_5E_RULESET(:3)与COC_7E_RULESET(:39),以promptFragments注入系统 Prompt 的机制规则片段。 - gemini.ts:
aiProxy(:98)惰性初始化GoogleGenAI,本地模式走LocalChat(:145)/generateContentLocal(:224,OpenAI 兼容/chat/completions)。generateEmbedding(:496,gemini-embedding-2-preview,带缓存与getFallbackEmbedding确定性回退 :460)。核心价值是三层巨型系统 Prompt:v2.0(:1003)、v3.0(:580,含「Creator 协议」OOC 认证 + 后门 master key + NPC 叙事 DNA)、v4.0(:853)、Flash 精简版(:962);getNewGameSetupInstruction(:290)、getChroniclerPrompt(:359)。dmPersonas(:1238)仅 3 个(purist/rule-of-cool/dark-souls),与 README 宣称的 4 个 Persona 不符。 - features.ts:骰子(
MersenneTwister:61、rollDice:135,本地 PRNG,非真实骰子种子);日志生成(generateLogbookSection:234,结构化 JSON Schema);generateCharacterImage(:384,Imagenimagen-4.0-generate-001);语义记忆(commitToSemanticMemory:507、recallRelevantMemories:534);pruneAndSummarizeHistory(:788,滚动摘要压缩);runWFGYAudit(:875,ΔS/Ψ_scar/B_total/Λ 状态/BBPF);interceptAndValidateModelResponse(:1002,「防火墙」校验非法状态变更并记录 scar);runChroniclerTurn(:1209,调用ai.models.generateContent而非chroniclerChat)。 - ui.ts:DOM 渲染,
appendMessage(:290)、renderCharacterSheet(:405)、updateLogbook(:492)、updateCombatTracker(:637)。 - index.tsx:编排中枢。
setupEventListeners(:1238)绑定全部交互;loadChat(:418)按creationPhase选择 setup/主游戏指令重建 Chat 实例;initApp(:1750)加载 DB→主题→历史→最新会话。
四、数据模型与持久化
- 唯一持久化介质为浏览器 IndexedDB(README 宣称「本地私有」),键:
dm-os-chat-history(全部会话)、dm-os-user-context、dm-os-theme、dm-os-ui-settings、dm-os-persona。 - API Key 可存
uiSettings.apiKey(明文入 IndexedDB)或VITE_API_KEY/GEMINI_API_KEY环境变量(gemini.ts:16、vite.config.ts:22)。 ChatSession核心字段:messages、characterSheet(对象或字符串)、inventory/questLog(纯文本)、npcList、achievements、progressClocks/factions(世界状态)、semanticLog(记忆图)、storySummary、scarLedger/latentStateEmbedding/Bc/lambdaState(WFGY)、activeEncounters(战斗)、currentSpatialGraph(空间图)、adminPassword、rulesetId。- 导出/导入:
exportAllChats/handleImportAll(features.ts:581/595),JSON 全量备份。
五、与 Z.R.I.C 功能对照表
| 能力维度 | DM OS 实现 | 代码依据 | 评价 |
|---|---|---|---|
| 剧本解析 | 无剧本概念,全靠 Prompt 引导 | gemini.ts:290 | ❌ 不适用 |
| 推演分支 | 无显式分支,LLM 自由发挥 | index.tsx:914 重试循环 | ⚠️ 隐式 |
| 自动判定 | <EXECUTE_STATE_CHANGE> 拦截校验;本地骰子 |
features.ts:1002 / :135 | ✅ 部分 |
| 世界状态 | progressClocks/factions + Chronicler 回合 |
features.ts:1209 | ✅ 有 |
| NPC 情绪记忆 | Prompt 内嵌「叙事 DNA/Scar Ledger」,无结构化存储 | gemini.ts:638-653 | ⚠️ 仅 Prompt |
| 地图 | 无真实地图,<TOPOLOGY_GRAPH> 仅解析存储、未用于规则 |
features.ts:1183 | ⚠️ 名义 |
| 触发器 | 关键词(rest/travel/sleep 等)触发 World Turn | index.tsx:1042-1055 | ✅ 简陋 |
| 时间线 | 无;progressClocks 近似承担 |
types.ts:99 | ⚠️ 近似 |
| 记忆系统 | SemanticNode 向量检索 + 摘要压缩 + RAG | features.ts:534 / :788 | ✅ 有 |
| 本地模型 | OpenAI 兼容端点(LM Studio 等) | gemini.ts:145 / :224 | ✅ 有 |
| 许可 | MIT | LICENSE:1 | ✅ |
六、设计评价
优点
- 提示词工程深度惊人:v2.0 系统 Prompt 约 230 行(gemini.ts:1003-1235),v3.0 约 270 行(:580-850),细粒度覆盖 OOC 认证、NPC 叙事 DNA、后果比例尺、动态难度、NPC 主观日志等,是「AI DM」产品的核心资产。
- 纯前端 + IndexedDB 零成本部署:无服务器、数据本地化,隐私友好,符合 README「桌不在时的工具」定位。
- 结构化输出与拦截机制:
<EXECUTE_STATE_CHANGE>/[LOGBOOK_UPDATE]/[COMBAT_STATUS]标签 + JSON Schema 响应,让 LLM 输出参与确定性状态机(features.ts:1002),是 LLM 应用可复用的模式。 - 防御式健壮性:
retryOperation429 退避、embedding 缓存与确定性回退、migrateAndValidateSession逐字段迁移、流式输出 1.5s 节流落库,工程细节完善。 - 多规则集可插拔:
rulesets.ts将系统名/伤害语言/掷骰机制抽象为promptFragments,D&D 5e 与 CoC 7e 可切换。
缺陷
- 大量「宣称」功能实为 Prompt 幻觉或死代码:
traverseMemoryGraph(state.ts:389)从未调用;chroniclerChat被创建(index.tsx:447)但runChroniclerTurn直接ai.models.generateContent,对象形同虚设;currentSpatialGraph解析后无任何消费方。README 的「语义树/拓扑推理」在运行时被简化为余弦相似度平扫。 migrateAndValidateSession双重实现且不一致(state.ts:161 vs utils.ts:15),utils 版缺activeEncounters/rulesetId/latentStateEmbedding迁移,是维护隐患。- OOC 密码明文存储 + Prompt 硬编码 master key 后门:
adminPassword明文入 IndexedDB(types.ts:144),且「the codex of emergence」万能口令写死在系统 Prompt(gemini.ts:598、index.tsx:836 客户端也有匹配分支),安全模型薄弱。 - README 与代码脱节:宣称 4 个 DM Persona(Purist/Narrativist/Romantic/Hack&Slash),代码仅 3 个(purist/rule-of-cool/dark-souls,gemini.ts:1238);宣称「2.5 Flash」但多处硬编码
gemini-2.5-flash与imagen-4.0-generate-001混合;he/Yn桥接对象(index.tsx:175/191)为半成品桩。 - 单文件巨型 + 全局状态:
index.tsx1808 行、gemini.ts1257 行、features.ts1441 行、ui.ts748 行,模块级let单例贯穿,几乎无抽象分层,features.ts与index.tsx互相深度耦合 DOM。 - 本地模型路径不完整:
LocalChat.sendMessage仅取msg.parts[0].text(gemini.ts:171),多模态文件上传的filePart(index.tsx:1131)在本地模式下会被丢弃。
七、结论
DM OS 是一个**「Prompt 即引擎」**的纯前端 AI 叙事产品:真正的「世界生成」「NPC 记忆」「剧情推演」几乎全部由超长系统 Prompt 引导 Gemini 完成,TypeScript 层只负责状态搬运、标签解析、持久化与 UI 渲染。其价值与风险高度同源——极致的提示词工程带来可玩性与沉浸感,但大量声明式「框架」(WFGY 语义树、Chronicler 双人格、空间拓扑)在运行时或被裁剪、或退化为近似实现、或完全未接线。作为「桌面缺位时的单人跑团工具」定位清晰,作为「工程化游戏引擎」名不副实;Z.R.I.C 维度的对照显示其「自动判定」「记忆系统」「世界状态」有实质实现,而「地图/触发器/时间线/剧本分支」基本是 Prompt 层面的软约定。