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

系统架构与核心设计文档

前言:从宏观到微观

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


第一章:概述

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 (神经中枢) :基于 Zustand 和 Immer 的全局单例。它管理前端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助手:

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

结语

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

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

相关推荐
sell-cloud1 小时前
Prompt Engineering要凉了?Fable 5.5能“猜“意图,但银行正在封杀AI Agent——企业AI的真正护城河是什么
人工智能·prompt
Navicat中国3 小时前
Navicat 18 内置 AI 助手让数据库开发从繁琐操作迈向智能协作
大数据·人工智能·数据库开发
4SAPI3 小时前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
魔乐社区3 小时前
翼芯・智算测试与适配优化专区,让国产算力“选得准、跑得通、用得好“
人工智能·开源·大模型
XCDoris5 小时前
郴州logo设计机构
大数据·人工智能·python
Goboy5 小时前
一个人带三个Agent,我用全新TRAE从0到1搭了个资讯周刊站
人工智能·trae
俊哥V5 小时前
每日 AI 研究简报 · 2026-10-19
人工智能·ai
AI_AGENT_DEV_AI5 小时前
AI英语教培智能体的开发
人工智能
物联网软硬件开发-轨物科技6 小时前
【技术白皮书】光伏清检一体化机器人系统解决方案技术白皮书
大数据·运维·网络·人工智能·机器人
海宇数据6 小时前
零信任架构实战:基于海宇网上踪迹欺诈行为识别构建自动化信贷资信评估网关
运维·人工智能·架构·自动化