【文字三国志:第二篇】天命重构,系统架构与核心设计文档

系统架构与核心设计文档

前言:从宏观到微观

欢迎加入天命三国项目。这份文档将带您从宏观的游戏定位出发,逐步深入到具体的子系统、技术选型、核心流程,最后探讨未来的扩展方向。


第一章:概述

1.1 天命三国

天命三国不是一款传统的、规则固定的三国策略游戏。它是一款 基于Web的回合制策略叙事游戏,其核心乐趣在于:

  • 沉浸式叙事:系统通过大语言模型(LLM)动态生成富有文言风格的剧情,让每一次选择都独一无二。
  • 多维决策 :玩家不仅需要在军事 上运筹帷幄,还要在政治、外交、占星等多个维度进行权衡,影响天下大势。
  • 蝴蝶效应:游戏会通过"世界变化"提示,让玩家清晰地感知到自己的决策如何像蝴蝶扇动翅膀一样,引发后续一系列事件。

简而言之,我们是在用现代化的AI技术,去实现一个充满古典浪漫与不确定性的三国幻想世界。

1.2 技术目标

为了支撑上述体验,我们确立了四个核心的技术目标,这也是我们所有架构设计的基石:

  1. 绝对的类型安全:使用 TypeScript (TS) 和 Prisma,从前端到数据库,确保数据类型在编译时就能发现错误,杜绝运行时因数据结构不一致导致的"灵异事件"。
  2. 高可维护性:严格的代码分层(UI、业务逻辑、数据持久化分离),让每一部分代码职责清晰,便于定位问题、修改功能和新人上手。
  3. 可观测性:通过结构化日志、实时推送 (SSE) 和定时任务 (Cron),让系统的运行状态、玩家行为和AI决策过程都"透明可见",方便调试和运营。
  4. 可扩展性:API路由设计为插件化,剧情脚本和LLM提示词可热插拔、可配置,为未来的功能增加和多语言支持留足空间。

第二章:系统的骨架与血肉 ------ 关键子系统概览

