2026-03-20 更新: 当前仓库已经完成 Phase 1 的开源单机化落地,完成 Phase 2 的 faction/world 系统,并进入 Phase 3 的 relationship/bond 层。运行时事实已经从“PostgreSQL + Redis + 远程配置 + 远程静态资源 + 支付/登录分支”切换到“SQLite + 本地配置 + 本地资源 + 单机默认用户 +
/mcp+ 帮派外循环世界模拟 + 统一 NPC Bond 底座”。
MOB.AI 当前是一个以修仙题材为核心的 AI 驱动叙事游戏仓库。它仍然是一个 Next.js 单体应用,但已经具备三层同时运行的能力:
- 玩家本地游玩的前端与主流程
- 本地配置和持久化驱动的服务端动作
- 对外暴露给 agent 的 MCP / skills 接口
这份文档记录的是“当前事实架构”,用于后续继续迭代 faction/world 与 relationship/bond 层。
| 层级 | 当前实现 |
|---|---|
| Web 框架 | Next.js 15 App Router |
| UI | React 18 + Tailwind CSS v4 + 少量 Radix UI |
| 客户端状态 | Recoil |
| ORM / 数据库 | Prisma + SQLite (prisma/dev.db) |
| 配置中心 | 本地 JSON 配置 (data/local-config.json) |
| AI 调用 | Vercel AI SDK + stableGenerateObject |
| 模型路由 | src/utils/modelAdapter.ts |
| 媒体 | public/assets/ + public/generated/ |
| 用户模式 | 单机默认用户自动创建 |
| 图像生成 | 可选功能,默认关闭 |
| 埋点 | 默认关闭,可选开启 |
| Agent 兼容 | MCP (/mcp) + skills/*/SKILL.md + OpenClaw 示例配置 |
.
├── src/
│ ├── app/ # App Router 页面、Server Actions、游戏主流程
│ ├── interfaces/ # schema、DTO、共享类型
│ ├── lib/ # Prisma、本地配置、MCP、错误处理等基础设施
│ └── utils/ # 模型适配、Prompt/配置桥、AI 工具
├── prisma/ # SQLite schema
├── scripts/ # SQLite 初始化、资源同步
├── public/
│ ├── assets/ # 本地 UI 资源
│ └── generated/ # 本地生成图片
├── skills/ # 标准 SKILL.md 资产
├── openclaw/ # OpenClaw 示例配置
└── docs/ # 架构、规则、roadmap、重构设计
src/app/layout.tsx- 注入全局样式。
- 按本地配置决定是否启用 Umami。
src/app/ClientRoot.tsx- 包裹
RecoilRoot、ToastProvider。 - 渲染固定头部与设置入口。
- 负责本地用户状态在客户端的同步。
- 包裹
src/app/components/PageLayout.tsx- 主流程容器,靠 Recoil
pageState在home/create/loading/char/story间切换。
- 主流程容器,靠 Recoil
src/app/components/PageHome.tsx- 首页、角色列表、快速开局、导入分享入口。
src/app/components/PageCreateChar.tsx- 灵根、属性点、姓名、角色背景创建。
src/app/components/PageChar.tsx- 角色档案、立绘、开始修行入口。
- 当前也承载 faction 与 bond 的轻量入口。
src/app/components/PageStory.tsx- 剧情展示、掷骰演出、选项推进、自定义输入、死亡/突破跳转。
- 在突破成功后承载“道侣许愿”强制节点,并展示关系侧栏摘要。
src/app/pages/*- 独立路由页,目前保留历史、设置、死亡、头像、世界地图等页面。
- 关系系统新增
pages/bonds与pages/bond-chat。
src/app/actions/** 是当前应用真正的后端接口层,核心包括:
character/action.ts- 创建角色、获取角色、突破、复生,并在角色创建/读取时注入 faction / bond 数据。
game/action.tsstartGame()、pushGame()。
faction/action.ts- 读取角色对应的 faction 世界快照。
bond/action.ts- 读取关系快照、提交道侣愿望、收徒/拒绝候选、私语聊天。
settings/action.ts- 本地模型配置、Prompt 模板、功能开关、连接测试。
revive/action.ts- 单机复生动作。
story_segment/action.ts- 剧情片段读取。
image-generation/action.ts- 可选剧情配图触发。
当前规则仍然没有被完全抽成独立 domain/,主要逻辑集中在:
GameCharacterRefactored.ts- 主协调器,负责角色装载、推进、突破/死亡判定、current push 切换,并在响应里注入 faction / bond 载荷。
GamePushService.ts- 创建剧情推进、调用 LLM、落库新 push,并把 faction / bond 世界上下文注入故事 Prompt。
OptionService.ts- 选项推进与预加载衔接。
PreloadService.ts- 给选项提前掷骰并准备结果。
factionSystem.ts- 负责世界生成、帮派关系、地图节点、帮派任务、外循环 world turn、旧存档补建与 UI payload 组装。
bondSystem.ts- 负责统一 NPC Bond 底座、道侣愿望兑现、弟子候选刷新、关系记忆、轻量事件编排、聊天与剧情上下文注入。
checkSystem.ts- 2d6 检定规则。
attributeSystem.ts- 状态初始化、状态变化、死亡判定。
OptionAnalysisService.ts- 自定义输入的动作分类和难度分析。
src/lib/prisma.ts- Prisma 单例。
src/utils/config-client.ts- 本地配置桥,保留旧
ConfigService形式以减少业务改动。
- 本地配置桥,保留旧
src/lib/local-config/*- 默认 Prompt Pack、本地配置存储、设置页读写接口。
src/lib/local-user.ts- 单机默认用户引导。
src/lib/local-media.ts- 本地图像落盘。
src/lib/mcp/server.ts- MCP server 定义,并暴露 faction 设计/roadmap 等资源。
src/utils/modelAdapter.ts- 把本地配置映射到 AI SDK provider。
src/utils/stableGenerateObject.ts- 统一对象生成、修复、重试、日志落库。
flowchart TD
A["创建角色"] --> B["生成角色档案"]
B --> C["开始修行"]
C --> D["展示剧情与选项"]
D --> E["2d6 检定与状态变动"]
E --> F["写入新的 GamePush"]
F --> G{"死亡 / 突破 / 继续"}
G -->|继续| D
G -->|死亡| H["死亡页 -> 本地复生"]
G -->|突破| I["突破结算"]
当前仍是双轨结构:
- 主游戏循环使用 Recoil
pageState - 历史、死亡、设置、头像使用 App Router 独立页面
当前 faction 地图已经采用独立页面 src/app/pages/world/page.tsx,并在角色页、故事页通过入口按钮跳转。
flowchart TD
A["创建角色"] --> B["生成 faction world 草图"]
B --> C["持久化 World / Faction / MapNode / Relation"]
C --> D["分配玩家帮派身份与初始任务"]
D --> E["开始剧情"]
E --> F["玩家推进一次剧情"]
F --> G["更新帮派任务进度与贡献/信任"]
G --> H{"是否达到 world turn 间隔"}
H -->|是| I["运行帮派意图与战争/联盟结算"]
H -->|否| J["继续剧情"]
I --> K["写入 WorldEvent 与新闻摘要"]
K --> J
flowchart TD
A["角色达到筑基"] --> B["突破成功后强制许愿"]
B --> C["写入 BondWish"]
C --> D["后续剧情推进时检查目标回合"]
D --> E{"道侣愿望是否兑现"}
E -->|是| F["生成 BondActor + CharacterBond"]
E -->|否| G["继续主剧情"]
F --> H["在角色页/剧情页/缘簿页展示"]
H --> I["私语聊天写入 BondMemory"]
I --> M["按冷却触发关系事件并生成 story hook"]
M --> N{"是否跨过关系阶段阈值"}
N -->|是| O["写入阶段升级记忆并刷新关系摘要/UI"]
N -->|否| G
A --> J["角色达到金丹"]
J --> K["按槽位刷新候选弟子"]
K --> L["玩家收徒或暂不点头"]
L --> P["按信任/忠诚更新弟子关系阶段"]
P --> G
| 模型 | 作用 |
|---|---|
User |
本地单用户主体,含复生状态 |
Character |
角色档案、加点、灵根、当前推进指针 |
World |
帮派世界种子、world turn、季节、新闻摘要 |
MapNode |
世界节点图上的山门、坊市、渡口、秘境等 |
Faction |
帮派势力、目标、首府、控制节点与风格摘要 |
FactionRelation |
势力间关系分数、关系类型、最近原因 |
CharacterFactionState |
玩家在帮派中的身份、贡献、信任、地位、当前节点 |
FactionMission |
帮派派给玩家的任务与奖励 |
WorldEvent |
战争、结盟、占领、任务完成等世界事件 |
BondActor |
关系 NPC 的静态画像 |
CharacterBond |
道侣/弟子的运行态关系、lifecycle 阶段、关系进展阶段、数值与摘要 |
BondMemory |
关系记忆摘要与聊天片段 |
BondWish |
道侣愿望、结构化偏好与兑现状态 |
GamePush |
每一步剧情推进节点 |
StorySegment |
与推进一对一的剧情片段快照 |
Avatar / AvatarTask |
角色头像与生成任务 |
Dictionary |
兼容旧逻辑的字典表 |
PromptHistory |
Prompt 版本记录 |
LlmCallLog |
LLM 调用日志 |
Character.currentPushId指向当前剧情节点Character.worldId把角色接到 faction/world 层Character.bondActors / bonds / bondWishes把角色接到 relationship/bond 层Character.gamePush[]保存推进历史Character.factionState维护帮派身份、贡献、当前任务CharacterBond.actorId把静态 NPC 画像与关系运行态拆开CharacterBond.progressStage独立表示“牵丝 / 相偎 / 缠心 / 同契”或“入门 / 亲随 / 得力 / 倚重”BondMemory.bondId维护关系对话与关键事件摘要BondWish.fulfilledBondId把“许愿”与“兑现后的道侣”串起来GamePush.fatherId形成推进树StorySegment与GamePush一对一World -> Faction -> MapNode / FactionRelation / WorldEvent组成世界外循环骨架Character -> BondWish -> CharacterBond -> BondMemory组成长期关系外循环骨架- 复生不重建角色,而是重置状态并继续角色生命线
当前 Prompt 与模型配置已经本地化,但业务层仍保留“配置服务”抽象:
ConfigService.getConfig(name)现在读取本地配置文件- 每个配置项包含:
- provider
- base URL
- API key
- model name
- system prompt / user prompt
- thinking / feature 参数
modelAdapter.ts再把这些配置映射到 AI SDK providerOptions
这让旧代码改动面较小,但也意味着“本地配置中心”目前仍是兼容层,不是纯净的新设计。
- 路径:
src/app/mcp/route.ts - 协议:标准 Streamable HTTP MCP
- SDK:
@modelcontextprotocol/sdk - 入口:
POST /mcp
当前暴露:
- tools:角色查询、角色创建、开始游戏、推进、突破、设置读取
- resources:架构文档、规则文档、roadmap、faction 设计文档、skills、Prompt 模板
- prompts:重构顾问、游戏主持
仓库当前提供:
skills/mobai-gameplay/SKILL.mdskills/mobai-refactor/SKILL.md
文件格式为 YAML frontmatter + Markdown body,面向 Claude Code / Codex / Cursor / OpenClaw 风格工作流。
- 示例配置在
openclaw/example-config.json - 文档在
docs/OPENCLAW_INTEGRATION.md
后续重构必须保留以下视觉资产:
- 宣纸感浅米底色
#F2EBD9 - 黑墨 / 深褐色文字,而不是通用后台对比色
- 古籍/明朝体取向
- 大量图片化按钮
- 移动端全屏叙事感
- 五行色系和金色点缀
换句话说,Phase 2 的 faction/map 已经按这个方向落地,不能退化成普通管理后台或标准沙盒地图。
主循环与独立路由页并存。当前 faction/map 已经进入独立路由页,但与 Recoil 主循环仍有状态桥接成本。
GameCharacterRefactored、GamePushService 既管规则又直接打 Prisma,后续适合拆成 domain + repository + orchestration。
cookie、localStorage、Recoil 同时存在,SSR/CSR 一致性仍有维护成本。
代码已经摆脱远端 config service,但 ConfigService 语义仍在。后续可以考虑彻底改成显式本地配置仓储。
当前帮派 AI 采用“代码掌控状态,LLM 负责叙事上下文”的混合模式。后续如果要继续增强自治深度,应保持这个边界,不要把可验证规则重新交还给模型。
当前 bond 系统也沿用相同边界:
- 代码控制解锁、槽位、候选刷新、愿望兑现、关系阶段阈值、树状事件分支、数值结算、记忆裁剪
- LLM 只负责愿望结构化、私语回复、关系事件包装与剧情风味
- 成年道侣线允许更明显但仍克制的暧昧拉扯;弟子线只增强玩梗、闯祸、护短和求夸
这保证了“道侣一定兑现”“弟子槽位稳定”“主循环不被关系系统抢走控制权”。
旧支付/后台文档已经不再代表当前产品,后续开发应以 README.md、docs/ROADMAP.md、当前源码为准。
- faction 不要重写主流程,而是作为世界上下文层插入
- 地图先做节点图 / 区域图,不直接上复杂 tile map
- world loop 要让代码掌握状态与结算,LLM 只负责意图和叙事增色
- MCP 资源层后续可以直接补 faction/world 文档、世界状态摘要、地图资源
- relationship/bond 后续也应继续沿用统一底座,不要把道侣和弟子拆成两套平行状态机