NeverEndingQuest 静态分析:模块设计与工作原理

对象:MoonlightByte/NeverEndingQuest · 方法:纯静态分析

一、总体架构

项目为纯 Python 单进程引擎(另含 web/frontend React 前端与 Node 构建脚本),无独立数据库、无 ORM,状态以 JSON 文件持久化。分层如下(ASCII):

┌─ 入口/界面层:main.py(终端) · run_web.py · web/web_interface.py(Flask+SocketIO) · React(/play/)
├─ 游戏逻辑层:core/ai/action_handler.py(命令分发) · core/managers/*(各子系统管理器)
├─ 上下文/压缩层:core/ai/{conversation_utils,chunked_compression,ultra_compressor,cumulative_summary,adv_summary}.py
├─ AI 模型层:core/ai/api_client.py(多供应商路由) · model_config.py(逐调用点模型矩阵) · core/generators/*
└─ 数据层:modules/ · schemas/ · data/(SRD) · utils/file_operations.py(原子写)

主要数据流(主循环,main.py:5551 main_game_loop):

用户输入 → action_predictor(路由) → get_ai_response(LLM) → validate_ai_response(校验)
        → process_action(action_handler 命令模式) → [Manager] → 原子持久化(file_operations)
        → 位置/模块转换触发压缩 → 保存会话历史

Manager 模式(ARCHITECTURE.md:241)贯穿子系统:CampaignManager、CombatManager、StorageManager、LocationManager、LevelUpManager、StatusManager;战斗等复杂子系统以「信号返回」(needs_post_combat_narrationenter_levelup_mode 等,action_handler.py:1638/2196)交还主循环(ARCHITECTURE.md:494-528)。

二、核心工作流(最重要链路)

链路 A:单回合「输入 → 推演 → 判定 → 状态更新」

  1. 输入:main_game_loop 循环内 input() 取玩家指令(main.py:6177),循环顶部先做 truncate_dm_notesremove_duplicate_messages、位置转换压缩(main.py:6052-6080)。
  2. 动作预测路由:utils/action_predictor.py:141 predict_actions_required 用 mini 模型二分类该回合是否需要结构化 JSON 动作,失败/畸形一律保守回退全模型(action_predictor.py:184-224)。
  3. 推演:main.py:5121 get_ai_response(经 capture_and_fanoutcore/ai/api_client.py:280 create_completion 路由到 OpenAI/Gemini/本地)。
  4. 校验:main.py:1782 validate_ai_responsecore/validation/dm_response_validator.py 等对 LLM 输出做规则/语义校验,不合规重试。
  5. 状态更新:core/ai/action_handler.py:1374 process_action 按命令模式分发(updateCharacterInfo/transitionLocation/createEncounter/updatePlot/updateWorldTime 等,action_handler.py:34-40),落到 Manager 后原子落盘。
  6. 压缩:位置转换时 main.py:2321 check_and_process_location_transitions;模块转换时 campaign_manager 归档+生成 living summary。

链路 B:模组生成(story-first 流水线)

module_builder.py(编排器) → story_first/pipeline.py(崩溃安全 7 阶段:outline→area_binding→plot_derivation→location_fill→npc_repair→candidate_hardening→creature_compilepipeline.py:65-73),每阶段经 jsonschema 校验+语义纠错(core/generators/story_first/validators.py),模型能力不足时降级到兼容生成器(module_builder.py:91-101)。产物写入 modules/<name>/{areas,encounters,media,module_plot.json,...} 并生成 _BU.json 复位备份(module_builder.py:2034-2074)。

三、模块逐一分析

1. 多供应商 AI 抽象(core/ai/api_client.py + model_config.py + utils/capture/multi_model_capture.py)

2. Token 压缩系统(多套并存)

3. 记忆系统(core/memories/)

4. SRD 规则集成(数据文件,非硬编码)

5. Module Toolkit / 模组解析

6. 战斗子系统(core/combat/ + core/managers/combat_manager.py)

7. 战役/模块转换子系统(core/managers/campaign_manager.py)

8. 存储/住房子系统(core/managers/storage_manager.py)

9. 效果/时间系统(core/effects/)

10. Web 界面(web/web_interface.py + web/frontend/)

四、数据模型与持久化

五、与 Z.R.I.C 功能对照表

Z.R.I.C 功能 本项目实现 位置 备注
剧本解析 story-first 7 阶段 + jsonschema 校验 story_first/pipeline.py:65contracts.py 有语义纠错与降级
推演分支 plotPoints/nextPoints/sideQuests 结构 + LLM 推演 modules/*/module_plot_BU.json:4-27updates/plot_update.py 分支由 AI 依上下文决定,非确定性脚本
自动判定 战斗确定性裁决 + 效果 tick core/combat/resolver.py:328/559core/effects/* 代码持有算术,LLM 只选意图
世界状态 world_registry.json / campaign.json / party_tracker.json campaign_manager.pyREADME.md 跨模块后果由 living summary 承载
NPC 情绪记忆 5 维情绪向量 + 行为特征 + 结晶/重力检索 core/memories/emotional_vectors.py:25companion_memory.py 压缩存储 _schema_spec_v2.json
地图 map_schema(rooms/connections/coordinates/layout 2D 网格) schemas/map_schema.jsonmodules/*/map_*_BU.json 位置 ID 用 A/B/AA 字母前缀
触发器 效果 tick 触发器(start/end of turn/round);故事级显式触发器未读到 core/effects/model.py:16 无独立「剧情触发器」脚本系统
时间线 幻想历法 + 会话按序归档 + visitCount/首末次日期 core/effects/clock.pycampaign_manager.py 无显式 timeline.json
记忆系统 会话压缩 + living summary + chronicle + 伙伴记忆 chunked_compression.pycumulative_summary.pycore/memories/* 多层「压缩即记忆」
本地模型 LM Studio/OpenAI 兼容端点 provider api_client.pymodel_config.py:1426utils/openai_client.py 默认 http://localhost:1234/v1
许可 Fair Source License 1.0(5 年后转 Apache-2.0)+ SRD CC-BY 4.0 LICENSELICENSE-SRDREADME.md:218-236 双许可

六、设计评价

优点(附代码依据)

  1. 多供应商与逐调用点模型矩阵隔离良好:provider 差异集中在 api_client.py + model_config.py,调用点只传命名 config dict,get_provider() 延迟读取避免快照失效(model_config.py:1274-1283)。
  2. 数据完整性工程化程度高:原子写(file_operations.py)+ _BU.json 复位种子 + 战斗「预掷池」防 LLM 篡改骰子(rolls.py:186)+ 模块完成/迁移有崩溃恢复与锁(campaign_manager.py 大量 _recover_*/transaction lock)。
  3. 压缩体系层次分明:从角色卡/提示词/战斗叙述/会话分块到 living summary,且「代码持算术、LLM 持意图」把不确定性收敛到可验证边界(resolver.pyaction_predictor.py:184 保守回退)。
  4. 契约驱动、可测性强:大量 task_id(T013/T040/T082…)与 callsite 注册(register_callsite),并配有针对性的 pytest(.gitignore 白名单中 20+ 测试文件)。