#mermaid-svg-8odpwOMrqp1VaI2B{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8odpwOMrqp1VaI2B .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8odpwOMrqp1VaI2B .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8odpwOMrqp1VaI2B .error-icon{fill:#552222;}#mermaid-svg-8odpwOMrqp1VaI2B .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8odpwOMrqp1VaI2B .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8odpwOMrqp1VaI2B .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8odpwOMrqp1VaI2B .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8odpwOMrqp1VaI2B .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8odpwOMrqp1VaI2B .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8odpwOMrqp1VaI2B .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8odpwOMrqp1VaI2B .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8odpwOMrqp1VaI2B .marker.cross{stroke:#333333;}#mermaid-svg-8odpwOMrqp1VaI2B svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8odpwOMrqp1VaI2B p{margin:0;}#mermaid-svg-8odpwOMrqp1VaI2B .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-8odpwOMrqp1VaI2B .cluster-label text{fill:#333;}#mermaid-svg-8odpwOMrqp1VaI2B .cluster-label span{color:#333;}#mermaid-svg-8odpwOMrqp1VaI2B .cluster-label span p{background-color:transparent;}#mermaid-svg-8odpwOMrqp1VaI2B .label text,#mermaid-svg-8odpwOMrqp1VaI2B span{fill:#333;color:#333;}#mermaid-svg-8odpwOMrqp1VaI2B .node rect,#mermaid-svg-8odpwOMrqp1VaI2B .node circle,#mermaid-svg-8odpwOMrqp1VaI2B .node ellipse,#mermaid-svg-8odpwOMrqp1VaI2B .node polygon,#mermaid-svg-8odpwOMrqp1VaI2B .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8odpwOMrqp1VaI2B .rough-node .label text,#mermaid-svg-8odpwOMrqp1VaI2B .node .label text,#mermaid-svg-8odpwOMrqp1VaI2B .image-shape .label,#mermaid-svg-8odpwOMrqp1VaI2B .icon-shape .label{text-anchor:middle;}#mermaid-svg-8odpwOMrqp1VaI2B .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8odpwOMrqp1VaI2B .rough-node .label,#mermaid-svg-8odpwOMrqp1VaI2B .node .label,#mermaid-svg-8odpwOMrqp1VaI2B .image-shape .label,#mermaid-svg-8odpwOMrqp1VaI2B .icon-shape .label{text-align:center;}#mermaid-svg-8odpwOMrqp1VaI2B .node.clickable{cursor:pointer;}#mermaid-svg-8odpwOMrqp1VaI2B .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8odpwOMrqp1VaI2B .arrowheadPath{fill:#333333;}#mermaid-svg-8odpwOMrqp1VaI2B .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8odpwOMrqp1VaI2B .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8odpwOMrqp1VaI2B .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8odpwOMrqp1VaI2B .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8odpwOMrqp1VaI2B .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8odpwOMrqp1VaI2B .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8odpwOMrqp1VaI2B .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8odpwOMrqp1VaI2B .cluster text{fill:#333;}#mermaid-svg-8odpwOMrqp1VaI2B .cluster span{color:#333;}#mermaid-svg-8odpwOMrqp1VaI2B div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8odpwOMrqp1VaI2B .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8odpwOMrqp1VaI2B rect.text{fill:none;stroke-width:0;}#mermaid-svg-8odpwOMrqp1VaI2B .icon-shape,#mermaid-svg-8odpwOMrqp1VaI2B .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8odpwOMrqp1VaI2B .icon-shape p,#mermaid-svg-8odpwOMrqp1VaI2B .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8odpwOMrqp1VaI2B .icon-shape .label rect,#mermaid-svg-8odpwOMrqp1VaI2B .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8odpwOMrqp1VaI2B .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8odpwOMrqp1VaI2B .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8odpwOMrqp1VaI2B :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 持久化与辅助
业务子系统
后端核心
前端
用户操作
调用
构造Prompt
返回叙事/结果
调用具体逻辑
调用具体逻辑
...
...
...
读写数据
推送事件
解锁成就
推送更新
更新
驱动
触发季节/存档
用户界面 React
全局状态管理 Zustand
实时通知 Hook
API 路由层
游戏引擎 Narratve Engine
大语言模型 ZAI
战斗系统
外交系统
占星系统
政策系统
成就系统
数据库 PostgreSQL
定时任务 Cron
实时推送 SSE

  • Narrative Engine (核心大脑) :位于 src/lib/game/engine.ts。它是整个游戏的"导演",负责接收玩家指令,拼装上下文给AI,解析AI返回的剧情,并协调所有子系统(战斗、外交等)完成一次"回合"的变更。
  • 业务子系统 (五脏六腑):战斗、外交、占星、政策、成就等系统,它们是游戏的具体规则实现。引擎只负责"叫"它们做事,具体怎么做,由它们自己决定。
  • Store & State Layer (神经中枢) :基于 ZustandImmer 的全局单例。它管理前端UI的所有状态,并负责与后端同步。前端组件只关心这个Store,不需要知道数据从哪里来。
  • Real-time Notification (感官系统) :通过 Server-Sent Events (SSE) 实现。当后端有重要事件(如回合结束、成就解锁),会立刻"推送"给前端,前端通过 use-game-notifications Hook 接收并更新界面,实现毫秒级响应。

第三章:技术栈详解

我选择的每一项技术,都是为了解决一个特定问题。

分类 技术栈 角色与理由
前端框架 Next.js 13 (App Router) + React 18 提供服务端渲染 (SSR),让首屏加载更快,利于SEO;App Router的文件夹结构让路由管理更清晰。
编程语言 TypeScript 类型安全是项目的生命线,TS确保了我们写的每一行代码都在预期之内。
UI与样式 TailwindCSS + shadcn/ui 快速开发且风格统一。shadcn/ui 提供了一系列无样式、可访问的基础组件,我们可以自由定制,不背"样式债"。
状态管理 Zustand + SWR Zustand 轻量且强大,适合管理复杂的游戏全局状态;SWR 专门用于数据获取,自动处理缓存和重试。
后端逻辑 Next.js API Routes 利用 Next.js 的API路由作为Serverless函数,无需单独部署后端服务,项目结构统一。
数据库 Prisma ORM + PostgreSQL Prisma 提供了类型安全的数据库访问,其模型定义即为"单一事实来源"。PostgreSQL 可靠、功能强大,生产环境首选。开发环境用轻量的 SQLite。
AI 集成 Z-AI SDK 统一封装了对大语言模型的调用,方便后续切换或升级模型。
部署与运维 Docker + Caddy + GitHub Actions Docker 保证环境一致性;Caddy 自动处理 HTTPS 证书;CI/CD 自动化构建和部署,减少人工失误。
监控与日志 Prometheus + Grafana + Loki Prometheus 收集指标,Grafana 可视化展示;日志统一收集到 Loki,方便检索和排查问题。

第四章:一局游戏的旅程 ------ 核心业务流程

让我们跟随玩家的操作,看数据是如何在整个系统中流动的:
Cron SSE推送 数据库 LLM 游戏引擎 API路由 前端UI 玩家 Cron SSE推送 数据库 LLM 游戏引擎 API路由 前端UI 玩家 #mermaid-svg-qYvRiyHYxcIlQL1w{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qYvRiyHYxcIlQL1w .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qYvRiyHYxcIlQL1w .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qYvRiyHYxcIlQL1w .error-icon{fill:#552222;}#mermaid-svg-qYvRiyHYxcIlQL1w .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qYvRiyHYxcIlQL1w .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qYvRiyHYxcIlQL1w .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qYvRiyHYxcIlQL1w .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qYvRiyHYxcIlQL1w .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qYvRiyHYxcIlQL1w .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qYvRiyHYxcIlQL1w .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qYvRiyHYxcIlQL1w .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qYvRiyHYxcIlQL1w .marker.cross{stroke:#333333;}#mermaid-svg-qYvRiyHYxcIlQL1w svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qYvRiyHYxcIlQL1w p{margin:0;}#mermaid-svg-qYvRiyHYxcIlQL1w .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qYvRiyHYxcIlQL1w text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-qYvRiyHYxcIlQL1w .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qYvRiyHYxcIlQL1w .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-qYvRiyHYxcIlQL1w .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-qYvRiyHYxcIlQL1w .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-qYvRiyHYxcIlQL1w #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-qYvRiyHYxcIlQL1w .sequenceNumber{fill:white;}#mermaid-svg-qYvRiyHYxcIlQL1w #sequencenumber{fill:#333;}#mermaid-svg-qYvRiyHYxcIlQL1w #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-qYvRiyHYxcIlQL1w .messageText{fill:#333;stroke:none;}#mermaid-svg-qYvRiyHYxcIlQL1w .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qYvRiyHYxcIlQL1w .labelText,#mermaid-svg-qYvRiyHYxcIlQL1w .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-qYvRiyHYxcIlQL1w .loopText,#mermaid-svg-qYvRiyHYxcIlQL1w .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-qYvRiyHYxcIlQL1w .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qYvRiyHYxcIlQL1w .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-qYvRiyHYxcIlQL1w .noteText,#mermaid-svg-qYvRiyHYxcIlQL1w .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-qYvRiyHYxcIlQL1w .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qYvRiyHYxcIlQL1w .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qYvRiyHYxcIlQL1w .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qYvRiyHYxcIlQL1w .actorPopupMenu{position:absolute;}#mermaid-svg-qYvRiyHYxcIlQL1w .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-qYvRiyHYxcIlQL1w .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qYvRiyHYxcIlQL1w .actor-man circle,#mermaid-svg-qYvRiyHYxcIlQL1w line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-qYvRiyHYxcIlQL1w :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 引擎核心处理阶段 alt成就解锁 loop回合循环 1. 登录/开始新游戏POST /api/game/start调用 startGame()创建会话、角色、世界状态返回成功返回初始数据200 OK + 游戏数据更新 Zustand Store,渲染界面2. 在底部控制栏做出决策 (例如"出征")POST /api/game/action {action: "attack"}调用 processAction()读取最新游戏状态构建LLM上下文 (buildContextMessage)调用LLM,传入Prompt返回叙事JSON解析JSON,应用世界变化 (applyWorldChanges)调用战斗/外交等子系统处理特定逻辑3. 持久化所有变更 (回合、日志、属性)4. 检查游戏结束/成就解锁写入成就记录推送 achievementUnlocked 事件5. 推送 turnResult 事件6. SSE 推送游戏结果useGameNotifications Hook 接收更新 Store 和 UI7. 展示新的剧情与变化定时触发 (季节事件)生成系统事件剧情推送系统事件