缺陷(附代码依据)

  1. 遗留代码与缺失依赖并存:conversation_compression.py:13-14 导入的三模块在仓库中未读到(glob 无命中),该文件实为断裂/死代码;dm_wrapper.py:11-15enhanced_dm_wrapper.py:10-13 自标 DEPRECATED。
  2. 单一巨型模块:main.py 7427 行、module_stitcher.py 4939 行、campaign_manager.py 3804 行、action_handler.py 3672 行,职责过度集中、耦合高,main.py 混入大量校验/压缩/归档细节。
  3. 文档与实现不一致:README 宣称分块压缩「8 transitions」而 chunked_compression_config.py:11-12 实际 COMPRESSION_TRIGGER=12, CHUNK_SIZE=6;README「70-90% 成本削减」缺乏仓库内可复现基准(telemetry 数据被 gitignore)。
  4. 状态分散于文件系统:以 JSON 文件为唯一真相源、靠路径约定与锁串行化,无 schema 迁移版本管理(effects 迁移另设 effects_migration.py 补丁),并发/跨模块一致性维护成本高。

七、结论

NeverEndingQuest 是一个「AI 驱动 DM + JSON 文件持久化」的单体 Python 引擎,工程重心不在规则引擎而在上下文治理:用压缩(会话分块、@TAG 符号化、living summary、伙伴情绪记忆)对抗 LLM 上下文窗口,用逐调用点多模型矩阵控制成本,用「代码持算术、LLM 持叙事」的 agentic 战斗与预掷骰保证规则可验证。SRD 5.2.1 规则以数据文件(data/spell_repository.json 等)+ 查询层集成而非硬编码,战斗/效果由 Python 确定性裁决。架构上优点(原子写、崩溃恢复、provider 隔离、契约可测)与缺点(巨型文件、遗留断链代码、文档与实现漂移、文件态一致性)并存,符合其 75★、v0.3.5 Alpha 的成熟度定位。