流程解读:

  1. 开始新局:后端正向您描述的那样,初始化一个干净的游戏世界。
  2. 玩家行动 :每一次点击"下一回合"或做出选择,都会触发一个 POST 请求到 /api/game/action
  3. 引擎调度 :后端收到请求后,processAction 函数开始工作。它不是 硬编码所有规则,而是:
    • 读取最新状态。
    • 将玩家选择、世界状态、角色属性等"喂"给LLM。
    • LLM像一个"故事大王",根据上下文生成符合逻辑的叙事文本和结构化的数据变化(比如:民心+5,粮草-100,触发一场遭遇战)。
    • 引擎解析这些数据,并调用对应的子系统(如 resolveCombat)来完成计算,最后更新数据库。
  4. 实时反馈 :整个计算过程结束后,后端通过SSE将增量更新(而不是整个页面)推送给前端。前端无缝更新UI,玩家立即看到故事发展和数值变化。
  5. 后台时间:Cron定时任务模拟了"时间流逝",即使在玩家不操作时,也会触发季节更替、NPC行动等事件,让世界"活"起来。

第五章:面向未来的设计 ------ 可扩展性路线图

一个优秀的架构,必须能优雅地拥抱变化。我们已经为未来的可能性埋下了种子。

  • 插件化剧情 :您提到在 src/app/api/game/<module>/ 下添加新路由。这正是目前的设计。未来,我们可以实现一个"剧情加载器",扫描指定文件夹下的脚本文件(JSON或JS),动态注册新的API端点和引擎处理函数,实现真正的"热插拔"。

  • 多语言支持 :利用 next-i18next 等成熟的i18n方案。我们的策略是:

    1. 所有UI文案抽离到 locales/ 目录。
    2. LLM Prompt 进行改造 :不再使用自然语言描述语言,而是显式地在Prompt中加入 [LANG: zh-CN][LANG: en] 标记,指导AI输出对应语言的叙事。
  • 社区化与AI助手

    • 社区功能 :新增 FriendshipLeaderboard 表非常简单。难点在于联盟战争等跨玩家PVP逻辑,这需要设计更复杂的并发控制事件锁机制,防止数据冲突。
    • AI助手 :可以独立为一个微服务。当前端请求"AI建议"时,API网关将该玩家的脱敏状态发给AI助手服务,由它通过另一个LLM实例分析战局,返回策略建议。这解耦了主游戏引擎和辅助功能,互不影响。

结语

这份文档是您探索天命三国代码世界的起点。它描绘了我们的蓝图、选择与思考。后续章节的细化文档(如数据库结构、API规范、UI组件库指南)将为您提供更实操性的指引。

请记住我们的核心原则:类型安全、逻辑清晰、系统可观测、架构可扩展。祝您开发愉快,与我们一起开创这个天命交织的三国世界!

相关推荐
枫叶林FYL11 小时前
Explore with Long-term Memory:基于多模态大语言模型与强化学习的具身探索框架
大数据·人工智能·语言模型
有为少年11 小时前
深度隐式层 | 深度平衡模型 (Deep Equilibrium, DEQ)
人工智能·深度学习·神经网络·机器学习
完成大叔11 小时前
学习导师:从工具模式到感知模式的整合
人工智能
梦想三三11 小时前
【Open CV图像处理】修改运算与平滑处理
人工智能·opencv·计算机视觉
lqqjuly11 小时前
状态空间模型:从经典控制论到现代序列建模——S4、Mamba 及其理论体系的完整论述(三)
人工智能
财经资讯数据_灵砚智能11 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年5月28日
大数据·人工智能·python·信息可视化·自然语言处理·ai编程·灵砚智能
weixin_4684668511 小时前
基于OpenCV的工业相机标定技术实战
图像处理·人工智能·opencv·计算机视觉·相机标定·机器视觉·工业相机
徐安安ye11 小时前
FlashAttention输出全是NaN?数值问题排查指南
人工智能·深度学习·机器学习