init with react+axum+spacetimedb
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-26 18:06:23 +08:00
commit cbc27bad4a
20199 changed files with 883714 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,635 @@
# AI 角色形象与角色动画 MVP PRD
更新时间:`2026-04-19`
## 0. 一句话结论
本次 MVP 要做的不是一个泛化的“AI 动画平台”,而是一个能直接服务当前项目角色资产生产的最小闭环:
1. 用户先输入角色形象设定并上传参考图,或直接上传现成角色素材
2. 系统生成或规范化出一张**符合当前游戏侧视角色素材视角**的主形象图
3. 用户确认主形象后,再为该角色生成与当前项目可扮演角色动作槽位匹配的基础动作集
4. 用户可预览、重新生成,并最终发布为当前仓库可直接读取的角色资产
一句话说:
**MVP 先解决“怎么稳定产出能进游戏的角色主形象和基础动作”,而不是先追求所有技能动作和复杂演出。**
---
## 1. 背景
当前仓库已经有:
- 可扮演角色与角色型 NPC
- `CharacterAnimator` 运行时播放链路
- 角色预设与 override 机制
- 本地 API 插件机制
- NPC 静态形象编辑器
但当前缺少一条可用的角色资产生产链:
1. 角色主形象仍依赖手工素材整理
2. 动作资产缺少“从角色设定到可播放动作集”的编辑器闭环
3. 没有把“AI 生成结果”稳定沉淀为当前项目的标准角色资源
因此本期 MVP 的目标不是重做运行时战斗系统,而是补齐:
- 主形象生产
- 基础动作生产
- 预览与重新生成
- 发布到现有角色资源体系
---
## 2. MVP 要解决的问题
## 2.1 用户侧问题
当前如果想给项目新增一个角色,成本很高:
- 要先准备适合当前游戏视角的主形象
- 再补动作资源
- 还要手工整理资源目录和配置
MVP 要把这件事改成一个编辑器工作流。
## 2.2 项目侧问题
当前项目并不适合把 AI 直接放进运行时实时生成动作,因为:
- 运行时需要稳定、可回放、可测试的资源
- 战斗和剧情都依赖固定动作槽位
- 生成结果如果不资产化,会让维护成本失控
所以 MVP 的正确方向是:
**把 AI 用在编辑器里的资产生产链,而不是运行时即时生成。**
---
## 3. MVP 目标
## 3.1 产品目标
提供一个最小可用的“角色资产工坊”,满足以下闭环:
1. 生成或上传角色主形象
2. 预览并重选角色主形象
3. 基于主形象生成基础动作
4. 预览并重选动作结果
5. 发布为当前项目可直接使用的角色资源
## 3.2 技术目标
MVP 必须满足:
1. 只依赖国内可用模型与服务
2. 只生成当前项目能消费的标准资产
3. 不改动现有战斗规则与剧情规则
4. 生成结果必须走本地后处理与发布流程
5. 运行时只读本地标准化资产
## 3.3 成功标准
当以下条件同时成立时,视为 MVP 成功:
1. 编辑器里可以完成“主形象 -> 基础动作 -> 发布”闭环
2. 发布后的角色能被当前 `CharacterAnimator` 播放
3. 基础动作槽位不存在空映射
4. 用户可以对主形象和动作分别进行重新生成
---
## 4. 非目标
本期不做:
1. 不做运行时实时动画生成
2. 不做怪物动画生成链路
3. 不做通用 NPC 群像流水线
4. 不做技能动作全自动补齐
5. 不做批量生产多个角色的自动流水线
6. 不做多供应商路由调度
说明:
- 本期只先做好**单角色、单次编辑器操作**的最小闭环
- 技能动作可后续补,但**基础动作槽位不能为空**
---
## 5. 目标用户与使用场景
## 5.1 目标用户
- 项目策划
- 项目美术 / 技术美术
- 负责角色内容生产的开发者
## 5.2 核心使用场景
### 场景 A新建角色
用户输入角色设定词、参考图,生成当前项目风格可用的主形象和基础动作。
### 场景 B已有角色素材导入
用户已有一张角色图,希望快速裁切、规范化,并继续生成基础动作。
### 场景 C已有角色动作质量不满意
用户不改主形象,只重新生成单个或多个动作槽位。
---
## 6. MVP 用户流程
## 6.1 阶段 A主形象生成 / 导入
1. 用户选择角色
2. 输入角色形象设定文本
3. 上传角色参考图,或直接上传现成角色素材
4. 系统做尺寸、裁剪、构图校验
5. 提交生成或规范化任务
6. 返回多个候选预览图
7. 用户可:
- 预览
- 重新生成
- 设为当前主形象
## 6.2 阶段 B基础动作生成
1. 用户基于已确认主形象进入动作页
2. 系统展示当前基础动作槽位状态
3. 用户选择:
- 直接使用动作模板
- 上传参考动作视频
4. 提交动作生成任务
5. 生成完成后进入动作预览
6. 用户可:
- 保留结果
- 重新生成单动作
- 替换当前动作
## 6.3 阶段 C发布
只有在基础动作槽位全部有有效资源时,才允许发布。
发布后:
1. 写入主形象资源
2. 写入动画资源
3. 生成 manifest
4. 更新角色 override / 映射关系
---
## 7. 主形象阶段需求
## 7.1 输入方式
MVP 支持三种主形象输入方式:
1. 文生图
- 用户输入形象设定
2. 图生图
- 用户输入形象设定并上传参考图
3. 直接上传素材
- 用户上传已有角色图,不强制重新生成
## 7.2 视角要求
主形象必须贴近当前项目现有角色素材体系:
- 2D 侧视动作素材视角
- 单人全身
- 人物朝向右侧
- 脚底完整可见
- 武器和关键轮廓完整
- 不做正面立绘
- 不做强透视镜头
这是硬约束,不是美术建议。
原因:
- 当前项目运行时通过镜像处理左右朝向
- 如果主形象不是侧视动作素材视角,后续动作生成和运行时挂接都会失真
## 7.3 尺寸与裁剪要求
推荐规格:
- 推荐输入:`1024x1536`
- 可接受比例:`2:3``3:4`
- 最低建议:短边 `>= 768`
- 统一输出标准图:`1024x1536`
构图要求:
- 角色主体占画面高度约 `70% ~ 85%`
- 头顶保留少量留白
- 脚底必须完整露出
- 背景尽量简单
- 只允许单角色
## 7.4 主形象阶段交互要求
用户必须可以:
- 查看候选结果
- 放大预览
- 丢弃某个候选
- 基于同样输入重新生成
- 选择一个候选作为主形象
用户不能直接跳过主形象确认进入动作阶段,除非已经锁定主形象。
---
## 8. 动作阶段需求
## 8.1 基础动作槽位要求
MVP 必须与当前项目可扮演角色动作槽位对齐。
当前落地实现补充约束(`2026-04-20`
- 角色资产工坊固定生成入口仍为 `idle / run / attack / die`
- `run / attack` 是固定基础必生成动作
- `idle / die` 改为固定可选动作,不再作为发布硬门槛
- `idle` 未生成时默认直接使用主图静止显示
- `die` 未生成时默认播放一段基于主图的向后倒地过渡动画,并最终停在翻转倒地姿态
- 角色已配置的每个技能,都必须在技能编辑面板里补出对应动作预览
- 图生视频默认走火山方舟 `Seedance` 首尾帧方案
- 接口请求体中的两张参考图分别固定为 `first_frame / last_frame`
- 固定参数为 `1:1``480p``4 秒`、单次 `1` 个视频
- 提示词中的动作名统一传英文动作名
第一版动作生成按下面两层规则落地:
| 类别 | 动作槽位 | 是否必填 | 备注 |
| -------- | ------------------------------- | -------- | -------------------------------------------------- |
| 基础动作 | `run` | 必填 | 角色移动主循环动作 |
| 基础动作 | `attack` | 必填 | 角色普通攻击主动作 |
| 技能动作 | `skills[*].actionPreviewConfig` | 必填 | 当前角色每个已配置技能都要有独立动作资源 |
| 可选动作 | `idle` | 可选 | 缺失时默认走主图静止待机 |
| 可选动作 | `die` | 可选 | 缺失时默认走主图向后倒地过渡动画,最终停在翻转倒地姿态 |
这里“必生成”指的是:
- `run / attack` 必须最终指向可播放资源
- 每个已配置技能都必须带独立 `actionPreviewConfig`
- 发布判定不再要求 `idle / die` 一定存在动画映射
- 运行时仍然不能出现无可用表现;`idle / die` 的缺口由默认兜底承担
## 8.2 技能动作要求
本期不再要求把整套固定技能枚举一次性自动补齐,但对“角色当前实际配置的技能”改为必做:
- 不要求预先把 `skill1 / skill2 / skill3 / skill4` 这套历史枚举全部补满
- 只要求当前角色 `skills` 数组里的每个技能都生成独立动作预览
- 技能动作生成入口继续放在技能编辑面板逐个处理,不塞进固定四按钮里
结论:
- 技能动作从“固定枚举可选”调整为“按角色已配技能必做”
- 固定基础动作收敛为 `run / attack`
- `idle / die` 保留为可选增强动作
## 8.3 动作生成方式
MVP 支持两种方式:
1. 模板动作生成
- 用户选择动作模板
2. 参考视频驱动
- 用户上传参考动作视频
优先级:
- 基础动作优先走模板
- 个性化动作再用参考视频驱动
## 8.4 动作阶段交互要求
用户必须可以:
- 查看每个动作槽位当前状态
- 单独预览某个动作
- 单独重新生成某个动作
- 保留某些已满意动作,只重生其余动作
- 在所有基础动作齐全后再发布
---
## 9. 生成策略约束
## 9.1 角色一致性优先
动作生成阶段只能使用已锁定的主形象,不允许每个动作重新随机生成角色外观。
## 9.2 首尾帧控制
参考用户提供的视频方向MVP 固化以下策略:
### 循环动作
- `idle`
- `run`
要求首尾姿态尽量接近,便于循环。
### 一次性动作
- `attack`
- `jump_attack`
- `die`
要求末帧清晰,不与下一动作切换冲突。
## 9.3 高分辨率生成,低分辨率落地
MVP 不要求模型直接输出最终像素逐帧。
正确流程是:
1. 生成较稳定的高分辨率动作视频
2. 本地解帧、对齐、清理
3. 再转成当前项目可用的像素化资产
---
## 10. 技术方案边界
## 10.1 模型选择
MVP 统一采用国内可用的阿里云百炼方案:
- 主形象生成:`wan2.7-image-pro` / `wan2.7-image`
- 动作生成:`wan2.2-animate-move`
- 高质量换角动作:`wan2.2-animate-mix`
选择理由:
1. 国内可用
2. 图像和动作链路在同一平台
3. 便于 MVP 先收敛到单平台实现
## 10.2 本地后处理
MVP 必须包含本地后处理:
1. 解帧
2. 主体裁切
3. 背景清理
4. 稳帧
5. 像素化
6. 打包 Sprite Sheet
7. 输出 manifest
## 10.3 运行时边界
运行时不直接请求第三方模型接口。
运行时只读取:
- 主形象标准资源
- 动画标准资源
- override / manifest 配置
---
## 11. MVP 数据与接口
## 11.1 角色主形象资源
建议最小结构:
```ts
type GeneratedCharacterVisualAsset = {
id: string;
characterId: string;
sourceMode: 'text-to-image' | 'image-to-image' | 'upload';
masterImagePath: string;
previewImagePaths: string[];
width: number;
height: number;
facing: 'right';
locked: boolean;
};
```
## 11.2 角色动画资源
```ts
type GeneratedCharacterAnimationAsset = {
id: string;
characterId: string;
visualAssetId: string;
action: string;
frameCount: number;
fps: number;
loop: boolean;
spriteSheetPath: string;
framePaths: string[];
previewVideoPath: string;
};
```
## 11.3 最小接口
建议新增:
- `POST /api/character-visual/jobs`
- `GET /api/character-visual/jobs/:id`
- `POST /api/character-visual/publish`
- `POST /api/animation/jobs`
- `GET /api/animation/jobs/:id`
- `GET /api/animation/templates`
- `POST /api/animation/publish`
职责:
### `POST /api/character-visual/jobs`
- 创建主形象生成或规范化任务
### `GET /api/character-visual/jobs/:id`
- 查询主形象任务状态与结果
### `POST /api/character-visual/publish`
- 锁定主形象并写入主形象 manifest
### `POST /api/animation/jobs`
- 创建动作生成任务
### `GET /api/animation/jobs/:id`
- 查询动作任务状态与结果
### `GET /api/animation/templates`
- 返回动作模板列表
### `POST /api/animation/publish`
- 发布动作资源并更新动画映射
---
## 12. 与当前仓库的接入点
第一批建议接入:
- `src/components/CharacterAnimator.tsx`
- `src/types/characters.ts`
- `src/data/characterOverrides.json`
- `server-node/src/modules/assets/**`
建议新增:
- `src/components/CharacterAssetStudio.tsx`
- `src/data/characterAnimationOverrides.json`
- 角色主形象 manifest 读取逻辑
- 动画 manifest 读取逻辑
运行时优先级建议:
1. 角色 AI 生成动画 override
2. 角色原始 `animationMap`
3. 默认回退动画
---
## 13. 验收标准
## 13.1 主形象验收
1. 用户可以通过文生图 / 图生图 / 直接上传素材三种方式得到主形象
2. 主形象视角符合当前项目侧视角色素材要求
3. 主形象可预览、可重新生成、可锁定
## 13.2 动作验收
1. 所有基础动作槽位均有有效资源
2. 用户可以单独预览和重新生成某个动作
3. 发布后动作能被当前 `CharacterAnimator` 播放
## 13.3 资产验收
1. 发布后可生成主形象资源目录
2. 发布后可生成动画资源目录
3. 可生成对应 manifest / override 映射
## 13.4 体验验收
1. 用户不需要手工整理最终资源目录
2. 用户不需要每次都从头重做全部动作
3. 主形象和动作两阶段都可回看和重生
---
## 14. 风险与对策
## 14.1 风险:主形象视角不稳定
对策:
- 把“侧视、朝右、全身、脚底完整”作为硬校验
- 不合格结果不允许直接进入动作阶段
## 14.2 风险:动作循环不自然
对策:
- `idle``run` 强制使用循环模板优先
- 引入首尾帧接近度校验
## 14.3 风险基础动作槽位过多MVP 开发压力大
对策:
- 允许 `acquire``double_jump``wall_slide` 等少数槽位由近似动作衍生
- 但运行时最终槽位仍必须非空
## 14.4 风险:生成成本过高
对策:
- 先只支持单角色编辑
- 基础动作优先模板化
- 仅对不满意动作单独重生
---
## 15. MVP 开发顺序
## 阶段 1主形象闭环
目标:
- 跑通主形象生成 / 上传 / 预览 / 锁定
产出:
- `CharacterAssetStudio` 的主形象页
- 主形象任务 API
- 主形象 manifest
## 阶段 2基础动作闭环
目标:
- 跑通单动作生成、预览与替换
产出:
- 动作任务 API
- 动作模板列表
- 预览与重新生成流程
## 阶段 3基础动作补齐与发布
目标:
- 让必生成动作全部就绪,并为 `idle / die` 提供明确默认兜底
产出:
- 动作状态面板
- 发布逻辑
- override / manifest 写入
## 阶段 4运行时接入
目标:
- 让发布后的角色直接在现有运行时播放
产出:
- `CharacterAnimator` 读取生成动画能力
- 角色 override 映射接入
---
## 16. 最终结论
对当前仓库来说,最可落地的 MVP 不是“先做一个很强的 AI 动画系统”,而是:
1. 先固定角色主形象生产流程
2. 再固定基础动作生产流程
3. 只补能进当前项目运行时的最小动作集
4. 把预览、重新生成和发布做完整
这样做的价值在于:
- 范围可控
- 路径清晰
- 能真正进入当前仓库
- 后续可以在此基础上再加技能动作、剧情演出和多供应商增强路线

View File

@@ -0,0 +1,796 @@
# AI 原生 Agent-First 自定义世界创作工具第二阶段技术落地方案
更新时间:`2026-04-13`
## 0.1 当前状态说明2026-04-21
这份文档保留为第二阶段历史落地方案。
补充边界:
1. 文中提到的 `CustomWorldAgentIntentSummaryPanel``CustomWorldAgentClarificationPanel``CustomWorldAgentLockBar``CustomWorldAgentQuickActions` 等旧副面板,已经在当前版本收口判断中退出主链并物理删除
2. 这些内容现在只能作为历史设计参考,不再作为当前版本默认待接线项
3. 当前如果要重新设计这些能力的消费方式,应基于现行主链重新定义
## 0. 文档目的
这份文档用于把以下两份文档进一步收束成第二阶段实现方案:
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md)
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE1_IMPLEMENTATION_PLAN_2026-04-13.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE1_IMPLEMENTATION_PLAN_2026-04-13.md)
如果说第一阶段的目标是:
**先把创作页面和 Agent 工作区的外壳搭起来**
那么第二阶段的目标就是:
**让 Agent 会话真正开始理解创作者输入,并把自然语言聊天沉淀成结构化创作锚点。**
一句话定义:
**第二阶段先把“收集最小锚点、追问缺口、更新创作意图、同步草稿摘要”这条主链打通,而不是先急着生成完整世界。**
---
## 1. 阶段衔接关系
## 1.1 第一阶段已经完成什么
第二阶段默认建立在第一阶段已经完成的能力之上:
1. 从世界选择页可以进入创作页面
2. 创作页面可以展示草稿和已发布作品
3. 新建作品可以创建 Agent session
4. 可以进入 Agent 工作区
5. 用户发送消息后,服务端会写入 user / assistant 消息
6. session snapshot 和 operation 可以持久化与恢复
## 1.2 第二阶段不再重做什么
以下内容第二阶段不重做:
1. 不重做创作页面整体布局
2. 不重做 session 基础持久化
3. 不重做 operation 轮询主链
4. 不重做 workspace 基础壳层
第二阶段只在第一阶段骨架上继续补:
1. 意图提取
2. 最小锚点判断
3. 澄清问题生成
4. `creatorIntent` 持续更新
5. 创作页面草稿摘要变得更像“作品”
---
## 2. 第二阶段在八阶段中的位置
八阶段拆分如下:
1. 阶段 1创作页面入口、Agent 会话主链与工作区骨架
2. 阶段 2最小锚点收集与澄清流程
3. 阶段 3世界底稿生成与草稿卡编译
4. 阶段 4草稿设定编辑与 AI 新增角色/场景生成
5. 阶段 5角色主图与动作资产工坊接入
6. 阶段 6场景背景图工坊接入
7. 阶段 7长尾内容扩展与自动补齐
8. 阶段 8发布、世界库接入与继续创作恢复
本文件只覆盖:
**阶段 2最小锚点收集与澄清流程**
---
## 3. 第二阶段目标
第二阶段只做 6 件必须一起成立的事:
1. 把用户自然语言输入持续抽取为结构化 `creatorIntent`
2. 明确最小锚点是否齐备
3. 当锚点不足时,生成 `1~3` 个高杠杆澄清问题
4. 在 Agent 工作区中展示“已收集锚点摘要”和“待补充问题”
5.`creatorIntent` 的变化同步反映到创作页面草稿卡片摘要里
6. 当最小锚点齐备时,把 session 阶段推进到 `foundation_review`
一句话目标:
**让第二阶段结束时Agent 不再只是会回话,而是真正开始把“聊天内容”沉淀成“世界锚点”。**
---
## 4. 第二阶段完成定义
第二阶段完成后,必须同时满足以下结果:
1. 用户连续输入多轮自然语言后,`creatorIntent` 会被持续更新。
2. `creatorIntent` 中至少这些字段会真实变化:
- `worldHook`
- `themeKeywords`
- `toneDirectives`
- `playerPremise`
- `openingSituation`
- `coreConflicts`
- `keyCharacters`
- `iconicElements`
- `forbiddenDirectives`
3. 当最小锚点不完整时workspace 右侧会显示待澄清问题。
4. Agent 的回复不再只做“复述”,而会围绕缺失锚点主动追问。
5. 当最小锚点齐备时session 会进入 `foundation_review`,并明确告知“已可以进入下一阶段生成世界底稿”。
6. 创作页面里的草稿作品标题和摘要会随着 `creatorIntent` 更新而变得更准确,不再只是空壳草稿。
7. 第二阶段仍然不要求真正生成世界底稿,也不要求编出角色卡和地点卡。
---
## 5. 范围控制
## 5.1 第二阶段纳入范围
纳入范围的模块:
- `packages/shared/src/contracts/customWorldAgent.ts`
- `src/services/customWorldCreatorIntent.ts`
- `src/services/aiService.ts`
- `src/components/custom-world-home/CustomWorldCreationHub.tsx`
- `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
- `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
- `server-node/src/services/customWorldWorkSummaryService.ts`
- `server-node/src/services/customWorldAgentSessionStore.ts`
- `server-node/src/services/customWorldAgentOrchestrator.ts`
新增前端模块:
- `src/components/custom-world-agent/CustomWorldAgentIntentSummaryPanel.tsx`
- `src/components/custom-world-agent/CustomWorldAgentClarificationPanel.tsx`
新增服务端模块:
- `server-node/src/services/customWorldAgentIntentExtractionService.ts`
- `server-node/src/services/customWorldAgentClarificationService.ts`
## 5.2 第二阶段明确不做
以下内容不放进第二阶段:
1. 不生成世界底稿
2. 不生成 draftCards
3. 不进入角色、地点、势力、章节的实体卡编译
4. 不做锁定逻辑
5. 不做角色资产工坊
6. 不做场景图工坊
7. 不做长尾扩展
8. 不做发布
原因:
**第二阶段的唯一重点,是把 Agent 会话从“能聊”推进到“能收集创作锚点”。**
---
## 6. 第二阶段最小闭环
建议把第二阶段的最小闭环定义为:
```text
创作页面新建作品
-> 进入 Agent 工作区
-> 用户输入世界想法
-> 服务端提取 creatorIntent patch
-> 更新 creatorIntent / anchorPack / pendingClarifications
-> Agent 回复补问或确认
-> 前端展示已收集锚点摘要
-> 用户继续补充
-> 最小锚点齐备
-> session 进入 foundation_review
-> 创作页面草稿摘要同步更新
```
这个闭环里,先只强接两条高价值链路:
1. 对话 -> creatorIntent
2. creatorIntent -> 草稿摘要
---
## 7. 第二阶段产品行为定义
## 7.1 最小锚点定义
第二阶段必须明确判定“最小锚点是否齐备”。
建议统一收束成以下 6 组:
1. 世界一句话与核心幻想
- 对应:`worldHook`
2. 玩家身份与开局困境
- 对应:`playerPremise + openingSituation`
3. 主题气质与禁忌边界
- 对应:`themeKeywords + toneDirectives + forbiddenDirectives`
4. 核心冲突
- 对应:`coreConflicts`
5. 关键关系钩子
- 对应:`keyCharacters`
- 最低要求:至少有 1 个关键人物种子,且带 `relationToPlayer``hiddenHook`
6. 标志性要素
- 对应:`iconicElements`
## 7.2 最小锚点齐备规则
建议使用 deterministic 规则判断:
```ts
type CreatorIntentReadiness = {
isReady: boolean;
completedKeys: string[];
missingKeys: string[];
};
```
### 判定要求
#### `world_hook`
满足任一条件即视为完成:
1. `worldHook.trim().length >= 8`
2. `rawSettingText.trim().length >= 24` 且可提取稳定世界命题
#### `player_premise`
必须:
1. `playerPremise` 非空
2. `openingSituation` 非空
#### `theme_and_tone`
满足:
1. `themeKeywords.length >= 1`
2. `toneDirectives.length >= 1`
`forbiddenDirectives` 可选,但一旦用户明确提到禁忌,必须写入
#### `core_conflict`
满足:
1. `coreConflicts.length >= 1`
#### `relationship_seed`
满足:
1. `keyCharacters.length >= 1`
2. 至少一个条目同时满足:
- `name` 非空
-`relationToPlayer``hiddenHook` 非空
#### `iconic_element`
满足:
1. `iconicElements.length >= 1`
## 7.3 缺口澄清规则
`isReady === false`Agent 必须追问,但必须遵守:
1. 一次最多追问 `3` 个问题
2. 问题必须优先覆盖最高杠杆缺口
3. 问题不能像问卷
4. 每个问题最好给一个方向提示
### 优先级顺序
1. `world_hook`
2. `player_premise`
3. `core_conflict`
4. `theme_and_tone`
5. `relationship_seed`
6. `iconic_element`
## 7.4 阶段推进规则
### 初始
- `collecting_intent`
### 缺口存在
- `clarifying`
### 最小锚点齐备
- `foundation_review`
### 说明
第二阶段进入 `foundation_review` 后,不代表已经生成底稿;
只代表:
**已经具备进入第三阶段生成世界底稿的输入条件。**
## 7.5 Agent 回复行为
第二阶段起assistant 回复必须升级成 3 段结构:
1. 已确认内容
2. 仍缺内容
3. 下一步提问或建议
### 示例结构
```text
我先把目前已经明确的部分收一下:
- ...
现在还缺两块最关键的信息:
- ...
- ...
你可以先告诉我:
1. ...
2. ...
```
禁止:
1. 只说“收到”
2. 一次问超过 3 个问题
3. 明知缺世界核心还继续追问长尾细节
---
## 8. 数据结构落地方案
## 8.1 修改 `CustomWorldCreatorIntent`
继续复用 `src/services/customWorldCreatorIntent.ts` 的现有结构,不新增第二套意图对象。
第二阶段要求:
1. 所有字段都支持增量 patch
2. patch 合并必须是“补充 + 覆盖用户明确改写”
3. 不允许每次新消息都重置整个 intent
## 8.2 新增 `CreatorIntentReadiness`
建议新增到:
- `packages/shared/src/contracts/customWorldAgent.ts`
```ts
export interface CreatorIntentReadiness {
isReady: boolean;
completedKeys: string[];
missingKeys: string[];
}
```
## 8.3 扩展 `pendingClarifications`
当前第一阶段里的澄清结构太轻,第二阶段要扩成:
```ts
export interface CustomWorldPendingClarification {
id: string;
label: string;
question: string;
targetKey:
| 'world_hook'
| 'player_premise'
| 'theme_and_tone'
| 'core_conflict'
| 'relationship_seed'
| 'iconic_element';
priority: number;
answer?: string;
}
```
## 8.4 扩展 `CustomWorldAgentSessionSnapshot`
第二阶段必须新增:
```ts
creatorIntentReadiness: CreatorIntentReadiness;
```
并把:
```ts
pendingClarifications: CustomWorldPendingClarification[];
```
替换掉第一阶段的轻量问题数组。
## 8.5 扩展 `CustomWorldWorkSummary`
为了让创作页面草稿卡更像一个“作品”,第二阶段必须要求草稿摘要从 `creatorIntent` 实时编译。
规则:
### 标题
按优先级取:
1. `creatorIntent.worldHook`
2. `rawSettingText` 截断
3. `未命名草稿`
### 摘要
按优先级取:
1. `buildCustomWorldCreatorIntentDisplayText(intent)`
2. `rawSettingText` 截断
3. 默认空态文案
### 阶段文案
按 session.stage 直接映射。
---
## 9. 服务端实现方案
## 9.1 新增 `customWorldAgentIntentExtractionService.ts`
### 文件
`server-node/src/services/customWorldAgentIntentExtractionService.ts`
### 职责
输入:
1. 当前 `creatorIntent`
2. 最新用户消息
3. 最近若干轮对话摘要
输出:
```ts
type ExtractedCreatorIntentPatch = {
worldHook?: string;
themeKeywords?: string[];
toneDirectives?: string[];
playerPremise?: string;
openingSituation?: string;
coreConflicts?: string[];
keyCharacters?: CreatorCharacterSeed[];
iconicElements?: string[];
forbiddenDirectives?: string[];
};
```
### 推荐实现策略
第一优先:
1. 使用 deterministic 规则提取明显字段
第二优先:
2. 用一个轻量 LLM contract 只提取 patch不生成世界内容
### 第一阶段之外、第二阶段之内的硬要求
这一步的 LLM 输出必须只做“结构提取”,不能夹带世界扩写。
## 9.2 新增 `customWorldAgentClarificationService.ts`
### 文件
`server-node/src/services/customWorldAgentClarificationService.ts`
### 职责
1. 根据 `creatorIntent` 计算 readiness
2. 生成 `pendingClarifications`
3. 按优先级裁剪到 `1~3` 个问题
### 导出函数建议
```ts
evaluateCreatorIntentReadiness(intent)
buildPendingClarifications(intent, readiness)
```
## 9.3 修改 `customWorldAgentOrchestrator.ts`
第二阶段它要从“写消息 + 回固定话术”升级为:
1. 写入 user message
2. 提取 intent patch
3. 合并 intent
4. 更新 anchorPack
5. 计算 readiness
6. 生成 clarifications
7. 生成更结构化的 assistant 回复
8. 更新 snapshot
### 关键顺序
必须严格按下面顺序:
```text
收到用户消息
-> 提取 intent patch
-> merge creatorIntent
-> build anchorPack
-> evaluate readiness
-> build pendingClarifications
-> compose assistant reply
-> 写回 snapshot
```
### 第一阶段兼容要求
如果提取失败:
1. 不允许清空原有 intent
2. assistant 仍要给出可继续的澄清回复
## 9.4 修改 `customWorldWorkSummaryService.ts`
第二阶段它必须从 session 中读取:
1. `creatorIntent`
2. `creatorIntentReadiness`
3. `stage`
并生成更准确的:
1. 草稿标题
2. 草稿摘要
3. 当前阶段标签
---
## 10. 前端实现方案
### 当前状态补充2026-04-21
这一节描述的是第二阶段编写当时的右侧副面板方案。
但当前版本已经明确:
1. `CustomWorldAgentIntentSummaryPanel`
2. `CustomWorldAgentClarificationPanel`
3. `CustomWorldAgentLockBar`
4. `CustomWorldAgentQuickActions`
这组旧副面板不再作为当前版本默认待接线方向,其中对应已落地但退出主链的文件也已物理删除。
因此本节以下内容应视为历史设计稿,不再直接代表当前版本执行方案。
## 10.1 修改 `CustomWorldAgentWorkspace.tsx`
第二阶段它不再只是空壳工作区,而要新增:
1. 意图摘要区
2. 澄清问题区
### 右侧结构建议
1. `CustomWorldAgentIntentSummaryPanel`
2. `CustomWorldAgentClarificationPanel`
3. `CustomWorldAgentLockBar`
4. `CustomWorldAgentDraftDrawer`
5. `CustomWorldAgentQuickActions`
说明:
第二阶段虽然还没有真正 `draftCards`,但壳层继续保留。
## 10.2 新增 `CustomWorldAgentIntentSummaryPanel.tsx`
### 职责
展示当前已收集的最小锚点摘要。
### 展示项
1. 世界一句话
2. 玩家身份
3. 开局处境
4. 核心冲突
5. 主题气质
6. 标志性要素
### 空态
未收集到时显示:
- `还在收集你的世界锚点`
## 10.3 新增 `CustomWorldAgentClarificationPanel.tsx`
### 职责
展示当前 `pendingClarifications`
### 展示规则
1. 每个问题显示 label + question
2. 最多展示 3 个
3.`isReady === true`,显示:
- `最小锚点已齐备,可以进入下一阶段`
## 10.4 修改 `CustomWorldCreationHub.tsx`
第二阶段必须让草稿卡开始体现“已收集锚点”的变化。
要求:
1. 草稿卡标题和摘要来自统一 `CustomWorldWorkSummary`
2. 列表刷新后可以看到标题变化
3. 草稿从“未命名草稿”变成更接近创作主题的标题
## 10.5 修改 `CustomWorldAgentQuickActions.tsx`
第二阶段只保留轻动作:
1. `总结当前设定`
2. `继续补充锚点`
不允许展示:
1. `生成世界底稿`
2. `发布世界`
因为这属于后续阶段。
---
## 11. 交互时序
## 11.1 用户补充锚点
```text
用户发消息
-> 前端 POST /messages
-> 后端提取 creatorIntent patch
-> 更新 creatorIntent
-> 更新 readiness 和 pendingClarifications
-> 写入 assistant 回复
-> 前端刷新 snapshot
-> 前端刷新意图摘要和澄清问题
```
## 11.2 锚点齐备
```text
用户最后一轮补齐关键锚点
-> 后端 evaluate readiness = true
-> session.stage 切到 foundation_review
-> assistant 回复“已可进入下一阶段”
-> 前端显示完成态
-> 创作页面草稿摘要同步更新
```
---
## 12. 第一阶段到第二阶段的兼容要求
第二阶段必须兼容第一阶段已有数据。
## 12.1 旧 session 兼容
如果存在第一阶段创建的 session没有
1. `creatorIntentReadiness`
2. 新版 `pendingClarifications`
则读取时要自动补 fallback。
## 12.2 旧草稿兼容
如果草稿还没有明确 `worldHook`
1. 继续显示 `未命名草稿`
2. 不允许报错
---
## 13. 落地文件清单
### 当前状态补充2026-04-21
本节列的是第二阶段历史文件清单。
其中涉及旧副面板的部分,现在只保留历史参考价值,不再等同于当前版本待落地项。
## 13.1 shared
必须修改:
1. `packages/shared/src/contracts/customWorldAgent.ts`
## 13.2 frontend
必须新增:
1. `src/components/custom-world-agent/CustomWorldAgentIntentSummaryPanel.tsx`
2. `src/components/custom-world-agent/CustomWorldAgentClarificationPanel.tsx`
必须修改:
1. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
2. `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
3. `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
4. `src/services/aiService.ts`
5. `src/services/customWorldCreatorIntent.ts`
## 13.3 backend
必须新增:
1. `server-node/src/services/customWorldAgentIntentExtractionService.ts`
2. `server-node/src/services/customWorldAgentClarificationService.ts`
必须修改:
1. `server-node/src/services/customWorldAgentOrchestrator.ts`
2. `server-node/src/services/customWorldWorkSummaryService.ts`
3. `server-node/src/services/customWorldAgentSessionStore.ts`
---
## 14. 测试要求
## 14.1 服务端测试
至少要补:
1. 用户消息能提取到 `creatorIntent` patch
2. patch 合并不会覆盖无关旧字段
3. readiness 能正确判断缺失项
4. clarifications 最多只返回 3 个
5. readiness 达标后 stage 会切到 `foundation_review`
## 14.2 前端测试
至少要补:
1. intent summary panel 能展示已收集锚点
2. clarification panel 能展示待补充问题
3. readiness 达标后显示完成态
4. 创作页面草稿卡能随着摘要变化更新
## 14.3 手工回归
至少走这 4 条:
1. 用户输入一段简单世界想法 -> 被正确提取为 worldHook
2. 用户补充“玩家是谁” -> summary 更新
3. 用户补充核心冲突 -> clarification 继续减少
4. 锚点齐备 -> session 进入 foundation_review
---
## 15. 第二阶段验收标准
做到以下几点,才算第二阶段真正完成:
1. Agent 会话已经可以持续收集并更新 `creatorIntent`
2. 最小锚点不足时,系统会追问真正缺失的高杠杆问题。
3. 最小锚点齐备时session 会进入 `foundation_review`
4. 创作页面中的草稿摘要会明显变得更像一个作品,而不是空壳 session。
5. 第二阶段仍然不生成世界底稿,不越权进入第三阶段。
---
## 16. 一句话结论
第二阶段最重要的不是“让 Agent 写得更长”,而是:
**先让它学会把用户说过的话,稳定地变成创作锚点。**

View File

@@ -0,0 +1,987 @@
# AI 原生 Agent-First 自定义世界创作工具第四阶段技术落地方案
更新时间:`2026-04-14`
## 0.1 当前状态说明2026-04-21
这份文档保留为第四阶段历史落地方案。
补充边界:
1. 文中聚焦的草稿详情编辑链与实体生成弹窗链,在当前版本收口判断中已经退出主链
2. 对应的 `CustomWorldAgentDraftDetailPanel``CustomWorldDraftEditPanel``CustomWorldGenerateEntityModal``CustomWorldAgentQuickActions` 等文件已物理删除
3. 当前版本不再把这套旧副面板链作为默认待接线方向
## 0. 文档目的
这份文档用于把以下几份文档进一步收束成第四阶段实现方案:
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md)
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE1_IMPLEMENTATION_PLAN_2026-04-13.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE1_IMPLEMENTATION_PLAN_2026-04-13.md)
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE2_IMPLEMENTATION_PLAN_2026-04-13.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE2_IMPLEMENTATION_PLAN_2026-04-13.md)
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE3_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE3_IMPLEMENTATION_PLAN_2026-04-14.md)
如果说第三阶段的目标是:
**把已经收集好的创作锚点编译成第一版世界底稿**
那么第四阶段的目标就是:
**让创作者直接修改这版草稿设定,并且继续用 AI 为这版草稿扩出新的角色和场景。**
一句话定义:
**第四阶段把“世界已经长出来”升级成“世界开始可编辑、可继续长新内容”。**
---
## 1. 阶段衔接关系
## 1.1 第三阶段已经完成什么
第四阶段默认建立在第三阶段已经完成的能力之上:
1. session 已进入 `object_refining`
2. `draftProfile` 已经非空
3. `draftCards` 已经非空
4. 工作区可以展示世界、势力、角色、地点、线程和第一幕卡片
5. 用户可以查看卡片详情
6. 创作页面草稿卡已经能显示更像作品的标题、摘要与对象数量
## 1.2 第四阶段不再重做什么
以下内容第四阶段不重做:
1. 不重做最小锚点收集
2. 不重做 foundation draft 生成主链
3. 不重做基础 draftCards 编译
4. 不重做创作页面和工作区壳层
第四阶段只继续补:
1. 草稿设定编辑
2. 编辑后的草稿对象写回
3. 新增角色的 AI 生成
4. 新增场景的 AI 生成
5. 新卡片插入与摘要重编译
6. assistant 变更总结与 checkpoint
---
## 2. 第四阶段在八阶段中的位置
八阶段拆分如下:
1. 阶段 1创作页面入口、Agent 会话主链与工作区骨架
2. 阶段 2最小锚点收集与澄清流程
3. 阶段 3世界底稿生成与草稿卡编译
4. 阶段 4草稿设定编辑与 AI 新增角色/场景生成
5. 阶段 5角色主图与动作资产工坊接入
6. 阶段 6场景背景图工坊接入
7. 阶段 7长尾内容扩展与自动补齐
8. 阶段 8发布、世界库接入与继续创作恢复
本文件只覆盖:
**阶段 4草稿设定编辑与 AI 新增角色/场景生成**
---
## 3. 第四阶段目标
第四阶段只做 7 件必须一起成立的事:
1. 用户可以直接修改 draft card 中的可编辑设定字段
2. 编辑后的内容会稳定写回 `draftProfile`
3. 写回后 `draftCards` 摘要会同步更新
4. 用户可以让 AI 新增角色
5. 用户可以让 AI 新增场景
6. 新生成的角色和场景会插入 `draftProfile` 并出现为新的 `draftCards`
7. 每次编辑或新增后,系统都要写入 assistant 变更摘要和 checkpoint
一句话目标:
**让第四阶段结束时,创作者第一次能像在真正做作品一样修改草稿、继续长出新对象。**
---
## 4. 第四阶段完成定义
第四阶段完成后,必须同时满足以下结果:
1. 用户可以在 world / faction / character / landmark / thread / chapter 卡详情中进入编辑模式。
2. 用户保存编辑后,`draftProfile` 会真实变化,而不是只改前端显示。
3. 保存后,对应 `draftCards` 的标题、副标题、摘要会更新。
4. 用户可以通过 AI 生成 `1~3` 个新角色卡。
5. 用户可以通过 AI 生成 `1~3` 个新场景卡。
6. 新角色卡和新场景卡插入后draft drawer 能立即看到新增对象。
7. 创作页面里的草稿作品卡数量统计会同步增加。
8. 第四阶段仍然不要求做视觉资产工坊、长尾扩展和发布。
---
## 5. 范围控制
## 5.1 第四阶段纳入范围
纳入范围的模块:
- `packages/shared/src/contracts/customWorldAgent.ts`
- `src/components/custom-world-home/CustomWorldCreationHub.tsx`
- `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
- `src/components/custom-world-agent/CustomWorldAgentDraftDrawer.tsx`
- `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
- `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
- `src/services/aiService.ts`
- `server-node/src/services/customWorldAgentSessionStore.ts`
- `server-node/src/services/customWorldAgentOrchestrator.ts`
- `server-node/src/services/customWorldAgentDraftCompiler.ts`
- `server-node/src/services/customWorldWorkSummaryService.ts`
新增前端模块:
- `src/components/custom-world-agent/CustomWorldDraftEditPanel.tsx`
- `src/components/custom-world-agent/CustomWorldGenerateEntityModal.tsx`
新增服务端模块:
- `server-node/src/services/customWorldAgentDraftEditService.ts`
- `server-node/src/services/customWorldAgentEntityGenerationService.ts`
- `server-node/src/services/customWorldAgentChangeSummaryService.ts`
## 5.2 第四阶段明确不做
以下内容不放进第四阶段:
1. 不做锁定
2. 不做局部重生成
3. 不做角色主图与动作资产工坊接入
4. 不做场景图工坊接入
5. 不做长尾内容自动补齐
6. 不做发布
原因:
**第四阶段只解决“这版底稿怎么继续被编辑和扩展”的问题。**
---
## 6. 第四阶段最小闭环
建议把第四阶段的最小闭环定义为:
```text
第三阶段已有 foundation draft
-> 用户打开某张角色卡
-> 修改角色压力与关系描述
-> 保存
-> draftProfile 更新
-> 对应 draftCard 摘要更新
-> 用户点击“新增角色”
-> AI 生成 2 个新角色
-> draftProfile.storyNpcs 增加
-> 新角色卡出现在 drawer
-> 创作页面草稿卡数量同步增加
```
这个闭环里,先只强接两条高价值链路:
1. `draftCard -> draftProfile 编辑`
2. `AI 新增对象 -> draftProfile 扩展`
---
## 7. 第四阶段产品行为定义
## 7.1 可编辑的卡片类型
第四阶段允许直接编辑这些卡片:
1. `world`
2. `faction`
3. `character`
4. `landmark`
5. `thread`
6. `chapter`
7. `camp`
## 7.2 编辑模式规则
第四阶段采用:
**卡片详情内编辑**
不采用:
1. 大型全局表单
2. 多卡同时编辑
3. 独立复杂后台编辑器
### 编辑流程
```text
打开卡片详情
-> 点击“编辑设定”
-> 进入编辑模式
-> 修改字段
-> 点击保存
-> 写回 draftProfile
-> 重编译 draftCards
-> 写入 assistant action_result
```
### 取消规则
用户点击取消后:
1. 丢弃本次未保存草稿
2. 回到只读详情模式
## 7.3 各卡片可编辑字段
为了避免实现漂移,第四阶段明确限定每种卡的可编辑字段。
### `world`
允许编辑:
1. `title`
2. `subtitle`
3. `summary`
4. `playerGoal`
5. `tone`
6. `coreConflicts`
### `faction`
允许编辑:
1. `title`
2. `subtitle`
3. `summary`
4. `publicGoal`
5. `tension`
### `character`
允许编辑:
1. `name`
2. `role`
3. `publicMask`
4. `hiddenHook`
5. `relationToPlayer`
6. `summary`
### `landmark`
允许编辑:
1. `name`
2. `purpose`
3. `mood`
4. `secret`
5. `summary`
### `thread`
允许编辑:
1. `title`
2. `summary`
3. `conflictType`
4. `stakes`
### `chapter`
允许编辑:
1. `title`
2. `summary`
3. `openingEvent`
4. `playerGoal`
5. `understandingShift`
### `camp`
允许编辑:
1. `name`
2. `description`
## 7.4 第四阶段不允许编辑的内容
为控制范围,以下内容第四阶段不开放:
1. 技能
2. 初始物品
3. 场景连接网络
4. sceneNpcIds
5. 背景章节分段
6. 视觉资产引用
这些内容留给后续阶段。
## 7.5 AI 新增角色
第四阶段要支持:
```text
新增角色
```
### 目标对象
默认新增:
1. `storyNpcs`
说明:
第四阶段不默认新增 `playableNpcs`,避免过早引入玩家入口角色平衡问题。
### 输入
用户可以提供:
1. 一句话要求
2. 角色数量
3. 可选参考卡片
### 数量限制
每次允许:
1. `1~3` 个角色
### 必须生成的字段
每个新角色至少要带:
1. `id`
2. `name`
3. `role`
4. `description`
5. `visualDescription`
6. `actionDescription`
7. `sceneVisualDescription`
8. `publicMask`
9. `hiddenHook`
10. `relationToPlayer`
11. `summary`
### 角色资产工坊默认文本来源
`visualDescription` 是角色主形象生成入口的默认形象描述主源,必须在可扮演角色 / 场景角色的草稿生成步骤中跟随角色一并生成,不允许在资产工坊打开时再用本地规则把 `description``role``tags` 拼成默认文案。
生成要求:
1. `description` 只写角色定位,控制在 8 到 18 个汉字内,用于角色卡摘要。
2. `visualDescription` 专门写角色外观,包含轮廓、服饰 / 身体特征、携带物或材质气质,不写性格规则和玩法说明。
3. `actionDescription` 专门写动作气质,用于动作生成默认文本。
4. `sceneVisualDescription` 专门写角色常出现的场景氛围,用于场景图或角色场景联动默认文本。
5. 资产工坊默认值优先读取 `visualDescription`,只有历史草稿缺失该字段时才允许回退到 `description`
### 插入规则
生成后:
1. 写入 `draftProfile.storyNpcs`
2. 重新编译 `character` 类 draftCards
3. 在 drawer 中显示
## 7.6 AI 新增场景
第四阶段要支持:
```text
新增场景
```
### 目标对象
默认新增:
1. `landmarks`
### 输入
用户可以提供:
1. 一句话要求
2. 场景数量
3. 可选参考线程 / 角色 / 势力
### 数量限制
每次允许:
1. `1~3` 个场景
### 必须生成的字段
每个新场景至少要带:
1. `id`
2. `name`
3. `description``summary`
5. `purpose`
6. `mood`
### 插入规则
生成后:
1. 写入 `draftProfile.landmarks`
2. 重新编译 `landmark` 类 draftCards
3. 在 drawer 中显示
## 7.7 新增对象的归类规则
为了避免新增对象漂移,第四阶段新增对象必须绑定至少一个已有语义锚点:
### 新角色至少要绑定一个:
1. 线程
2. 势力
3. 玩家关系
### 新场景至少要绑定一个:
1. 线程
2. 角色
3. 势力
如果 AI 生成结果无法绑定任何现有锚点,则:
1. 允许生成
2. 但卡片标记为 `warning`
---
## 8. 数据结构落地方案
## 8.1 扩展 `CustomWorldAgentActionRequest`
第四阶段必须正式启用以下 action
```ts
| {
action: 'update_draft_card';
cardId: string;
sections: Array<{
sectionId: string;
value: string;
}>;
}
| {
action: 'generate_characters';
count: number;
promptText?: string | null;
anchorCardIds?: string[];
}
| {
action: 'generate_landmarks';
count: number;
promptText?: string | null;
anchorCardIds?: string[];
}
```
### 第一版限制
1. `count` 只能是 `1~3`
2. `anchorCardIds` 可选
3. `sections` 不能为空
## 8.2 扩展 `CustomWorldAgentOperationType`
第四阶段新增:
```ts
| 'update_draft_card'
| 'generate_characters'
| 'generate_landmarks'
```
## 8.3 扩展 `CustomWorldDraftCardDetail`
第四阶段开始detail 里需要返回:
```ts
editable: boolean;
editableSectionIds: string[];
```
### 规则
1. 第四阶段所有可编辑卡返回 `editable = true`
2. 非可编辑卡返回 `editable = false`
## 8.4 `draftProfile` 写回规则
第四阶段的所有保存动作都必须最终落到 `draftProfile` 对应对象上。
不得:
1. 只改 `draftCards`
2. 只改前端详情临时数据
顺序必须是:
```text
update draftProfile
-> recompile draftCards
-> return snapshot
```
---
## 9. 服务端实现方案
## 9.1 新增 `customWorldAgentDraftEditService.ts`
### 文件
`server-node/src/services/customWorldAgentDraftEditService.ts`
### 职责
1. 校验 card 是否存在
2. 校验 card 是否可编辑
3. 校验 sectionId 是否允许编辑
4. 把 section patch 写回对应对象
5. 返回新的 `draftProfile`
### 导出函数建议
```ts
updateDraftCardSections(params)
```
### 输入
```ts
type UpdateDraftCardSectionsParams = {
draftProfile: Record<string, unknown>;
cardId: string;
sections: Array<{
sectionId: string;
value: string;
}>;
};
```
## 9.2 新增 `customWorldAgentEntityGenerationService.ts`
### 文件
`server-node/src/services/customWorldAgentEntityGenerationService.ts`
### 职责
1. 生成新增角色
2. 生成新增场景
3. 把新增对象插入 `draftProfile`
### 导出函数建议
```ts
generateAdditionalCharacters(params)
generateAdditionalLandmarks(params)
```
### 输入
必须包含:
1. `creatorIntent`
2. `anchorPack`
3. `draftProfile`
4. `count`
5. `promptText`
6. `anchorCardIds`
### 生成原则
1. 只围绕当前已生成的 foundation draft 扩展
2. 不能重做已有对象
3. 不能直接扩成完整长尾
## 9.3 新增 `customWorldAgentChangeSummaryService.ts`
### 职责
每次编辑或新增对象后,生成一段简短变更摘要。
要求至少包含:
1. 改了什么卡 / 新增了什么对象
2. 影响到哪些对象数量
3. 下一步建议
## 9.4 修改 `customWorldAgentOrchestrator.ts`
第四阶段必须启用以下 action
1. `update_draft_card`
2. `generate_characters`
3. `generate_landmarks`
### `update_draft_card` 流程
```text
收到 update_draft_card
-> 校验 cardId
-> 调用 DraftEditService
-> 更新 draftProfile
-> 调用 DraftCompiler
-> 更新 draftCards
-> 写入 assistant action_result
-> 写入 checkpoint
-> operation completed
```
### `generate_characters` 流程
```text
收到 generate_characters
-> 校验 count
-> 调用 EntityGenerationService
-> 更新 draftProfile.storyNpcs
-> 调用 DraftCompiler
-> 更新 draftCards
-> 写入 assistant action_result
-> 写入 checkpoint
-> operation completed
```
### `generate_landmarks` 流程
```text
收到 generate_landmarks
-> 校验 count
-> 调用 EntityGenerationService
-> 更新 draftProfile.landmarks
-> 调用 DraftCompiler
-> 更新 draftCards
-> 写入 assistant action_result
-> 写入 checkpoint
-> operation completed
```
## 9.5 修改 `customWorldAgentDraftCompiler.ts`
第四阶段它必须继续承担:
1. 根据新的 `draftProfile` 重编译摘要
2. 对新增角色生成新的 character 卡
3. 对新增场景生成新的 landmark 卡
### 第四阶段新增要求
对 detail 详情返回:
1. `editable`
2. `editableSectionIds`
---
## 10. 前端实现方案
### 当前状态补充2026-04-21
这一节描述的是第四阶段编写当时的草稿详情编辑链与实体生成弹窗链。
但当前版本已经明确:
1. `CustomWorldAgentDraftDetailPanel.tsx`
2. `CustomWorldDraftEditPanel.tsx`
3. `CustomWorldGenerateEntityModal.tsx`
4. `CustomWorldAgentQuickActions.tsx`
已在当前版本收口判断中退出主链并物理删除。
因此本节以下内容只保留历史设计参考价值,不再直接代表当前版本执行方向。
## 10.1 修改 `CustomWorldAgentDraftDetailPanel.tsx`
第四阶段它要从只读详情升级成:
1. 只读模式
2. 编辑模式
### 新增动作
1. `编辑设定`
2. `保存`
3. `取消`
4. `新增角色`
5. `新增场景`
### 模式规则
#### 只读模式
显示:
1. sections
2. 编辑设定按钮
#### 编辑模式
`editableSectionIds` 对应的 section 渲染输入框:
1. 短字段用 `input`
2. 长字段用 `textarea`
## 10.2 新增 `CustomWorldDraftEditPanel.tsx`
### 职责
承接 detail panel 的编辑表单。
### props
```ts
{
detail: CustomWorldDraftCardDetail;
onSave: (sections) => void;
onCancel: () => void;
}
```
## 10.3 新增 `CustomWorldGenerateEntityModal.tsx`
### 职责
统一承接:
1. AI 新增角色
2. AI 新增场景
### 模式
```ts
mode: 'character' | 'landmark'
```
### 字段
1. `count`
2. `promptText`
3. 当前参考卡提示
### 第一版限制
1. 不做复杂多选引用 UI
2. `anchorCardIds` 可先默认使用当前焦点卡
## 10.4 修改 `CustomWorldAgentQuickActions.tsx`
第四阶段开始可以根据 session.stage 显示:
1. `新增角色`
2. `新增场景`
说明:
这些只是快捷入口,本质仍然打开 modal 并走 action route。
## 10.5 修改 `CustomWorldAgentWorkspace.tsx`
第四阶段它要新增:
1. `editMode`
2. `showGenerateEntityModal`
3. `generateEntityMode`
同时要支持:
1. 打开详情并进入编辑
2. 保存编辑
3. 打开新增角色 modal
4. 打开新增场景 modal
## 10.6 修改 `CustomWorldCreationHub.tsx`
第四阶段它必须支持作品摘要继续升级:
1. 新增角色后,数量变化
2. 新增场景后,数量变化
3. 编辑世界卡后,标题或摘要变化
---
## 11. 交互时序
## 11.1 编辑草稿设定
```text
用户打开角色卡详情
-> 点击编辑设定
-> 修改字段
-> 点击保存
-> 前端 POST /actions { action: update_draft_card }
-> 服务端更新 draftProfile
-> 服务端重编译 draftCards
-> 服务端写入变更摘要
-> 前端刷新 snapshot
```
## 11.2 AI 新增角色
```text
用户点击新增角色
-> 打开 generate modal
-> 输入数量和补充描述
-> 前端 POST /actions { action: generate_characters }
-> 服务端新增角色
-> 服务端更新 draftProfile.storyNpcs
-> 服务端重编译 draftCards
-> 前端刷新 snapshot
```
## 11.3 AI 新增场景
```text
用户点击新增场景
-> 打开 generate modal
-> 输入数量和补充描述
-> 前端 POST /actions { action: generate_landmarks }
-> 服务端新增场景
-> 服务端更新 draftProfile.landmarks
-> 服务端重编译 draftCards
-> 前端刷新 snapshot
```
---
## 12. 与第三阶段的兼容要求
## 12.1 旧 draftCards 兼容
第三阶段生成的 card detail 如果没有:
```ts
editable
editableSectionIds
```
服务端读取时应自动补:
```ts
editable: true/false
editableSectionIds: []
```
## 12.2 旧 draftProfile 兼容
如果旧 draftProfile 缺少某些新增字段:
1. 编辑时允许 fallback
2. 不允许因为字段缺失直接报错
## 12.3 新增角色/场景 ID 规则
新增对象时,必须使用稳定 id 生成规则,不能临时用数组下标。
---
## 13. 落地文件清单
### 当前状态补充2026-04-21
本节列的是第四阶段历史文件清单。
其中涉及草稿详情编辑链与实体生成弹窗链的部分,不再等同于当前版本待落地清单。
## 13.1 shared
必须修改:
1. `packages/shared/src/contracts/customWorldAgent.ts`
## 13.2 frontend
必须新增:
1. `src/components/custom-world-agent/CustomWorldDraftEditPanel.tsx`
2. `src/components/custom-world-agent/CustomWorldGenerateEntityModal.tsx`
必须修改:
1. `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
2. `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
3. `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
4. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
5. `src/services/aiService.ts`
## 13.3 backend
必须新增:
1. `server-node/src/services/customWorldAgentDraftEditService.ts`
2. `server-node/src/services/customWorldAgentEntityGenerationService.ts`
3. `server-node/src/services/customWorldAgentChangeSummaryService.ts`
必须修改:
1. `server-node/src/services/customWorldAgentOrchestrator.ts`
2. `server-node/src/services/customWorldAgentDraftCompiler.ts`
3. `server-node/src/services/customWorldAgentSessionStore.ts`
4. `server-node/src/routes/customWorldAgent.ts`
---
## 14. 测试要求
## 14.1 服务端测试
至少要补:
1. `update_draft_card` 能正确写回 draftProfile
2. 写回后 draftCards 摘要会更新
3. `generate_characters` 会新增 `storyNpcs` 并生成新的 character 卡
4. `generate_landmarks` 会新增 `landmarks` 并生成新的 landmark 卡
5. 每次编辑或新增后会写入 checkpoint
## 14.2 前端测试
至少要补:
1. detail panel 可以进入编辑模式
2. 保存编辑会调用 action route
3. 可以打开新增角色 modal
4. 可以打开新增场景 modal
5. 操作完成后 drawer 与创作页面摘要会更新
## 14.3 手工回归
至少走这 5 条:
1. 编辑世界总卡标题和摘要
2. 编辑一张角色卡的压力与关系
3. 新增 2 个角色
4. 新增 2 个场景
5. 返回创作页面确认数量与摘要变化
---
## 15. 第四阶段验收标准
做到以下几点,才算第四阶段真正完成:
1. 用户可以直接修改草稿中的设定。
2. 修改后的内容会真正写回 draftProfile而不是只改前端展示。
3. 用户可以继续用 AI 新增角色和场景。
4. 新增角色和场景会成为新的草稿卡。
5. 创作页面草稿作品卡会同步反映这些变化。
6. 第四阶段仍然不越界去做资产工坊、长尾扩展和发布。
---
## 16. 一句话结论
第四阶段最重要的不是“继续控制已有结果不动”,而是:
**让这版世界草稿开始具备真正的可编辑性和可扩展性。**

View File

@@ -0,0 +1,818 @@
# AI 原生 Agent-First 自定义世界创作工具第五阶段技术落地方案
更新时间:`2026-04-14`
## 0.1 当前状态说明2026-04-21
这份文档保留为第五阶段历史落地方案。
补充边界:
1. 文中继续沿用的 `CustomWorldAgentDraftDetailPanel``CustomWorldAgentQuickActions` 等旧副面板,在当前版本已经退出主链并物理删除
2. 因此这份文档里的实现安排,不应再被直接视为当前版本执行清单
3. 当前版本是否重引入相关能力,必须基于新的主链设计重新判断
## 0. 文档目的
这份文档用于把以下几份文档进一步收束成第五阶段实现方案:
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md)
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE3_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE3_IMPLEMENTATION_PLAN_2026-04-14.md)
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE4_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE4_IMPLEMENTATION_PLAN_2026-04-14.md)
- [AI_CHARACTER_VISUAL_ANIMATION_MVP_PRD_2026-04-04.md](./AI_CHARACTER_VISUAL_ANIMATION_MVP_PRD_2026-04-04.md)
如果说第四阶段的目标是:
**让草稿世界变得可编辑、可继续长出新角色和新场景**
那么第五阶段的目标就是:
**把草稿里的角色第一次接上正式的主图与核心动作资产工坊。**
一句话定义:
**第五阶段把“角色只是文字卡”升级成“角色开始有可预览、可应用的主形象和动作资产”。**
---
## 1. 阶段衔接关系
## 1.1 第四阶段已经完成什么
第五阶段默认建立在第四阶段已经完成的能力之上:
1. `draftProfile` 已经可编辑
2. 用户可以新增角色
3. `draftCards` 中已经有稳定的 `character`
4. `CustomWorldAgentDraftDetailPanel` 已经存在
5. 用户可以从工作区聚焦到某个具体角色
## 1.2 第五阶段不再重做什么
以下内容第五阶段不重做:
1. 不重做 foundation draft 生成
2. 不重做 draftCards 主链
3. 不重做草稿设定编辑
4. 不重做 AI 新增角色 / 场景
第五阶段只继续补:
1. 角色主图候选生成
2. 角色主图发布
3. 角色核心动作生成
4. 角色核心动作发布
5. 资产状态写回 session 与 draftProfile
6. 角色卡资产状态展示
---
## 2. 第五阶段在八阶段中的位置
八阶段拆分如下:
1. 阶段 1创作页面入口、Agent 会话主链与工作区骨架
2. 阶段 2最小锚点收集与澄清流程
3. 阶段 3世界底稿生成与草稿卡编译
4. 阶段 4草稿设定编辑与 AI 新增角色/场景生成
5. 阶段 5角色主图与动作资产工坊接入
6. 阶段 6场景背景图工坊接入
7. 阶段 7长尾内容扩展与自动补齐
8. 阶段 8发布、世界库接入与继续创作恢复
本文件只覆盖:
**阶段 5角色主图与动作资产工坊接入**
---
## 3. 第五阶段目标
第五阶段只做 7 件必须一起成立的事:
1. 用户可以从角色卡打开资产工坊
2. 用户可以为角色生成主图候选
3. 用户可以选择主图候选并发布为角色主图
4. 用户可以基于已发布主图生成核心动作
5. 用户可以发布核心动作资产
6. 发布成功后,角色对象会写回 `imageSrc / generatedVisualAssetId / generatedAnimationSetId / animationMap`
7. 工作区和创作页面能感知角色资产状态变化
一句话目标:
**让第五阶段结束时,至少部分关键角色已经不只是“设定存在”,而是“能动起来”。**
---
## 4. 第五阶段完成定义
第五阶段完成后,必须同时满足以下结果:
1. 用户从某张 `character` 卡进入详情后,可以点击“角色资产”打开 `CustomWorldRoleAssetStudioModal`
2. 用户可以生成主图候选,并能预览多个候选。
3. 用户选择候选并发布后,对应角色会得到:
- `imageSrc`
- `generatedVisualAssetId`
4. 用户可以基于主图继续生成核心动作草稿。
5. 用户发布动作后,对应角色会得到:
- `generatedAnimationSetId`
- `animationMap`
6. assetCoverage 中对应角色状态会更新。
7. 工作区中的角色卡会显示主图 / 动作状态变化。
8. 第五阶段仍然不要求场景背景图接入,也不要求所有角色都必须完成资产生成。
---
## 5. 范围控制
## 5.1 第五阶段纳入范围
纳入范围的模块:
- `packages/shared/src/contracts/customWorldAgent.ts`
- `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
- `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
- `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
- `src/components/CustomWorldRoleAssetStudioModal.tsx`
- `src/components/asset-studio/characterAssetWorkflowPersistence.ts`
- `src/services/aiService.ts`
- `server-node/src/services/customWorldAgentSessionStore.ts`
- `server-node/src/services/customWorldAgentOrchestrator.ts`
- `server-node/src/services/customWorldAgentDraftCompiler.ts`
- `server-node/src/services/customWorldWorkSummaryService.ts`
- `server-node/src/modules/assets/characterAssetRoutes.ts`
新增服务端模块:
- `server-node/src/services/customWorldAgentAssetBridgeService.ts`
- `server-node/src/services/customWorldAgentRoleAssetStateService.ts`
## 5.2 第五阶段明确不做
以下内容不放进第五阶段:
1. 不做场景背景图工坊接入
2. 不做长尾角色批量自动出图
3. 不做所有角色的自动动作补齐
4. 不做发布时强制所有角色资产齐全
5. 不做视频导入高级编辑链
6. 不做口型 / 对话特写
原因:
**第五阶段只解决“选中的角色如何进入资产工坊并成功把结果写回草稿世界”。**
---
## 6. 第五阶段最小闭环
建议把第五阶段的最小闭环定义为:
```text
第四阶段已有角色卡
-> 用户打开某张角色卡详情
-> 点击“角色资产”
-> 打开角色资产工坊
-> 生成主图候选
-> 选择并发布主图
-> 生成核心动作
-> 发布动作
-> sync_role_assets
-> role card / assetCoverage / 创作页面摘要同步更新
```
这个闭环里,先只强接两条高价值链路:
1. `character card -> asset studio`
2. `asset studio publish -> session sync`
---
## 7. 第五阶段产品行为定义
## 7.1 哪些角色可以进入资产工坊
第五阶段允许以下角色进入资产工坊:
1. `playableNpcs`
2. `storyNpcs`
但默认推荐优先处理:
1. 主线关键角色
2. 可扮演角色
3. 创作者重点想看的角色
## 7.2 入口位置
### 当前状态补充2026-04-21
这一节以下描述依赖当时仍被视为现行方案的旧详情面板链与旧快捷动作链。
但当前版本已经明确:
1. `CustomWorldAgentDraftDetailPanel.tsx`
2. `CustomWorldAgentQuickActions.tsx`
已退出主链并物理删除。
因此这里关于入口位置的说明,现在只能作为历史资产工坊设计参考,不再代表当前版本 UI 入口。
### 角色卡详情入口
`CustomWorldAgentDraftDetailPanel` 中,当当前卡类型为:
```ts
kind === 'character';
```
显示按钮:
- `角色资产`
### 快捷动作入口
当当前 focus card 为角色卡时,`CustomWorldAgentQuickActions` 可显示:
- `生成角色主图与动作`
说明:
快捷动作与详情按钮最终都打开同一个 modal。
## 7.3 第五阶段支持的资产流程
### 阶段 A主图候选
允许:
1. `text-to-image`
2. `image-to-image`
不做:
1. 批量上传模式
2. 一次性批量生成多个角色主图
### 阶段 B主图发布
用户在候选中选择一个结果后,发布主图。
### 阶段 C核心动作草稿
基于主图生成当前工坊支持的核心动作:
1. `run`
2. `attack`
可选增强动作:
1. `idle`
2. `die`
补充约束:
1. `run / attack` 为固定必生成动作
2. 角色已配置技能时,对应技能动作也属于必生成动作
3. `idle / die` 只作为可选增强,缺失时分别走主图静止 / 主图向后倒地过渡动画兜底,死亡动画带轻微过冲回落,最终停在翻转倒地姿态
### 阶段 D动作发布
将动作草稿发布为正式动画资产,并写回角色。
## 7.4 第五阶段不强制的事情
第五阶段明确不强制:
1. 每个角色都必须立刻生成主图
2. 每个角色都必须立刻生成动作
3. 没有资产的角色不能继续文本创作
说明:
这一步是“角色开始接资产”,不是“所有角色必须立刻完工”。
## 7.5 积分消耗提示规则
当前项目已经明确:
**不做预算限制,但高成本生成前必须明确提示积分消耗。**
因此第五阶段必须遵守:
### 主图候选生成前
必须提示:
1. 本次会消耗多少积分
2. 这是候选抽卡,不是最终发布
### 动作草稿生成前
必须提示:
1. 本次会消耗多少积分
2. 这是动作草稿,不是最终发布
### 发布前
发布动作或主图本身不应再次重复收积分,除非现有资产接口明确要求。
---
## 8. 角色资产状态定义
## 8.1 `assetCoverage.roleAssets`
第五阶段必须开始真正使用它。
建议状态:
```ts
type CustomWorldRoleAssetStatus =
| 'missing'
| 'visual_ready'
| 'animations_ready'
| 'complete';
```
### 含义
#### `missing`
角色还没有正式主图
#### `visual_ready`
角色已经有:
1. `imageSrc`
2. `generatedVisualAssetId`
但没有完整动作
#### `animations_ready`
角色已经有:
1. `generatedAnimationSetId`
2. 至少一组核心动作映射
但若需要更严格区分,也允许继续映射到 `complete`
#### `complete`
角色有:
1. 主图
2. 核心动作
### 第五阶段建议判定
为了避免漂移,直接使用:
1. 只有主图:`visual_ready`
2. 主图 + 五组核心动作都齐:`complete`
第五阶段不强制使用 `animations_ready` 作为单独过渡,可选保留。
## 8.2 角色对象写回字段
发布主图成功后,必须写回:
```ts
imageSrc;
generatedVisualAssetId;
```
发布动作成功后,必须写回:
```ts
generatedAnimationSetId;
animationMap;
```
### 明确要求
第五阶段不允许只更新 `assetCoverage`,不更新角色对象本身。
---
## 9. 数据结构落地方案
## 9.1 扩展 `CustomWorldAgentActionRequest`
第五阶段正式启用:
```ts
| { action: 'generate_role_assets'; roleIds: string[] }
| {
action: 'sync_role_assets';
roleId: string;
portraitPath: string;
generatedVisualAssetId: string;
generatedAnimationSetId?: string | null;
animationMap?: JsonObject | null;
}
```
### 第五阶段限制
1. `generate_role_assets` 第一版只允许单角色:
- `roleIds.length === 1`
2. 批量角色资产生成留到后续阶段
## 9.2 扩展 `CustomWorldRoleAssetSummary`
第五阶段开始必须真正填:
1. `portraitPath`
2. `generatedVisualAssetId`
3. `generatedAnimationSetId`
4. `status`
5. `missingAnimations`
6. `nextPointCost`
## 9.3 新增角色资产同步结果结构
建议新增:
```ts
type SyncRoleAssetsResult = {
roleId: string;
updatedRole: Record<string, unknown>;
updatedAssetSummary: CustomWorldRoleAssetSummary;
};
```
---
## 10. 服务端实现方案
## 10.1 新增 `customWorldAgentAssetBridgeService.ts`
### 文件
`server-node/src/services/customWorldAgentAssetBridgeService.ts`
### 职责
负责连接:
1. Agent session
2. 现有角色资产路由与持久化能力
### 第一版职责
1. 将角色卡编译成资产工坊启动参数
2. 接收工坊发布结果
3. 转换为 session 可写回的标准结果
### 输入
```ts
buildRoleAssetStudioContext(snapshot, roleId);
applyRoleAssetPublishResult(snapshot, payload);
```
### 说明
它不自己生成图片或动作,仍然复用现有资产链。
## 10.2 新增 `customWorldAgentRoleAssetStateService.ts`
### 文件
`server-node/src/services/customWorldAgentRoleAssetStateService.ts`
### 职责
根据角色对象真实字段,更新:
1. `assetCoverage.roleAssets`
2. `draftCards` 中角色卡的副摘要
3. 创作页面作品卡统计
### 导出函数建议
```ts
rebuildRoleAssetCoverage(draftProfile);
mergeRoleAssetIntoDraftProfile(draftProfile, payload);
```
## 10.3 修改 `customWorldAgentOrchestrator.ts`
第五阶段必须启用:
1. `generate_role_assets`
2. `sync_role_assets`
### `generate_role_assets` 流程
```text
收到 generate_role_assets
-> 校验 roleIds
-> 构建 role asset studio context
-> 返回 operation completed
-> 前端打开资产工坊
```
说明:
这里的 operation 不是生成图片,而是准备进入工坊。
### `sync_role_assets` 流程
```text
收到 sync_role_assets
-> 校验 roleId
-> 写回 draftProfile 中的角色字段
-> 重建 assetCoverage.roleAssets
-> 重新编译角色卡摘要
-> 写入 assistant action_result
-> 写入 checkpoint
-> operation completed
```
## 10.4 修改 `customWorldAgentDraftCompiler.ts`
第五阶段它必须让 `character` 卡摘要带出资产状态。
### 角色卡摘要新增要求
`subtitle``summary` 中追加:
1. `主图已就绪`
2. `动作已就绪`
3. `待生成主图`
但不要让卡片默认变成技术清单。
推荐形式:
- `外显身份 / 主图已就绪`
或:
- `当前压力……(动作待补)`
## 10.5 修改 `customWorldWorkSummaryService.ts`
第五阶段创作页面草稿卡应支持展示:
1. 已有多少角色具备主图
2. 已有多少角色具备动作
第一版如果不想上具体数字,也至少要能在草稿卡上体现:
- `角色资产进行中`
---
## 11. 前端实现方案
### 当前状态补充2026-04-21
本节以下内容依赖旧详情面板链与旧快捷动作面板。
这些文件当前已经退出主链并删除,所以这里不再是当前版本的直接执行清单。
## 11.1 修改 `CustomWorldAgentDraftDetailPanel.tsx`
当卡片类型为 `character` 时,新增:
1. `角色资产` 按钮
2. 资产状态 badge
### 状态显示建议
1. `待生成主图`
2. `主图已就绪`
3. `动作已就绪`
## 11.2 修改 `CustomWorldAgentQuickActions.tsx`
当当前 focus 为角色卡时,可显示:
1. `生成角色主图与动作`
点击后:
1. 调用 `generate_role_assets`
2. 成功后打开 `CustomWorldRoleAssetStudioModal`
## 11.3 修改 `CustomWorldAgentWorkspace.tsx`
新增状态:
```ts
activeRoleAssetTargetId?: string | null;
showRoleAssetStudio: boolean;
```
### 打开逻辑
1. 来自 detail panel
2. 来自 quick actions
### 关闭逻辑
关闭后不代表写回成功。
必须等:
1. 工坊发布成功
2. `sync_role_assets` 成功
之后才刷新角色资产状态。
## 11.4 修改 `CustomWorldRoleAssetStudioModal.tsx`
第五阶段不重做这个组件,但必须调整为:
1. 接收来自 Agent 工作区的角色对象
2. 发布成功后,不直接改本地 profile
3. 统一回调:
```ts
onPublishSuccess(payload);
```
### `onPublishSuccess` 最小字段
```ts
{
roleId: string;
portraitPath: string;
generatedVisualAssetId: string;
generatedAnimationSetId?: string | null;
animationMap?: Record<string, unknown> | null;
}
```
## 11.5 修改 `CustomWorldCreationHub.tsx`
第五阶段它必须支持草稿作品卡的“资产进度感”。
第一版至少做到:
1. 草稿卡可展示:
- 角色资产进行中
- 或若数量可得,则展示主图 / 动作完成数
不要求这一版做得很重。
---
## 12. 交互时序
## 12.1 打开角色资产工坊
```text
用户点击角色卡
-> 打开 detail panel
-> 点击“角色资产”
-> 前端 POST /actions { action: generate_role_assets }
-> 服务端校验角色
-> 服务端返回可进入工坊
-> 前端打开 CustomWorldRoleAssetStudioModal
```
## 12.2 发布主图
```text
用户在工坊中选择主图候选
-> 发布主图
-> 工坊获得 portraitPath + generatedVisualAssetId
-> 暂不关闭会话
-> 可继续生成动作
```
## 12.3 发布动作并同步
```text
用户发布动作
-> 工坊获得 generatedAnimationSetId + animationMap
-> 前端调用 sync_role_assets
-> 服务端写回 draftProfile.character
-> 服务端重建 assetCoverage.roleAssets
-> 服务端重编译角色卡摘要
-> 前端刷新 snapshot
-> 工坊关闭
```
---
## 13. 与第四阶段的兼容要求
## 13.1 兼容新增角色
第四阶段新增的角色对象只要已经在 `draftProfile.storyNpcs``playableNpcs` 中,均允许进入资产工坊。
不要求:
1. 该角色必须有完整长背景
2. 该角色必须已进入后续发布阶段
## 13.2 兼容无主图角色
如果某角色完全无:
1. `imageSrc`
2. `generatedVisualAssetId`
也允许打开工坊,从零开始生成。
## 13.3 兼容有主图无动作角色
如果角色已经有:
1. `imageSrc`
2. `generatedVisualAssetId`
但没有:
1. `generatedAnimationSetId`
则工坊默认直接进入动作阶段。
---
## 14. 落地文件清单
## 14.1 frontend
必须修改:
1. `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
2. `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
3. `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
4. `src/components/CustomWorldRoleAssetStudioModal.tsx`
5. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
6. `src/services/aiService.ts`
## 14.2 backend
必须新增:
1. `server-node/src/services/customWorldAgentAssetBridgeService.ts`
2. `server-node/src/services/customWorldAgentRoleAssetStateService.ts`
必须修改:
1. `server-node/src/services/customWorldAgentOrchestrator.ts`
2. `server-node/src/services/customWorldAgentDraftCompiler.ts`
3. `server-node/src/services/customWorldAgentSessionStore.ts`
4. `server-node/src/services/customWorldWorkSummaryService.ts`
---
## 15. 测试要求
## 15.1 服务端测试
至少要补:
1. `generate_role_assets` 仅允许单角色
2. `sync_role_assets` 能正确写回角色字段
3. 写回后 `assetCoverage.roleAssets` 状态更新
4. 写回后角色卡摘要更新
5. 写回后 checkpoint 存在
## 15.2 前端测试
至少要补:
1. character 卡详情可显示角色资产入口
2. quick actions 可打开角色资产工坊
3. 工坊发布成功后会触发 `sync_role_assets`
4. snapshot 刷新后角色卡显示新状态
## 15.3 手工回归
至少走这 4 条:
1. 为一个无主图角色生成主图
2. 为该角色继续生成并发布核心动作
3. 返回 workspace 确认角色卡状态变化
4. 返回创作页面确认草稿卡摘要变化
---
## 16. 第五阶段验收标准
做到以下几点,才算第五阶段真正完成:
1. 角色卡已经可以接入并打开角色资产工坊。
2. 主图发布成功后,角色对象会写回 `imageSrc / generatedVisualAssetId`
3. 动作发布成功后,角色对象会写回 `generatedAnimationSetId / animationMap`
4. 角色资产状态会同步反映到 session snapshot 和角色卡摘要。
5. 角色资产接入不会阻塞继续文本创作。
6. 第五阶段仍然不越界去做场景背景图、长尾扩展和发布逻辑。
---
## 17. 一句话结论
第五阶段最重要的不是“让所有角色都立刻变成完整资产”,而是:
**先把草稿世界里的角色,真正接到一条可预览、可发布、可写回的资产工坊链路上。**

View File

@@ -0,0 +1,721 @@
# AI 原生 Agent-First 自定义世界创作工具第六阶段技术落地方案
更新时间:`2026-04-14`
## 0.1 当前状态说明2026-04-21
这份文档保留为第六阶段历史落地方案。
补充边界:
1. 文中继续引用的 `CustomWorldAgentDraftDetailPanel``CustomWorldAgentQuickActions` 等旧副面板,在当前版本已经退出主链并物理删除
2. 这份文档可用于回看当时的资产工坊设想,但不代表当前版本仍按这里逐项补齐
3. 当前执行边界以最新优化规划和阶段四清理边界文档为准
## 0. 文档目的
这份文档用于把以下几份文档进一步收束成第六阶段实现方案:
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md)
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE4_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE4_IMPLEMENTATION_PLAN_2026-04-14.md)
- [AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE5_IMPLEMENTATION_PLAN_2026-04-14.md](./AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PHASE5_IMPLEMENTATION_PLAN_2026-04-14.md)
如果说第五阶段的目标是:
**把草稿世界里的角色第一次接上正式的主图与核心动作资产工坊**
那么第六阶段的目标就是:
**把草稿世界里的营地和关键场景第一次接上正式的背景图工坊。**
一句话定义:
**第六阶段把“场景只是文字卡”升级成“场景开始有可预览、可应用的背景图资产”。**
---
## 1. 阶段衔接关系
## 1.1 第五阶段已经完成什么
第六阶段默认建立在第五阶段已经完成的能力之上:
1. 角色卡已经可以接入资产工坊
2. 角色主图与动作可以写回 `draftProfile`
3. `assetCoverage.roleAssets` 已开始发挥作用
4. 工作区已具备“卡片详情 -> 资产工坊 -> session 同步”的基本模式
## 1.2 第六阶段不再重做什么
以下内容第六阶段不重做:
1. 不重做 foundation draft 生成
2. 不重做草稿设定编辑
3. 不重做 AI 新增角色 / 场景
4. 不重做角色主图与动作资产工坊接入
第六阶段只继续补:
1. 营地背景图资产工坊
2. 场景背景图资产工坊
3. 场景图状态写回 session 与 draftProfile
4. 场景卡资产状态展示
---
## 2. 第六阶段在八阶段中的位置
八阶段拆分如下:
1. 阶段 1创作页面入口、Agent 会话主链与工作区骨架
2. 阶段 2最小锚点收集与澄清流程
3. 阶段 3世界底稿生成与草稿卡编译
4. 阶段 4草稿设定编辑与 AI 新增角色/场景生成
5. 阶段 5角色主图与动作资产工坊接入
6. 阶段 6场景背景图工坊接入
7. 阶段 7长尾内容扩展与自动补齐
8. 阶段 8发布、世界库接入与继续创作恢复
本文件只覆盖:
**阶段 6场景背景图工坊接入**
---
## 3. 第六阶段目标
第六阶段只做 7 件必须一起成立的事:
1. 用户可以从 `landmark` 卡和 `camp` 卡打开场景图工坊
2. 用户可以为场景生成背景图候选
3. 用户可以预览生成结果
4. 用户可以选择结果并保存为正式场景图
5. 保存成功后,场景对象会写回 `imageSrc / generatedSceneAssetId / generatedScenePrompt / generatedSceneModel`
6. `assetCoverage.sceneAssets` 状态会更新
7. 工作区和创作页面能感知场景资产状态变化
一句话目标:
**让第六阶段结束时,至少部分关键场景已经不只是“设定存在”,而是“有可用背景图”。**
---
## 4. 第六阶段完成定义
第六阶段完成后,必须同时满足以下结果:
1. 用户从某张 `landmark``camp` 卡进入详情后,可以点击“场景背景图”打开场景图工坊。
2. 用户可以输入 prompt 并生成场景背景图结果。
3. 用户可以预览生成结果,并在保存前决定是否继续重试。
4. 用户保存成功后,对应场景对象会得到:
- `imageSrc`
- `generatedSceneAssetId`
- `generatedScenePrompt`
- `generatedSceneModel`
5. `assetCoverage.sceneAssets` 中对应场景状态会更新。
6. 工作区中的地点卡 / 营地卡会显示背景图状态变化。
7. 第六阶段仍然不要求所有场景都立刻完成背景图,也不要求进入发布。
---
## 5. 范围控制
## 5.1 第六阶段纳入范围
纳入范围的模块:
- `packages/shared/src/contracts/customWorldAgent.ts`
- `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
- `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
- `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
- `src/services/ai.ts`
- `src/services/aiService.ts`
- `server-node/src/services/customWorldAgentSessionStore.ts`
- `server-node/src/services/customWorldAgentOrchestrator.ts`
- `server-node/src/services/customWorldAgentDraftCompiler.ts`
- `server-node/src/services/customWorldWorkSummaryService.ts`
- `server-node/src/services/sceneImageService.ts`
- `server-node/src/routes/runtimeRoutes.ts`
新增前端模块:
- `src/components/custom-world-agent/CustomWorldSceneAssetStudioModal.tsx`
新增服务端模块:
- `server-node/src/services/customWorldAgentSceneAssetStateService.ts`
## 5.2 第六阶段明确不做
以下内容不放进第六阶段:
1. 不做角色资产工坊改造
2. 不做长尾场景批量自动出图
3. 不做场景图批量预生成
4. 不做发布时强制所有场景图齐全
5. 不做场景图精修工作流
6. 不做地图连接与场景图自动同步生成
原因:
**第六阶段只解决“选中的营地或场景如何进入背景图工坊并成功把结果写回草稿世界”。**
---
## 6. 第六阶段最小闭环
建议把第六阶段的最小闭环定义为:
```text
第五阶段已有 landmark/camp 卡
-> 用户打开某张地点卡详情
-> 点击“场景背景图”
-> 打开场景图工坊
-> 输入 prompt 并开始生成
-> 预览结果
-> 保存
-> sync_scene_assets
-> landmark/camp card / assetCoverage / 创作页面摘要同步更新
```
这个闭环里,先只强接两条高价值链路:
1. `landmark/camp card -> scene asset studio`
2. `scene asset studio save -> session sync`
---
## 7. 第六阶段产品行为定义
## 7.1 哪些对象可以进入场景图工坊
第六阶段允许以下对象进入场景图工坊:
1. `camp`
2. `landmark`
不处理:
1. 其他卡片类型
## 7.2 入口位置
### 当前状态补充2026-04-21
这一节以下描述依赖当时仍被视为现行方案的旧详情面板链与旧快捷动作链。
但当前版本已经明确:
1. `CustomWorldAgentDraftDetailPanel.tsx`
2. `CustomWorldAgentQuickActions.tsx`
已退出主链并物理删除。
因此这里关于入口位置的说明,现在只保留历史场景资产工坊设计参考价值。
### 地点卡详情入口
`CustomWorldAgentDraftDetailPanel` 中,当当前卡类型为:
```ts
kind === 'landmark' || kind === 'camp'
```
显示按钮:
- `场景背景图`
### 快捷动作入口
当当前 focus card 为 `landmark``camp` 时,`CustomWorldAgentQuickActions` 可显示:
- `生成场景背景图`
说明:
快捷动作与详情按钮最终都打开同一个 modal。
## 7.3 第六阶段支持的场景图流程
### 阶段 A场景图生成
允许:
1. 输入场景内容描述
2. 上传一张可选参考图
3. 基于当前场景语义生成背景图
### 阶段 B场景图预览
用户必须可以:
1. 看到新生成图片
2. 对比当前图片
3. 决定是否保存
### 阶段 C场景图保存
保存后把结果写回:
1. `imageSrc`
2. `generatedSceneAssetId`
3. `generatedScenePrompt`
4. `generatedSceneModel`
## 7.4 第六阶段不强制的事情
第六阶段明确不强制:
1. 每个场景都必须立刻生成背景图
2. 每个背景图都必须一次满意
3. 没有背景图的场景不能继续文本创作
说明:
这一步是“场景开始接资产”,不是“所有场景必须立刻完工”。**
## 7.5 积分消耗提示规则
和第五阶段保持一致:
**不做预算限制,但高成本生成前必须明确提示积分消耗。**
因此第六阶段必须遵守:
### 生成前
必须提示:
1. 本次会消耗多少积分
2. 这是候选生成,不是最终发布
### 保存前
保存本身不应再次重复收积分,除非现有场景图服务明确要求。
---
## 8. 场景资产状态定义
## 8.1 `assetCoverage.sceneAssets`
第六阶段必须开始真正使用它。
建议状态:
```ts
type CustomWorldSceneAssetStatus = 'missing' | 'ready';
```
### 含义
#### `missing`
场景还没有正式背景图
#### `ready`
场景已经有:
1. `imageSrc`
2. `generatedSceneAssetId`
## 8.2 场景对象写回字段
保存成功后,必须写回:
```ts
imageSrc
generatedSceneAssetId
generatedScenePrompt
generatedSceneModel
```
### 明确要求
第六阶段不允许只更新 `assetCoverage`,不更新场景对象本身。
---
## 9. 数据结构落地方案
## 9.1 启用 `CustomWorldAgentActionRequest`
第六阶段正式启用:
```ts
| {
action: 'sync_scene_assets';
sceneId: string;
sceneKind: 'camp' | 'landmark';
imageSrc: string;
generatedSceneAssetId: string;
generatedScenePrompt?: string | null;
generatedSceneModel?: string | null;
}
```
### 第六阶段说明
不新增新的 `generate_scene_assets` 前置准备 action。
原因:
当前场景图生成链已经由 `generateCustomWorldSceneImage(...)` 直接承接,
因此第六阶段只需要在保存成功后做 session 同步。
## 9.2 扩展 `CustomWorldSceneAssetSummary`
第六阶段开始必须真正填:
1. `imageSrc`
2. `generatedSceneAssetId`
3. `status`
4. `nextPointCost`
## 9.3 新增场景资产同步结果结构
建议新增:
```ts
type SyncSceneAssetsResult = {
sceneId: string;
sceneKind: 'camp' | 'landmark';
updatedScene: Record<string, unknown>;
updatedAssetSummary: CustomWorldSceneAssetSummary;
};
```
---
## 10. 服务端实现方案
## 10.1 新增 `customWorldAgentSceneAssetStateService.ts`
### 文件
`server-node/src/services/customWorldAgentSceneAssetStateService.ts`
### 职责
根据营地或场景对象真实字段,更新:
1. `assetCoverage.sceneAssets`
2. `draftCards` 中地点卡 / 营地卡的副摘要
3. 创作页面作品卡统计
### 导出函数建议
```ts
rebuildSceneAssetCoverage(draftProfile)
mergeSceneAssetIntoDraftProfile(draftProfile, payload)
```
## 10.2 修改 `customWorldAgentOrchestrator.ts`
第六阶段必须启用:
1. `sync_scene_assets`
### `sync_scene_assets` 流程
```text
收到 sync_scene_assets
-> 校验 sceneId
-> 校验 sceneKind
-> 写回 draftProfile.camp 或 draftProfile.landmarks
-> 重建 assetCoverage.sceneAssets
-> 重新编译地点卡 / 营地卡摘要
-> 写入 assistant action_result
-> 写入 checkpoint
-> operation completed
```
### camp 写回规则
当:
```ts
sceneKind === 'camp'
```
写回:
```ts
draftProfile.camp
```
### landmark 写回规则
当:
```ts
sceneKind === 'landmark'
```
写回:
```ts
draftProfile.landmarks.find(...)
```
## 10.3 修改 `customWorldAgentDraftCompiler.ts`
第六阶段它必须让:
1. `landmark` 卡摘要带出场景图状态
2. `camp` 卡摘要带出场景图状态
### 推荐展示方式
`subtitle``summary` 中追加:
1. `背景图已就绪`
2. `待生成背景图`
但不要把卡片变成技术表。
## 10.4 修改 `customWorldWorkSummaryService.ts`
第六阶段创作页面草稿卡应支持展示:
1. 已有多少场景具备背景图
第一版如果不想上具体数字,也至少要能体现:
- `场景资产进行中`
---
## 11. 前端实现方案
## 11.1 新增 `CustomWorldSceneAssetStudioModal.tsx`
### 来源
从当前 `CustomWorldEntityEditorModal.tsx` 中的 `SceneImageGenerationModal` 思路抽出,
但改成可被 Agent 工作区调用的版本。
### props
```ts
{
profile: Pick<CustomWorldProfile, 'id' | 'name' | 'summary' | 'tone' | 'playerGoal' | 'settingText'>;
scene: {
id: string;
kind: 'camp' | 'landmark';
name: string;
description: string;
imageSrc?: string;
};
onPublishSuccess: (payload) => void;
onClose: () => void;
}
```
### 功能
1. 输入场景 prompt
2. 上传可选参考图
3. 调用 `generateCustomWorldSceneImage(...)`
4. 展示预览
5. 保存并回调 `onPublishSuccess`
## 11.2 修改 `CustomWorldAgentDraftDetailPanel.tsx`
当卡片类型为 `landmark``camp` 时,新增:
1. `场景背景图` 按钮
2. 资产状态 badge
### 状态显示建议
1. `待生成背景图`
2. `背景图已就绪`
## 11.3 修改 `CustomWorldAgentQuickActions.tsx`
当当前 focus card 为 `landmark``camp` 时,可显示:
- `生成场景背景图`
点击后:
1. 直接打开 `CustomWorldSceneAssetStudioModal`
## 11.4 修改 `CustomWorldAgentWorkspace.tsx`
新增状态:
```ts
activeSceneAssetTarget?: {
sceneId: string;
sceneKind: 'camp' | 'landmark';
} | null;
showSceneAssetStudio: boolean;
```
### 打开逻辑
1. 来自 detail panel
2. 来自 quick actions
### 关闭逻辑
关闭不代表写回成功。
必须等:
1. 场景图生成完成并保存
2. `sync_scene_assets` 成功
之后才刷新场景资产状态。
## 11.5 修改 `CustomWorldCreationHub.tsx`
第六阶段它必须支持草稿作品卡的“场景资产进度感”。
第一版至少做到:
1. 草稿卡可展示:
- 场景资产进行中
- 或若数量可得,则展示场景背景图完成数
---
## 12. 交互时序
## 12.1 打开场景图工坊
```text
用户点击地点卡
-> 打开 detail panel
-> 点击“场景背景图”
-> 前端打开 CustomWorldSceneAssetStudioModal
```
## 12.2 保存场景图
```text
用户在工坊中生成场景图
-> 预览结果
-> 点击保存
-> 工坊得到 imageSrc + generatedSceneAssetId + prompt + model
-> 前端调用 sync_scene_assets
-> 服务端写回 draftProfile.camp 或 landmark
-> 服务端重建 assetCoverage.sceneAssets
-> 服务端重编译地点卡摘要
-> 前端刷新 snapshot
-> 工坊关闭
```
---
## 13. 与第五阶段的兼容要求
## 13.1 兼容有图场景
如果某场景已经有:
1. `imageSrc`
2. `generatedSceneAssetId`
仍允许继续打开工坊重新生成,再保存覆盖。
## 13.2 兼容无图场景
如果某场景完全无:
1. `imageSrc`
2. `generatedSceneAssetId`
也允许打开工坊从零生成。
## 13.3 兼容新增场景
第四阶段新增的 `landmark` 一旦存在于 `draftProfile.landmarks` 中,立即允许进入场景图工坊。
---
## 14. 落地文件清单
## 14.1 frontend
必须新增:
1. `src/components/custom-world-agent/CustomWorldSceneAssetStudioModal.tsx`
必须修改:
1. `src/components/custom-world-agent/CustomWorldAgentWorkspace.tsx`
2. `src/components/custom-world-agent/CustomWorldAgentDraftDetailPanel.tsx`
3. `src/components/custom-world-agent/CustomWorldAgentQuickActions.tsx`
4. `src/components/custom-world-home/CustomWorldCreationHub.tsx`
5. `src/services/ai.ts`
6. `src/services/aiService.ts`
## 14.2 backend
必须新增:
1. `server-node/src/services/customWorldAgentSceneAssetStateService.ts`
必须修改:
1. `server-node/src/services/customWorldAgentOrchestrator.ts`
2. `server-node/src/services/customWorldAgentDraftCompiler.ts`
3. `server-node/src/services/customWorldAgentSessionStore.ts`
4. `server-node/src/services/customWorldWorkSummaryService.ts`
5. `server-node/src/services/sceneImageService.ts`
6. `server-node/src/routes/runtimeRoutes.ts`
---
## 15. 测试要求
## 15.1 服务端测试
至少要补:
1. `sync_scene_assets` 能正确写回 `camp`
2. `sync_scene_assets` 能正确写回 `landmark`
3. 写回后 `assetCoverage.sceneAssets` 状态更新
4. 写回后地点卡 / 营地卡摘要更新
5. 写回后 checkpoint 存在
## 15.2 前端测试
至少要补:
1. landmark/camp 卡详情可显示背景图入口
2. quick actions 可打开场景图工坊
3. 工坊保存成功后会触发 `sync_scene_assets`
4. snapshot 刷新后场景卡显示新状态
## 15.3 手工回归
至少走这 4 条:
1. 为一个无图场景生成背景图
2. 为营地生成背景图
3. 返回 workspace 确认场景卡状态变化
4. 返回创作页面确认草稿卡摘要变化
---
## 16. 第六阶段验收标准
做到以下几点,才算第六阶段真正完成:
1. 场景卡和营地卡已经可以接入并打开背景图工坊。
2. 保存成功后,场景对象会写回 `imageSrc / generatedSceneAssetId / generatedScenePrompt / generatedSceneModel`
3. 场景资产状态会同步反映到 session snapshot 和场景卡摘要。
4. 场景图接入不会阻塞继续文本创作。
5. 第六阶段仍然不越界去做长尾自动补齐和发布逻辑。
---
## 17. 一句话结论
第六阶段最重要的不是“让所有场景都立刻有图”,而是:
**先把草稿世界里的营地和关键场景,真正接到一条可预览、可保存、可写回的背景图工坊链路上。**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,233 @@
# AI Native 战斗单行为 Function PRD2026-04-18
## 1. 目标
本次迭代把战斗中的 function 从“战术风格 function”收敛为“单次可直接结算的原子行为 function”。
核心目标:
1. 战斗中一次点击只完成一个明确行为,不再做连续多轮击打、连续多 actor 轮转的 function 设计。
2. 战斗中除逃跑外,不再为每次动作额外触发剧情推理,而是直接结算数值并刷新下一轮战斗选项。
3. 只有在逃跑成功或战斗正式结束后,才触发一次剧情推理,生成脱战后的 storyText 与后续剧情选项。
---
## 2. 新战斗 option 池
`inBattle = true` 时,默认战斗选项池固定收敛为以下结构,顺序按下列规则输出:
1. `battle_attack_basic`
2. `battle_recover_breath`
3. `inventory_use`
4. `battle_use_skill`
5. `battle_escape_breakout`
其中第 4 项不是单个 option而是“每个技能一个 option 实例”。
### 2.1 普通攻击
- functionId`battle_attack_basic`
- 含义:不消耗灵力的基础攻击。
- 结算:直接结算一次基础伤害。
- 不触发剧情推理。
### 2.2 恢复
- functionId`battle_recover_breath`
- 含义:本回合做恢复与节奏调整。
- 结算:直接恢复血量/灵力,并推进技能冷却。
- 不触发剧情推理。
### 2.3 使用物品
- functionId`inventory_use`
- 含义:战斗中直接使用一个可结算的消耗品。
- 本期战斗选项池只给一个“推荐可用物品” option不展开整包物品列表。
- option 必须携带 `runtimePayload.itemId`
- 若当前没有可用消耗品,则仍保留该项,但以 disabled 态展示。
- 不触发剧情推理。
### 2.4 使用技能
- functionId`battle_use_skill`
- 每个角色技能都生成一个独立 option。
- option 文案直接对应技能名,不再包装成“稳扎试探 / 破架 / 终结窗口”这类抽象战术文案。
- option 必须携带 `runtimePayload.skillId`
- 若技能因蓝量不足或冷却中不可用,仍保留该 option但以 disabled 态展示。
- 点击后直接结算该技能本次效果,不触发剧情推理。
### 2.5 逃跑
- functionId`battle_escape_breakout`
- 含义:立即尝试脱离当前战斗。
- 结算:直接处理脱战结果。
- 逃跑成功后必须触发剧情推理。
---
## 3. 旧战斗 function 的处理
以下旧 function 不再进入默认战斗选项池:
- `battle_all_in_crush`
- `battle_guard_break`
- `battle_probe_pressure`
- `battle_feint_step`
- `battle_finisher_window`
兼容规则:
- 后端仍允许解析这些旧 functionId避免旧存档 / 旧 currentStory 点击时报错。
- 兼容结算统一按“单次攻击型行为”处理,不再保留旧的战术风格分支。
- 新生成的新选项、新 currentStory、新 viewModel 不再继续下发这些旧 function。
---
## 4. 单行为结算规则
### 4.1 单次点击的边界
一次点击只允许完成一次玩家声明行为:
- 普通攻击
- 恢复
- 使用物品
- 使用某个具体技能
- 逃跑
不再允许一次点击里继续串:
- 多轮连续攻击
- 多个技能连续释放
- 多个角色依次轮转
- 为了“表现完整”再补一整串额外战斗回合
### 4.2 回合感保留
虽然不再做连续多轮击打,但每个战斗动作仍然视为消耗了一个战斗回合,因此:
- 技能冷却要按“本次动作结束后”推进
- 恢复类动作可额外提供冷却推进收益
- 物品动作在战斗态下也算一次战斗回合
- 战斗中使用物品要先结算物品恢复 / buff / 额外冷却收益,再结算这一回合是否承受敌方单次反击
### 4.3 结果文本
ongoing battle 的本地/后端结果文本只负责说明这一次动作结算结果,不负责续写新的剧情段落。
例如:
- 你挥出一记普通攻击,命中前方敌人。
- 你稳住呼吸,恢复了部分气血与灵力。
- 你立刻服下疗伤药,当前状态回升。
- 你释放了【试锋斩】,直接压低了对方血线。
---
## 5. 剧情推理触发边界
### 5.1 不触发剧情推理的情况
当动作执行后仍处于战斗中时,以下 function 不触发剧情推理:
- `battle_attack_basic`
- `battle_recover_breath`
- `inventory_use`
- `battle_use_skill`
- 旧攻击类兼容 function
此时系统行为为:
1. 直接结算动作
2. 更新 HP / MP / CD / 物品 / 战斗状态
3. 直接刷新新一轮战斗选项
4. `storyText` 直接使用本次结算结果文本,不请求 AI 续写
### 5.2 必须触发剧情推理的情况
以下情况必须触发剧情推理:
1. `battle_escape_breakout` 执行后成功脱战
2. 任意战斗动作执行后,战斗正式结束
战斗正式结束包括:
- 敌方被击败
- 切磋结束
- 玩家被系统判定为本轮战斗已断开
此时系统行为为:
1. 先完成数值结算与状态落地
2. 再以“本次动作 + 本次战斗结果”为上下文触发一次剧情推理
3. 生成脱战后的 `storyText` 与非战斗态 options
---
## 6. 前后端数据约束
### 6.1 Option 扩展字段
为了支持“单 functionId + 多实例技能/物品 option”战斗 option 允许携带以下运行时字段:
- `runtimePayload`
- `skillId?: string`
- `itemId?: string`
- `disabled?: boolean`
- `disabledReason?: string`
### 6.2 前端职责
- 前端只负责展示 option、透传 `runtimePayload`、展示 disabled 态
- 前端不再自己推导战斗中“是否需要剧情推理”
- 前端不再把技能 option 重写成抽象战术描述
### 6.3 后端职责
- 后端负责生成战斗 option 池
- 后端负责解析 `skillId / itemId`
- 后端负责决定 battle ongoing / battle end / escape 后是否触发剧情推理
---
## 7. 本次落地范围
本期必须落地:
1. 后端 runtime 战斗 option 池切换到单行为模型
2. 后端 combat resolution 支持普通攻击 / 指定技能 / 恢复 / 战斗物品 / 逃跑
3. 后端只在逃跑或战斗结束后做剧情推理
4. 前端支持透传战斗 option 的 `runtimePayload`
5. 前端支持 disabled battle option 展示
6. 文档、测试同步更新
补充落地备注2026-04-20
- `inventory_use` 在战斗中按战斗动作结算,而不是按非战斗库存动作直接短路返回
- 战斗态 `inventory_use` 使用后要消费物品、累计 `itemsUsed`、推进 1 回合基础冷却,再叠加物品自带的 `cooldownReduction`
- 若物品动作结算后战斗仍在继续,`storyText` 直接等于本次战斗结果文本,不触发 AI 续写
本期不做:
1. 新增复杂目标选择 UI
2. 一次展开完整背包的战斗 item 子面板
3. 重做整套战斗演出系统
4. 把所有旧本地 battle plan 彻底删除到只剩后端一条链
---
## 8. 验收口径
满足以下条件视为本次需求完成:
1. 战斗中不再出现 `battle_all_in_crush / battle_guard_break / battle_probe_pressure / battle_feint_step / battle_finisher_window` 作为默认候选项。
2. 战斗默认候选项能看到:
- 普通攻击
- 恢复
- 使用物品
- 每个技能一个独立技能项
- 逃跑
3. 点击普通攻击 / 恢复 / 使用物品 / 技能时,不请求新的剧情推理,直接返回结算结果并刷新下一轮战斗 options。
4. 点击逃跑成功后,会请求一次剧情推理并切回脱战后的剧情 options。
5. 任意攻击或技能把敌人打死后,会请求一次剧情推理并切回脱战后的剧情 options。
6. 旧存档里残留旧 battle functionId 时,不会因为 function 不识别而报错。

View File

@@ -0,0 +1,498 @@
# AI 原生经典 RPG 体验对标引擎 PRD
更新时间:`2026-04-06`
## 0. 目标
这份 PRD 建立在已有的:
- `AI_NATIVE_CROSS_GENRE_STORY_ENGINE_PRD_2026-04-06.md`
- `AI_NATIVE_NARRATIVE_THREAD_ITEM_AND_WORLD_NPC_PRD_2026-04-06.md`
之上,进一步回答一个更明确的问题:
**如何让当前仓库里的 AI 原生剧情引擎,不只是“会生成剧情”,而是能在现有游戏框架中,驱动出对标《仙剑》《轩辕剑》《古剑》《黑神话:悟空》《博德之门》这类经典作品的角色扮演体验。**
这里的“对标”不是复制题材、桥段或美术风格,而是抽取这些作品背后的体验能力:
1. 让玩家记住角色,而不只是记住设定。
2. 让世界里的地点、旧物、传闻、队友、任务彼此互相讲同一件事。
3. 让玩家的选择、立场、关系、误判、探索真正改变后续体验。
4. 让剧情推进同时拥有“作者性”和“系统性”。
一句话目标:
**把当前项目的 AI 原生叙事,升级成一种能稳定产出“经典单机 RPG 体验质感”的剧情引擎。**
## 1. 研究结论先说
综合参考对象后,可以把这几类经典体验抽象成 5 个核心方向:
1. `仙剑` 型体验
- 强角色记忆点
- “人”和“情”优先
- 主线、支线、传记、碎片化叙事共同塑造角色
2. `轩辕剑` 型体验
- 历史 / 神话 /文化意象共同构成宏大冲突
- 大时代与个人成长同时成立
- 系统玩法本身带文化与世界观意味
3. `古剑` 型体验
- 世界观先行
- 主题先行
- 角色命题、支线补完、衍生叙事共同构成厚世界
4. `黑神话` 型体验
- 空间本身讲故事
- 物件、残痕、命名、演出都带文化锚点
- 旅程像一次带试炼感的穿行,而不是纯任务导航
5. `博德之门` 型体验
- 队友强反应
- 选择有代价
- 关系状态、立场差异、任务分支和系统规则一起驱动叙事
对当前项目来说,这意味着剧情引擎必须补的,不是更多文案,而是下面 10 项能力:
1. 世界线程图谱
2. 题材适配层
3. 角色命题与秘密档案
4. 队友反应与关系矩阵
5. 信息可见性裁剪
6. 地点 / 物件 / 文书 / 残痕的叙事编译
7. 情境导演与节奏控制
8. 线程 -> 合约 -> 信号推进
9. 回响与长期记忆
10. 当前框架可落地的 orchestration 主链
## 2. 经典作品拆解
## 2.1 从《仙剑》系列提炼什么
《仙剑》最值得提炼的,不是仙侠题材,而是:
1. 角色与情感先于设定说明
2. 玩家会因为“人”和“情”记住剧情
3. 主线之外的角色剧情、人物传记、碎片信息都在持续加深理解
4. 角色魅力是分阶段投放,不是一口气灌输
对引擎的要求就是:
1. 每个重点角色都必须有“高光入口”
2. 角色认知要通过多载体逐步加深
3. 情感关系不能只挂在恋爱线,要覆盖友情、亲情、师承、旧债、牺牲、错过
4. 碎片化叙事必须和主线、支线互文,而不是散落设定
## 2.2 从《轩辕剑》系列提炼什么
《轩辕剑》最值得提炼的,不是具体朝代,而是:
1. 历史与神话共存
2. 宏观时代与个人命运互相牵引
3. 每一代往往有明确中心主题
4. 世界里的神器、法宝、炼妖壶、符鬼等系统并不是纯玩法道具,而是世界观的一部分
对引擎的要求就是:
1. 每个世界必须有明确的大时代冲突
2. 每段主线必须能同时看到“苍生线”和“个人线”
3. 每一轮内容生成都要知道自己服务的是哪条主题轴
4. 系统物件、战斗能力、资源名称、任务机制都要与世界观绑定
## 2.3 从《古剑》系列提炼什么
《古剑》最值得提炼的,不是台词风格,而是:
1. 世界观不是背景板,而是叙事发动机
2. 主题是预先确定的,比如“重生”“问道”
3. 游戏中只展示世界的一角,但能感到背后有更大的历史层
4. 支线、小说、传记、远古设定共同构成世界厚度
对引擎的要求就是:
1. 先生成“世界故事图谱”,再生成角色和剧情
2. 每个世界必须有自己的主题母题
3. 重点角色都要有“命题”
4. 支线不能只是奖励入口,而要承担世界观展开和人物补完
## 2.4 从《黑神话:悟空》提炼什么
《黑神话:悟空》最值得提炼的,不是神话题材本身,而是:
1. 空间叙事强
2. 旅程感强
3. 文化意象直接进入地点、敌人、物件、建筑和命名
4. 玩家不是靠大段讲解理解世界,而是靠穿行、观察、搏斗和残痕去感受
对引擎的要求就是:
1. 场景必须有“故事残痕层”
2. 路线推进要像试炼 / 朝圣 / 追索 / 深入禁地,而不是只弹任务文本
3. 重点物件必须是文化锚点和旧事证人
4. 敌人与地标也应属于叙事载体,而不只是战斗内容
## 2.5 从《博德之门》提炼什么
《博德之门》最值得提炼的,不是西式奇幻题材,而是:
1. 队友是强叙事引擎
2. 不同角色对同一行为会有不同立场反应
3. 关系推进有信任门槛
4. 玩家选择会改变关系、任务理解和队伍结构
5. 系统层会用可控的“认可 / 不认可”“信任 / 不信任”来表达复杂反应,而不是无限写分支
对引擎的要求就是:
1. 每个重点队友都要有可追踪的立场轴和信任轴
2. 对同一选择,队友必须出现差异化反应
3. 关系状态要进入后续任务、聊天、协战、赠礼、剧情揭示
4. 系统必须允许“有限分支 + 强反馈”,而不是追求不可控的全分支写作
## 3. 对标能力矩阵
## 3.1 引擎必须支持的体验支柱
建议把“经典 RPG 体验”拆成下面 8 根支柱:
1. 角色羁绊支柱
2. 主题表达支柱
3. 世界厚度支柱
4. 路线试炼支柱
5. 选择后果支柱
6. 队友反应支柱
7. 叙事载体支柱
8. 回响记忆支柱
## 3.2 支柱与经典作品的对照
| 支柱 | 仙剑 | 轩辕剑 | 古剑 | 黑神话 | 博德之门 |
| --- | --- | --- | --- | --- | --- |
| 角色羁绊 | 强 | 中 | 强 | 中 | 强 |
| 主题表达 | 强 | 强 | 强 | 中到强 | 强 |
| 世界厚度 | 中到强 | 强 | 强 | 强 | 强 |
| 路线试炼 | 中 | 中 | 中 | 强 | 中 |
| 选择后果 | 中 | 中 | 中 | 轻 | 强 |
| 队友反应 | 中 | 中 | 中 | 轻 | 强 |
| 叙事载体 | 中 | 强 | 强 | 强 | 强 |
| 回响记忆 | 中 | 强 | 强 | 中 | 强 |
结论不是“每个游戏都做一样多”,而是:
**要想对标这些经典作品的总和体验,引擎不能只强其中一项。**
## 4. 面向当前项目的引擎能力设计
## 4.1 世界线程图谱
用于承载:
- 《轩辕剑》式的大时代冲突
- 《古剑》式的远古 / 旧史 / 深层设定
- 《仙剑》式的主线与碎片化叙事互文
最低要求:
1. 每个世界有 `明线线程`
2. 每个世界有 `暗线线程`
3. 每个世界有 `旧事伤痕`
4. 每个世界有 `主题母题`
## 4.2 角色命题与秘密档案
用于承载:
- 《仙剑》式角色高光与感情曲线
- 《古剑》式角色命题与主题性成长
- 《博德之门》式角色秘密与立场差异
每个重点角色必须有:
1. 外显身份
2. 当前压力
3. 表面目标
4. 真实目标
5. 已付代价
6. 关系负债
7. 禁区
8. 可触发反应的关键词
## 4.3 队友反应与关系矩阵
这是当前项目对标《博德之门》最需要补的一块。
建议每个重点队友都至少维护:
```ts
interface CompanionStanceProfile {
trust: number;
warmth: number;
ideologicalFit: number;
fearOrGuard: number;
loyalty: number;
currentConflictTag?: string | null;
recentApprovals: string[];
recentDisapprovals: string[];
}
```
作用:
1. `trust`
- 决定是否愿意跟随你深入风险。
2. `warmth`
- 决定情感表达密度。
3. `ideologicalFit`
- 决定在价值观选择上的反应强度。
4. `fearOrGuard`
- 决定低关系阶段是不是更容易误会、回避、抗拒。
5. `loyalty`
- 决定关键节点是否站队。
## 4.4 信息可见性层
这是对标《古剑》的世界层深度、对标《仙剑》的分段投放、对标《博德之门》的可控分支,以及修复当前自定义世界 prompt 泄露问题的共同底座。
核心要求:
1. 角色知道什么
2. 玩家知道什么
3. 角色此刻愿意说什么
4. 当前场景允许模型看到什么
必须分开建模。
## 4.5 叙事载体编译层
这是对标《黑神话》《轩辕剑》《古剑》最关键的一层。
载体不能只限于装备物品,应统一抽象为:
1. 遗物
2. 证物
3. 文书
4. 材料
5. 禁物
6. 装置
7. 记忆碎片
8. 残痕场景
每个载体都要有:
1. 可见线索
2. 见证痕
3. 未完成问题
4. 当前出现理由
5. 后续反应钩子
## 4.6 情境导演与节奏层
这是对标《仙剑》的情感推进、《黑神话》的旅程压迫、《博德之门》的分支张力时最重要的“节奏控制器”。
导演层要先判断:
1. 当前是情感深化回合,还是冲突升级回合
2. 当前应推进明线、暗线、关系线、还是主题线
3. 当前需要推前台的是角色、地点、还是物件
4. 当前披露预算应该是低、中还是高
没有导演层AI 文本会持续飘散。
## 4.7 线程 -> 合约 -> 信号推进
这是把经典单机 RPG 的作者性故事,转成 AI 原生可持续运行结构的关键。
统一抽象如下:
1. 线程
- 这段故事在讲哪条线。
2. 合约
- 当前线的阶段目标、参与者、条件、失败态与回报。
3. 信号
- 玩家做了什么,导致哪个关系、地点、物件、真相片段发生变化。
## 4.8 回响与长期记忆
这是决定剧情是否像“经典作品”的最后一层。
玩家之所以会觉得这些作品有余味,不是因为文本多,而是因为:
1. 旧事会回来
2. 旧物会再被提起
3. 旧误解会被翻案
4. 旧角色会因为你做过的事改变口风
因此系统必须维护:
1. 事件记忆
2. 关系记忆
3. 线索记忆
4. 误解记忆
5. 已揭示真相记忆
## 5. 当前框架接入方案
## 5.1 `src/services/customWorld.ts`
从“批量生成 NPC 和地标”升级为:
1. 先生成 `ThemePack`
2. 再生成 `WorldStoryGraph`
3. 再生成 `ActorNarrativeProfile`
4. 最后补 `backstoryReveal / skills / initialItems`
它将成为当前项目里最接近“古剑式世界观先行 + 轩辕剑式宏大主题”的入口。
## 5.2 `src/services/prompt.ts`
从“组装上下文”升级为:
1. 读取 `VisibilitySlice`
2. 读取 `SceneNarrativeDirective`
3. 只注入当前阶段可见、可说、可推的最小剧情上下文
它将成为:
- 对标《博德之门》强反应又可控
- 对标《仙剑》分阶段角色理解
- 修复当前全知视角泄露
的核心模块。
## 5.3 `src/data/npcInteractions.ts`
从“关系规则函数集合”升级为:
1. 首遇状态机
2. 队友立场矩阵
3. 认可 / 不认可反馈
4. 关系冲突 tag
5. 私聊 / 队伍 / 营地事件触发
它将承担当前项目里最接近《博德之门》队友系统和《仙剑》角色关系成长的部分。
## 5.4 `src/services/questDirector.ts`
从“任务导演”升级为:
1. 剧情线程导演
2. 合约生成器
3. 信号推进器
4. 阶段揭示器
它将承担对标《轩辕剑》宏观主线推进和《博德之门》分支任务反馈的主链。
## 5.5 `src/data/runtimeItemDirector.ts` / `src/data/runtimeItemNarrative.ts`
从“运行时奖励导演”升级为:
1. 通用叙事载体编译器
2. 重点物件故事指纹生成器
3. 角色 / 场景 / 势力 / 旧事的回响载体
它将承担对标《黑神话》物件文化锚点、对标《轩辕剑》器物世界观、对标《古剑》旧史残痕的能力。
## 5.6 `src/hooks/useStoryGeneration.ts`
从“剧情总 orchestrator”收束为
1. 读取导演结果
2. 发起对应 contract
3. 驱动生成
4. 回写记忆与信号
不要继续把越来越多叙事细节直接塞进这个 hook而是让它只做总线协调。
## 6. 体验验收标准
如果要说“能对标经典单机 RPG 体验”,至少要达到下面这些结果。
## 6.1 角色体验
1. 玩家在一次完整体验后,能明确记住至少 `3~5` 个队友 / 核心角色的个性、矛盾和关键旧事。
2. 低好感角色不会只是“冷淡”,而是会带明确压力、错位说辞和暗线钩子。
3. 高关系角色会在聊天、任务、协战、赠礼、事件节点中显著改变表达与立场。
## 6.2 世界体验
1. 玩家能感到世界背后有更深层的旧史与暗线,而不是所有信息都在主线上直接交代。
2. 场景、地点、支线、人物传记、物件描述之间会互相印证。
3. 世界主题在命名、系统、任务、人物冲突上持续一致。
## 6.3 选择体验
1. 玩家选择能被至少一名队友明确认可或反对。
2. 至少一部分选择会影响后续任务理解、关系推进、额外剧情或可见信息。
3. 系统既要让选择有重量,又不能因为分支爆炸而失控。
## 6.4 旅程体验
1. 场景推进要有“试炼 / 追索 / 深入 / 回望”的旅程感。
2. 不是所有叙事都靠对话框完成,空间和载体也必须承担讲故事的职责。
3. 玩家会因为一个地标、一个旧物、一次反应,主动去拼出暗线。
## 7. 推荐落地顺序
## 阶段 A先补对标经典作品的共同底座
优先做:
1. `ThemePack`
2. `WorldStoryGraph`
3. `ActorNarrativeProfile`
4. `VisibilitySlice`
## 阶段 B优先把当前项目最能出效果的两条链做强
1. 队友 / NPC 关系反应链
2. 运行时物件 / 场景残痕叙事链
这是当前最容易直接提升“像经典 RPG”的地方。
## 阶段 C把任务和主线推进改成线程化
重点补:
1. 线程
2. 合约
3. 信号
4. 阶段揭示
## 阶段 D补营地 / 旅途中队友事件
这是当前项目对标《仙剑》与《博德之门》体验非常关键的一步。
建议新增:
1. 营地对话
2. 旅途中短反应
3. 关键选择后的队友插话
4. 队友之间的互相评价
## 阶段 E做经典体验压力测试
至少要用 5 类体验场景去压测引擎:
1. 情感型主线
2. 历史 / 神话型大事件
3. 世界观层层揭示型流程
4. 旅程试炼型场景链
5. 队友强反应分支型流程
## 8. 一句话结论
要让当前项目的 AI 原生剧情引擎真正对标《仙剑》《轩辕剑》《古剑》《黑神话》《博德之门》这些经典作品,关键不是去模仿哪一种题材,而是让引擎同时具备:
- 让人记住角色的能力
- 让世界互相说话的能力
- 让选择产生后果的能力
- 让地点与物件承担叙事的能力
- 让长线回响沉淀下来的能力
只有这些能力一起成立当前框架里跑出来的体验才会从“AI 会写剧情”真正跨到“AI 能驱动经典 RPG 质感”。

View File

@@ -0,0 +1,554 @@
# AI 原生跨题材剧情引擎 PRD
更新时间:`2026-04-06`
## 0. 定位
这份 PRD 的目标不是为某一种题材写一套“更会编故事的文案系统”,而是设计一套:
**可适配奇幻、武侠、仙侠、科幻、悬疑、恐怖、末世、都市、校园、神话等多种题材的 AI 原生游戏剧情引擎。**
它应该解决的不是单一题材里的句子风格,而是更底层的问题:
1. 世界的明线、暗线如何被系统化组织。
2. 角色、地点、物件、文书、怪物、装置、尸体、遗迹这些叙事载体如何共同讲故事。
3. 玩家当前能知道什么、误以为知道什么、还不能知道什么,如何被稳定控制。
4. AI 如何负责叙事生成,本地规则如何负责边界、状态、可见性、推进信号与玩法编译。
一句话定位:
**它是一个“剧情引擎层”,不是一个“某题材内容包”。**
## 1. 设计目标
这套引擎要同时满足 6 个目标:
1. 跨题材
- 核心语义不写死在武侠、奇幻、修仙、蒸汽朋克等具体题材上。
2. AI 原生
- 剧情文本、现场张力、角色表述、线索回响由 AI 参与生成,而不是只做静态模板替换。
3. 规则可控
- 世界状态、信息泄露边界、关系推进、任务推进、奖励发放仍由本地规则约束。
4. 叙事网状化
- 故事不只存在于主线任务里,而是分布在角色、物件、地点、事件余波与传闻中。
5. 可扩展
- 新增题材时,优先新增“题材适配层”,而不是推翻剧情引擎本体。
6. 可验证
- 能明确验收“是否有故事感”“是否埋得住暗线”“是否越权泄露”“是否跨题材仍成立”。
## 2. 参考方法抽象
本次设计参考的是成熟叙事游戏的方法,不是照搬具体剧情。
## 2.1 可借鉴的方法来源
1. CRPG 方法
- 代表思路:角色秘密、阵营立场、任务分支、物件与角色的反应联动。
- 可借鉴点:角色不是独立设定卡,而是世界冲突中的活节点。
2. 沉浸式侦查 / 推理方法
- 代表思路:线索不是一次性交代,而是靠地点、证物、口供、误导与缺失共同成立。
- 可借鉴点:信息差、误判、再解释,是故事感的重要来源。
3. 系统叙事方法
- 代表思路:事件、状态、关系、资源变化会自然生成“像故事”的结果。
- 可借鉴点:引擎应先保证状态与因果,再让 AI 把它叙事化。
4. Roguelike / 重复游玩叙事方法
- 代表思路:角色关系、旧伤、遗物、失败记录、阶段揭示会在多轮体验中叠加意义。
- 可借鉴点:故事不是一次性讲完,而是通过回响与累积形成。
5. 强氛围题材方法
- 代表思路:名字、物件、俗称、禁忌称呼、残损意象本身就携带故事。
- 可借鉴点:叙事载体不只靠大段说明,也能靠命名与残痕表达。
## 2.2 抽象结论
综合这些方法后,这套引擎应固定采用下面这 5 个叙事原则:
1. 故事必须网状分布,不能只挂在主线任务上。
2. 信息披露必须分层,不能让模型默认全知。
3. 低关系、低信任、低理解阶段,不能减少故事密度,只能减少披露深度。
4. 物件与地点必须是故事证人,而不只是功能容器。
5. 题材差异应该主要落在“词汇、意象、制度、冲突形式”上,而不是改变剧情引擎基本语法。
## 3. 引擎核心原则
1. AI 负责叙事表达,本地负责规则裁决。
2. 世界先于角色,角色先于对白,状态先于文案。
3. 所有剧情都必须能回到“谁知道什么、谁想隐藏什么、谁正在承受什么”。
4. 明线、暗线、代价线、回响线是所有题材共通的最小叙事单元。
5. 信息可见性必须被数据化,而不能只靠 prompt 口头提醒。
6. 引擎关注“剧情语法”,题材包只负责“表现词汇”。
## 4. 引擎总架构
建议把 AI 原生剧情引擎拆成 8 个层:
1. 世界语义层
2. 题材适配层
3. 角色与阵营层
4. 信息可见性层
5. 情境导演层
6. 合约与信号推进层
7. 叙事载体编译层
8. 记忆与回响层
关系如下:
```text
世界语义层
-> 题材适配层
-> 角色与阵营层
-> 信息可见性层
-> 情境导演层
-> 合约与信号推进层
-> 叙事载体编译层
-> 记忆与回响层
```
## 5. 世界语义层
## 5.1 目标
让所有题材都先被翻译成一套统一的世界叙事骨架,而不是直接开始生成角色和对白。
## 5.2 建议的数据结构
```ts
interface StoryThread {
id: string;
title: string;
visibility: 'visible' | 'hidden';
summary: string;
conflictType: string;
stakes: string;
involvedFactionIds: string[];
involvedActorIds: string[];
relatedLocationIds: string[];
}
interface StoryScar {
id: string;
title: string;
pastEvent: string;
publicResidue: string;
hiddenTruth: string;
relatedActorIds: string[];
relatedLocationIds: string[];
}
interface StoryMotif {
id: string;
label: string;
semanticRole: 'institution' | 'ritual' | 'technology' | 'taboo' | 'ruin' | 'memory' | 'resource' | 'creature';
lexicalHints: string[];
}
interface WorldStoryGraph {
visibleThreads: StoryThread[];
hiddenThreads: StoryThread[];
scars: StoryScar[];
motifs: StoryMotif[];
}
```
## 5.3 为什么它必须在最前面
没有这层图谱,就会出现这类问题:
1. 角色各自有设定,但彼此没有共享暗线。
2. 物件命名很酷,但和世界冲突没有关系。
3. 场景有氛围,但和主要矛盾不互相印证。
4. 每次 AI 输出都像重新发明一个宇宙。
## 6. 题材适配层
## 6.1 目标
让题材差异变成一个可替换的“表现层”,而不是把剧情引擎本体写死成某一类世界观。
## 6.2 建议的数据结构
```ts
interface ThemePack {
id: string;
displayName: string;
toneRange: string[];
institutionLexicon: string[];
tabooLexicon: string[];
artifactClasses: string[];
actorArchetypes: string[];
conflictForms: string[];
clueForms: string[];
namingPatterns: string[];
revealStyles: string[];
}
```
## 6.3 题材适配层负责什么
它只负责:
1. 把“机构”翻译成宗门、财团、学会、调查局、帮派、舰队、公司、教团等。
2. 把“禁忌”翻译成邪术、封印、机密协议、校园旧规、污染区准则等。
3. 把“叙事载体”翻译成遗物、枪械、芯片、病例、证物、祭器、录像带、样本、航图等。
4. 把“冲突形式”翻译成宫廷斗争、公司内斗、调查失踪、阵营战争、神话追索、生存竞争等。
它不负责:
1. 决定角色到底知道什么。
2. 决定剧情推进是否合法。
3. 决定哪些信息此刻允许披露。
## 7. 角色与阵营层
## 7.1 角色不是“背景文本”,而是“叙事立场体”
每个角色都必须被拆成下面几个面向:
1. 外显身份
2. 当前处境
3. 表面目标
4. 真实目标
5. 隐藏关系
6. 已付代价
7. 不愿被碰的禁区
8. 会触发反应的关键词
## 7.2 建议的数据结构
```ts
interface ActorNarrativeProfile {
publicMask: string;
firstContactMask: string;
visibleLine: string;
hiddenLine: string;
contradiction: string;
debtOrBurden: string;
taboo: string;
immediatePressure: string;
relatedThreadIds: string[];
relatedScarIds: string[];
reactionHooks: string[];
}
```
## 7.3 低关系角色的引擎规则
低关系、低好感、低信任角色必须满足:
1. 有压力
2. 有保留
3. 有错位
4. 有反应钩子
不能只是:
1. 说得少
2. 更冷淡
3. 更短句
正确做法应该是:
- 披露深度更低
- 戏剧张力更高
- 错误说辞更多
- 观察与试探更明显
## 8. 信息可见性层
## 8.1 这是 AI 原生剧情引擎的核心
如果不把“可见性”数据化AI 叙事会天然滑向全知视角。
因此必须明确区分:
1. 事实是否存在
2. 玩家是否知道
3. 当前角色是否愿意说
4. 当前 prompt 是否允许注入
5. 玩家是否只是误以为知道
## 8.2 建议的数据结构
```ts
interface KnowledgeFact {
id: string;
content: string;
ownerActorIds: string[];
relatedThreadIds: string[];
visibility: 'public' | 'discoverable' | 'private' | 'forbidden';
}
interface VisibilitySlice {
factIds: string[];
sayableFactIds: string[];
inferredFactIds: string[];
forbiddenFactIds: string[];
misdirectionHints: string[];
}
```
## 8.3 运行时规则
1. prompt 只吃 `VisibilitySlice`
2. 未解锁章节不等于不存在,但不能进当前 prompt
3. 角色知道某事,不等于此刻愿意承认
4. 玩家接触到线索,不等于系统要直接盖章真相
## 9. 情境导演层
## 9.1 目标
每一轮剧情生成都不是“让 AI 自由写”,而是先由导演层判断:
1. 此刻最重要的压力是什么
2. 谁在主导场面
3. 当前最适合推进的是明线、暗线还是关系线
4. 哪些叙事载体应该被推到前台
## 9.2 导演层输入
- 当前场景
- 当前实体
- 当前关系状态
- 当前可见信息
- 最近信号变化
- 玩家上一步行动
- 尚未回响的故事线程
## 9.3 导演层输出
```ts
interface SceneNarrativeDirective {
primaryPressure: string;
activeThreadIds: string[];
foregroundActorIds: string[];
foregroundCarrierIds: string[];
revealBudget: 'low' | 'medium' | 'high';
emotionalCadence: 'tense' | 'curious' | 'hostile' | 'intimate' | 'tragic' | 'mysterious';
}
```
## 10. 合约与信号推进层
## 10.1 目标
让剧情推进不依赖纯脚本,而是依赖“意图 -> 合约 -> 信号”。
## 10.2 统一抽象
1. 意图
- 当前想推动什么关系、冲突、调查或获取。
2. 合约
- 把意图翻译成可追踪的步骤、条件、参与者与回报。
3. 信号
- 玩家行动、地点变化、物件获取、关系变化、战斗结果、情报拼接后触发推进。
## 10.3 为什么这层跨题材都成立
因为不管是:
- 武侠寻仇
- 科幻调查
- 校园秘密
- 末世生存
- 神话追索
它们最终都能抽象成:
- 某种线索被拿到
- 某个误会被确认或打破
- 某种关系被推进或撕裂
- 某个真相片段被解锁
## 11. 叙事载体编译层
## 11.1 不要只把“物品”当成装备
跨题材剧情引擎里,叙事载体不应仅仅是“装备 / 道具”,而应统一抽象成:
```ts
type NarrativeCarrierType =
| 'artifact'
| 'document'
| 'evidence'
| 'device'
| 'resource'
| 'corpse'
| 'sample'
| 'relic'
| 'ritual_object'
| 'memory_fragment';
```
## 11.2 每个载体必须包含的叙事指纹
```ts
interface CarrierStoryFingerprint {
visibleClue: string;
witnessMark: string;
unresolvedQuestion: string;
currentAppearanceReason: string;
relatedThreadIds: string[];
relatedScarIds: string[];
reactionHooks: string[];
}
```
## 11.3 编译规则
每个叙事载体都至少要能回答:
1. 它是谁、哪处、哪次事留下的痕迹?
2. 它为什么现在出现?
3. 它之后能让谁产生反应?
4. 它和哪条线程有关系?
这层的作用,是让:
- 奇幻里的遗物
- 武侠里的旧兵器
- 科幻里的芯片
- 悬疑里的口供
- 恐怖里的录像带
- 校园题材里的匿名纸条
都能进入同一套剧情引擎。
## 12. 记忆与回响层
## 12.1 目标
让世界对玩家行动和已获取的叙事载体产生长期回响,而不是每轮都像第一次发生。
## 12.2 记忆分层
建议至少拆成:
1. 事件记忆
2. 关系记忆
3. 线索记忆
4. 误解记忆
5. 已揭示真相记忆
## 12.3 回响规则
一个故事线程真正成立,不是因为它被写过一次,而是因为它能在后续这些地方重新出现:
1. 别的角色说法里
2. 新地点残痕里
3. 新载体命名里
4. 新任务前提里
5. 关系变化反应里
## 13. Prompt Contract 设计
## 13.1 建议拆成 6 类 contract
1. 世界图谱 contract
2. 角色叙事档案 contract
3. 章节解锁 contract
4. 场景导演 contract
5. 叙事载体意图 contract
6. 回响总结 contract
## 13.2 contract 总原则
1. AI 只拿当前阶段需要的最小上下文
2. AI 不直接决定数值、库存、状态迁移、任务合法性
3. AI 输出优先是“意图 / 钩子 / 视角 / 叙事指纹”,不是庞大成品对象
4. 所有未解锁信息都不能被默认注入
## 14. 与当前仓库的接入方式
这套引擎并不是脱离当前项目另起炉灶,而是可以沿着已有骨架往前升级。
## 14.1 可直接复用的现有基础
1. `customWorld.ts`
- 已有世界生成骨架,可升级成“世界图谱 + 角色叙事档案”生成入口。
2. `prompt.ts`
- 已有上下文组织能力,可升级成“基于可见性切片”的 prompt 裁剪器。
3. `questDirector.ts`
- 已有任务导演方向,可升级成“线程 -> 合约 -> 信号”的推进器。
4. `runtimeItemDirector.ts` / `runtimeItemNarrative.ts`
- 已有运行时奖励与叙事包装能力,可升级成“叙事载体编译器”。
5. `npcInteractions.ts`
- 已有关系状态和首遇逻辑,可升级成“关系与披露双轴控制器”。
## 14.2 建议新增的模块
- `src/services/storyEngine/themePack.ts`
- `src/services/storyEngine/worldStoryGraph.ts`
- `src/services/storyEngine/visibilityEngine.ts`
- `src/services/storyEngine/actorNarrativeDossier.ts`
- `src/services/storyEngine/sceneNarrativeDirector.ts`
- `src/services/storyEngine/carrierNarrativeCompiler.ts`
- `src/services/storyEngine/echoMemory.ts`
## 15. 验收标准
这套引擎至少要满足下面这些标准,才能算“跨题材 AI 原生剧情引擎”而不是“某一类题材文案增强器”。
1. 同一套引擎在至少 3 种明显不同的题材包里都能产出结构稳定的世界线程、角色秘密与叙事载体。
2. 低关系角色在不同题材下都能做到“有压力、有错位、有暗线钩子”,而不是只会变冷淡。
3. 未解锁信息不会在首遇、低披露或无关场景中提前进入 prompt。
4. 至少 `80%` 的重点叙事载体都能被玩家看出与某条故事线程、某个旧伤或某个角色关系有关。
5. 玩家在不看后台数据的情况下,仍能通过角色、物件、地点、任务描述拼出世界里的明线与暗线。
6. 新增一个题材时,主要工作量集中在 `ThemePack` 与词汇适配,而不是重写剧情主逻辑。
## 16. 推荐落地顺序
## 阶段 A先做引擎底层不先卷文案
先补:
- 世界图谱
- 可见性切片
- 角色叙事档案
## 阶段 B再接当前项目最需要的两个落点
1. 大世界 NPC 背景与首遇表达
2. 运行时物件名称、描述与回响
## 阶段 C再把任务、地点、关系、载体接成一张网
重点做:
- 线程推进
- 合约生成
- 信号触发
- 回响回写
## 阶段 D最后做多题材验证
至少选 3 种差异足够大的题材做压力测试:
1. 高奇幻 / 武侠神话类
2. 科幻 / 调查类
3. 悬疑 / 恐怖 / 校园 / 现代类
## 17. 最后结论
真正可复用的 AI 原生剧情引擎,不应该先问“这句像不像某个题材”,而应该先问:
1. 世界有哪些正在运行的明线和暗线?
2. 谁知道什么?谁不肯说什么?谁在承受什么?
3. 哪些角色、地点、物件、证物正在共同讲同一件事?
4. 当前这一轮,玩家应该感到的是压力、怀疑、诱惑、误导,还是揭示?
只有当这些问题被引擎层回答清楚之后,不同题材的外观、词汇和风格,才会真正长在同一套 AI 原生剧情框架之上。

View File

@@ -0,0 +1,724 @@
# AI 原生自定义世界生成流程优化 PRD
更新时间:`2026-04-06`
## 0. 文档目的
这份 PRD 用于基于 [CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md](../design/CUSTOM_WORLD_CREATOR_INPUT_AND_AI_BOUNDARY_DESIGN_2026-04-06.md) 的分工结论,系统优化当前自定义世界生成流程。
目标不是推翻当前已经存在的多阶段生成链,而是解决下面这个核心错位:
**当前仓库已经开始把世界生成拆成 `framework -> themePack -> storyGraph -> role outline -> dossier -> narrativeProfile` 的分阶段 AI 编译流程,但创作者入口仍然是“一段大文本”,结果页又把大量低杠杆字段重新扔回给创作者人工兜底。**
一句话定义本次优化:
**让创作者先定义世界灵魂锚点,再让 AI / 系统围绕锚点分层生成、分层展开、分层可控地完成长尾内容。**
## 1. 当前流程现状
## 1.1 当前用户流程
当前自定义世界的实际产品链路大致是:
1. 世界选择页点击“创建自定义世界”
2. 弹出创建弹窗,只输入一段 `世界设定文本`
3. 调用 `generateCustomWorldProfile(...)`
4. 进入分阶段生成页,依次跑:
- 世界框架
- 题材适配层
- 世界线程图谱
- 可扮演角色骨架
- 场景角色骨架
- 场景骨架
- 场景连接
- 角色叙事补全
- 角色档案补全
- 角色叙事档案补全
- 最终归档
5. 生成完成后进入结果页
6. 在结果页里按 `世界 / 可扮演角色 / 场景角色 / 场景` 四个页签逐项编辑
7. 保存并进入世界
对应当前仓库的主要模块:
- 输入入口:`src/components/SelectionCustomizationModals.tsx`
- 预开局流程:`src/components/game-shell/PreGameSelectionFlow.tsx`
- 分阶段生成:`src/services/ai.ts`
- prompt 与结构归一:`src/services/customWorld.ts`
- 扩展与编译:`src/services/customWorldBuilder.ts`
- 结果页:`src/components/CustomWorldResultView.tsx`
- 结果目录:`src/components/CustomWorldEntityCatalog.tsx`
- 实体编辑器:`src/components/CustomWorldEntityEditorModal.tsx`
## 1.2 当前流程已经做对了什么
当前流程并不是“完全错误”,它已经有几个很值得保留的基础:
1. 生成链已经不是单次大 JSON 直出,而是分阶段生成。
2. 已经存在 `themePack / storyGraph / narrativeProfile / knowledgeFacts / threadContracts` 这类更接近 AI 原生剧情引擎的结构。
3. 已经有阶段进度反馈,而不是黑盒等待。
4. 已经有结果页与人工编辑能力,可以作为后续工作台的基础。
5. 已经有 normalize / fallback / repair prompt 机制,说明链路具备继续工程化的基础。
本次优化应尽量复用这些已有能力,而不是回到“单次 prompt 直接生世界”的旧思路。
## 1.3 当前流程的核心问题
## 1.3.1 创作者入口过于粗糙
当前创建入口只有一块大文本输入框。
这会直接导致:
1. 不会写长描述的用户很难开局。
2. 愿意精细创作的用户没有结构化落点。
3. 系统无法明确分辨“哪些是创作者真正想锁定的锚点,哪些只是随口补充的描述”。
结果就是:
**输入端自由但信息信号不稳定AI 虽然能生成很多内容,却不一定生成的是创作者真正关心的内容。**
## 1.3.2 创作者与 AI 的职责发生倒置
当前流程实际上是:
- 创作者先写一段泛化设定
- AI 再把整个世界铺满
- 创作者最后回到结果页,人工修改大量角色、章节、技能、初始物品、场景连接等细节
这与“低创作门槛、高创作自由度”的目标相反。
因为真正应该由创作者控制的,是:
- 世界核心命题
- 主题与气质
- 玩家视角
- 核心冲突
- 关键角色
- 关键地点
- 标志性物件 / 怪物 / 禁忌
而不是让创作者在结果页里逐个补:
- `backstoryReveal.chapters`
- `skills`
- `initialItems`
- `sceneNpcIds`
- `connections`
- 各类长尾角色与场景的细枝末节
## 1.3.3 关键内容与长尾内容没有分层
当前流程会稳定生成:
- `5` 个可扮演角色
- `25+` 个场景角色
- `10+` 个场景
问题不在数量本身,而在于系统并没有明确区分:
1. 哪些是创作者应重点塑造的关键对象
2. 哪些只是 AI 应自动展开的长尾铺量
这会导致两个问题:
1. AI 在早期就花大量成本生成长尾内容,等待时间长。
2. 创作者在结果页里面对的是一整套“全部都生成了”的世界,而不是“先抓关键锚点,再决定是否继续铺开”。
## 1.3.4 当前结果页暴露了过多低杠杆字段
当前结果页和实体编辑器允许编辑的字段过多,而且很多是低创作价值、系统结构化字段:
- 背景章节的标题、阈值、teaser、content、contextSnippet
- 角色技能与初始物品
- 场景 NPC 分配
- 场景连接网络
这对“专业创作者”当然有帮助,但对目标用户来说,容易把工具变成:
**看起来自由度很高,实际上需要承担很多系统编辑工作。**
## 1.3.5 当前重新生成是“整世界覆盖式”的
当前结果页的“重新生成”会清空并重做当前世界的所有信息。
这意味着:
1. 创作者一旦修改过内容,就会担心被覆盖。
2. 没有“锁定关键内容,只重生成长尾部分”的机制。
3. AI 无法真正成为创作搭档,只像一次性大批量生成器。
## 1.3.6 当前生成阶段是“模型视角”,不是“创作者视角”
当前生成页展示的是系统批次和阶段进度,这很好,但它主要回答的是:
- 现在模型在跑哪一步
没有回答的是:
- 创作者最关心的关键角色是否已经成型
- 世界冲突是否已经稳定
- 当前这轮已经锁定了哪些核心创意
- 接下来生成的是关键锚点,还是长尾内容
也就是说:
**当前链路的进度可见了,但创作过程仍然没有真正可见。**
## 2. 本次优化的设计目标
这次优化要同时满足 6 个目标:
1. 降低输入门槛
- 不要求创作者一上来写长文,不要求理解系统字段。
2. 提高高杠杆创作自由度
- 让创作者直接控制世界灵魂锚点,而不是低价值细节。
3. 明确创作者与 AI 的职责边界
- 创作者负责“决定什么值得创作”AI 负责“把它展开并跑起来”。
4. 保留现有分阶段生成骨架
- 不推翻 `framework -> themePack -> storyGraph -> role/landmark` 的已有结构。
5. 引入锁定与局部重生成
- 让创作者能保住自己在乎的内容,只重做其余部分。
6. 把结果页从“数据总表”升级成“创作工作台”
- 让编辑界面按创作价值组织,而不是按底层对象堆字段。
## 3. 核心产品结论
优化后的自定义世界流程应该改为:
```text
创作者输入世界锚点
-> AI 编译创作者意图摘要
-> 创作者确认 / 锁定关键锚点
-> AI 先生成关键角色与关键地点
-> 创作者可局部修改 / 局部重生成
-> AI 再展开长尾 NPC、长尾场景与运行时编译结构
-> 结果页以“锚点 / 关键对象 / 扩展内容 / 运行时摘要”方式组织
-> 保存并进入世界
```
一句话:
**先做创作决策,再做内容展开;先做关键对象,再做长尾铺量;先让创作者锁定灵魂,再让 AI 扩散世界。**
## 4. 输入层优化方案
## 4.1 把“单一大文本”升级为“创作卡片”
新的输入层不应只有一块大 textarea而应拆成卡片式输入。
建议至少包含 9 张卡:
1. 世界一句话
2. 主题与气质
3. 玩家是谁
4. 核心冲突
5. 关键势力
6. 关键角色
7. 关键地点
8. 标志性要素
9. 禁止事项
每张卡都支持:
1. 一句话输入
2. 标签 / 选项辅助
3. 高级补充展开
这样做的目的不是让用户填更多,而是让:
- 不会写长文的人,也能靠卡片完成创作输入
- 愿意深挖的人,也有明确位置继续提升质量
## 4.2 保留“自由输入模式”,但不再只靠它
当前的 `settingText` 不应被废弃,而应保留为:
1. 快速模式
2. 导入模式
3. 兜底模式
系统应支持两种输入入口:
1. 快速文本模式
- 用户只写一段设定,系统自动拆分成创作卡片建议
2. 卡片模式
- 用户直接按结构化方式输入世界锚点
两种模式最终都编译成统一的创作者意图对象。
## 4.3 必填与选填要分开
不应要求用户每一张卡都填完。
建议:
- 必填:
- 世界一句话
- 主题与气质
- 玩家是谁
- 核心冲突
- 选填:
- 关键势力
- 关键角色
- 关键地点
- 标志性要素
- 禁止事项
这样既能保证世界最小成型,又不会把创作者门槛抬高。
## 4.3.1 抽象统一“聊天补充设定”能力
RPG 创作工作台、拼图创作工作台、大鱼吃小鱼创作工作台都应走同一套“聊天补充设定”能力,而不是各自维护按钮、提交 payload 和自动补全规则。
统一能力需要覆盖:
1. 普通聊天提交:只携带用户输入文本与统一生成的 `clientMessageId`
2. 总结当前设定:快捷动作统一展示为“总结当前设定”,但总结消息允许各玩法保留领域文案。
3. 补充剩余设定:快捷动作统一展示为“补充剩余设定”,并统一进入自动补全模式。
用户完成至少两轮对话后,工作台展示“补充剩余设定”快捷操作。点击后前端只发送一次聊天消息,不再弹出额外表单或追问面板:
- 消息文本固定为 `请补充剩余设定。`
- 请求必须携带 `quickFillRequested: true`
- `focusCardId` 固定为空,`selectedCardIds` 固定为空数组
后端各玩法 Agent 收到 `quickFillRequested: true` 后必须进入强制补全模式,并复用统一公共规则:
1. 不再继续向用户追问缺失设定。
2. 基于已有对话与已推断卡片自行补齐剩余关键字。
3. 输出可进入对应生成结果的完整结构。
4. 将进度推进到可提交状态,避免用户点击后仍停留在问答循环。
三入口只允许保留领域差异:聊天消息 ID 前缀、总结文案、最终生成按钮名称、领域 payload 额外字段、领域 prompt 对“缺失内容范围”的补充说明。除此之外,聊天动作的展示、触发语义与自动补全硬规则必须统一维护。
## 4.4 明确支持“锁定”
每张卡片、每个关键角色、每个关键地点都应支持锁定。
锁定后:
1. AI 不得在重生成时覆盖该内容
2. 长尾内容只能围绕它展开
3. 结果页里应明确显示其为“创作者锚点”
## 5. 生成链路优化方案
## 5.1 新增“创作者意图编译层”
在真正开始世界生成前,先新增一个轻量阶段:
**Creator Intent Compile**
输入:
- 文本模式输入
- 或卡片模式输入
输出:
- 创作者意图摘要
- 世界锚点摘要
- 系统识别出的关键角色 / 冲突 / 地点 / 禁忌
这一步的作用不是生成世界,而是先回答:
1. 系统理解到的世界核心是什么
2. 哪些内容将被视为创作者强锚点
3. 哪些内容将交给 AI 扩展
## 5.2 把当前生成链改成“关键先行、长尾后补”
当前 `generateCustomWorldProfile(...)` 的分阶段结构可以保留,但生成顺序需要更创作者化。
建议改成 5 层:
### 第一层:世界锚点层
先生成:
- 世界框架
- ThemePack
- StoryGraph 的基础版
- 创作者锚点摘要
这一层完成后,系统应能让创作者看到:
- 世界现在到底被理解成了什么
- 哪些冲突 / 势力 / 意象被识别出来了
### 第二层:关键对象层
优先生成:
- 关键可扮演角色
- 关键场景角色
- 关键地点
这一层优先围绕创作者明确输入的角色和地点,而不是先铺满全部数量。
### 第三层:创作者校对层
在继续展开长尾内容前,应允许创作者做一次轻量校对:
- 确认关键角色是否对
- 确认关键地点是否对
- 锁定已经满意的内容
- 对不满意的关键对象做局部重生成
### 第四层:长尾展开层
在关键层稳定后,再生成:
- 普通场景角色
- 路人 / 杂兵 / 补位 NPC
- 次级地点
- 扩展连接关系
- 长尾命名和描述
### 第五层:运行时编译层
最后再编译:
- `themePack`
- `storyGraph`
- `knowledgeFacts`
- `threadContracts`
- `narrativeProfile`
- 各类运行时支持结构
## 5.3 支持“快速开局生成”和“完整展开生成”
建议提供两种生成策略:
1. 快速开局
- 先完成世界锚点 + 关键对象 + 最小可玩档案
- 用户可以更快看到世界雏形
2. 完整展开
- 一次性继续补齐长尾场景角色、地标和完整世界网络
这样做的价值很高:
1. 降低首次等待焦虑
2. 让创作者更早介入关键对象校正
3. 避免系统在创作方向还没稳定前,先铺满大量长尾内容
## 5.4 角色与场景生成要改成“锚点优先 + 长尾补位”
当前角色与场景的生成方式更像“按配额批量产出”。
优化后应改为:
1. 先生成创作者明确指定的关键角色 / 地点
2. 再根据世界冲突自动补位缺失的角色原型和场景功能位
3. 最后再铺长尾
这样生成出来的世界会更像“围绕创作者意图长出来”,而不是“先生成了一个完整世界,再让创作者去认领”
## 6. 结果页与编辑工作台优化方案
## 6.1 结果页不应再按“底层对象目录”组织为主
当前结果页主要按:
- 世界
- 可扮演角色
- 场景角色
- 场景
来组织。
优化后建议改成 4 层工作台:
1. 创作锚点
- 展示创作者输入和锁定内容
2. 关键对象
- 关键角色、关键地点、关键冲突对象
3. 扩展内容
- AI 自动展开的长尾角色、长尾地点、补位内容
4. 世界编译摘要
- 展示世界线程、题材包、运行时摘要,但默认不要求创作者编辑
## 6.2 编辑界面应遵守“高价值字段前置,低价值字段折叠”
对创作者默认暴露的应是:
- 角色一句话定位
- 角色表面面貌
- 角色真正想要什么
- 角色与谁有关
- 地点为什么重要
- 地点承载什么冲突
- 世界哪些规则不能动
不应默认把下面这些字段摆在第一屏:
- `backstoryReveal.chapters`
- `skills`
- `initialItems`
- `contextSnippet`
- `sceneNpcIds`
- `connections`
这些应被系统下沉到:
- 自动生成
- 高级模式
- 或局部展开区域
## 6.3 新增局部重生成
结果页必须支持至少 4 种局部重生成:
1. 仅重生成某个关键角色
2. 仅重生成某个关键地点
3. 仅重生成长尾场景角色
4. 仅重生成场景网络 / 长尾连接
并且所有局部重生成都必须:
- 尊重锁定内容
- 显示影响范围
- 避免全局覆盖
## 6.4 新增“AI 建议修订”而非“只允许手改”
结果页不应只提供人工编辑,还应提供:
- 让 AI 重写一句话定位
- 让 AI 补强冲突张力
- 让 AI 改得更克制 / 更黑暗 / 更传奇 / 更现实
- 让 AI 只围绕已锁定内容变体
这样才能真正体现“AI 是创作辅助,而不是一次性生成器”。
## 7. 数据结构建议
## 7.1 新增 `CustomWorldCreatorIntent`
建议新增创作者输入的统一结构:
```ts
interface CustomWorldCreatorIntent {
sourceMode: 'freeform' | 'card';
rawSettingText: string;
worldHook: string;
themeKeywords: string[];
toneDirectives: string[];
playerPremise: string;
openingSituation: string;
coreConflicts: string[];
keyFactions: CreatorFactionSeed[];
keyCharacters: CreatorCharacterSeed[];
keyLandmarks: CreatorLandmarkSeed[];
iconicElements: string[];
forbiddenDirectives: string[];
}
```
作用:
- 把“创作者真正输入了什么”从最终 `CustomWorldProfile` 中分离出来
## 7.2 新增 `CustomWorldAnchorPack`
建议新增系统编译后的锚点包:
```ts
interface CustomWorldAnchorPack {
worldSummary: string;
creatorIntentSummary: string;
lockedAnchorIds: string[];
keyConflictSummaries: string[];
keyFactionSummaries: string[];
keyCharacterAnchors: ActorAnchor[];
keyLandmarkAnchors: LandmarkAnchor[];
motifDirectives: string[];
}
```
作用:
- 让后续长尾扩展、局部重生成、结果页工作台都围绕同一套“创作锚点”工作
## 7.3 新增 `CustomWorldLockState`
```ts
interface CustomWorldLockState {
worldLockedFields: string[];
lockedCharacterIds: string[];
lockedLandmarkIds: string[];
lockedConflictIds: string[];
lockedFactionIds: string[];
}
```
作用:
- 明确哪些内容 AI 不能重写
## 7.4 新增 `CustomWorldGenerationDraft`
```ts
interface CustomWorldGenerationDraft {
creatorIntent: CustomWorldCreatorIntent;
anchorPack: CustomWorldAnchorPack | null;
profile: CustomWorldProfile | null;
lockState: CustomWorldLockState;
generationMode: 'fast' | 'full';
generationStatus: 'idle' | 'compiling' | 'generating_key' | 'generating_long_tail' | 'ready';
}
```
作用:
- 让“创作者输入、AI 编译、结果编辑”成为连续工作流,而不是只有最终成品对象
## 8. 与当前仓库的接入建议
## 8.1 输入层
优先改:
- `src/components/SelectionCustomizationModals.tsx`
- `src/components/game-shell/PreGameSelectionFlow.tsx`
目标:
- 把单 textarea 升级为“快速模式 + 卡片模式”
- 新增创作者意图状态
- 新增锁定和局部重生成入口
## 8.2 prompt 与生成服务层
优先改:
- `src/services/customWorld.ts`
- `src/services/ai.ts`
目标:
- 新增 Creator Intent Compile prompt
- 新增 Anchor Pack compile prompt
- 新增局部重生成 prompt
- 保留现有 `framework / themePack / storyGraph / role / landmark` 生成骨架
## 8.3 Builder 与结构层
优先改:
- `src/services/customWorldBuilder.ts`
- `src/types/customWorld.ts`
目标:
-`CustomWorldProfile` 增加创作者意图与锚点相关扩展字段
- 保持旧档兼容
- 让现有 builder 能同时消费 `creatorIntent + anchorPack + profile seed`
## 8.4 结果页与编辑器层
优先改:
- `src/components/CustomWorldResultView.tsx`
- `src/components/CustomWorldEntityCatalog.tsx`
- `src/components/CustomWorldEntityEditorModal.tsx`
目标:
- 结果页由“数据目录”转为“创作工作台”
- 支持局部重生成
- 高价值字段前置,低价值字段折叠
- 允许 AI 辅助改写,而不只是手工编辑
## 9. 明确不做什么
本次优化不做以下事情:
1. 不推翻当前自定义世界最终输出仍是 `CustomWorldProfile` 的兼容目标
2. 不把所有运行时结构都暴露给创作者直接编辑
3. 不要求创作者理解 `themePack / storyGraph / knowledgeFacts / threadContracts` 等系统结构
4. 不把复杂数值平衡、掉落预算、build 预算转移给创作者
5. 不把“高自由度”理解成“所有字段都手工可改”
## 10. 验收标准
做到以下几点,才算这次优化真正成立:
1. 创作者可以不用写长文,只靠卡片输入也能完成自定义世界创建。
2. 系统会明确区分“创作者锚点”和“AI 自动展开内容”。
3. 创作者不再需要默认手改大量 `skills / initialItems / backstoryReveal / scene connections` 才能得到可用世界。
4. 结果页支持锁定关键角色、关键地点、关键冲突,并支持局部重生成。
5. 重新生成不再默认覆盖整个世界。
6. 当前 `framework -> themePack -> storyGraph -> role/landmark` 生成主链可以继续复用,而不是被废弃。
7. 结果页默认展示的是高创作价值对象,而不是系统级低层字段。
8. 长尾内容生成明显后置于关键对象生成,创作者能更早看到并修正关键对象。
9. 旧的自由文本输入模式仍然可用,但不再是唯一入口。
## 11. 推荐落地顺序
## 阶段 A先加创作者意图层
先做:
- `CustomWorldCreatorIntent`
- 输入卡片 UI
- 快速文本 -> 卡片建议编译
目标:
- 先把创作者输入从“单一大文本”升级成“可识别的创作锚点”
## 阶段 B再加锚点包与锁定能力
先做:
- `CustomWorldAnchorPack`
- `CustomWorldLockState`
- 锁定 UI
目标:
- 让后续生成真正知道“哪些不能动”
## 阶段 C再改生成顺序
先做:
- 关键对象优先
- 长尾内容后置
- 快速开局模式
目标:
- 缩短“看到关键结果”的等待时间
## 阶段 D最后重做结果页工作台
先做:
- 锚点页
- 关键对象页
- 扩展内容页
- 局部重生成
目标:
- 让结果页真正成为创作工具,而不是人工补表页面
## 12. 一句话结论
当前自定义世界流程最需要优化的,不是“让 AI 再多生成一点内容”,而是:
**把创作者从低价值字段编辑里解放出来,让创作者负责世界灵魂锚点,让 AI 负责围绕这些锚点分层生成、分层展开、分层可控地把世界长出来。**

View File

@@ -0,0 +1,959 @@
# AI 原生自定义世界创作页面 PRD
更新时间:`2026-04-20`
## 0. 文档目的
这份 PRD 用于定义一个新的、独立的“自定义世界创作页面”。
目标不是继续沿用当前“世界选择页里弹出创建弹窗”的旧流程,而是把“创作入口”和“历史作品管理”正式从世界选择页中抽出来,形成一个专门承接创作行为的页面。
这份 PRD 要解决的核心问题是:
**当用户在世界选择页点击“创建自定义世界”后,不应该立刻被丢进一个弹窗或某个具体工作流,而应该先进入一个专门的创作页面,在这里完成:**
1. 新建作品
2. 继续创作草稿
3. 查看历史已发布作品
4. 从创作页面进入具体 Agent 创作工作区
一句话目标:
**让“创作自定义世界”从一个一次性动作,升级成一个正式的创作入口与作品管理入口。**
---
## 1. 当前问题
## 1.1 当前创建入口过于直接
当前链路是:
```text
世界选择页
-> 点击创建自定义世界
-> 直接打开创建弹窗
```
这会带来几个问题:
1. 入口太窄
- 用户只有“立刻创建”这一个选择,没有“先看看历史作品”“继续草稿”的缓冲页。
2. 创作与管理没有分层
- 新建、继续创作、查看已发布作品都混在世界选择页这个入口层里。
3. 后续 Agent 工作区不好接
- 如果直接从世界选择页跳进 Agent session用户缺少“这是一个创作空间”的过渡。
## 1.2 历史作品入口不完整
当前世界选择页里虽然能展示已保存的自定义世界,但它更像“世界卡片列表”,不是一个真正的创作历史页。
缺口主要有:
1. 草稿和已发布作品没有统一视图
2. 草稿没有正式“继续创作”入口体系
3. 已发布作品只是“世界库内容”,不是“创作成果”
4. 用户看不到自己的创作历史全貌
## 1.3 未来 Agent 工作区缺少前置首页
后续 Agent-first 创作工具一定会有:
1. 草稿 session
2. 已发布世界
3. 继续创作入口
4. 发布后的回看入口
如果没有一个专门的创作页面,这些入口只能继续塞在:
- 世界选择页
- 结果页
- 临时 modal
最终会让流程越来越乱。
---
## 2. 产品目标
这次要做的创作页面,必须同时满足 6 个目标:
1. 把“新建作品”和“管理作品”放到同一入口里
2. 支持同时展示草稿和已发布作品
3. 让用户从世界选择页进入后,先感知到“这里是创作空间”
4. 为后续 Agent 创作工作区提供稳定前置页
5. 保持移动端优先,界面清爽,不堆规则说明
6. 前端只负责展示和跳转,数据聚合与状态归类全部交给后端
---
## 3. 核心结论
新的用户主链应该改成:
```text
世界选择页
-> 点击“创建自定义世界”
-> 进入“创作页面”
-> 用户选择:
- 新建作品
- 继续创作草稿
- 查看已发布作品
-> 再进入具体 Agent 工作区或正式世界
```
一句话:
**创作页面是“创作中心”,不是“又一个创建弹窗”。**
---
## 4. 页面定位
## 4.1 页面名称
建议名称:
`创作页面`
UI 主标题建议:
`自定义世界创作`
## 4.2 页面职责
这个页面只负责 4 件事:
1. 提供“新建作品”入口
2. 列出用户历史草稿
3. 列出用户已发布作品
4. 把用户带到正确的下一步页面
这个页面不负责:
1. 直接进行世界锚点编辑
2. 直接进行 Agent 长对话创作
3. 直接进行结果页细改
4. 直接发布作品
也就是说:
**它是创作首页,不是创作工作区本体。**
---
## 5. 用户流程
## 5.1 世界选择页进入创作页面
当前世界选择页里的“创建自定义世界”按钮行为改为:
```text
点击创建自定义世界
-> 不再打开旧 modal
-> 进入 custom-world-home
```
第一阶段只要求:
1. 进入专门创作页面
2. 能看到新建入口和历史作品
## 5.2 在创作页面新建作品
流程:
```text
创作页面
-> 点击“新建作品”
-> 在首屏新建作品卡片中直接选择游戏创作模板
-> 创建新的 Agent session
-> 进入 custom-world-agent
```
说明:
- 新建作品依然走 Agent session 主链
- 创作页面不自己生成世界
- 可创建玩法模板直接露出在首屏卡片中,不再额外弹一次类型 launcher
## 5.3 在创作页面继续草稿
流程:
```text
创作页面
-> 点击草稿卡片的“继续创作”
-> 打开该 session
-> 进入 custom-world-agent
```
## 5.4 在创作页面查看已发布作品
已发布作品卡片支持两种动作:
1. `进入世界`
2. `查看作品`
说明:
- `进入世界` 直接进入当前已发布世界
- `查看作品` 进入只读详情页或结果总览页
第一版如果不单独做只读详情页,可先只保留:
1. `进入世界`
但卡片展示层必须把“它是已发布作品”表达清楚。
---
## 6. 信息架构
## 6.1 页面整体结构
创作页面必须包含 4 个区域:
1. 首屏新建作品区
2. 新建作品区
3. 历史作品筛选区
4. 作品列表区
## 6.2 首屏新建作品区
这是页面首屏最高优先级区域,默认不再单独展示返回按钮和“创作中心 / 自定义世界创作”标题,直接把注意力留给可创建模板与作品列表。
必须包含:
1. `新建作品` 主标题
2. 一段极短说明文案
3. 游戏创作模板快捷卡片
模板卡片要求:
1. 直接展示当前可创建玩法,如 `角色扮演 RPG``大鱼吃小鱼``拼图玩法`
2. 锁定中的玩法保留占位,但必须显式禁用
3. 点击可创建玩法后直接进入对应创作工作台,不再额外弹二次选择面板
说明文案要求:
1. 只一两句
2. 不要写规则说明
3. 不要写长解释
推荐文案方向:
- `直接选择游戏创作模板,立刻进入对应的共创工作台。`
## 6.3 历史作品筛选区
建议用 3 个 tab
1. `全部`
2. `草稿`
3. `已发布`
默认:
- `全部`
第一版不强制上搜索框,但如果作品数超过 `8` 个,建议补搜索。
## 6.4 作品列表区
列表区统一展示作品卡片,但卡片要区分两类:
1. 草稿卡片
2. 已发布卡片
默认排序:
-`updatedAt desc`
---
## 7. 作品卡片定义
## 7.1 草稿卡片
草稿卡片必须展示:
1. 标题
2. 草稿状态标识
3. 最近更新时间
4. 当前阶段标签
5. 简短摘要
6. 封面图
7. 主要操作按钮
### 标题规则
按优先级取:
1. `draftProfile.name`
2. `anchorPack.worldSummary`
3. `creatorIntent.worldHook`
4. `未命名草稿`
### 摘要规则
按优先级取:
1. `anchorPack.creatorIntentSummary`
2. `creatorIntent.rawSettingText`
3. 默认摘要占位文本
### 封面图规则
按优先级取:
1. `draftProfile.cover.imageSrc`,当 `sourceType``uploaded / generated`
2. `draftProfile.sceneChapterBlueprints[0].acts[0].backgroundImageSrc` 作为默认封面底图
3. 默认封面底图上叠加 `draftProfile.cover.characterRoleIds` 对应的角色主形象
4. 若未显式指定角色,则按 `playableNpcs` 顺序取前 `3` 个有主图的角色
5. 若开局场景第一幕图片为空,则依次回退到 `draftProfile.camp.imageSrc`、首个 `landmark.imageSrc`、首个角色主图或默认占位图
### 草稿卡片主操作
第一版必须有:
1. `继续创作`
可选:
1. `删除草稿`
2. `复制草稿`
第一版如来不及,可不做删除和复制,但接口结构应预留。
## 7.2 已发布卡片
已发布卡片必须展示:
1. 世界名称
2. 已发布标识
3. 发布时间或更新时间
4. 世界摘要
5. 封面图
6. 主要操作按钮
### 标题规则
直接取:
1. `CustomWorldProfile.name`
### 摘要规则
直接取:
1. `CustomWorldProfile.summary`
### 封面图规则
按优先级取:
1. `CustomWorldProfile.cover.imageSrc`,当 `sourceType``uploaded / generated`
2. 开局场景第一幕图片作为默认封面底图
3. 默认封面底图上叠加 `cover.characterRoleIds` 指定的角色主形象
4. 若未显式指定角色,则按 `playableNpcs` 顺序取前 `3` 个有主图的角色
5. 若默认底图不可用,则依次回退到 `camp.imageSrc`、首个 `landmark.imageSrc`、第一可扮演角色立绘或默认占位图
## 7.3 作品封面属性
作品必须新增显式封面属性,作为作者可编辑的作品资产,而不再只靠“卡片展示时临时猜一张图”。
建议字段:
```ts
type CustomWorldCoverSourceType = 'default' | 'uploaded' | 'generated';
interface CustomWorldCoverProfile {
sourceType: CustomWorldCoverSourceType;
imageSrc?: string | null;
characterRoleIds?: string[];
}
```
字段含义:
1. `sourceType = default`
- 表示继续使用系统默认封面布局
- `imageSrc` 不作为最终封面图使用
- 底图固定优先取“开局场景第一幕图片”
- 前景角色取 `characterRoleIds`
2. `sourceType = uploaded`
- 表示作者直接上传了一张最终封面
- 卡片与详情页直接显示 `imageSrc`
- 不再叠加默认角色前景
3. `sourceType = generated`
- 表示作者通过 AI 生成了一张最终封面
- 卡片与详情页直接显示 `imageSrc`
- 不再叠加默认角色前景
- 生成时允许作者补一句封面描述,系统会结合世界主题、场景素材、角色素材共同构图
## 7.4 默认封面布局
默认封面布局不是单纯“取开局场景图”,而是:
```text
开局场景第一幕图片
+ 前景主角色主形象 2~3 个
+ 用于列表卡片和作品详情的统一封面预览
```
明确规则:
1. 默认封面底图固定优先取 `sceneChapterBlueprints[0].acts[0].backgroundImageSrc`
2. 若开局场景第一幕图片不存在,则依次回退到 `camp.imageSrc` 与首个 `landmark.imageSrc`
3. 默认前景角色固定从 `playableNpcs` 中取前 `3` 个有主图的角色
4. 若作者在 `cover.characterRoleIds` 中显式指定角色,则优先按指定顺序展示
5. 前端只负责把后端给出的“底图 + 角色主图列表”渲染成封面,不在前端做封面规则推理
6. 已上传或已生成的最终封面,直接作为成品图显示,不再做默认布局叠加
## 7.5 作者操作
作者在作品编辑态至少支持 4 个动作:
1. `使用默认封面`
2. `上传封面`
3. `AI 生成封面`
4. `重置为默认`
约束:
1. 上传和 AI 生成都必须把最终图片落到后端资产目录,前端不能长期持有 Data URL 作为作品封面
2. 重置为默认后,`sourceType` 回到 `default`
3. 草稿与已发布作品都读取同一份封面属性,不允许出现“草稿页是一个封面、发布后又自动换另一张”的漂移
## 7.6 AI 封面生成与上传约束
### AI 生成输入
作者点击 `AI 生成封面` 后,面板至少支持 3 类输入:
1. 一句封面图描述
2. 可选参考图
3. 角色出镜选择
系统生成封面时,后端必须自动拼接以下上下文,而不是只吃用户那一句描述:
1. 世界名、副标题、世界概述、主题基调、玩家目标
2. 开局场景第一幕标题、摘要、背景图
3. 营地图与关键场景图
4. 可扮演角色主形象
5. 已选择的封面角色顺序
结论:
**封面 AI 生成必须是“用户一句描述 + 系统世界素材拼接”的生成链,而不是裸 prompt。**
### AI 生成结果要求
1. 默认生成尺寸固定为 `16:9`
2. 第一版统一生成 `1600 × 900`
3. 结果图不允许出现标题字、水印、按钮、UI 边框
4. 结果图要优先满足移动端卡片裁切后的主体可读性
5. 结果图保存后直接写入作品封面资产目录
### 上传封面要求
作者点击 `上传封面` 后,不能直接把原图原样落库,必须经过独立裁剪面板处理。
裁剪链路要求:
1. 上传后先进入独立裁剪面板
2. 裁剪框比例固定为 `16:9`
3. 作者只能平移和缩放,不允许自由改比例
4. 裁剪完成后,再提交给后端保存
### 上传大小与格式限制
第一版约束:
1. 仅支持 `png / jpg / webp`
2. 上传原图大小上限固定为 `10 MB`
3. 后端落库前必须统一裁剪并缩放到 `1600 × 900`
4. 后端保存时需要做体积压缩,目标成品图不超过 `1.5 MB`
5. 若压缩后仍超过限制,返回明确错误,不允许静默保存超标文件
### 前后端分工
1. 前端负责提供裁剪交互、预览与提交裁剪框
2. 后端负责最终裁剪、缩放、压缩和大小校验
3. 前端不能直接把本地裁剪结果当最终事实来源
4. 同一张上传封面在草稿页、作品库、详情页必须读取同一后端成品地址
### 已发布卡片主操作
第一版必须有:
1. `进入世界`
可选:
1. `查看作品`
2. `基于此作品继续创作`
第一版不强制做“基于已发布作品继续创作”,避免先把发布后再开草稿链带复杂。
---
## 8. 作品摘要数据结构
## 8.1 新增统一作品摘要结构
建议新增:
```ts
type CustomWorldWorkStatus = 'draft' | 'published';
type CustomWorldWorkSource = 'agent_session' | 'published_profile';
interface CustomWorldWorkSummary {
workId: string;
sourceType: CustomWorldWorkSource;
status: CustomWorldWorkStatus;
title: string;
subtitle: string;
summary: string;
coverImageSrc?: string | null;
coverRenderMode?: 'image' | 'scene_with_roles';
coverCharacterImageSrcs?: string[];
updatedAt: string;
publishedAt?: string | null;
stage?: string | null;
stageLabel?: string | null;
playableNpcCount: number;
landmarkCount: number;
sessionId?: string | null;
profileId?: string | null;
canResume: boolean;
canEnterWorld: boolean;
}
```
## 8.2 字段解释
### `workId`
统一主键,用于前端列表渲染。
建议格式:
- 草稿:`draft:${sessionId}`
- 已发布:`published:${profileId}`
### `sourceType`
用于区分:
1. Agent 草稿 session
2. 已发布 profile
### `status`
只允许两类:
1. `draft`
2. `published`
### `stage / stageLabel`
仅草稿需要。
已发布作品可为空。
### `canResume`
仅草稿为 `true`
### `canEnterWorld`
仅已发布作品为 `true`
### `coverRenderMode / coverCharacterImageSrcs`
用于支撑默认封面布局。
规则:
1. 当作品封面为上传或 AI 生成成图时:
- `coverRenderMode = image`
- `coverCharacterImageSrcs = []`
2. 当作品封面为默认布局时:
- `coverRenderMode = scene_with_roles`
- `coverImageSrc = 开局场景图`
- `coverCharacterImageSrcs = 需要叠加的角色主图列表`
一句话:
**后端负责告诉前端“这张封面该怎么画”,前端只负责把它画出来。**
---
## 9. 后端接口设计
## 9.1 新增作品列表接口
必须新增:
`GET /api/runtime/custom-world/works`
这是创作页面的核心接口。
它负责返回:
1. 当前用户的草稿 session 摘要
2. 当前用户的已发布世界摘要
3. 按统一结构聚合后的作品列表
## 9.2 接口返回结构
```ts
interface ListCustomWorldWorksResponse {
items: CustomWorldWorkSummary[];
}
```
### 第一版要求
1. 后端一次性返回全量列表
2. 前端做 tab 过滤
3. 不做服务端分页
原因:
- 当前用户作品量预计不大
- 先把结构做稳,比先做分页更重要
### 公开浏览与登录边界
创作首页与世界选择页必须拆分两类数据:
1. 公开浏览数据
2. 当前用户私有数据
其中以下接口必须定义为公开只读:
- `GET /api/runtime/custom-world-gallery`
- `GET /api/runtime/custom-world-gallery/:ownerUserId/:profileId`
明确约束:
1. 未登录用户进入世界选择页时,也必须能读取公开作品广场
2. 公开作品广场读取不能依赖 access token也不能因为 refresh 失败返回 401
3. 已发布作品详情允许未登录用户查看
4. 只有“继续创作 / 发布 / 下架 / 删除 / 查看我的草稿 / 查看我的统计”等私有能力必须要求登录
也就是说:
**平台首页要支持“先浏览公开作品,再决定是否登录进入世界或开始创作”。**
## 9.3 数据来源
### 草稿来源
来自:
- `customWorldAgentSessionStore`
筛选规则:
1. `stage !== published`
2. 未被标记为归档 / 删除
### 已发布来源
来自:
- 当前自定义世界库
即:
- `runtimeRepository.listCustomWorldProfiles(userId)`
## 9.4 聚合服务
建议新增服务:
`server-node/src/services/customWorldWorkSummaryService.ts`
职责:
1. 读取草稿 session
2. 读取已发布 profile
3. 编译成统一的 `CustomWorldWorkSummary[]`
### 明确要求
不允许在 route 里直接拼草稿和已发布数据。
---
## 10. 前端页面设计
## 10.1 页面组件
建议新增页面组件:
`src/components/custom-world-home/CustomWorldCreationHub.tsx`
这是新的创作页面主组件。
## 10.2 子组件建议
建议拆成:
1. `CustomWorldCreationHubHeader.tsx`
2. `CustomWorldCreationStartCard.tsx`
3. `CustomWorldWorkTabs.tsx`
4. `CustomWorldWorkCard.tsx`
5. `CustomWorldWorkList.tsx`
6. `CustomWorldCreationHubEmptyState.tsx`
第一版如果不想拆太多,也允许先做成一个主组件加一个作品卡组件。
## 10.3 页面状态
页面至少要支持:
1. `loading`
2. `ready`
3. `error`
4. `empty`
### `loading`
展示骨架屏,不展示空白页。
### `ready`
正常展示:
1. 新建作品区
2. 筛选 tabs
3. 作品列表
### `error`
展示:
1. 错误文案
2. `重试` 按钮
### `empty`
分两类空态:
1. `全量空态`
- 没有任何草稿,也没有已发布作品
2. `筛选空态`
- 比如只看草稿时为空
## 10.4 页面交互
### 新建作品
点击后:
1. 打开 Agent launcher
2. 创建新 session
3. 成功后跳入 Agent workspace
### 草稿卡片点击
主按钮:
1. `继续创作`
触发:
1. 进入 `custom-world-agent`
2.`sessionId`
### 已发布卡片点击
主按钮:
1. `进入世界`
触发:
1. 读取对应 `profile`
2. 调用当前进入世界流程
---
## 11. 与现有流程的接入方式
## 11.1 修改 `SelectionStage`
建议新增:
```ts
type SelectionStage =
| 'start'
| 'world'
| 'custom-world-home'
| 'custom-world-agent'
| ...
```
## 11.2 世界选择页创建按钮改造
当前:
```text
点击创建自定义世界
-> 打开创建 modal
```
改为:
```text
点击创建自定义世界
-> setSelectionStage('custom-world-home')
```
## 11.3 创作页面与 Agent 工作区关系
关系必须明确:
1. 创作页面
- 管理入口
- 新建入口
- 历史作品页
2. Agent 工作区
- 具体创作编辑页
这两个页面不能混成一个组件。
---
## 12. UI 与交互约束
## 12.1 移动端优先
页面默认以移动端竖屏成立。
要求:
1. 新建作品区位于首屏
2. tabs 横向可滚
3. 平台“创作”页中的“我的创作”列表在移动端至少双列展示,不能继续沿用横向滚动卡片的固定宽度
4. 不使用桌面化大表格
5. 双列卡片必须采用紧凑栅格布局,标题、状态、时间允许换行或截断,但不能横向溢出或出现参差错位
## 12.2 页面保持清爽
遵守当前项目约束:
1. 不在页面中堆规则说明
2. 不默认展示很多系统字段
3. 不出现“大型表单式管理后台”感
## 12.3 作品卡信息密度
每张卡默认最多展示:
1. 标题
2. 标签
3. 更新时间
4. 一行摘要
5. 一张封面
6. 一个主按钮
不要默认堆:
1. 大量统计字段
2. 多排操作按钮
3. 技术字段
---
## 13. 明确不做什么
本次创作页面 PRD 不做:
1. 不做完整 Agent 工作区
2. 不做世界底稿生成
3. 不做作品删除确认流
4. 不做作品搜索排序高级功能
5. 不做发布世界管理后台
6. 不做已发布作品的二次派生创作
这些内容后续可接,但不属于本次页面 PRD 核心闭环。
---
## 14. 验收标准
做到以下几点,才算这个创作页面真正成立:
1. 世界选择页点击“创建自定义世界”后,进入的是独立创作页面,不再是旧弹窗。
2. 创作页面能同时展示草稿和已发布作品。
3. 草稿作品可以继续创作。
4. 已发布作品可以进入世界。
5. 新建作品入口可以正确创建 Agent session 并跳转到创作工作区。
6. 页面在移动端首屏可用,信息层级清楚。
7. 草稿与已发布作品都通过后端聚合接口返回,前端不自己拼数据来源。
---
## 15. 推荐落地顺序
## 阶段 A先做后端聚合接口
先做:
1. `GET /api/runtime/custom-world/works`
2. `customWorldWorkSummaryService`
验收:
- 能返回统一的作品摘要数组
## 阶段 B再做前端创作页面
先做:
1. `custom-world-home` stage
2. `CustomWorldCreationHub`
3. 作品卡片和 tabs
验收:
- 能看到新建入口和历史作品
## 阶段 C最后接 Agent workspace 跳转
先做:
1. 新建作品 -> 创建 session -> 进入 workspace
2. 草稿 -> 恢复 session
3. 已发布作品 -> 进入世界
验收:
- 三条主路径都通
---
## 16. 一句话结论
“创建自定义世界”不应该继续只是一个弹窗动作,而应该升级成一个正式的创作入口。
这个创作页面的本质价值,不是多做一个页面,而是把:
- 新建作品
- 继续草稿
- 查看已发布作品
这三类本来分散的行为,正式收口到同一个创作中心里。

View File

@@ -0,0 +1,734 @@
# AI 原生叙事线索驱动的物品命名与大世界 NPC 背景系统 PRD
更新时间:`2026-04-06`
## 0. 目标
这份 PRD 面向当前仓库,解决两个直接影响“故事感”的核心问题:
1. 实时生成的物品名称、描述虽然已经能贴合 build 和来源,但整体仍偏模板拼接,缺少“它背后发生过什么”的故事重量。
2. 大世界生成的 NPC 背景目前更像设定摘要,尤其是初始好感度低的角色,容易只剩“冷淡 / 戒备 / 不说”,却没有真正的戏剧张力和暗线钩子。
本次设计参考《博德之门 3》《黑神话悟空》这类 RPG 的叙事组织方式,但不照搬具体内容,而是提炼出适合当前项目的 4 个目标:
1. 每个 NPC 都不仅有“公开设定”,还要有能被逐步识别的明线、暗线、代价线与回响线。
2. 每个运行时物品都不仅是“当前 build 的奖励”,还要像某件旧事留下的证物、遗物、债物或禁物。
3. 初始好感度低不等于故事薄;低好感角色要更像“有东西不肯说”,而不是“没有东西可说”。
4. AI 继续负责叙事表达与意图,本地规则继续负责数值、合法性、状态迁移与编译。
一句话目标:
**让角色背景、物品名称、物品描述都成为世界主线与暗线的载体,而不是玩法奖励外面包的一层随机文案。**
## 1. 当前问题定位
## 1.1 运行时物品叙事目前仍偏模板拼接
当前实现已经有 `runtimeItemContext -> runtimeItemDirector -> runtimeItemCompiler -> runtimeItemNarrative` 这条主链,玩法层是成立的,但叙事密度仍然不够。
主要问题有 3 个:
1. `src/data/runtimeItemNarrative.ts`
- 名称仍然主要依赖 `来源词 + 关系词 + 功能词` 的固定拼接。
- 描述仍然主要是“谁留下的什么 + 为什么出现 + 偏向什么 build”的单模板句式。
2. `src/data/runtimeItemNarrative.ts`
- fallback 的 `reasonToAppear` 仍是“与最近局势把它推到了你面前”这一类通用解释。
- 这能解释“为什么它不是纯随机”,但解释不了“它到底见证过什么”。
3. `src/services/runtimeItemAiPrompt.ts`
- 当前 AI contract 仍聚焦 `shortNameSeed / sourcePhrase / reasonToAppear / relationHooks / desiredBuildTags`
- 它能产出“贴合当前局势”的轻量意图,但还不够支撑“证物感、传闻感、宿命感、旧债感”。
结果就是:
- 物品已经不再是纯随机装备,但还没有成为能埋故事线索的叙事节点。
- 玩家会知道“它适合当前 build”但不一定会对“它从哪段旧事里来”产生兴趣。
## 1.2 自定义世界 NPC 生成仍偏“字段补齐”,不够像故事角色
当前 `src/services/customWorld.ts` 的自定义世界生成已经能产出完整的:
- `backstory`
- `personality`
- `motivation`
- `combatStyle`
- `backstoryReveal`
- `skills`
- `initialItems`
但问题在于,它更像一份“角色设定卡 JSON”而不是“能在游玩里逐步显影的故事人物”。
当前的主要限制有:
1. 单次生成字段很多,但每个字段长度被压得很短。
2. `backstoryReveal` 固定 4 章,但更像摘要切片,而不是围绕世界冲突组织的叙事章节。
3. 生成要求强调“不要改定位、不要超字段、字符串尽量简洁”,这对结构稳定有帮助,但会明显牺牲戏剧性。
结果就是:
- NPC 有设定,但缺少真正的事件痕迹。
- NPC 有动机,但缺少真正的秘密、债务、误认、旧案、禁忌、未完成关系。
- NPC 有章节,但章节之间没有足够强的剧情递进与回响。
## 1.3 自定义世界 NPC 的信息边界仍在越权泄露
这部分是当前“低好感角色仍然不神秘”的一个关键根因。
目前在 `src/services/prompt.ts` 中,自定义世界 NPC 遭遇描述仍会注入:
1. 完整 `backstory`
2. 所有 `backstoryReveal.chapters`
3. 技能与初始物品细节
同时 `describeCustomWorldSection(...)` 还会把多名 NPC 的:
- 公开背景
- 完整背景
- 动机
- 技能
- 初始物品
- 章节 teaser
打成“自定义世界补充档案”整体注入。
这会直接导致两个问题:
1. 模型在第一次见面、低好感、甚至仅仅“面前遭遇”阶段,就已经站在“全知视角”上写角色。
2. 角色表面上虽然还在说得很少,但模型其实已经知道太多,所以写出来的话会天然带着“设定卡背书感”,而不是“此刻只肯露一角”。
## 1.4 初始低好感角色目前更多是“收口”,不是“施压”
低好感角色无聊,核心不在于他们说得少,而在于他们缺少下面这些东西:
1. 面前局势里的压力
2. 说辞与真实动机之间的错位
3. 对某个旧事件、旧物、旧人、旧地的条件反射
4. 让玩家感觉“这人知道点什么,但现在不肯给”的钩子
也就是说:
**当前低好感角色更多是信息减少了,但戏剧密度没有同步提高。**
## 2. 设计参考转译
本次设计参考的不是具体桥段,而是两类成熟 RPG 的叙事组织方法。
## 2.1 来自《博德之门 3》的可借鉴点
1. 角色秘密不是独立文本,而是会影响初见印象、后续关系、任务走向与物品反应。
2. 物品、书信、遗物、口供、尸体、地标都在一起构成线索网,而不是各说各话。
3. 真正有意思的角色,往往不是“设定很多”,而是“表面、欲望、隐瞒、代价”彼此错位。
## 2.2 来自《黑神话:悟空》的可借鉴点
1. 名称本身就带旧事与异感,不只是功能标签。
2. 很多信息不是直接说明,而是通过残缺线索、旧痕、俗称、误传、传闻去显影。
3. 角色和物件都会带一种“事已经发生过,但后劲还在”的叙事余震。
## 2.3 对当前项目的转译原则
转成当前仓库可落地的做法后,所有重点 NPC 与重点物品都必须携带四条线:
1. 明线
- 玩家当前就能感知到的表层目标、来意、用途、冲突位置。
2. 暗线
- 与世界冲突、旧事件、秘密关系、禁忌知识有关,但此刻不完全说透的线。
3. 代价线
- 角色或物品背后已经失去过什么、欠着什么、被谁盯上、为什么不能轻易松口。
4. 回响线
- 能与其他 NPC、场景、任务、物品互相印证的共享线索、意象、事件伤痕或势力痕迹。
## 3. 设计原则
1. AI 负责叙事层,本地负责规则层。
- 不能让模型直接决定数值、掉落预算、好感变化和状态迁移。
2. 首次接触只给“可见的一角”,不给“全量设定”。
- 低好感阶段更要严格限制 prompt 注入范围。
3. 低好感降低的是披露深度,不是故事密度。
- 对方可以不坦白,但必须有压力、矛盾、误导、观察和反应。
4. 物品必须先是叙事证物,再是功能容器。
- build 倾向依然重要,但需要嵌在“它是谁留下的、为什么出现在这里”之中。
5. 世界里的 NPC、物品、场景要共享同一套叙事词根与事件节点。
- 不允许每次生成都像一个独立小宇宙。
6. UI 展示保持克制。
- 不在面板里默认堆规则说明,只展示结果与线索感,符合项目已有的清爽游戏 UI 要求。
## 4. 核心系统结论
建议把当前“物品叙事 + 大世界 NPC 背景”升级为:
**世界叙事图谱 -> NPC 叙事档案 -> 运行时物品叙事指纹 -> prompt 可见性裁剪 -> 反应与回响回写**
它不是新起一套独立玩法,而是补在当前这些模块之上:
- `src/services/customWorld.ts`
- `src/services/prompt.ts`
- `src/data/runtimeItemContext.ts`
- `src/data/runtimeItemDirector.ts`
- `src/data/runtimeItemNarrative.ts`
- `src/services/runtimeItemAiPrompt.ts`
## 5. 世界级叙事图谱设计
## 5.1 目标
给自定义世界补一层比 `summary / tone / factions / landmarks` 更强的叙事骨架,让 NPC 和物品都不是凭空生出来,而是从同一套世界秘密与旧事件里长出来。
## 5.2 建议新增的数据结构
```ts
interface WorldNarrativeThread {
id: string;
title: string;
lineType: 'visible' | 'shadow';
summary: string;
involvedFactions: string[];
involvedNpcIds: string[];
relatedLandmarkIds: string[];
motifIds: string[];
}
interface WorldNarrativeScar {
id: string;
title: string;
pastEvent: string;
visibleResidue: string;
hiddenTruth: string;
relatedNpcIds: string[];
relatedLandmarkIds: string[];
}
interface WorldNarrativeMotif {
id: string;
label: string;
usage: 'name' | 'item' | 'dialogue' | 'landmark';
examples: string[];
}
interface CustomWorldNarrativeGraph {
visibleThreads: WorldNarrativeThread[];
shadowThreads: WorldNarrativeThread[];
scars: WorldNarrativeScar[];
motifs: WorldNarrativeMotif[];
}
```
并挂到:
```ts
interface CustomWorldProfile {
narrativeGraph?: CustomWorldNarrativeGraph;
}
```
## 5.3 叙事图谱最少产出要求
每个自定义世界最少应生成:
1. `3` 条明线线程
2. `4~6` 条暗线线程
3. `6~10` 个旧事件伤痕
4. `12~20` 个世界词根 / 意象母题
这些词根不是为了写百科,而是为了让:
- NPC 名字外的说话习惯
- 物品名称中的来源词
- 物品描述中的事件痕迹
- 地标描述中的遗留痕迹
能够反复互相印证。
## 6. 大世界 NPC 叙事档案设计
## 6.1 当前 `backstoryReveal` 的问题
当前 `backstoryReveal` 已经有“按好感解锁”的结构,但更接近“把背景拆成 4 段”,还不够像“有明线暗线的角色档案”。
建议保留现有外层结构,但新增一层更强的叙事骨架。
## 6.2 建议新增的数据结构
```ts
interface NpcNarrativeDossier {
publicMask: string;
firstContactMask: string;
visibleLine: string;
shadowLine: string;
contradiction: string;
debtOrOath: string;
hiddenFearOrTaboo: string;
scenePressure: string;
relatedThreadIds: string[];
relatedScarIds: string[];
motifIds: string[];
reactionHooks: string[];
linkedItemSeeds: string[];
}
```
建议挂到:
```ts
interface CustomWorldRoleProfile {
narrativeDossier?: NpcNarrativeDossier;
}
```
字段含义如下:
- `publicMask`
- 外人最容易听到或看到的版本。
- `firstContactMask`
- 第一次接触时这人会先拿出来挡在前面的那层说辞。
- `visibleLine`
- 当前出现在此地、此刻最能被玩家感知到的表层线。
- `shadowLine`
- 背后真正连着哪条暗线,但还不会直接说透。
- `contradiction`
- 这个角色最值得被玩家察觉的“说辞与事实错位”。
- `debtOrOath`
- 让角色更像活在故事中的关键债务、誓言、旧命令或未结关系。
- `hiddenFearOrTaboo`
- 这个角色不愿被提起的人、事、地、物或称谓。
- `scenePressure`
- 这个角色此刻为什么紧绷、拖延、转移、误导。
- `reactionHooks`
- 未来哪些人名、物名、伤痕、势力称呼会触发反应。
## 6.3 低初始好感角色的写法规则
低好感不是“少写”,而是换成“斜着写、卡着写、顶着写”。
建议按初始好感分 4 档处理。
| 初始好感区间 | 角色手感 | 必须出现的内容 | 禁止出现的内容 |
| --- | --- | --- | --- |
| `<= -10` | 敌意、误认、警惕、试图抢占叙事主导权 | 现场威胁、对玩家的判断、一个错误说辞、一个破绽 | 上来完整交代来历 |
| `-9 ~ 14` | 戒备、带压力的克制、把话题往表层拖 | 当前局势、表面理由、一个不愿明说的对象、一个观察细节 | 平铺直叙式自我介绍 |
| `15 ~ 39` | 正常交流但不交底 | 表层目标、与场景关联、一个旧事余波 | 直接说最终动机 |
| `>= 40` | 有合作空间但仍保留底牌 | 合作可能、旧债或旧誓、阶段性真相 | 一次性摊牌全部秘密 |
关键规则:
1. 低好感角色的首轮输出必须带“错位感”。
2. 至少要有一个让玩家觉得“这句话不全对”的缝隙。
3. 至少要有一个和此地事件、旧痕、物件、人物有关的具体钩子。
## 6.4 背景章节的重组方式
当前仍可保留 4 章,但不建议继续把它们仅仅当成“摘要 1、摘要 2、摘要 3、摘要 4”。
建议把 4 章改成稳定的功能分层:
1. `surface`
- 表层来意 / 当下伪装 / 公开身份切口
2. `scar`
- 旧事裂痕 / 已经失去的东西 / 不愿再提的一次失败
3. `bind`
- 关系债务 / 誓言 / 阵营绑缚 / 必须维护的错误
4. `truth`
- 真正目标 / 最终底牌 / 真相代价
保留 `id` 稳定,标题允许按世界主题动态生成,而不是固定文案。
## 6.5 章节文本的写法要求
每一章都必须同时回答两件事:
1. 这段旧事和世界哪条明线 / 暗线有关?
2. 它为什么会影响这个 NPC 今天的说话方式、站位、物品、关系或敌意?
也就是说,章节正文不该只是“以前发生了什么”,而要能连回“现在为什么会这样”。
## 7. 运行时物品叙事指纹设计
## 7.1 当前问题
当前运行时物品已经能贴合:
- 场景
- 遭遇
- build 缺口
- 关系锚点
但它更像“上下文化奖励”,还不够像“故事痕迹”。
## 7.2 建议新增的数据结构
```ts
interface RuntimeItemStoryFingerprint {
visibleClue: string;
witnessMark: string;
unfinishedBusiness: string;
hiddenHook: string;
relatedThreadIds: string[];
relatedScarIds: string[];
motifIds: string[];
reactionHooks: string[];
namingPattern:
| 'npc_relic'
| 'scene_relic'
| 'faction_issue'
| 'monster_trophy'
| 'quest_evidence'
| 'forbidden_object';
}
```
并挂到:
```ts
interface RuntimeItemMetadata {
storyFingerprint?: RuntimeItemStoryFingerprint;
}
```
## 7.3 每件重点物品必须携带的叙事要素
`rare` 及以上,或者 `narrativeWeight = medium / heavy` 的物品,至少要同时有:
1. 一个可见线索
- 玩家光看名字、描述或出处就能捕到的痕迹。
2. 一个见证痕
- 它像谁留下的、从哪次旧事里滚出来的、带着什么使用痕迹。
3. 一个未完成问题
- 这件物品背后还有什么没结掉。
4. 一个当前出现理由
- 为什么偏偏是现在、是这里、是你拿到它。
5. 一个可回响对象
- 哪个 NPC / 场景 / 势力 / 任务之后可能对它起反应。
## 7.4 命名系统升级
当前的三段式命名方向是对的,但需要从“词块拼装”升级为“叙事指纹编译”。
建议按来源分 6 种命名范式:
| 命名范式 | 适用来源 | 推荐结构 | 示例风格 |
| --- | --- | --- | --- |
| 人物遗物 | NPC 奖励、遗失物 | 旧称 / 誓约 / 功能物 | `断旗旧誓护心佩` |
| 场景遗物 | 宝藏、废墟、秘境 | 地标 / 灾痕 / 品类 | `沉炉灰纹短刃` |
| 势力制式 | 商店、军需、黑市 | 势力 / 制式 / 用途 | `巡河司缉印符` |
| 怪物战利 | 怪物掉落、生态素材 | 生态 / 异化 / 精粹 | `雾骨猎印精粹` |
| 任务证物 | 委托、追查、交付 | 事件 / 口供 / 信物 | `沉港失契信物` |
| 禁忌物 | 关键宝藏、暗线物 | 禁名 / 封痕 / 器类 | `烬名封缄骨匣` |
要求不是字数更长,而是:
- 名字里至少有一个世界词根
- 至少有一个事件痕或关系痕
- 最后才落到功能词或器类词
## 7.5 描述文案升级
当前描述模板需要升级为三层表达:
1. 第一层:可见痕迹
- 这件东西看起来像经历过什么。
2. 第二层:旧事牵连
- 它和谁、哪处、哪次旧事有关。
3. 第三层:当前局势意义
- 为什么此刻来到玩家手里,以及它偏向什么战斗或 build 方向。
示例结构:
```text
表面痕迹句。旧事牵连句。当前局势与玩法意义句。
```
要求:
1. 第二句必须有“谁 / 哪处 / 哪次事”的具体指向之一。
2. 不能只有“适合当前 build”这种系统性总结。
3. 允许保留一点空白,不要把暗线直接讲穿。
## 8. Prompt Contract 升级
## 8.1 自定义世界 NPC 生成 prompt 的问题
当前 prompt 的主要问题,不是字段不够,而是:
1. 生成阶段没有先产“世界叙事图谱”,导致 NPC 和物品共享词根不稳定。
2. 角色阶段过早要求完整字段,导致模型更像在补设定表。
3. 文本长度限制过严,压缩掉了故事张力。
## 8.2 建议改成三阶段生成
### 阶段 A世界叙事图谱
先产出:
- `visibleThreads`
- `shadowThreads`
- `scars`
- `motifs`
### 阶段 B角色骨架
只产出:
- `name`
- `title`
- `role`
- `description`
- `initialAffinity`
- `relationshipHooks`
- `tags`
- `narrativeDossier`
### 阶段 C背景章节、技能、初始物品
基于前两阶段结果,再补:
- `backstory`
- `backstoryReveal`
- `skills`
- `initialItems`
这样做的目的不是把流程变复杂,而是防止:
- 世界叙事图谱还没稳定,角色就先各自长成独立设定卡。
## 8.3 自定义世界 NPC 生成时的必填叙事约束
每个 NPC 必须明确写出:
1. 当前站在哪条明线上
2. 真正卷入哪条暗线
3. 一件已经发生过、仍在影响他的旧事
4. 一个不愿被直问的对象、地点、称呼或物件
5. 一个与玩家可能建立连接的切入口
## 8.4 运行时物品 AI contract 升级
建议在当前 `RuntimeItemAiIntent` 外增加叙事指纹字段:
```ts
interface RuntimeItemAiIntent {
shortNameSeed: string;
sourcePhrase: string;
reasonToAppear: string;
relationHooks: string[];
desiredBuildTags: string[];
desiredFunctionalBias: Array<'heal' | 'mana' | 'cooldown' | 'guard' | 'damage'>;
tone: 'grim' | 'mysterious' | 'martial' | 'ritual' | 'survival';
visibleClue?: string;
witnessMark?: string;
unfinishedBusiness?: string;
hiddenHook?: string;
reactionHooks?: string[];
namingPattern?: string;
}
```
AI 仍然不直接产出成品,只负责:
- 提供线索
- 提供见证感
- 提供未完成之事
- 提供命名范式建议
本地编译层再决定:
- 最终名称
- 最终描述
- metadata 回写
- 稀有度与 build 预算
## 9. Prompt 可见性裁剪规则
## 9.1 自定义世界 NPC 遭遇 prompt
必须修正为:
1. 首遇或低披露阶段
- 只注入 `publicSummary`
- 只注入 `firstContactMask / visibleLine / scenePressure`
- 只注入已解锁章节的 `contextSnippet`
2. 禁止直接注入
- 完整 `backstory`
- 未解锁 `backstoryReveal.content`
- 全量章节摘要
## 9.2 自定义世界总档案注入
`buildCustomWorldReferenceText(...)` 不能再把多名 NPC 的完整背景和章节提示整体塞进主 prompt。
建议改成:
1. 世界摘要
2. 叙事图谱摘要
3. 与当前场景 / 当前遭遇最相关的少量 NPC 索引
每名 NPC 只保留:
- 名称
- 身份
- 公开背景
- 所在线程
- 关键反应钩子
## 9.3 低好感阶段的 prompt 目标
模型应该知道的是:
- 这个角色此刻为什么不松口
- 他在盯什么
- 哪个问题会让他产生反应
模型不应该知道的是:
- 他完整的人生说明书
## 10. UI 表达建议
UI 侧保持项目当前的清爽方向,不默认堆规则说明文案。
建议只做这几种表达:
1. NPC 档案页
- 公开背景
- 已解锁章节
- 未解锁章节 teaser
- 不额外展示系统术语
2. 重点物品 tooltip / 描述区
- 名称
- 三层式描述
- 如需增加额外信息,只显示“来历”或“传闻”一行,不做规则说明板
3. 与物品 / 人物的回响
- 优先通过剧情文本、反应文本、任务追加线索体现
- 不优先通过 UI 标签硬显示“这是一条暗线”
## 11. 验收标准
做到以下几点,才算这次需求真正成立:
1. 随机抽样 `20` 个运行时重点物品时,至少 `80%` 的名称能看出明确来源词与事件痕,不再像纯功能拼接词。
2. 随机抽样 `20` 个运行时重点物品时,`100%` 的描述都能同时回答“它经历过什么”和“为什么此刻出现”。
3. 随机抽样 `20` 个自定义世界 NPC 时,`100%` 都能指出自己挂在哪条明线、暗线和哪道旧伤上。
4. 初始好感度低于 `15` 的 NPC首轮文本中至少有一个“说辞与真实意图错位”的点。
5. 首遇与低披露阶段的自定义世界 NPC prompt 中,不再直接注入完整 `backstory` 与未解锁章节。
6. 同一世界内物品名、场景名、NPC 章节和剧情文本之间,能够复用同一组词根与事件痕,而不是每次随机飘散。
7. 玩家在不看后台数据的情况下,也能从名字、描述、对话和档案 teaser 中隐约拼出世界里的明线与暗线。
## 12. 推荐落地顺序
## 阶段 A先修正信息边界与现状问题
优先改:
- `src/services/prompt.ts`
- `src/services/customWorld.ts`
- `src/services/customWorldReferenceText` 相关逻辑
目标:
- 堵住完整背景与未解锁章节的越权注入
- 让低好感阶段先重新成立
## 阶段 B补世界叙事图谱
新增:
- `CustomWorldNarrativeGraph`
- 世界线程、旧伤、意象词根
目标:
- 让 NPC 与物品共享同一套故事母题
## 阶段 C补 NPC 叙事档案
新增:
- `NpcNarrativeDossier`
调整:
- `backstoryReveal` 的生成逻辑
- 低初始好感 NPC 的首遇表达规则
目标:
- 让“低好感但有戏”成为稳定产物
## 阶段 D补运行时物品叙事指纹
新增:
- `RuntimeItemStoryFingerprint`
调整:
- `runtimeItemAiPrompt`
- `runtimeItemNarrative`
目标:
- 让物品名称与描述能承载旧事、见证与未完成问题
## 阶段 E做回响与反应
最后接:
- NPC 对特定物品的反应
- 任务对物品线索的承接
- 场景与旧伤的互相印证
目标:
- 让“名字和背景有故事”真正进入游玩闭环,而不是只停在文案层
## 13. 涉及文件建议
建议优先改动这些区域:
- `src/types/customWorld.ts`
- `src/types/runtimeItem.ts`
- `src/services/customWorld.ts`
- `src/services/prompt.ts`
- `src/services/runtimeItemAiPrompt.ts`
- `src/data/runtimeItemNarrative.ts`
- `src/data/runtimeItemDirector.ts`
建议新增这些模块:
- `src/services/customWorldNarrative.ts`
- `src/services/customWorldNarrativePrompt.ts`
- `src/data/runtimeItemStoryCompiler.ts`
## 14. 一句话结论
这次要做的,不是把物品文案写得更华丽,也不是把 NPC 背景写得更长,而是:
**让世界里的每个人、每件物都像被主线和暗线真正碰过,名字里有来路,描述里有旧事,对话里有保留,低好感时也能让玩家感觉到背后压着一整段没被说出来的故事。**

View File

@@ -0,0 +1,496 @@
# AI 原生 NPC 单轮聊天会话迭代 PRD
更新时间:`2026-04-18`
## 0. 文档目的
本 PRD 只定义 `npc_chat` 在冒险主面板中的这一轮迭代落地方式。
目标不是新建一套聊天系统,而是在保持现有游戏 UI 外壳、剧情面板结构、消息流位置不变的前提下,把 `npc_chat` 从“触发一次后回到普通剧情流”升级为“进入可持续续写的单轮聊天会话”。
本次文档必须直接指导编码,避免需求落地漂移。
---
## 1. 一句话定义
玩家点击 `npc_chat` 后,进入 NPC 聊天模式;每次只完成一轮“玩家输入 -> NPC 回复 -> 角色形象播出好感度变化特效 -> 下一轮 3 个建议选项 + 1 个自定义输入”,直到玩家主动退出聊天。
---
## 2. 背景与问题
当前 `npc_chat` 更接近“触发一段剧情性对话”,而不是“持续聊天”:
1. 玩家点击聊天后,常常是一次性生成较长结果,再回到普通冒险选项。
2. 缺少稳定的续聊状态,无法把多轮聊天作为一个连续会话维持。
3. 好感度变化更多停留在逻辑层,玩家在消息流中感知不明显。
4. 没有单独的退出聊天控制,用户只能被动等系统切回普通状态。
5. 选项形态仍偏剧情动作,不够像聊天接话。
这会导致 `npc_chat` 的体验不像“和角色对话”,而像“触发一个剧情功能”。
---
## 3. 本次目标
本次迭代必须同时满足以下目标:
1. `npc_chat` 触发后进入聊天交互态。
2. 聊天态沿用当前主冒险面板,不新增页面、不弹新系统。
3. 每次用户只推进一轮对话。
4. 每轮结束后稳定出现 `3` 个建议续聊选项。
5. 每轮结束后稳定出现 `1` 个自定义输入框。
6. 玩家选择建议项或提交自定义输入后,继续在同一消息队列中续写。
7. 好感度增减不能再作为聊天系统消息插入队列,必须改为角色形象上的数值特效反馈。
8. NPC 回复必须支持流式传输,并在前端边接收边解析显示。
9. 背包按钮所在行的最右侧必须新增“退出聊天”按钮。
10. 退出聊天后恢复普通冒险态,不保留当前聊天输入框与聊天建议项。
---
## 4. 明确不做
本次不做:
1. 不新建独立聊天页面。
2. 不重做现有主面板 UI 结构。
3. 不引入多 NPC 并行聊天。
4. 不做聊天记录存档面板。
5. 不做复杂关系公式配置后台。
6. 不做语音输入、表情、附件等扩展输入能力。
7. 不把前端改成承担关系计算或剧情判定。
---
## 5. 核心体验
## 5.1 进入聊天
当玩家点击 `npc_chat` 选项时:
1. 保持当前冒险面板布局不变。
2. 中部内容区切换为聊天消息流展示模式。
3. 底部选项区切换为聊天建议区。
4. 底部附加一个自定义输入框与发送按钮。
5. 顶层不跳转、不弹窗、不覆盖成新页面。
## 5.2 单轮推进
单轮定义固定为:
1. 玩家通过“建议选项”或“自定义输入”提交一句话。
2. 玩家消息立即进入消息队列。
3. NPC 回复开始流式显示。
4. 流式结束后,如果有关系变化,在角色形象上播放一次对应的数值特效。
5. 系统刷新下一轮 `3` 个建议选项。
6. 系统保留自定义输入入口,等待下一轮。
## 5.3 退出聊天
玩家点击“退出聊天”后:
1. 当前聊天态结束。
2. 面板底部恢复普通冒险选项区域。
3. 本轮聊天输入框、聊天建议项消失。
4. 当前故事内容回到普通故事展示逻辑。
退出聊天不触发额外确认弹窗。
---
## 6. UI 设计要求
## 6.1 保持不变的部分
以下 UI 外壳保持当前实现:
1. 主冒险面板整体框架。
2. 对话消息区所在位置。
3. 底部操作区的整体层级。
4. 队伍按钮、背包按钮的视觉风格。
## 6.2 必须变化的部分
### 消息区
1. 聊天态下,消息区按时间顺序展示:
- 玩家消息
- NPC 消息
2. 好感度变化不再插入聊天消息流。
3. 消息区不额外追加“关系升温 / 关系转冷”类文字提示。
### 角色形象特效
1. 若本轮好感度提升,必须在当前聊天对象的角色形象上飞出心形正向特效。
2. 正向特效内必须显示本轮增加数值,例如:`+3`
3. 若本轮好感度下降,必须在当前聊天对象的角色形象上飞出负向特效。
4. 负向特效内必须显示本轮减少数值,例如:`-2`
5. 特效应挂载在当前角色形象区域,而不是消息区、选项区或额外弹窗。
6. 同一轮只播一次最近结算结果,不重复插入历史文本。
### 底部按钮区
1. 左侧仍保留队伍、背包按钮。
2. 右侧在聊天态下展示“退出聊天”按钮。
3. “退出聊天”按钮必须位于该行最右侧。
4. 非聊天态下,该位置仍保持原有刷新选项按钮逻辑。
### 选项区
1. 聊天态下只展示 `3` 个续聊选项。
2. 聊天态下不展示普通剧情选项附带的说明文案、目标提示、影响摘要。
3. 聊天态下选项文案本身就是“下一句怎么接”。
### 输入区
1. 聊天态下在 3 个建议项下方展示输入框。
2. 输入框右侧固定展示发送按钮。
3. 输入框在请求进行中禁用。
4. 点击发送或回车提交时,进入下一轮。
## 6.3 移动端要求
1. 移动端优先保证输入框与发送按钮可点击。
2. 三个建议选项必须保持纵向堆叠,不做横向卡片排布。
3. “退出聊天”按钮在小屏下仍需完整可见,不允许被背包按钮挤出。
4. 输入框与发送按钮在窄屏下优先保证输入框宽度,其次压缩按钮内边距。
---
## 7. 前后端职责边界
遵循“前端只负责表现,逻辑和数据放后端”原则。
## 7.1 前端职责
前端只负责:
1. 进入/退出聊天态的 UI 切换。
2. 渲染当前消息队列。
3. 发送玩家本轮输入。
4. 接收流式事件并实时更新 NPC 当前回复文本。
5. 渲染角色形象上的好感度变化特效。
6. 渲染下一轮 `3` 个建议项与自定义输入框。
前端不负责:
1. 生成 NPC 回复文本。
2. 生成建议续聊选项。
3. 计算关系增减。
4. 解析剧情逻辑分支。
## 7.2 后端职责
后端负责:
1. 接收 NPC 单轮聊天请求。
2. 结合当前世界、角色、NPC 状态、历史消息构建 prompt。
3. 流式生成 NPC 回复。
4. 解析回复内容。
5. 生成下一轮 3 个建议续聊选项。
6. 计算并返回本轮关系增减。
7. 通过 SSE 向前端发送流式事件与最终结果。
---
## 8. 数据结构要求
## 8.1 前端故事态扩展
`StoryMoment` 需要具备聊天态附加状态:
```ts
type StoryNpcChatState = {
npcId: string;
npcName: string;
turnCount: number;
customInputPlaceholder?: string;
};
```
要求:
1. 仅当当前故事处于 NPC 聊天模式时写入。
2. `turnCount` 表示已完成的轮数。
3. `npcId` 用于保证只续写当前聊天对象。
## 8.2 聊天消息结构
消息队列继续支持系统消息,用于战斗结算、流程收束等非好感提示:
```ts
type StoryDialogueTurn = {
speaker: 'player' | 'npc' | 'companion' | 'system';
speakerName?: string;
text: string;
affinityDelta?: number;
};
```
要求:
1. `system` 只用于关系变化、系统反馈类消息。
2. `affinityDelta` 不再用于向聊天消息流插入好感提示。
新增聊天态特效事件:
```ts
type StoryNpcAffinityEffect = {
eventId: string;
npcId: string;
delta: number;
};
```
要求:
1. 仅在本轮聊天真实发生好感变化时写入。
2. `delta > 0` 表示正向心形特效。
3. `delta < 0` 表示负向减少特效。
4. 该事件只负责驱动角色形象表现,不负责生成消息文本。
## 8.3 单轮接口契约
请求:
```ts
type NpcChatTurnRequest = {
worldType: WorldType;
player: Character;
encounter: Encounter;
history: StoryMoment[];
dialogue: StoryDialogueTurn[];
playerMessage: string;
npcState: {
affinity: number;
chattedCount: number;
recruited: boolean;
};
context: StoryGenerationContext;
};
```
返回完成事件载荷:
```ts
type NpcChatTurnResult = {
npcReply: string;
affinityDelta: number;
affinityText: string;
suggestions: string[];
};
```
---
## 9. 流式协议
本次统一使用 SSE。
## 9.1 事件类型
后端至少输出以下事件:
1. `reply_delta`
2. `complete`
3. `error`
## 9.2 事件含义
### `reply_delta`
用途:
1. 逐步推送 NPC 当前回复文本增量。
2. 前端收到后立即更新消息流中“当前 NPC 气泡”的文本。
### `complete`
用途:
1. 标记本轮流式输出结束。
2. 一次性返回最终结果对象:
- `npcReply`
- `affinityDelta`
- `affinityText`
- `suggestions`
### `error`
用途:
1. 标记本轮失败。
2. 前端停止流式态并回退到可继续输入的状态。
## 9.3 前端解析规则
1. 当收到第一个 `reply_delta` 时,若消息流末尾还没有 NPC 临时消息,前端先插入一条空的 NPC 消息。
2. 每次收到 `reply_delta`,替换该临时 NPC 消息文本。
3. 收到 `complete` 后,把临时 NPC 消息固化为最终文本。
4. 如果 `affinityDelta !== 0`,在 NPC 消息后追加一条系统关系消息。
5. 之后再刷新下一轮建议选项。
---
## 10. 关系变化显示规则
## 10.1 显示位置
关系变化必须作为一条独立消息插入消息队列,位置在本轮 NPC 回复之后、下一轮建议项之前。
## 10.2 文案规则
1. 有增长时显示正向文案,例如:`关系升温 好感 +3`
2. 有下降时显示负向文案,例如:`关系转冷 好感 -2`
3. 无变化时不强制插入系统消息。
## 10.3 视觉规则
1. 关系变化消息居中显示。
2. 关系变化消息使用不同于普通对话气泡的视觉样式。
3. 正向变化可使用更暖色的边框/底色。
4. 负向变化与中性反馈使用系统消息样式。
---
## 11. 交互流程
## 11.1 进入流程
```text
玩家点击 npc_chat
-> 系统进入聊天态
-> 当前故事切换为聊天消息模式
-> 展示本轮可选接话
-> 展示自定义输入框
```
## 11.2 单轮流程
```text
玩家点击建议项或提交输入
-> 玩家消息立即入队
-> 前端发起 /runtime/chat/npc/turn/stream
-> 后端流式返回 NPC 回复
-> 前端边接收边渲染 NPC 当前回复
-> complete 返回最终结果
-> 前端插入关系变化系统消息
-> 前端刷新下一轮 3 个建议项
-> 等待下一轮输入
```
## 11.3 退出流程
```text
玩家点击退出聊天
-> 清理当前聊天态标记
-> 当前故事回到普通冒险展示
-> 恢复普通选项区
```
---
## 12. 状态更新规则
每完成一轮聊天,系统必须更新:
1. `npcState.affinity`
2. `npcState.chattedCount`
3. `npcState.relationState`
4. `npcState.stanceProfile`
5. `storyHistory`
6. `currentStory.dialogue`
7. `currentStory.npcChatState.turnCount`
要求:
1. 当前轮玩家输入和 NPC 回复都要进入故事历史。
2. 关系变化消息属于展示型系统消息,可进入当前对话队列,但不要求作为独立剧情行动历史参与模型推理。
---
## 13. 异常与兜底
## 13.1 流式失败
如果流式失败:
1. 当前轮玩家消息保留。
2. 不保留半截乱码式 NPC 文本。
3. 前端恢复可继续输入状态。
4. 使用后端或前端兜底建议项,保证仍有 3 个建议续聊选项可选。
## 13.2 建议项不足
如果后端返回建议项不足 `3` 条:
1. 由后端优先补齐兜底话术。
2. 前端只展示最多 `3` 条。
## 13.3 空输入
空输入、纯空格输入不发请求。
---
## 14. 代码落点
本次迭代应优先落在现有链路:
### 前端
1. `src/hooks/story/npcEncounterActions.ts`
2. `src/hooks/story/useStoryInteractionCoordinator.ts`
3. `src/hooks/story/useStoryFlowCoordinator.ts`
4. `src/hooks/useStoryGeneration.ts`
5. `src/services/aiService.ts`
6. `src/components/AdventurePanel.tsx`
7. `src/components/GameShell.tsx`
### 共享契约
1. `packages/shared/src/contracts/story.ts`
### 后端
1. `server-node/src/routes/runtimeRoutes.ts`
2. `server-node/src/services/chatService.ts`
3. `server-node/src/modules/ai/chatPromptBuilders.ts`
4. `server-node/src/modules/ai/chatOrchestrator.ts`
要求:
1. 复用现有故事流、运行时接口和主面板。
2. 不另起新页面、新 store、新聊天系统。
---
## 15. 验收标准
以下全部满足才算通过:
1. 点击 `npc_chat` 后,面板进入聊天态而不是跳去新页面。
2. 当前消息区能连续展示玩家消息、NPC 消息、系统关系消息。
3. 每轮结束后稳定出现 `3` 个建议项。
4. 每轮结束后稳定出现 `1` 个自定义输入框。
5. 点击建议项可继续下一轮。
6. 输入自定义文本后点击发送或回车可继续下一轮。
7. NPC 回复支持流式逐字/逐段显示。
8. 好感度变化会以消息形式插入聊天队列。
9. 背包按钮所在行最右侧可见“退出聊天”按钮。
10. 点击“退出聊天”后恢复普通冒险态。
11. 聊天态下不显示普通剧情选项的说明、目标提示、影响摘要。
12. 移动端下输入框、发送按钮、退出按钮均可正常操作。
---
## 16. 后续可扩展方向
本次上线后,再考虑后续迭代:
1. 更精细的关系变化公式。
2. 基于 NPC 性格的建议续聊风格差异。
3. 聊天摘要沉淀到长期记忆。
4. 聊天中触发支线、任务、物品、邀约等事件。
5. 退出聊天后保留“最近一次聊天摘要”。

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,789 @@
# AI 原生游戏任务系统 PRD
更新时间:`2026-04-02`
## 0. 设计目标
这份方案针对当前仓库,回答的是:
**如果要把现有“接受任务 -> 推进 -> 完成 -> 交付”的轻量任务链路,升级成真正的 AI 原生任务系统,应该怎样设计,才能既让任务更像从当前剧情里长出来,又不把规则、奖励和平衡交给模型失控决定?**
这里的“AI 原生”不是指:
- 让模型随时随地自由生成一个任务标题和奖励
- 让模型直接修改任务状态、数值或掉落
- 让任务系统变成纯文案系统
这里的“AI 原生”指的是:
- AI 负责理解当前故事局面,生成任务语义、动机、话术、阶段转折和关系变化
- 本地规则负责验证任务是否合法、如何推进、何时完成、奖励如何结算、存档如何兼容
- 任务系统不再只是“静态模板挂在 NPC 身上”,而是“从当前局面推导出来的可控任务合约”
一句话总结:
**AI 决定这份任务在叙事上是什么,本地规则决定它在系统上如何成立。**
## 1. 当前系统现状
从当前仓库实现看,任务系统已经有一个可工作的最小闭环:
- `src/data/questFlow.ts`
- 负责构造任务、接受任务、推进任务、完成任务、交付任务
- `src/hooks/story/npcEncounterActions.ts`
- 负责 NPC 交互里的 `quest_accept` / `quest_turn_in`
- `src/hooks/useStoryGeneration.ts`
- 负责在战斗、宝藏、NPC 交互后更新 quest progress
- `src/types/story.ts`
- 当前 `QuestLogEntry` 是运行时任务主结构
- `src/components/AdventurePanel.tsx`
- 负责任务 UI 展示与奖励领取
当前系统已经支持:
1. NPC 提供任务
2. 玩家接受任务
3. 击败怪物 / 调查宝藏 / 与 NPC 切磋 三类目标推进
4. 任务完成后领取奖励
5. 奖励影响货币、背包和 NPC affinity
这说明基础闭环是成立的,问题不在“有没有任务系统”,而在于:
- 当前任务更像“局部规则脚手架”还不是“AI 原生任务系统”
- AI 目前主要参与任务文案氛围和选项重写,没有真正参与任务语义生成
- 任务结构太扁平,无法承载阶段变化、关系转折、后续分支和任务记忆
## 2. 当前系统的核心限制
## 2.1 任务来源仍然偏静态
当前 `buildQuestForEncounter(...)` 的生成逻辑,本质还是:
- 看当前 scene 有没有 hostile npc
- 没有就看 monsterIds
- 再没有就看 treasureHints
- 最后 fallback 到 spar
这套逻辑稳定,但仍然是:
**本地 if/else 在选任务类型AI 只是在外围写故事。**
结果是:
- 任务叙事贴合度有限
- 任务动机比较像通用模板
- 很难让任务明显体现“为什么偏偏是这个 NPC、这个时刻、这个场景、这个玩家”
## 2.2 任务结构只有“单目标单阶段”
当前 `QuestLogEntry.objective` 只有:
- `kind`
- `targetMonsterId`
- `targetNpcId`
- `targetSceneId`
- `requiredCount`
它适合最小任务闭环,但不适合承载:
- 多阶段任务
- 前置调查 -> 中段确认 -> 最终结算
- NPC 关系驱动的任务升级
- 同一任务在不同世界/场景下的变体
- 任务完成方式差异带来的后续影响
## 2.3 任务状态过粗
当前状态只有:
- `active`
- `completed`
- `turned_in`
这会导致任务系统无法表达:
- 已发现但未正式接取
- 已接受但未激活下一阶段
- 已满足隐藏条件但未显式揭示
- 已失败 / 已过期 / 已被替代
- 已分支到不同结局
## 2.4 奖励是固定规则,不随任务语义演化
当前奖励主要由 `buildQuestReward(worldType, roleText)` 生成。
优点:
- 稳定
- 易控
- 好测试
问题:
- 奖励和任务语义绑定弱
- 很难体现“这个 NPC 因为什么给你这份奖励”
- 不能承载 AI 原生任务中更重要的“关系、线索、世界信息、后续机会”
## 2.5 AI 没有任务层专属 contract
当前 `StoryGenerationContext` 很强,但任务相关信息还没有独立建模。于是:
- prompt 里只能把任务作为周边信息描述
- AI 无法明确返回“任务意图”
- 本地也无法验证 AI 给出的任务建议是否合法
这意味着任务系统还没有形成:
**专门面向任务设计的 AI <-> Rule contract**
## 3. 设计原则
## 3.1 AI 负责叙事,本地负责规则
这是本项目已经验证有效的核心边界,这次任务系统继续沿用。
AI 负责:
- 为什么现在出现这份任务
- 任务在关系和剧情上的意义
- 任务目标的话术表达
- 阶段推进时的语义转折
- 奖励在叙事上的来源解释
本地负责:
- 任务是否能生成
- 任务目标类型是否合法
- 可推进事件有哪些
- 任务进度如何累计
- 奖励数值、掉落、affinity、货币如何结算
- 存档结构与兼容
## 3.2 任务必须是“当前局面的产物”
AI 原生任务不应是抽象模板,而应明确绑定:
1. 当前 scene / landmark / threat
2. 当前 NPC 的身份、态度、关系阶段
3. 最近几条 story history
4. 玩家当前状态、build 缺口、队伍关系
5. 当前世界观与 custom world profile
如果一份任务脱离这些上下文也成立那它就还不是“AI 原生任务”。
## 3.3 任务应优先表达“意图”,再编译成“合约”
不要让 AI 直接返回最终 `QuestLogEntry`
更稳的方式是:
1. AI 先返回任务意图 `QuestIntent`
2. 本地把它编译成可执行的 `QuestContract`
3. 再由运行时把 `QuestContract` 映射成 UI 所需的 `QuestLogEntry`
这样能保证:
- AI 足够自由地表达语义
- 本地仍然保留最终裁决权
- 系统容易测试、回放和做 fallback
## 3.4 任务系统必须兼容“AI 不可用”
这个项目所有关键玩法都应该支持 fallback。
所以 AI 原生任务系统必须允许:
- AI 在线时,任务更贴剧情、更像当前局面的自然产物
- AI 离线时,任务仍可退回 deterministic builder
也就是说:
**AI 提升任务质量,但不成为任务闭环的单点故障。**
## 4. 建议的系统分层
建议把新任务系统拆成 5 层。
## 4.1 任务上下文采样层
先从当前运行时抽取一个统一的任务上下文:
```ts
type QuestGenerationContext = {
worldType: WorldType | null;
customWorldProfile?: CustomWorldProfile | null;
currentSceneId?: string | null;
currentSceneName?: string | null;
currentSceneDescription?: string | null;
issuerNpcId?: string | null;
issuerNpcName?: string | null;
issuerNpcContext?: string | null;
issuerAffinity?: number | null;
issuerDisclosureStage?: NpcDisclosureStage | null;
issuerWarmthStage?: NpcWarmthStage | null;
encounterKind?: "npc" | "monster" | "treasure" | "none";
recentStoryMoments: StoryMoment[];
playerCharacter: Character;
playerHp: number;
playerMaxHp: number;
playerMana: number;
playerMaxMana: number;
playerInventory: InventoryItem[];
playerEquipment: EquipmentLoadout;
activeCompanions: CompanionState[];
rosterCompanions: CompanionState[];
currentQuestSummary: Array<{
id: string;
title: string;
status: QuestStatus;
issuerNpcId: string;
}>;
};
```
这一层的目标不是直接生成任务,而是先回答:
**这次任务生成到底发生在什么局面里?**
## 4.2 AI 任务意图层
让 AI 只返回“任务意图”,而不是最终任务实例:
```ts
type QuestIntent = {
narrativeType: "bounty" | "escort" | "investigation" | "retrieval" | "relationship" | "trial";
dramaticNeed: string;
issuerGoal: string;
playerHook: string;
worldReason: string;
recommendedObjectiveKinds: Array<
"defeat_monster" | "inspect_treasure" | "spar_with_npc" | "deliver_item" | "reach_scene" | "talk_to_npc"
>;
urgency: "low" | "medium" | "high";
intimacy: "transactional" | "cooperative" | "trust_based";
rewardTheme: "currency" | "resource" | "relationship" | "intel" | "rare_item";
followupHooks: string[];
};
```
重点是:
- AI 告诉系统这份任务“像什么”
- 不直接决定最终字段值
- 不直接操作运行时状态
## 4.3 本地任务编译层
本地根据 `QuestIntent + QuestGenerationContext` 编译出真正可执行的任务合约:
```ts
type QuestContract = {
id: string;
issuerNpcId: string;
questArchetype: QuestIntent["narrativeType"];
title: string;
description: string;
summary: string;
steps: QuestStep[];
rewards: QuestRewardPackage;
narrativeBindings: QuestNarrativeBinding;
failPolicy: "never" | "leave_scene" | "issuer_hostile" | "time_window";
};
type QuestStep = {
id: string;
kind:
| "defeat_monster"
| "inspect_treasure"
| "spar_with_npc"
| "deliver_item"
| "reach_scene"
| "talk_to_npc";
targetSceneId?: string;
targetNpcId?: string;
targetMonsterId?: string;
targetItemId?: string;
requiredCount: number;
progress: number;
revealText: string;
completeText: string;
};
```
这层的职责是:
- 将 AI 的语义建议裁剪到系统允许的任务范式内
- 确保每一个 step 都能被现有事件流推进
- 给每一个任务生成稳定 id、稳定状态和可存档结构
## 4.4 任务运行时推进层
运行时只认本地任务合约和事件。
建议新增统一的任务推进事件:
```ts
type QuestProgressSignal =
| { kind: "monster_defeated"; sceneId?: string | null; monsterId: string }
| { kind: "treasure_inspected"; sceneId?: string | null }
| { kind: "npc_spar_completed"; npcId: string }
| { kind: "npc_talk_completed"; npcId: string }
| { kind: "scene_reached"; sceneId: string }
| { kind: "item_delivered"; npcId: string; itemId: string; quantity: number };
```
然后统一走:
- `applyQuestProgressSignal(contract, signal)`
而不是继续把推进逻辑分散到多处手写 helper。
这样做的价值是:
- 后续加新任务种类时,只需扩展 signal 与 compiler
- `useStoryGeneration` 只负责发 signal不负责理解具体任务细节
- 测试可以直接覆盖“某信号输入 -> 某任务状态输出”
## 4.5 任务叙事回写层
AI 原生任务真正有价值的一层,不只是“生成任务”,而是“在任务推进时改写故事”。
建议在以下节点允许 AI 回写叙事:
1. 任务生成时
2. 新阶段解锁时
3. 任务完成但未交付时
4. 交付奖励时
5. 完成方式影响关系时
这层应该只接收:
- 已经确定的任务 contract
- 已经发生的规则结果
而不是允许 AI 反向篡改规则结果。
## 5. 建议的数据结构升级
建议不要直接推翻当前 `QuestLogEntry`,而是在现有结构上新增一层 metadata。
## 5.1 新增任务元数据
```ts
type QuestNarrativeBinding = {
origin: "fallback_builder" | "ai_compiled";
narrativeType: "bounty" | "escort" | "investigation" | "retrieval" | "relationship" | "trial";
dramaticNeed: string;
issuerGoal: string;
playerHook: string;
worldReason: string;
followupHooks: string[];
};
type QuestRewardPackage = {
currency: number;
affinityBonus: number;
items: InventoryItem[];
intel?: {
codexEntry?: string;
rumorText?: string;
unlockedSceneId?: string;
};
};
```
## 5.2 扩展现有 QuestLogEntry
```ts
interface QuestLogEntry {
id: string;
issuerNpcId: string;
issuerNpcName: string;
sceneId: string | null;
title: string;
description: string;
summary: string;
objective: LegacyQuestObjective;
progress: number;
status: QuestStatus;
completionNotified?: boolean;
reward: QuestReward;
rewardText: string;
narrativeBinding?: QuestNarrativeBinding;
steps?: QuestStep[];
activeStepId?: string | null;
visibleStage?: number;
hiddenFlags?: string[];
}
```
这样做的原因是:
- UI 可以先继续读旧字段
- 新逻辑逐步切到 `steps`
- 旧存档仍然能兼容
## 5.3 扩展任务状态
建议未来把任务状态扩展为:
```ts
type QuestStatus =
| "discovered"
| "active"
| "ready_to_turn_in"
| "completed"
| "turned_in"
| "failed"
| "expired";
```
MVP 阶段不一定要一次性全上,但至少建议引入:
- `discovered`
- `ready_to_turn_in`
因为 AI 原生任务里,“被感知到”与“正式接取”往往不是同一刻。
## 6. AI 任务 contract 设计
## 6.1 新增专用 prompt contract
建议新增专用任务生成接口,而不是继续把任务生成混在通用 story completion 里。
建议新增:
- `src/services/questDirector.ts`
- `src/services/questPrompt.ts`
- `src/services/questTypes.ts`
AI 返回格式建议如下:
```json
{
"intent": {
"narrativeType": "investigation",
"dramaticNeed": "NPC 怀疑附近遗迹并不安全,但不敢直接深入",
"issuerGoal": "确认遗迹是否值得继续接近",
"playerHook": "玩家当前正好在此地,并且具备应对未知风险的能力",
"worldReason": "最近场景和对话都指向此处存在被掩盖的旧痕迹",
"recommendedObjectiveKinds": ["inspect_treasure", "talk_to_npc"],
"urgency": "medium",
"intimacy": "cooperative",
"rewardTheme": "intel",
"followupHooks": ["遗迹背后的旧势力", "NPC 曾经来过这里"]
}
}
```
重点规则:
- 只允许输出意图,不允许直接输出奖励数值
- 只允许使用本地支持的 objective kinds
- 只描述建议,不越权改状态
## 6.2 AI 负责的字段
AI 可以负责:
- `title` 的语义方向
- `description` 的叙事质感
- `summary` 的自然语言表达
- `dramaticNeed`
- `issuerGoal`
- `playerHook`
- `worldReason`
- `followupHooks`
AI 不负责:
- `id`
- `requiredCount`
- `status`
- `progress`
- `currency`
- `affinityBonus`
- 直接生成超出规则支持范围的 objective
## 6.3 本地编译时的裁决逻辑
本地应当做如下校验:
1. objective kind 是否在 allowlist 内
2. 当前 scene / npc / monster / treasure 是否真的存在
3. 当前 NPC 是否已存在未完成任务
4. 当前任务是否会与现有任务重复或冲突
5. 奖励是否符合 rarity / economy / relationship budget
如果 AI 返回不合法:
- 降级到 deterministic builder
- 但仍可保留 AI 提供的部分叙事字段作为文案参考
## 7. 任务生成时机设计
建议不是每次点 NPC 都无条件生成任务,而是让系统先判断“是否值得生成任务机会”。
## 7.1 建议的触发点
适合生成任务机会的节点:
1. 初次与某 NPC 深入互动
2. 某 NPC affinity 达到新阶段
3. 某场景首次发现异常实体或藏宝线索
4. 某条最近剧情暗示了未解决的局面
5. 玩家在当前区域停留较久且缺少明确目标
## 7.2 不建议触发的节点
以下节点不建议频繁生成任务:
- 每次普通聊天都生成任务
- 每次旅行都自动冒出新任务
- 当前已有多个未完成任务时继续塞新任务
- AI 仅凭最近一句话就突然变出高强度委托
## 7.3 任务机会判断器
建议先做本地 `questOpportunityEvaluator`
```ts
type QuestOpportunity = {
shouldOffer: boolean;
reason: string;
suggestedIssuerNpcId?: string;
suggestedThreatType?: "monster" | "treasure" | "relationship" | "travel";
};
```
这层先判断“该不该生成”,再决定“交给 AI 生成什么”。
这样能避免模型过度产出任务。
## 8. 任务推进设计
## 8.1 从“单字段进度”升级到“步骤机”
当前任务推进是:
- 一个 objective
- 一个 progress
建议升级为:
- 多 step
- 每个 step 自己推进
- active step 决定当前 UI 展示
例如:
```ts
[
{
id: "step_investigate_ruins",
kind: "inspect_treasure",
targetSceneId: "ruins_gate",
requiredCount: 1
},
{
id: "step_report_back",
kind: "talk_to_npc",
targetNpcId: "npc_scholar_lin",
requiredCount: 1
}
]
```
这样任务就能表达:
- 先调查
- 再回报
- 再领取奖励
## 8.2 允许“隐式推进,显式揭示”
AI 原生任务最有意思的一点,是任务可以先发生推进,再在叙事上被揭示。
例如:
- 玩家在探索时先完成了调查
- 回去交谈时 NPC 才明确说出“你已经替我确认了那里的情况”
这意味着系统上应允许:
- step 已完成
-`visibleStage` 仍未切换到下一步,直到触发 reveal
这样任务会更像故事,而不是机械 checklist。
## 9. 奖励设计
## 9.1 奖励不只是一包货币和道具
AI 原生任务里,奖励至少应拆成 4 类:
1. 经济奖励
- currency
- item bundles
2. 关系奖励
- affinity
- disclosure stage / warmth stage 解锁
3. 信息奖励
- rumor
- codex entry
- 场景/势力线索
4. 机会奖励
- 解锁新 scene
- 解锁新 NPC 交互
- 解锁后续任务机会
## 9.2 AI 负责解释奖励来源,不负责定奖励数值
建议奖励设计继续遵守:
- AI 解释“为什么这个 NPC 给这些”
- 本地决定“究竟给多少”
例如:
- AI 可说:这是 NPC 私藏的旧护符、只愿交给值得信任的人
- 本地则决定:这是 `rare relic + affinityBonus 12 + currency 72`
## 10. UI 表达建议
当前 `AdventurePanel` 已经有不错的任务面板基础AI 原生任务系统建议补的不是“更多卡片”,而是“更多阶段感”。
建议新增以下 UI 信息:
1. 任务来源语义
- 谁委托
- 为什么此刻委托
2. 当前阶段标题
- 当前不是只看进度条,还要看“现在在做哪一步”
3. 任务关系状态
- 交易型 / 协作型 / 信任型
4. 任务后续钩子
- 这件事可能会牵出什么
UI 上不建议直接暴露给玩家的内部字段:
- `dramaticNeed`
- `followupHooks` 原始数组
- 所有 hidden flags
这些字段应该被整理成更自然的面板文案。
## 11. 与当前仓库的接入点建议
## 11.1 第一批建议改动的文件
建议先从以下文件接入:
- `src/types/story.ts`
- 扩展 `QuestLogEntry`
- `src/services/aiTypes.ts`
- 增加任务生成上下文
- `src/data/questFlow.ts`
- 增加 contract compiler 和 step progression
- `src/hooks/story/npcEncounterActions.ts`
-`quest_accept` 改为“机会判断 -> AI 意图 -> 本地编译”
- `src/services/prompt.ts`
- 不直接负责任务生成,拆出 `questPrompt.ts`
## 11.2 第一批不建议碰的区域
这轮不建议一开始就深入改:
- `AdventurePanel` 的整体结构
- `useStoryGeneration` 的全部 orchestrator
- 所有现存 AI story prompt
原因是任务系统已经是主链路的一部分,第一步应该先把 contract 立住,而不是把整个 story 系统一起重写。
## 12. MVP 落地顺序
## 阶段 A先做任务 contract不改全部表现
新增:
- `src/services/questTypes.ts`
- `src/services/questDirector.ts`
- `src/services/questPrompt.ts`
目标:
- AI 能返回 `QuestIntent`
- 本地能编译成 `QuestContract`
- 旧 UI 仍然照常显示
## 阶段 B把 NPC 接任务改成 AI 原生生成
先只改:
- `quest_accept`
此时:
- 仍沿用现有三种基础 objective kind
- 但 title / description / rewardText / followupHooks 开始变成上下文生成
这是最稳的切入点,因为:
- 影响面小
- 可回退
- 容易观察质量提升
## 阶段 C把任务推进改成 step + signal
重点改:
- `applyQuestProgressFromMonsterVictory`
- `applyQuestProgressFromTreasure`
- `applyQuestProgressFromSpar`
把它们收口到统一 signal reducer。
## 阶段 D把交付奖励与后续机会联动起来
`quest_turn_in` 不再只是:
- 发货币
- 发道具
- 加 affinity
而是还能:
- 写入 rumor / intel
- 解锁后续任务机会
- 改变 NPC 对话阶段
## 13. 为什么这套方案适合当前仓库
这套方案不是重做一套新玩法,而是顺着仓库已经验证过的边界继续深化:
1. 仓库已经验证“AI 负责叙事,本地负责规则”是正确方向
2. 仓库已经有现成的 quest UI、quest status、quest reward、npc affinity 链路
3. 当前 `useStoryGeneration` 已经在汇总 story/combat/treasure/npc 事件,天然适合继续发 quest signal
4. 当前 `StoryGenerationContext` 已经足够强,只是还缺一个任务专用 contract
所以这次真正缺的不是“再加一个任务面板”,而是:
**把任务从‘规则附属物’升级成‘叙事与规则之间的正式中介层’。**
## 14. 最后结论
对这个项目来说,理想的 AI 原生任务系统不应该做成“AI 随机发委托”,而应该做成:
1. 系统先判断当前局面是否值得生成任务机会
2. AI 根据世界、场景、NPC、最近剧情和玩家状态生成任务意图
3. 本地将任务意图编译成稳定、可测试、可持久化的任务合约
4. 运行时通过统一 signal 推进任务步骤
5. AI 在任务生成、阶段切换、完成交付时回写叙事质感
6. 奖励既包括资源,也包括关系、情报和后续机会
这样生成出来的任务,才会同时满足三件事:
- **像从当前剧情里自然长出来的**
- **像系统里可验证、可推进、可存档的**
- **像 AI 原生游戏真正该有的任务结构**

View File

@@ -0,0 +1,637 @@
# AI 原生 RPG 模板开场动画 PRD
更新时间:`2026-04-25`
## 0. 文档目的
这份 PRD 用于把 RPG 模板中的“开场动画”从一张静态封面或一段普通介绍,升级成可由 AI 资产链稳定生成、可保存、可预览、可发布、可在开局自动播放的 `15` 秒视频。
本次开场动画采用当前 AI 视频生成更稳定的工程化工作流:
```text
RPG 世界草稿 / 模板锚点
-> 生成 4 张首尾关键帧图
-> 用关键帧 1-2 生成第 1 段 5 秒视频
-> 用关键帧 2-3 生成第 2 段 5 秒视频
-> 用关键帧 3-4 生成第 3 段 5 秒视频
-> 统一规格转码并拼接为 15 秒开场动画
-> 挂回 RPG 模板与作品资产
-> 玩家首次进入 RPG 运行态时播放,结束后进入开局场景
```
这份文档只做产品、数据、生成链路和落地边界设计,不直接改工程代码。
---
## 1. 在线工作流调研结论
### 1.1 为什么不用一次性生成 15 秒长视频
当前主流 AI 视频模型已经能直接生成较长视频,但对游戏开场来说,一次性生成 `15` 秒仍有 4 个风险:
1. 角色、服装、标志物和世界风格容易在中段漂移。
2. 镜头容易自发切换,导致关键叙事信息没有按顺序出现。
3. 第 15 秒无法稳定落到玩家即将进入的开局场景。
4. 失败后重跑成本高,不能只修某一幕。
因此本项目第一版采用“关键帧定锚 + 分段生成 + 后期拼接”的方式。每段只表达一个镜头目标,失败时只重跑对应片段。
### 1.2 可参考的行业能力
调研到的主流能力如下:
| 来源 | 对本项目有用的结论 |
| --- | --- |
| Google Vertex AI Veo | 官方支持上传起始帧与结束帧生成视频,控制视频首尾画面。文档更新时间为 `2026-04-24`。参考https://docs.cloud.google.com/vertex-ai/generative-ai/docs/video/generate-videos-from-first-and-last-frames |
| Runway Gen-4 | 官方建议 `5``10` 秒片段把每次生成视作单一场景并强调输入图决定起始视觉、提示词重点写运动。参考https://help.runwayml.com/hc/en-us/articles/39789879462419-Gen-4-Video-Prompting-Guide |
| Kling AI | 首尾帧功能用于上传两张图生成过渡视频,并提示两张图主题和构图越接近,`5` 秒内过渡越稳定差异太大会触发镜头切换。参考https://kling.ai/quickstart/ai-video-start-end-frames |
| Luma Ray | 强调关键帧、角色参考和跨镜头连续性,可用于理解“长镜头拆段 + 关键帧控制”的制作方向。参考https://lumalabs.ai/ray |
### 1.3 对本项目的工作流选择
本项目优先采用如下策略:
1. 用文本模型先从 RPG 模板锚点生成 `openingAnimationBlueprint`
2. 用图片模型一次性生成 `4` 张统一风格关键帧。
3. 用首尾帧视频模型生成 `3``5` 秒片段。
4. 用后端 `ffmpeg` 做统一转码、无缝拼接和封面帧提取。
5. 用 OSS + `asset_object` + `asset_entity_binding` 保存最终资产。
6. 前端只展示生成状态、预览视频和开局播放,不承担生成逻辑和视频拼接。
第一版模型供应商不写死在产品逻辑中。国内可用主链优先复用当前 Rust 资产生成链中已有的 Ark / DashScope 配置;如后续接入 Veo、Runway、Kling、Luma只作为 `provider` 扩展,不改变 RPG 模板数据结构。
---
## 2. 一句话定义
RPG 模板开场动画是一段由 `4` 张叙事关键帧和 `3``5` 秒 AI 视频片段组成的 `15` 秒多场景冒险开场演出,用于在玩家首次进入作品时快速建立世界观、核心冲突、目标牵引,并自然衔接到开局场景。
---
## 3. 本次目标
1. RPG 模板必须新增开场动画蓝图,作为世界草稿和发布作品的一部分。
2. 开场动画必须固定为 `4` 张关键帧、`3` 个视频片段、总时长 `15` 秒。
3. 四张关键帧必须分别表达:
- 第一幕:世界观
- 第二幕:核心冲突与核心角色出场
- 第三幕:核心目标
- 第四幕:衔接开局场景
4. 三段视频必须分别由相邻关键帧作为首尾帧生成:
- 视频 1关键帧 1 -> 关键帧 2
- 视频 2关键帧 2 -> 关键帧 3
- 视频 3关键帧 3 -> 关键帧 4
5. 最终成片必须能在 RPG 作品详情、创作结果页和运行时开局链路中复用。
6. 播放结束后必须进入 RPG 开局场景;如果玩家跳过,也进入同一个开局场景。
7. 开场动画生成失败不能阻断 RPG 发布和进入游戏,必须允许重新生成和无动画降级。
8. 所有生成、拼接、资产落库和状态流转都必须在 Rust 后端完成,禁止回到 `server-node`
---
## 4. 明确不做
1. 不做一次性长视频生成主链。
2. 不在前端浏览器里拼接视频。
3. 不把功能说明、规则解释默认写进游戏 UI。
4. 不新增独立的“开场动画系统页面”;入口嵌入现有 RPG 创作结果页和模板配置区。
5. 不要求第一版生成配音、字幕、音乐和音效。
6. 不要求运行时根据玩家选择动态改写开场动画。
7. 不在 SpacetimeDB reducer 内调用外部视频模型、OSS 或文件系统。
8. 不兼容 `server-node` 旧生成链;旧实现只允许参考和迁移。
---
## 5. 叙事设计
## 5.1 四幕语义
| 幕 | 关键表达 | 画面职责 | 与 RPG 模板字段关系 |
| --- | --- | --- | --- |
| 第一幕:世界观 | 这个世界是什么样,正在承受什么长期压力 | 展示地貌、文明、时代气质、异常现象或历史伤痕 | 读取 `worldTheme``worldHook`、世界线程、主题母题、核心地标 |
| 第二幕:核心冲突与核心角色 | 谁被卷入冲突,冲突以什么形式爆发 | 让可扮演角色或核心 NPC 出场,并露出敌对力量、灾变、追捕、仪式或阵营压迫 | 读取主角、核心 NPC、阵营线、明线冲突 |
| 第三幕:核心目标 | 玩家为什么要开始冒险 | 展示目标物、禁地、远方地标、失落遗物、必须抵达的地点或必须拯救的人 | 读取主线目标、初始任务、关键物件、章节目标 |
| 第四幕:开局衔接 | 玩家即将在哪里醒来、抵达或被迫行动 | 画面落到第一个可操作场景,构图必须可作为游戏开局背景的前导镜头 | 读取开局场景、多幕第一幕背景、初始 NPC |
### 5.2 镜头节奏
| 视频片段 | 时长 | 首尾帧 | 镜头目标 |
| --- | --- | --- | --- |
| `opening_clip_01` | `5s` | 世界观帧 -> 冲突帧 | 从宏观世界推进到冲突爆发,镜头可采用推进、俯冲、穿越云层、掠过地标 |
| `opening_clip_02` | `5s` | 冲突帧 -> 目标帧 | 让核心角色带着冲突压力朝目标靠近,镜头可采用跟随、转身、拔剑、奔跑、法阵亮起 |
| `opening_clip_03` | `5s` | 目标帧 -> 开局场景帧 | 从目标牵引落回玩家即将进入的地点,镜头可采用推门、坠落、醒来、抵达、火光转场 |
### 5.3 提示词原则
生成视频片段时,提示词只描述本段运动,不重复大段设定说明。
每段提示词必须包含:
1. 镜头运动:例如缓慢推进、低空掠过、跟随角色、从远景落到近景。
2. 主体运动:例如角色转身、队伍穿过遗迹、光芒汇聚、风暴逼近。
3. 场景运动:例如云层翻涌、旗帜震动、烛火摇曳、尘土散开。
4. 连续性约束:首帧和尾帧中的角色、服装、标志物、色彩基调保持一致。
5. 游戏开场质感:多场景冒险 RPG、电影感、清晰主体、可读构图。
每段提示词禁止:
1. 同时要求多个互相冲突的镜头切换。
2. 用抽象词替代具体运动。
3. 使用“不出现 / 不要 / 禁止”作为主要约束;应改写成正向描述。
4. 要求模型在 `5` 秒内完成跨时代、跨空间、跨角色的大跳变。
---
## 6. 数据结构设计
## 6.1 RPG 模板新增字段
在 RPG 模板 / 世界 profile 中新增:
```ts
type RpgOpeningAnimationBlueprint = {
id: string;
enabled: boolean;
status: 'not_started' | 'planning' | 'keyframes_generating' | 'clips_generating' | 'stitching' | 'ready' | 'failed';
version: number;
provider: string;
aspectRatio: '16:9';
totalDurationSec: 15;
clipDurationSec: 5;
keyframes: RpgOpeningAnimationKeyframe[];
clips: RpgOpeningAnimationClip[];
finalAsset?: RpgOpeningAnimationFinalAsset;
fallbackPosterAssetId?: string;
error?: RpgOpeningAnimationError;
createdAt: string;
updatedAt: string;
};
```
说明:
1. `enabled` 控制运行时是否播放。
2. `status` 由后端写入,前端只订阅和展示。
3. `provider` 表示真实使用的生成供应商,例如 `ark``dashscope``veo``runway``kling``luma`
4. 第一版只支持 `16:9`,移动端播放时做安全裁切,不生成竖版副本。
## 6.2 关键帧对象
```ts
type RpgOpeningAnimationKeyframe = {
id: string;
order: 1 | 2 | 3 | 4;
actRole: 'worldview' | 'conflict_and_role' | 'core_goal' | 'opening_scene_bridge';
title: string;
narrativeIntent: string;
prompt: string;
negativePrompt?: string;
sourceAnchorIds: string[];
assetObjectId?: string;
previewUrl?: string;
generationStatus: 'pending' | 'generating' | 'ready' | 'failed';
};
```
字段口径:
1. `title` 只用于后台调试和创作结果页内部管理,不直接作为游戏 UI 文案。
2. `narrativeIntent` 必须写清该帧承担的剧情功能。
3. `sourceAnchorIds` 记录本帧来自哪些模板锚点,便于后续重新生成时保持语义。
## 6.3 视频片段对象
```ts
type RpgOpeningAnimationClip = {
id: string;
order: 1 | 2 | 3;
fromKeyframeId: string;
toKeyframeId: string;
durationSec: 5;
prompt: string;
providerTaskId?: string;
assetObjectId?: string;
previewUrl?: string;
generationStatus: 'pending' | 'generating' | 'ready' | 'failed';
technicalProfile: {
width: number;
height: number;
fps: 24 | 25 | 30;
codec: 'h264';
container: 'mp4';
};
};
```
## 6.4 最终资产对象
```ts
type RpgOpeningAnimationFinalAsset = {
assetObjectId: string;
playbackUrl: string;
posterAssetObjectId: string;
posterUrl: string;
durationSec: 15;
width: number;
height: number;
fps: 24 | 25 | 30;
codec: 'h264';
container: 'mp4';
clips: string[];
generatedAt: string;
};
```
---
## 7. 后端生成流程
## 7.1 总流程
```text
POST /api/custom-world/:profileId/opening-animation/generate
-> 校验作品归属与 RPG 类型
-> 读取世界 profile / 模板锚点 / 开局场景 / 角色视觉描述
-> 生成 openingAnimationBlueprint 文本计划
-> 生成 4 张关键帧图
-> 生成 3 个首尾帧视频片段
-> 下载远端视频
-> 统一转码为同规格 mp4
-> 拼接为 final opening mp4
-> 提取 poster
-> 上传 OSS
-> 确认 asset_object
-> 绑定到 RPG profile 的 opening-animation 槽位
-> 写回状态 ready
```
## 7.2 生成计划阶段
生成计划由 `api-server` 调用 `platform-llm` 完成,不进入 SpacetimeDB reducer。
输入上下文最少包含:
1. 世界一句话钩子。
2. 主题母题。
3. 明线冲突。
4. 暗线冲突的非剧透摘要。
5. 主角 / 核心 NPC 的视觉描述。
6. 第一个场景章节和开局场景。
7. 初始任务目标。
8. 已有场景图 / 角色图资产 URL。
输出必须是结构化 JSON至少包含
1. 四幕 `narrativeIntent`
2. 四张关键帧图片 prompt。
3. 三段视频 motion prompt。
4. 风格统一约束。
5. 关键角色和标志物连续性约束。
## 7.3 关键帧生成阶段
关键帧生成必须优先复用已有图片生成链:
1. 统一走 Rust `api-server`
2. 真实请求外部图片服务。
3. 结果落 OSS。
4. 确认 `asset_object`
5. 绑定槽位:
- `rpg-opening-keyframe-1`
- `rpg-opening-keyframe-2`
- `rpg-opening-keyframe-3`
- `rpg-opening-keyframe-4`
关键帧生成要求:
1. 分辨率首版固定 `1280x720` 或供应商最接近的 `16:9` 输出。
2. 四张图必须共享同一 `styleSeed / visualBible`
3. 核心角色在第二幕和第三幕必须保持同一服装、轮廓、武器或标志物。
4. 第四幕必须与开局场景背景语义一致,必要时使用开局场景图作为参考图。
## 7.4 视频片段生成阶段
每段视频生成请求必须显式传入:
1. 首帧图片。
2. 尾帧图片。
3. `5` 秒时长。
4. `16:9` 比例。
5. 本段 motion prompt。
6. 连续性约束。
视频片段槽位:
1. `rpg-opening-clip-1`
2. `rpg-opening-clip-2`
3. `rpg-opening-clip-3`
如果供应商不支持首尾帧:
1. 该供应商不能作为首选主链。
2. 只允许作为内部实验 provider。
3. 不允许把只支持单首帧的结果标记为正式通过。
## 7.5 拼接与转码
后端必须在拼接前统一三段视频规格:
1. 容器:`mp4`
2. 编码:`h264`
3. 像素格式:`yuv420p`
4. 分辨率:`1280x720`
5. 帧率:优先 `24fps`,若供应商固定 `25fps``30fps`,三段必须统一。
6. 音频:第一版默认无音轨;如供应商返回音频,拼接前静音或统一移除。
拼接后必须提取:
1. `poster`:第 `0.5` 秒或第一张关键帧。
2. `endPoster`:第 `14.5` 秒,用于确认衔接开局场景。
3. `duration`:必须在 `14.5s ~ 15.5s`
---
## 8. SpacetimeDB 与 Rust 边界
### 8.1 SpacetimeDB 负责
1. 保存 RPG profile 中的开场动画蓝图状态。
2. 保存资产对象与业务槽位绑定关系。
3. 通过 reducer / procedure 更新可订阅状态。
4. 让前端通过订阅或查询拿到当前 `openingAnimationBlueprint`
### 8.2 SpacetimeDB 不负责
1. 不调用外部模型。
2. 不下载视频。
3. 不执行 `ffmpeg`
4. 不访问 OSS。
5. 不在 reducer 里生成随机非确定性内容。
### 8.3 Rust api-server 负责
1. 编排 LLM 计划、图片生成、视频生成、转码拼接。
2. 管理异步任务轮询。
3. 处理 OSS 上传与下载。
4. 调用 SpacetimeDB procedure 写入最终状态和资产绑定。
5. 对前端提供 HTTP / SSE 生成进度。
这条边界必须遵守 SpacetimeDB 规则reducer 是确定性事务,不能把外部 I/O 放进去。
---
## 9. 前端嵌入设计
## 9.1 创作结果页
入口位置:
1. 复用 RPG 创作结果页现有资产区。
2. 增加一个“开场动画”资产槽。
3. 点击槽位打开独立面板,不在当前卡片下方展开。
面板能力:
1. 预览最终 `15` 秒视频。
2. 展示四张关键帧缩略图。
3. 展示三段视频状态。
4. 支持重新生成全部。
5. 支持只重生某张关键帧,并自动标记相关视频片段需要重生。
6. 支持只重生某段视频。
7. 支持禁用开场动画。
UI 约束:
1. 不展示大段功能说明。
2. 状态用短标签和进度表达。
3. 移动端优先:关键帧横向滑动,视频预览保持 `16:9`
4. 按钮使用图标 + 短文本,避免规则说明型文案。
## 9.2 RPG 模板发布
发布时校验:
1. 如果 `enabled = true`,则 `finalAsset` 必须存在且可读取。
2. 如果生成失败,发布不阻断,但自动写入 `enabled = false` 并保留错误状态。
3. 发布后的作品详情页可展示开场动画 poster但不强制自动播放。
## 9.3 运行时开局播放
播放时机:
```text
玩家点击开始游戏 / 继续进入新开局
-> 完成角色选择
-> 初始化 RPG session
-> 若 openingAnimation.enabled 且 finalAsset 可用
-> 播放开场动画
-> 播放结束或跳过
-> 进入开局场景
```
规则:
1. 同一个存档只自动播放一次。
2. 玩家跳过后必须记录 `openingAnimationPlayed = true`
3. 继续游戏不自动播放,除非玩家从作品详情页手动预览。
4. 视频加载失败时直接进入开局场景。
5. 移动端播放必须提供明显的跳过按钮,但不写说明段落。
---
## 10. 状态机
```text
not_started
-> planning
-> keyframes_generating
-> clips_generating
-> stitching
-> ready
任意生成阶段
-> failed
-> planning / keyframes_generating / clips_generating
```
关键规则:
1. 重生关键帧 1会使视频 1 失效。
2. 重生关键帧 2会使视频 1 和视频 2 失效。
3. 重生关键帧 3会使视频 2 和视频 3 失效。
4. 重生关键帧 4会使视频 3 失效。
5. 重生某段视频后必须重新拼接最终成片。
6. 最终成片 ready 后,旧版本资产不能立即删除,至少保留最近 `2` 个版本用于回滚。
---
## 11. API 设计
### 11.1 生成开场动画
```http
POST /api/custom-world/:profileId/opening-animation/generate
```
请求:
```json
{
"mode": "full",
"provider": "auto",
"forceRegenerate": false
}
```
返回:
```json
{
"jobId": "opening_anim_job_xxx",
"status": "planning"
}
```
### 11.2 重生关键帧
```http
POST /api/custom-world/:profileId/opening-animation/keyframes/:keyframeId/regenerate
```
### 11.3 重生视频片段
```http
POST /api/custom-world/:profileId/opening-animation/clips/:clipId/regenerate
```
### 11.4 查询状态
```http
GET /api/custom-world/:profileId/opening-animation
```
返回当前 `RpgOpeningAnimationBlueprint`
### 11.5 订阅进度
```http
GET /api/custom-world/:profileId/opening-animation/jobs/:jobId/stream
```
SSE 事件:
1. `planning`
2. `keyframe_ready`
3. `clip_ready`
4. `stitching`
5. `ready`
6. `error`
---
## 12. 工程落地阶段
### 阶段 1文档与契约冻结
1. 确认 `RpgOpeningAnimationBlueprint` 字段。
2. 确认资产槽位命名。
3. 确认 provider 抽象。
4. 确认运行时只播放一次的状态字段。
验收:
1. 文档字段可直接编码。
2. 前后端对同一 JSON contract 无歧义。
### 阶段 2后端计划与关键帧生成
1. `api-server` 生成四幕计划。
2. 接入图片生成。
3. 关键帧落 OSS 和 `asset_object`
4. profile 写回关键帧状态。
验收:
1. 能在结果页看到四张真实生成图。
2. 第四张图语义上能衔接开局场景。
### 阶段 3首尾帧视频生成
1. 三段视频真实请求外部模型。
2. 每段固定 `5` 秒。
3. 每段落 OSS。
4. 支持失败重试与单段重生。
验收:
1. 三段视频都不是占位视频。
2. 每段首尾画面与对应关键帧一致。
### 阶段 4拼接发布与运行时播放
1. 后端统一转码。
2. 拼接成 `15` 秒成片。
3. 提取 poster。
4. RPG 运行态首次开局播放。
5. 播放结束或跳过进入开局场景。
验收:
1. 最终视频时长在 `14.5s ~ 15.5s`
2. 播放后进入的场景与第四幕一致。
3. 同一存档不会重复自动播放。
---
## 13. 质量验收标准
### 13.1 叙事验收
1. 第一幕不用字幕也能看出世界类型和主要气质。
2. 第二幕能看出冲突正在发生,并且核心角色可被识别。
3. 第三幕能看出玩家即将追求的目标。
4. 第四幕能自然落到开局场景,不像另一个无关地点。
5. 四幕之间存在视觉连续性,不是四张无关插图。
### 13.2 视频验收
1. 三段均为真实外部生成结果。
2. 每段约 `5` 秒。
3. 拼接后无明显黑帧、重复帧、尺寸跳变。
4. 主体没有严重形变、闪烁、消失。
5. 核心角色在第二、第三幕保持可识别一致。
6. 移动端播放不裁掉核心主体。
### 13.3 工程验收
1. 所有生成任务由 Rust `api-server` 编排。
2. 资产落 OSS并有 `asset_object` 记录。
3. 业务实体通过槽位绑定读取资产。
4. SpacetimeDB reducer 不包含外部 I/O。
5. 前端刷新后仍能恢复生成状态。
6. 生成失败有可重试状态,不写入假成功。
---
## 14. 风险与降级
| 风险 | 降级策略 |
| --- | --- |
| 关键帧风格不一致 | 用同一 visual bible、参考图和角色视觉描述重生四张图 |
| 首尾帧差异过大导致视频硬切 | 调整相邻关键帧构图,使主体、视角、色彩更接近 |
| 第二幕角色漂移 | 使用角色主形象作为参考图,并在第二、第三幕共享角色约束 |
| 视频生成超时 | 单段失败只重试该段,不重跑全流程 |
| 拼接后有黑帧 | 后端转码时强制统一 fps、分辨率、像素格式 |
| 移动端加载慢 | poster 先显示,视频懒加载;失败直接进开局场景 |
| 供应商审核失败 | 后端生成更保守的原创 prompt 重试一次,仍失败则标记 failed |
---
## 15. 后续扩展
1. 增加背景音乐和环境音,但不改变四帧三段主链。
2. 为移动端生成 `9:16` 竖版裁切版本。
3. 支持创作者手动上传某张关键帧,再生成相邻视频。
4. 支持发布后版本化替换开场动画。
5. 支持用第四幕直接生成开局场景动态背景。
6. 支持把开场动画拆出的关键帧回流为作品详情页轮播素材。

View File

@@ -0,0 +1,526 @@
# AI 原生游戏的运行时物品生成设计建议
更新时间:`2026-04-02`
## 0. 设计目标
这份方案针对当前项目,回答的是:
**如果要把运行时物品生成做成“AI 原生”,应该怎样设计,才能既贴合背景 / NPC / 当前事件,又不会把数值系统做崩。**
这里的“AI 原生”不是指“让模型直接胡乱造装备”,而是指:
- 物品的**语义、出处、命名、关系、叙事理由**由 AI 根据上下文生成
- 物品的**稀有度、build 标签、数值预算、持久化结果**由本地规则编译和裁剪
一句话:
**AI 决定这是什么,规则决定它能做什么。**
## 1. 设计原则
## 1.1 物品必须是“当前故事的一部分”
运行时物品不该只是“随机掉了个稀有剑”。
每个重要物品都至少回答 4 个问题:
1. 它为什么会出现在这里?
2. 它和哪个场景背景有关?
3. 它和哪个 NPC / 势力 / 怪物有关?
4. 它对当前玩家 build 为什么有意义?
## 1.2 物品收益以“标签倾向”优先,纯数值为辅
建议把 AI 原生物品的主要收益做成两大类:
1. **获得 build 标签**
- 永久标签:主要由装备 / 稀有饰品 / 关键遗物提供
- 限时标签:主要由消耗品 / 临时护符 / 战场符箓提供
2. **少量直接数值**
- 只做补充,不做主菜
- 避免数值碾压 build 语义
也就是说,运行时物品的第一身份应该是:
**“把玩家的构筑推向某种风格”**
而不是:
**“给一个更大的攻击数字”**
## 1.3 物品生成必须显式读取上下文
建议运行时物品生成必须至少读取以下上下文:
- 世界背景
- 当前场景 / 地标 / 氛围
- 当前 encounter / 相关 NPC / 相关怪物
- 最近 1~3 个关键剧情行为
- 玩家当前装备与激活 build 标签
- 玩家当前缺口
- 续航不够
- 控场不足
- 缺切后
- 缺护体
- 当前奖励渠道
- 宝藏
- 交易
- 委托
- 掉落
- 观察所得
## 1.4 AI 只产出“意图”,本地编译成成品
不要让 AI 直接返回最终 `InventoryItem`
建议让 AI 先返回的是“物品意图”:
- 物品主题
- 物品来源
- 关联对象
- 倾向标签
- 永久 / 限时
- 用途类型
然后本地再把它编译成:
- `category`
- `rarity`
- `tags`
- `statProfile`
- `useProfile`
- `buildProfile`
- `value`
这样才能稳定、可测试、可平衡。
## 2. 建议的系统结构
建议把新系统拆成 4 层。
## 2.1 上下文采样层
输入一份统一的 `RuntimeItemContext`
```ts
type RuntimeItemContext = {
worldType: WorldType | null;
customWorldProfile?: CustomWorldProfile | null;
sceneId?: string | null;
sceneName?: string | null;
sceneDescription?: string | null;
landmarkHints?: string[];
encounter?: Encounter | null;
relatedNpcState?: NpcPersistentState | null;
recentStoryMoments: StoryMoment[];
playerCharacter: Character;
playerEquipment: EquipmentLoadout;
activeBuildBuffs: TimedBuildBuff[];
activeBuildTags: string[];
generationChannel: "treasure" | "npc_trade" | "npc_reward" | "monster_drop" | "quest_reward" | "discovery";
};
```
这一层的目标不是做物品,而是把“这次生成到底是在什么局面下发生”说清楚。
## 2.2 AI 意图层
让模型只生成一个轻量蓝图:
```ts
type RuntimeItemIntent = {
narrativeTheme: string;
sourceKind: "npc" | "scene" | "monster" | "faction" | "quest" | "ancient";
sourceName: string;
reasonToAppear: string;
itemArchetype: "equipment" | "consumable" | "material" | "relic" | "quest";
permanence: "permanent" | "timed";
desiredBuildTags: string[];
desiredStatBias: Array<"hp" | "mana" | "outgoing" | "mitigation" | "cooldown">;
relationHooks: string[];
};
```
重点是:
- AI 负责“它像什么”
- 不负责“最终数值是多少”
## 2.3 本地编译层
本地把 `RuntimeItemIntent` 编译成正式物品:
- 先做标签规范化
-`normalizeBuildTags`
- 再判定品类
- 装备 / 消耗品 / 材料 / 稀有品 / 剧情物
- 再套预算
- rarity budget
- stat budget
- tag budget
- duration budget
- 最后写入:
- `buildProfile`
- `statProfile`
- `useProfile`
- `value`
## 2.4 叙事回写层
物品成品生成后,再把这些信息回写到叙事文本:
- 它看起来像什么
- 它为什么来自这个 NPC / 地点
- 它和哪条线索或关系有关
- 玩家为什么会觉得“这东西确实该在这里出现”
这一步仍然可以交给 AI但只能读“已经生成好的成品”。
## 3. 建议的物品类型设计
## 3.1 永久 build 标签物品
适合:
- 武器
- 护甲
- 饰品
- 关键遗物
建议规则:
- 常规装备最多给 `1` 个核心永久标签
- 稀有或史诗装备可给 `1` 个核心标签 + `1` 个协同标签
- 传说物品可以额外充当 set / faction / NPC build 锚点
示例:
- “渡口缉索短刃”
- 永久标签:`快袭`
- 协同标签:`追击`
- 小量数值:`outgoingDamageBonus`
- “镇河旧誓铜符”
- 永久标签:`守御`
- 协同标签:`护体`
- 小量数值:`maxManaBonus`
## 3.2 限时 build 标签物品
适合:
- 药剂
- 符箓
- 临时护符
- 战场应急工具
建议规则:
- 只通过 `useProfile.buildBuffs` 生效
- 持续 `1~3` 回合
- 一次最多提供 `1~2` 个标签
- 可叠加刷新时长,但不建议无限堆层
示例:
- “雾沼息行符”
- `2` 回合获得:`风行``游击`
- “火工催压油”
- `1` 回合获得:`爆发`
- 同时 `cooldownReduction: 1`
## 3.3 少量直接数值物品
适合做补充,而不是 build 主轴。
建议预算:
- 武器:
- `outgoingDamageBonus` 小幅增加
- 护甲:
- `maxHpBonus`
- 或少量 `incomingDamageMultiplier`
- 饰品:
- `maxManaBonus`
- 或轻量 `outgoingDamageBonus`
- 消耗品:
- `hpRestore`
- `manaRestore`
- `cooldownReduction`
建议约束:
- 常规运行时随机物品,数值权重应低于标签权重
- 不要让一个完全无标签的高数值物品压过语义鲜明的 build 物品
## 4. 如何保证“高度贴合背景和 NPC”
## 4.1 生成必须绑定三个锚点
建议每个 AI 原生物品至少有三个锚点:
1. **场景锚点**
- 例如矿道、渡口、祭坛、雾林、裂界前线
2. **关系锚点**
- 某个 NPC、某个势力、某类怪物、某段旧事
3. **玩法锚点**
- 玩家当前 build 缺口或当前风险
如果一个候选物品说不清这三个锚点,就不要发。
## 4.2 命名要使用世界词汇表,不要只按品类随机拼接
建议名字由三部分组成:
```text
来源词 + 关系词 + 品类词
```
例如:
- “锁风渡缉索短刃”
- “药谷回岚灵露”
- “断碑旧誓护心佩”
- “裂界巡守压纹符”
来源词来自:
- 场景 / 地标
- NPC 身份
- 势力 / 流派
- 当前任务线
而不是仅仅:
- 稀有前缀 + 武器名
## 4.3 描述文案要回答“为什么现在拿到它”
建议每个重要物品描述都带一句运行时来源理由:
- 是谁留下的
- 是从谁身上掉的
- 为什么这时能交易给你
- 为什么这次观察能发现它
这样玩家会感觉它是叙事结果,而不是系统掉表。
## 5. 建议的平衡规则
## 5.1 稀有度决定预算,不直接决定强度飞跃
建议把稀有度主要用于控制:
- 可带多少标签
- 是否允许 set / faction 锚点
- 叙事权重和经济价值
而不是简单理解为:
- 稀有度越高,数值就暴涨
建议预算参考:
| 稀有度 | 永久标签 | 限时标签 | 数值预算 |
| --- | --- | --- | --- |
| common | 0~1 | 1 | 很小 |
| uncommon | 1 | 1~2 | 小 |
| rare | 1+1协同 | 2 | 中等偏小 |
| epic | 2 或 set 锚点 | 2 | 中等 |
| legendary | 2 + 关系锚点 | 2~3 | 中等,但仍受上限约束 |
## 5.2 当前阶段优先支持“补短板”和“定方向”
建议运行时物品生成时,优先做这两类决策:
1. **补短板**
- 玩家 build 缺续航,就更容易拿到 `回复 / 续战 / 护体`
- 玩家 build 缺切后,就更容易拿到 `快袭 / 突进 / 风行`
2. **定方向**
- 当玩家已经有明显 build 倾向时,再投放协同物品,把这条路做深
不建议一味“追高强度”,否则玩家会频繁被迫换流派。
## 5.3 运行时物品要避免频繁彻底改流派
建议把随机物品对 build 的影响控制为:
- 大多数时候:
- 强化现有方向
- 或提供邻近方向
- 少数特殊奖励:
- 才允许提供“转流派锚点”
这样玩家会觉得构筑在成长,而不是被系统不断推翻。
## 6. 建议的接入点
## 6.1 宝藏奖励
当前最适合先改的是 `resolveTreasureReward`
建议把它升级为:
- 先收集:
- scene preset
- treasure hint
- 最近事件
- 当前遭遇 NPC / 怪物痕迹
- 再生成 1 个上下文物品
- 剩余奖励继续走稳定资源:
- 货币
- 基础材料
- 常规补给
这样宝藏会从“奖励池”变成“叙事发现”。
## 6.2 NPC 交易 / 赠礼 / 帮助
建议给 NPC 增加“关系定制物品”出口:
- 商人:
- 卖与你当前 build 有关、但带其身份烙印的物品
- 帮助奖励:
- 给限时道具或一次性符箓
- 高好感 NPC
- 才会给带永久 build 标签的私人遗物/信物
这样交易和关系系统就会真正联动。
## 6.3 怪物掉落
建议掉落分两层:
1. 基础掉落
- 继续走 preset / material / loot table
2. 语义掉落
- 从怪物生态、战斗风格、所在场景生成一个 build 倾向物品或精粹
例如:
- 重甲守卫掉:
- `守御精粹`
- `护体甲片`
- 雾林刺客掉:
- `快袭羽饰`
- `风行药囊`
## 6.4 委托奖励
任务奖励最适合给:
- 带关系来源的永久物品
- 剧情关键 rare / relic
- 能把玩家 build 往下一个阶段推一把的奖励
这类物品最适合绑定:
- 委托发布人
- 委托目标
- 地标
- 任务线真相
## 7. 建议新增的数据结构
建议在不推翻现有 `InventoryItem` 的前提下,新增一层来源元数据。
```ts
type RuntimeItemNarrativeBinding = {
generationChannel: "treasure" | "npc_trade" | "npc_reward" | "monster_drop" | "quest_reward" | "discovery";
sceneId?: string;
sceneName?: string;
relatedNpcId?: string;
relatedNpcName?: string;
relatedMonsterId?: string;
relatedFaction?: string;
storyReason: string;
eventHook?: string;
};
type RuntimeItemMetadata = {
origin: "catalog" | "procedural" | "ai_compiled";
seedKey?: string;
narrativeBinding?: RuntimeItemNarrativeBinding;
};
```
然后在 `InventoryItem` 上增加可选字段:
```ts
interface InventoryItem {
runtimeMetadata?: RuntimeItemMetadata;
}
```
这样后面 UI、日志、剧情回放都能解释
**这个物品到底从哪来。**
## 8. 推荐的最小落地顺序
建议不要一步把所有入口都改成 AI 原生,而是分三阶段。
## 阶段 A先做“上下文编译器”不改所有入口
新增:
- `src/data/runtimeItemDirector.ts`
- `src/data/runtimeItemCompiler.ts`
- `src/types/runtimeItem.ts`
先只负责:
- 接收上下文
- 生成意图
- 编译成 `InventoryItem`
## 阶段 B先接一个入口验证
优先接:
- `treasureInteractions.ts`
因为它最独立,风险最小,最容易观察“贴合背景”的提升。
## 阶段 C再接 NPC 与任务
等宝藏验证稳定后,再接:
- NPC 交易
- NPC 帮助奖励
- 任务奖励
最后再考虑怪物掉落的 AI 原生语义层。
## 9. 这套方案和当前仓库为什么契合
这套方案不是另起炉灶,而是直接复用当前仓库已经有的能力:
- 复用 `InventoryItem`
- 复用 `ItemStatProfile`
- 复用 `ItemUseProfile`
- 复用 `ItemBuildProfile`
- 复用 `normalizeBuildTags`
- 复用 `TimedBuildBuff`
- 复用装备、背包、锻造、build 结算
- 复用“AI 叙事,本地规则结算”的总边界
所以它不是推翻当前系统,而是补上当前系统最缺的那一层:
**上下文感知的运行时物品导演。**
## 10. 最后结论
对这个项目来说,理想的 AI 原生运行时物品生成不应该做成“AI 随机喷装备”,而应该做成:
1. AI 根据场景、背景、NPC、最近事件和玩家 build先生成物品语义意图。
2. 本地规则把这个意图编译成带永久或限时 build 标签、并附带少量数值加成的正式物品。
3. 物品必须能解释“为什么它会在这里,由谁带来,对当前玩家为什么有意义”。
4. 宝藏、交易、任务、掉落都逐步接入同一套导演层。
这样生成出来的物品才会同时满足三件事:
- **像故事里长出来的**
- **像 build 里需要的**
- **像系统里可控的**

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,901 @@
# AI 原生场景多幕配置与 NPC 相遇聊天流程 PRD
更新时间:`2026-04-20`
## 0. 文档目的
这份 PRD 用于把下面几条已经存在但还没真正接成一条产品主链的设计,收束成一次可直接编码的迭代:
- `docs/prd/AI_NATIVE_AGENT_FIRST_CUSTOM_WORLD_CREATOR_PRD_2026-04-12.md`
- `docs/prd/AI_NATIVE_SCENE_CHAPTER_GAMEPLAY_PRD_AND_EXECUTION_PLAN_2026-04-08.md`
- `docs/prd/AI_NATIVE_NPC_CHAT_SINGLE_TURN_SESSION_PRD_2026-04-18.md`
- `docs/design/NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md`
- `docs/design/SCENE_CHAPTER_LOOP_AND_FIRST_ENTRY_CHAPTER_QUEST_DESIGN_2026-04-08.md`
本次要解决的不是再新建一套场景系统或聊天系统,而是把现有:
1. 创作工作区
2. 场景章节闭环
3. NPC 多轮聊天
4. 场景背景资产
5. 好感度关系流
接成一条新的稳定流程:
**每个场景由创作者在工具中配置为 `2~5` 幕;每一幕都绑定独立背景图和相遇 NPC 顺序;每一幕的第一个 NPC 视为主角色;运行时按幕切换背景和可遇对象,并根据主角色当前好感度裁决聊天轮数与第 5 轮收束方式。**
本次还追加一条必须和草稿生成阶段一起落地的约束:
**Agent 在生成第一版世界草稿时,默认只生成 `1` 个可扮演角色、`2` 个场景章节、每个场景章节固定 `3` 幕、`5~10` 个场景角色;并且要在草稿生成过程中基于底层剧情引擎判定每一幕该由哪些角色出演、背景应该是什么样,再自动生成每幕背景图和每个角色的主形象。动作资产本期不生成。**
补充口径修正:
1. `scene_chapter` 在本期继续保留为数据层 / 编译层 / 运行时层概念。
2. `scene_chapter` 不作为创作者可见的独立 Tab、独立卡片或独立导航入口。
3. 创作者配置多幕的唯一入口,是现有“场景”列表里的场景编辑弹层。
4. 每一幕的 NPC 配置区必须直接叠在当前幕背景预览上,以“对面角色站位”的方式呈现;三个站位既是预览,也是编辑入口。
5. 幕编辑站位中每个角色只显示角色形象与名称,不展示额外信息块、规则说明或说明性标签。
6. 幕内小预览的构图固定为左侧玩家、右侧当前幕角色;右侧三个站位采用一前两后。
前排主角色的 y 轴必须与玩家角色对齐后排两个角色必须同一列、x 轴对齐,上下分布,且后排整体的 y 轴中点与前排主角色保持一致。
7. 新建幕默认仅预置 1 个主角色槽位内容,其余槽位留空,等待创作者补充。
8. 角色名称显示在角色形象上方,角色渲染不附带方形 UI 底板。
9. 世界档案的场景详情页不再单独展示“场景图片”和“场景内 NPC”字段相关兼容数据统一由多幕配置自动同步回场景对象。
这份文档必须能直接指导后续创作工具和游戏流程改造,避免需求落地漂移。
---
## 1. 一句话定义
把当前“一个场景只有一层平铺内容”的创作与运行方式,升级成“一个场景内有多幕推进、每幕有独立视觉和主角色相遇规则”的章节内流程。
---
## 2. 本次目标
本次迭代必须同时满足以下目标:
1. 创作者可以在现有创作页面中为每个场景章节配置多幕内容。
2. 每一幕都必须绑定一张正式背景图。
3. 每一幕都可以配置玩家会遇到哪些 NPC并且保留顺序。
4. 每一幕配置的第一个 NPC 必须被系统认定为该幕主角色。
5. 运行时进入某一幕时,背景图和可遇 NPC 必须随幕切换。
6. 当前幕主角色的聊天轮数必须按好感度裁决,而不是继续完全沿用统一规则。
7. 好感度大于 `0` 的主角色,在相遇后进入无限轮聊天态,直到玩家主动退出。
8. 好感度小于 `0` 的主角色,在相遇后最多只允许聊天 `5` 轮,第 `5` 轮必须输出一段为后续剧情开展铺垫的收束回应。
9. 前端继续只负责展示,幕切换、聊天限制、幕进度与数据裁决全部由 Express 后端负责。
10. 默认复用现有创作页面、草稿抽屉、详情弹层、场景章节和聊天流程,不新开独立系统或新页面。
11. 第一版世界草稿默认规模必须收束为:
- `1` 个可扮演角色
- `2` 个场景章节
- 每个场景章节固定 `3`
- `5~10` 个场景角色
12. 草稿生成阶段必须由后端基于底层剧情引擎直接判定每一幕的:
- 出演角色顺序
- 主角色
- 幕目标
- 幕背景语义
13. 草稿生成完成时,系统必须自动产出:
- 每一幕对应的背景图
- 每个场景角色的主形象
- 可扮演角色的主形象
14. 本期不生成动作、不生成动作预览、不生成动作发布资产。
---
## 3. 明确不做
本次明确不做下面这些事:
1. 不新建独立的“场景编辑器”页面。
2. 不把幕推进逻辑放到前端本地计算。
3. 不让创作者直接编辑底层运行时 `ChapterState` 或聊天状态对象。
4. 不做多 NPC 并行聊天。
5. 不做每一幕的复杂分支树可视化编辑器。
6. 不把“规则说明文案”默认堆到创作页或游戏 UI 面板里。
7. 不把“点击配置”实现成在当前卡片下面继续展开大段内容。
8. 不重写现有高好感委托链路,只在本次规则下明确它什么时候还能触发。
9. 不在草稿生成阶段默认补动作、待机、攻击、跑动或技能动作素材。
10. RPG 世界草稿的可扮演角色、场景角色与场景列表项不再直接展示“生成资产 / 生成场景图”按钮;资产生成由草稿生成链路或后续专门工坊入口承接,列表卡片只保留浏览、编辑、选择和删除等核心操作。
---
## 4. 现状判断
## 4.1 创作工具侧现状
当前仓库已经具备下面这些基础:
1. `src/types/customWorld.ts`
- 已有 `SceneChapterBlueprint / SceneActBlueprint / sceneChapterBlueprints` 数据结构。
2. `server-node/src/services/customWorldAgentDraftCompiler.ts`
- 已经能把草稿阶段生成的场景章节数据编译成正式多幕蓝图。
3. `src/components/CustomWorldEntityEditorModal.tsx`
- 已有现成的 `LandmarkEditor`,这是本期多幕配置的正确承载位置。
4. 现有场景背景图生成与发布链已存在。
但当前仍有 4 个缺口:
1. 场景章节没有“幕”这一层结构化对象。
2. 背景图是场景级资产,不是幕级资产。
3. NPC 与场景的关系主要还是地点级归属,不是幕级相遇编排。
4. 创作者无法在创作页里明确控制“这一幕谁先出场、谁是主角色”。
## 4.2 游戏运行侧现状
当前运行时已经具备下面这些基础:
1. `src/data/questFlow.ts`
- 已有 `scene chapter quest``buildSceneChapterId(...)`
2. `src/services/storyEngine/chapterDirector.ts`
- 已能按场景章节输出 `ChapterState`
3. `src/hooks/story/npcEncounterActions.ts`
- 已有 `npc_chat` 多轮聊天、`turnCount``pendingQuestOffer` 等状态。
4. `packages/shared/src/contracts/story.ts`
- 已有 `NpcChatTurnRequest` / `NpcChatTurnResult` 契约。
但当前仍有 5 个问题:
1. 场景内部仍偏单层推进,缺少“第几幕”的明确状态。
2. 场景背景不会随幕切换。
3. 场景可遇 NPC 不会随幕切换。
4. 主角色没有从配置顺序直接编译成运行时规则。
5. 负好感主角色聊天仍没有“最多 5 轮且第 5 轮收束铺垫”的规则。
一句话总结:
**现在我们有场景章节也有聊天系统但还没有“场景多幕蓝图”这一层把创作配置、背景资产、NPC 相遇顺序和聊天规则真正串起来。**
---
## 5. 核心决策
## 5.1 场景章节与场景幕的关系
本次新增一个明确约束:
- `场景章节` 仍然是场景级闭环容器
- `场景幕` 是场景章节内部的有序分段
关系定义如下:
| 层级 | 作用 |
| --- | --- |
| `scene chapter` | 表示这一整个场景在剧情上的一章 |
| `scene act` | 表示这章内部的第几幕、当前视觉和当前相遇主体 |
每个场景章节必须至少有 `2` 幕,最多 `5` 幕。
## 5.2 多幕数量与章节阶段映射
为了不引入第二套完全独立的运行时章节体系,本次规定场景幕按数量映射到现有 `ChapterState.stage`
| 幕数 | 编译规则 |
| --- | --- |
| `2` 幕 | 幕 1=`opening + expansion`,幕 2=`turning_point + climax + aftermath` |
| `3` 幕 | 幕 1=`opening`,幕 2=`expansion + turning_point`,幕 3=`climax + aftermath` |
| `4` 幕 | 幕 1=`opening`,幕 2=`expansion`,幕 3=`turning_point`,幕 4=`climax + aftermath` |
| `5` 幕 | 与 `opening / expansion / turning_point / climax / aftermath` 一一对应 |
这意味着:
1. 创作者在工具里编辑的是“第几幕”。
2. 运行时仍然只认现有章节阶段枚举。
3. `chapterDirector` 可以继续复用,只是数据来源从“纯 quest 推导”升级成“quest + 幕蓝图联合推导”。
## 5.3 主角色定义
每一幕配置的 `encounterNpcIds` 必须是有序数组。
规则固定为:
1. `encounterNpcIds[0]` 就是当前幕主角色。
2. 运行时会把它编译成 `primaryNpcId`
3. 主角色承担该幕默认的首次相遇、聊天轮数裁决和幕推进优先级。
4. 其余 NPC 视为辅助相遇角色,不直接承担本次“好感度聊天轮数规则”。
## 5.4 开局场景与普通场景的统一规则
本次新增一条必须落实到代码与数据结构的约束:
**开局场景不是一套特殊场景系统,只是“玩家开局所处的那一个场景”。**
因此,开局场景在创作工具、数据结构、保存链路、运行时编译上,都必须与普通场景保持同一套配置参数。
明确要求如下:
1. 开局场景允许配置的字段必须与普通场景一致,至少包括:
- `name`
- `description`
- `imageSrc`
- `sceneNpcIds`(仅作为兼容字段,由多幕配置自动派生,不再作为创作者可编辑字段)
- `connections`
- `sceneChapterBlueprints` 对应的多幕配置
2. 场景配置面板中,开局场景必须复用普通场景同级的配置 UI而不是继续保留一套缩水版表单。
3. 开局场景与普通场景的唯一产品差异,只能是:
- 它是玩家进入世界时默认所在的初始场景
- 它在列表或运行时可带“开局场景 / 初始场景”语义标记
4. 除“初始所在场景”语义之外,不允许再因为它是开局场景而裁掉 NPC、连接、多幕、危险度等配置能力。
5. 为兼容现有数据,当前 `camp` 字段可以继续保留,但其承载的结构必须与普通场景对齐,不能再是阉割版场景结构。
6. 运行时编译时,开局场景也必须按普通场景规则参与:
- 多幕相遇 NPC 编译
- 场景连接编译
- 多幕蓝图读取
- 场景图片 / 残痕 / 预览数据生成
一句话约束:
**“开局场景”是场景身份,不是场景能力分支。**
## 5.5 草稿默认规模与自动资产策略
为了让“生成游戏设定草稿”真正变成一个可直接进入精修的起点,而不是一份需要继续手动补骨架的半成品,本次新增下面这些硬约束:
### 5.5.1 第一版草稿固定规模
第一版 Agent 世界草稿必须默认产出:
1. `1` 个可扮演角色
2. `5~10` 个场景角色
3. `2` 个场景章节
4. 每个场景章节固定 `3`
这里不再沿用旧的“多 playable / 多 landmarks 先铺开”的策略。
原因:
1. 当前创作工作区已经进入“先收关键锚点、再逐步扩写”的阶段。
2. 一次铺太多 playable、场景和长尾对象会稀释创作者对第一版底稿的掌控感。
3. 本期还要把幕级背景图和角色主形象自动挂回草稿,如果对象规模不收束,等待时间和生成成本都会直接失控。
### 5.5.2 幕级出演角色与背景必须由剧情引擎判定
这次不允许继续使用“先生场景,再把同一组 sceneNpcIds 平铺复制到所有幕里”的宽松策略。
后端在生成 `scene chapter -> act` 时,必须基于底层剧情引擎已有结构综合裁定:
1. `storyGraph.visibleThreads / hiddenThreads`
2. 角色 `narrativeProfile / threadIds`
3. 地点 `linkedLandmarkIds / linkedThreadIds`
4. 当前场景章节的 `summary / actGoal / transitionHook`
最少要做出下面这几个结论:
1. 这一幕优先让哪些角色出场
2. 谁是该幕主角色
3. 这一幕的压力核心是什么
4. 这一幕的背景图应该突出什么空间氛围、危险感和叙事残痕
一句话要求:
**每一幕的演员和背景,不是静态复制,而是“线程压力 + 角色挂钩 + 地点语义”联合裁定的结果。**
### 5.5.3 自动生成的资产范围
第一版草稿生成成功后,后端必须自动继续生成并写回:
1. 每一幕的背景图
2. 每个场景角色的主形象
3. 可扮演角色的主形象
本期明确不做:
1. 不自动生成动作
2. 不自动生成精灵表
3. 不自动生成技能动作
4. 不自动生成 run / attack / hurt / die
也就是说,本期资产策略是:
**只产主形象和幕背景,不产动作。**
### 5.5.4 自动资产生成的回写要求
自动资产生成后,草稿层必须直接带回:
1. 角色:
- `imageSrc`
- `generatedVisualAssetId`
2. 场景幕:
- `backgroundImageSrc`
- `backgroundAssetId`
3. 资产覆盖摘要:
- 角色主形象是否就绪
- 场景幕背景是否就绪
这样创作者一进入草稿精修工作区,就能直接看到:
1. 角色已经带主形象
2. 每个场景章节的每一幕已经带背景图
3. 当前草稿哪些资产还缺失
而不是先看到一堆空白占位,再手工逐个点生成。
---
## 6. 数据结构要求
## 6.1 创作草稿层新增结构
建议在现有 `CustomWorldFoundationDraftProfile` 之上新增下面两层:
```ts
type SceneActAdvanceRule =
| 'after_primary_contact'
| 'after_active_step_complete'
| 'after_chapter_resolution';
interface CustomWorldFoundationDraftSceneAct {
id: string;
title: string;
summary: string;
stageCoverage: Array<
| 'opening'
| 'expansion'
| 'turning_point'
| 'climax'
| 'aftermath'
>;
backgroundImageSrc?: string | null;
backgroundAssetId?: string | null;
encounterNpcIds: string[];
primaryNpcId: string;
linkedThreadIds: string[];
actGoal: string;
transitionHook: string;
advanceRule: SceneActAdvanceRule;
}
interface CustomWorldFoundationDraftSceneChapter {
id: string;
sceneId: string;
sceneName: string;
title: string;
summary: string;
linkedThreadIds: string[];
linkedLandmarkIds: string[];
acts: CustomWorldFoundationDraftSceneAct[];
}
```
硬要求:
1. `primaryNpcId` 必须等于 `encounterNpcIds[0]`,不允许单独填写成别的角色。
2. 每幕必须至少有 `1` 个 NPC。
3. 每幕必须有 `backgroundImageSrc``backgroundAssetId`
4. `advanceRule` 由系统按幕位置默认编译,第一版不要求创作者手改。
## 6.2 发布到运行时的蓝图结构
创作草稿在发布时必须进一步编译成运行时蓝图:
```ts
interface SceneActBlueprint {
id: string;
sceneId: string;
title: string;
stageCoverage: Array<
| 'opening'
| 'expansion'
| 'turning_point'
| 'climax'
| 'aftermath'
>;
backgroundImageSrc?: string | null;
encounterNpcIds: string[];
primaryNpcId: string;
advanceRule:
| 'after_primary_contact'
| 'after_active_step_complete'
| 'after_chapter_resolution';
actGoal: string;
transitionHook: string;
}
interface SceneChapterBlueprint {
id: string;
sceneId: string;
title: string;
summary: string;
acts: SceneActBlueprint[];
}
```
建议把它挂入 `CustomWorldProfile` 的新字段中:
```ts
sceneChapterBlueprints?: SceneChapterBlueprint[] | null;
```
原因:
1. 现有 `landmarks` 只足够表达地点,不足够表达幕顺序。
2. 现有 `ChapterState` 是运行时状态,不适合直接兼做创作者蓝图。
3. 独立蓝图层更适合后端编译和发布校验。
## 6.3 聊天状态扩展
建议在现有 `StoryNpcChatState` 上新增有限聊天需要的状态:
```ts
interface StoryNpcChatState {
npcId: string;
npcName: string;
turnCount: number;
customInputPlaceholder?: string;
pendingQuestOffer?: {
quest: QuestLogEntry;
} | null;
sceneActId?: string | null;
turnLimit?: number | null;
remainingTurns?: number | null;
limitReason?: 'negative_affinity' | null;
forceExitAfterTurn?: boolean;
}
```
要求:
1. 正常无限聊天时,`turnLimit``remainingTurns``null`
2. 负好感主角色聊天时,`turnLimit=5`
3.`5` 轮结束后,`forceExitAfterTurn=true`,由后端明确告知前端结束当前聊天态。
## 6.4 NPC 聊天返回契约扩展
建议扩展 `NpcChatTurnResult`
```ts
type NpcChatTurnResult = {
npcReply: string;
affinityDelta: number;
affinityText: string;
suggestions: string[];
chatDirective?: {
turnLimit?: number | null;
remainingTurns?: number | null;
forceExit?: boolean;
closingMode?: 'free' | 'foreshadow_close';
};
};
```
这部分必须由后端给出,不允许前端自己猜。
---
## 7. 创作工具需求
## 7.1 入口与承载方式
本次必须继续复用现有:
1. `src/components/CustomWorldResultView.tsx`
2. `src/components/CustomWorldEntityCatalog.tsx`
3. `src/components/CustomWorldEntityEditorModal.tsx` 内的 `LandmarkEditor`
不新建独立页面,也不新增独立 `scene_chapter` Tab。
新增规则:
1. 创作者从现有“场景”列表点击任一场景卡,进入对应场景编辑弹层。
2. 多幕配置必须作为场景编辑弹层内的一个区块出现,归属于该场景。
3. `scene_chapter` 仅作为保存层和运行时蓝图存在,不单独暴露在创作者导航里。
4. 场景卡片可增加“幕数量”轻量摘要,但第一版不是阻塞项。
## 7.2 场景编辑弹层展示要求
场景编辑弹层至少展示:
1. 场景名称与描述
2. 多幕配置区块
3. 场景连接关系
补充约束:
1. “场景图片”不再作为场景详情页里的独立字段展示,创作者只能通过每一幕的“配置背景”入口管理视觉。
2. “场景内 NPC”不再作为场景详情页里的独立字段展示创作者只能通过每一幕角色槽位配置相遇 NPC。
3. 为兼容现有运行时与旧数据结构,场景对象上的 `imageSrc / sceneNpcIds` 仍然保留,但必须由多幕配置自动回填,前台不再暴露单独编辑控件,且不能再用 `sceneNpcIds` 限制每幕可选角色。
多幕区块至少展示:
1. 幕列表
2. 每幕与场景主图同规格的背景预览
3. 每幕对面角色的 `3` 个固定槽位
4. 每幕主角色标记
5. 每幕背景配置入口
6. 每幕预览入口
## 7.3 幕编辑交互
每个场景编辑弹层里的多幕区块必须支持下面这些操作:
1. 新增幕
2. 删除幕
3. 调整幕顺序
4. 绑定幕背景图
5. 在幕背景预览上点击角色槽位,为该槽位配置角色
6. 移除某个已配置槽位的角色
7. 开始当前幕预览
交互要求:
1. 幕列表在桌面端纵向堆叠,在移动端同样保持纵向,不做复杂双列。
2. 每幕是独立卡片,不把所有字段一次性铺满。
3. 三个角色槽位必须直接叠在幕背景图上,作为当前幕预览的一部分。
4. 每个槽位只显示角色形象与名称,不展开为信息块。
5. 空槽位以虚线站位展示,点击后进入角色选择弹层。
6. 点击“配置背景图”时必须打开独立面板或独立弹层,不允许在当前卡片下方内联展开。
7. 点击角色槽位时必须打开独立面板或独立弹层,不允许在当前卡片下方内联展开。
8. 单幕手工编辑区不再暴露“幕标题 / 幕摘要 / 幕目标 / 过渡铺垫”字段,这些内容继续留在 Agent 草稿生成与编译层维护。
9. 默认不展示大段规则说明文字。
## 7.4 幕背景图配置
背景图配置必须复用现有场景图资产链,而不是另造上传体系。
要求如下:
1. 一幕只绑定一张正式背景图。
2. 可从已生成场景图中选择,也可调用现有场景图生成链生成。
3. 幕背景图和场景总背景图不是同一个概念,允许不同幕使用不同图。
4. 发布前如果存在未绑定背景图的幕,必须阻止发布。
5. 幕切换时运行时优先使用幕背景图,而不是地点默认图。
6. 幕背景预览窗口长宽比与场景主图预览保持一致。
## 7.5 幕相遇 NPC 配置
NPC 配置面板必须支持:
1. 从当前世界的 `playableNpcs + storyNpcs` 中选择角色
2. 当前场景相关角色只能作为排序或推荐依据,不能过滤掉其他世界角色
3.`3` 个固定槽位进行配置,而不是长列表表单
4. 第一槽位明确标记为“主角色”
5. 允许同一角色出现在多个不同幕
6. 同一幕内不允许同一角色重复占用多个槽位
硬约束:
1. 每幕至少 `1` 名 NPC。
2. 第一槽位不能为空,后续槽位才能继续配置。
3. 不允许把不存在于当前世界角色池中的 id 写入幕配置。
4. 若主角色未与当前场景或线程建立任何关联,给出发布警告。
5. 存储时继续落到 `encounterNpcIds` 有序数组,槽位从左到右按顺序压缩写入。
6. `sceneNpcIds` 不再作为创作者字段,也不再作为幕角色选择范围;保存时只从所有幕的 `encounterNpcIds` 自动派生兼容值。
## 7.6 幕预览
创作者在场景编辑弹层里点击“幕预览”后,必须直接进入当前幕的运行时预览。
要求如下:
1. 预览必须复用正常游戏运行时,而不是单独写一个静态演示页。
2. 预览启动时要把当前幕设为活跃幕,并带上当前幕背景与当前幕主角色。
3. 若当前幕主角色好感度小于 `0`,预览中必须直接进入最多 `5` 轮的有限聊天态。
4. 若当前幕主角色好感度大于 `0`,预览中必须沿用无限轮聊天规则。
5. 预览面板使用独立全屏层,不挤压原场景编辑弹层布局。
## 7.7 创作校验
`CustomWorldQualityFinding` 至少新增下面这些检查项:
1. `scene_chapter_missing_act`
2. `scene_act_missing_background`
3. `scene_act_missing_primary_npc`
4. `scene_act_missing_encounter_npc`
5. `scene_act_primary_npc_not_first`
6. `scene_act_unlinked_thread`
7. `scene_act_unpublished_background`
发布阻断项:
1. 幕数小于 `2`
2. 任意一幕没有背景图
3. 任意一幕没有 NPC
4. 任意一幕的第一 NPC 为空
---
## 8. 游戏流程需求
## 8.1 幕运行时状态
运行时必须为每个场景章节维护独立幕进度:
```ts
interface SceneActRuntimeState {
sceneId: string;
chapterId: string;
currentActId: string;
currentActIndex: number;
completedActIds: string[];
visitedActIds: string[];
}
```
建议挂入当前 story engine memory 中,和现有 `openedSceneChapterIds` 并存。
## 8.2 进入场景时的流程
当玩家进入一个有 `SceneChapterBlueprint` 的场景时:
1. 后端定位当前场景对应的 `scene chapter blueprint`
2. 如果该场景首次进入,则激活第 `1`
3. 如果该场景未完成且已有幕进度,则恢复到当前未完成幕
4. 把当前幕的背景图写入前端展示模型
5. 把当前幕的 `encounterNpcIds` 作为本幕优先相遇池
6. 把当前幕的 `stageCoverage` 交给 `chapterDirector` 参与裁决,并结合 quest 进度输出单一 `ChapterState.stage`
## 8.3 幕推进规则
第一版不要求创作者手填推进条件,而是由系统按幕位置默认编译:
1.`1` 幕默认 `after_primary_contact`
- 玩家与主角色发生首次有效接触后可进入下一幕判定
2. 中间幕默认 `after_active_step_complete`
- 当前场景章节任务 active step 完成后进入下一幕判定
3. 最后一幕默认 `after_chapter_resolution`
- 当前场景章节任务完成或进入可收束状态后结束本场景章节
要求:
1. 幕推进由后端统一裁决。
2. 前端只接收“幕已切换”的结果,不自行判断。
3. 幕切换后必须触发背景切换与相遇池更新。
## 8.4 幕切换表现
游戏前台在幕切换时必须至少做到:
1. 显示当前幕标题
2. 更新背景图
3. 更新当前可遇 NPC
4. 给出一条轻量系统提示,说明进入了新一幕
注意:
1. 不新建独立页面。
2. 不弹全屏说明面板。
3. 移动端优先保证幕标题与背景切换不遮挡底部操作区。
---
## 9. NPC 相遇与聊天规则
## 9.1 规则适用范围
本次新增的“按好感度控制聊天轮数”规则,只对**当前幕主角色**生效。
也就是说:
1. 当前幕 `primaryNpcId` 命中的角色,使用本次新规则。
2. 当前幕其他辅助 NPC第一版继续沿用现有 `npc_chat` 通用流程。
3. 辅助 NPC 的聊天不直接推进幕进度,除非后端另有章节 step 裁决。
## 9.2 主角色好感度大于 0
当当前幕主角色对玩家的当前好感度 `> 0` 时:
1. 玩家与其相遇后可以进入聊天态。
2. 聊天轮数无限制。
3. 继续沿用现有:
- `3` 个续聊建议项
- `1` 个自定义输入框
- 主动退出聊天
4. 只要满足 `docs/design/NPC_HIGH_AFFINITY_CHAT_QUEST_OFFER_FLOW_2026-04-19.md` 中的条件,仍然允许在聊天内抛出委托。
## 9.3 主角色好感度等于 0
为了避免编码边界歧义,本 PRD 先明确:
1. `affinity = 0` 视为中立档,不归入负好感限制分支。
2. 中立档允许进入正常多轮聊天。
3. 中立档不自动享受“高好感委托时机”。
这意味着:
- `> 0`:无限聊,且可进入高好感委托逻辑
- `= 0`:无限聊,但不进入高好感委托逻辑
- `< 0`:最多 `5`
## 9.4 主角色好感度小于 0
当当前幕主角色对玩家的当前好感度 `< 0` 时,必须进入 `limited hostile chat mode`
1. 允许进入聊天,但最多 `5` 轮。
2. 聊天状态中必须显示剩余轮数。
3.`1~4` 轮仍然走正常“玩家一句 -> NPC 一句 -> 建议项刷新”的基本结构。
4.`5` 轮不是普通续聊,而是强制收束轮。
5.`5` 轮必须输出一段带方向的收束回应,为后续剧情开展铺垫。
6.`5` 轮结束后:
- 自定义输入框隐藏
- 当前聊天态结束
- 恢复普通冒险态或进入后续 action 选择
7. 如果玩家在当前幕主角色的本地战斗中取胜NPC 会重新开启一段战后聊天:
- 这段聊天必须把刚刚那场交锋的结果摘要与关键战斗日志带入上下文
- 如果该主角色此时好感仍然 `< 0`,则战后聊天依然只允许 `5` 轮,并从战后这次重新开启时重新计数
-`5` 轮结束后 NPC 离开当前对话态,玩家可以继续承接后续 action并在满足推进条件时前往下一幕
## 9.5 第 5 轮的“铺垫”定义
“为开展铺垫”在本次 PRD 中必须被明确解释为:
**NPC 在第 5 轮必须抛出一个明确的后续方向,不能只用一句敌意台词把对话硬截断。**
可接受的铺垫结果包括:
1. 抛出新的威胁或最后通牒
2. 指向某个地点、人物或线索
3. 把矛盾推向对峙、交易、追踪或战斗
4. 暗示自己下一步行动去向
5. 给玩家一个必须接住的悬念或条件
不可接受的结果:
1. 纯重复敌意表达
2. 没有任何新方向的信息
3. 第 5 轮结束后界面直接空掉,没有后续承接
## 9.6 对当前负好感拦截逻辑的调整
当前若主角色属于本幕 `primaryNpcId`,则需要覆盖现有“负好感直接不给持续聊天”的逻辑。
新规则如下:
1. 如果它是当前幕主角色,即使当前好感度 `< 0`,也允许进入有限聊天态。
2. 只有在完成第 `5` 轮铺垫收束后,才切回普通探索/对峙流程。
3. 如果该 NPC 不是当前幕主角色,仍可沿用现有负好感拦截逻辑。
---
## 10. 前端表现要求
## 10.1 创作页
创作页必须保持清爽,不默认塞规则说明。
必须做到:
1. 在“场景”列表点击场景卡后,可以看到多幕配置区块
2. 幕列表可编辑
3. 每幕以大图预览 + 角色槽位的方式编辑
4. 背景图选择、角色槽位选择、幕预览都走独立面板
5. 移动端仍能完成幕排序、背景选择、槽位换角与幕预览
## 10.2 游戏主面板
Adventure 主面板在本次迭代中至少增加下面这些表现:
1. 当前幕标题或幕序号标签
2. 当前幕背景图切换
3. 主角色负好感聊天时的“剩余轮数”轻量提示
4. 第 5 轮结束后的过渡系统消息
禁止:
1. 默认展示大段规则介绍
2. 把幕配置说明直接写进玩家面板
3. 为了展示幕切换而新建独立剧情页面
---
## 11. 前后端职责边界
## 11.1 前端职责
前端只负责:
1. 在现有场景编辑弹层中渲染多幕编辑 UI
2. 发起背景图配置和 NPC 配置请求
3. 渲染当前幕背景和幕标题
4. 渲染负好感聊天剩余轮数
5. 启动当前幕预览并承载正常游戏运行时
6. 根据后端返回切换幕、退出聊天、展示后续 options
前端不负责:
1. 计算主角色是谁
2. 计算好感度轮数限制
3. 判定什么时候切幕
4. 决定第 5 轮要输出什么铺垫
5. 本地拼接下一幕 encounter 池
## 11.2 后端职责
后端必须负责:
1. 把创作页幕配置编译成运行时蓝图
2. 校验每幕背景与 NPC 配置完整性
3. 维护 `SceneActRuntimeState`
4. 进入场景时确定当前幕
5. 输出当前幕背景与 encounter 池
6. 裁决主角色聊天轮数限制
7. 在第 `5` 轮生成铺垫式收束回应
8. 在满足条件时推进到下一幕
---
## 12. 影响模块
本 PRD 落地时,至少会影响下面这些模块:
1. `packages/shared/src/contracts/customWorldAgent.ts`
- 新增场景多幕草稿结构
2. `src/types/customWorld.ts`
- 新增发布态 `sceneChapterBlueprints`
3. `server-node/src/services/customWorldAgentDraftCompiler.ts`
- 编译 `scene_chapter` 草稿数据
4. `server-node/src/services/customWorldAgentDraftEditService.ts`
- 支持场景幕的增删改排序
5. `server-node/src/services/customWorldAgentQualityService.ts`
- 增加幕背景和幕 NPC 校验
6. `src/components/CustomWorldEntityCatalog.tsx`
- 继续承载场景列表入口
7. `src/components/CustomWorldEntityEditorModal.tsx`
-`LandmarkEditor` 中新增幕编辑 UI
8. `src/data/questFlow.ts`
- 让 scene chapter quest 感知当前幕
9. `src/services/storyEngine/chapterDirector.ts`
- 用当前幕映射章节阶段和摘要
10. `src/hooks/story/npcEncounterActions.ts`
- 新增主角色有限聊天与第 5 轮收束逻辑
11. `packages/shared/src/contracts/story.ts`
- 扩展 `NpcChatTurnResult`
12. `src/services/aiService.ts`
- 透传有限聊天新字段
13. `server-node/src/modules/ai/chatOrchestrator.ts`
- 生成第 `5` 轮铺垫式收束结果
---
## 13. 验收标准
当下面这些结果都成立时,视为本次 PRD 已被正确落地:
1. 创作者可以在现有场景编辑弹层中配置每个场景的多幕。
2. 每个场景章节都可以配置 `2~5` 幕。
3. 每一幕都可以绑定独立背景图。
4. 每一幕都可以配置有序 NPC 列表,第一位自动成为主角色。
5. 发布时缺少幕背景或幕 NPC 会被明确拦截。
6. 玩家进入场景后,当前幕背景图能正确显示。
7. 当前幕可遇 NPC 会按幕配置切换。
8. 当前幕主角色好感度 `> 0` 时可以无限续聊。
9. 当前幕主角色好感度 `< 0` 时最多只聊 `5` 轮。
10.`5` 轮结束后一定会出现为后续剧情开展铺垫的收束结果,而不是直接硬断。
11. 高好感委托链仍只在正好感聊天中触发。
12. 桌面端和移动端都能完成幕配置与幕切换使用。
---
## 14. 本稿默认假定
为了避免下一步编码时再出现语义歧义,这份 PRD 先明确采用下面两条默认假定:
1. `affinity = 0` 先按中立档处理:允许无限聊,但不进入高好感委托分支。
2. “第 5 轮为开展铺垫”先解释为“为后续剧情推进、对峙、追踪、交易或战斗制造明确下一跳”,而不是限定为必须开战。
如果后续你希望把:
- `affinity = 0` 改成也只聊 `5`
-`5` 轮明确收束到“开战前摇”
可以在下一版实现文档中单独收紧,不影响本稿主结构。

View File

@@ -0,0 +1,869 @@
# AI 原生剧情引擎第一阶段技术落地方案
更新时间:`2026-04-06`
## 0. 文档目的
这份方案用于把以下三份 PRD 收束成当前仓库可直接开工的第一阶段技术实现方案:
- `docs/prd/AI_NATIVE_CROSS_GENRE_STORY_ENGINE_PRD_2026-04-06.md`
- `docs/prd/AI_NATIVE_NARRATIVE_THREAD_ITEM_AND_WORLD_NPC_PRD_2026-04-06.md`
- `docs/prd/AI_NATIVE_CLASSIC_RPG_EXPERIENCE_BENCHMARK_PRD_2026-04-06.md`
目标不是一次把“经典 RPG 体验”全部做完,而是在当前项目框架内先做出一个最小但完整的剧情引擎闭环,让后续可以继续往《仙剑》《轩辕剑》《古剑》《黑神话》《博德之门》所代表的体验能力上叠。
这份方案必须满足两个约束:
1. 不推翻当前仓库已有的 `customWorld / prompt / npcInteractions / questDirector / runtimeItem` 主链。
2. 第一阶段做完后,玩家能立刻感知到内容质量提升,而不是只有内部结构更“先进”。
## 1. 第一阶段目标
第一阶段只做 4 件必须一起成立的事:
1. 给自定义世界补 `题材适配层 + 世界线程图谱 + 角色叙事档案`
2. 给运行时 prompt 补 `信息可见性裁剪 + 情境导演最小指令`
3. 给重点 NPC 补 `低好感也有戏` 的首遇表达与最小关系立场矩阵
4. 给重点运行时物件补 `叙事指纹`,让名称、描述、来源真正开始承载故事
一句话定义第一阶段:
**先把“世界会说话、角色会藏话、物件会带话、prompt 不再全知”这四个基础能力接起来。**
## 2. 第一阶段完成定义
第一阶段完成后,必须同时满足下面这些结果:
1. 新生成的自定义世界,结构里会稳定带上 `ThemePack``WorldStoryGraph``ActorNarrativeProfile`
2. 自定义世界 NPC 在首遇或低披露阶段,不再把完整 `backstory` 与所有未解锁章节直接注入 prompt。
3. 低初始好感 NPC 的首轮文本,会出现“当前压力 + 错位说辞 + 暗线钩子”,而不只是更冷淡。
4. 稀有以上或重点奖励物件,会带 `storyFingerprint`,名称与描述不再只是 build 方向模板句。
5. 旧存档和旧自定义世界数据仍能平滑读取,缺失字段有 fallback。
6. 至少一条主链已经把“世界线程 -> 角色档案 -> 可见信息 -> 文本生成 -> 记忆回写”跑通。
## 3. 范围控制
## 3.1 第一阶段纳入范围
纳入范围的模块:
- `src/services/customWorld.ts`
- `src/services/prompt.ts`
- `src/data/npcInteractions.ts`
- `src/hooks/useStoryGeneration.ts`
- `src/services/questDirector.ts`
- `src/services/runtimeItemAiPrompt.ts`
- `src/data/runtimeItemNarrative.ts`
- `src/types/customWorld.ts`
- `src/types/game.ts`
- `src/types/scene.ts`
- `src/types/runtimeItem.ts`
- `src/services/aiTypes.ts`
新增模块:
- `src/types/storyEngine.ts`
- `src/services/storyEngine/themePack.ts`
- `src/services/storyEngine/worldStoryGraph.ts`
- `src/services/storyEngine/actorNarrativeProfile.ts`
- `src/services/storyEngine/visibilityEngine.ts`
- `src/services/storyEngine/sceneNarrativeDirector.ts`
- `src/services/storyEngine/carrierNarrativeCompiler.ts`
## 3.2 第一阶段明确不做
以下内容留到第二阶段及以后,不放进本阶段:
1. 全量营地事件系统
2. 队友 approval / disapproval 的完整 UI 面板
3. 复杂多结局主线编排器
4. 全题材内容包与人工词典大规模沉淀
5. 所有叙事载体类型一次性接入
6. 全支线线程化改造
7. 复杂 scene residue 地图化编辑器
原因很简单:
**第一阶段的目标是把底层语法和最小闭环接通,而不是把所有经典 RPG 能力一次铺满。**
## 4. 第一阶段最小闭环
建议把第一阶段的最小闭环定义为:
```text
自定义世界生成
-> 题材适配层
-> 世界线程图谱
-> 角色叙事档案
-> 遭遇时构造可见性切片
-> 构造场景导演指令
-> 生成首遇 / 对话 / 任务 / 物件叙事
-> 回写最小剧情记忆
```
这个闭环里,先只强接两个高价值落点:
1. 大世界 NPC 遭遇
2. 运行时重点物件
原因:
- 这两条链最容易让玩家立刻感到“内容变得像经典 RPG 了”
- 也最符合当前仓库已经有的主链结构
## 5. 数据结构落地方案
## 5.1 新增 `src/types/storyEngine.ts`
建议把第一阶段的引擎基础类型集中到一个新文件,避免继续把新语义散进已有 `story.ts`
建议包含这些结构:
```ts
export interface ThemePack {
id: string;
displayName: string;
toneRange: string[];
institutionLexicon: string[];
tabooLexicon: string[];
artifactClasses: string[];
actorArchetypes: string[];
conflictForms: string[];
clueForms: string[];
namingPatterns: string[];
revealStyles: string[];
}
export interface StoryThread {
id: string;
title: string;
visibility: 'visible' | 'hidden';
summary: string;
conflictType: string;
stakes: string;
involvedFactionIds: string[];
involvedActorIds: string[];
relatedLocationIds: string[];
}
export interface StoryScar {
id: string;
title: string;
pastEvent: string;
publicResidue: string;
hiddenTruth: string;
relatedActorIds: string[];
relatedLocationIds: string[];
}
export interface StoryMotif {
id: string;
label: string;
semanticRole: string;
lexicalHints: string[];
}
export interface WorldStoryGraph {
visibleThreads: StoryThread[];
hiddenThreads: StoryThread[];
scars: StoryScar[];
motifs: StoryMotif[];
}
export interface ActorNarrativeProfile {
publicMask: string;
firstContactMask: string;
visibleLine: string;
hiddenLine: string;
contradiction: string;
debtOrBurden: string;
taboo: string;
immediatePressure: string;
relatedThreadIds: string[];
relatedScarIds: string[];
reactionHooks: string[];
}
export interface VisibilitySlice {
factIds: string[];
sayableFactIds: string[];
inferredFactIds: string[];
forbiddenFactIds: string[];
misdirectionHints: string[];
}
export interface SceneNarrativeDirective {
primaryPressure: string;
activeThreadIds: string[];
foregroundActorIds: string[];
foregroundCarrierIds: string[];
revealBudget: 'low' | 'medium' | 'high';
emotionalCadence: 'tense' | 'curious' | 'hostile' | 'intimate' | 'tragic' | 'mysterious';
}
export interface CarrierStoryFingerprint {
visibleClue: string;
witnessMark: string;
unresolvedQuestion: string;
currentAppearanceReason: string;
relatedThreadIds: string[];
relatedScarIds: string[];
reactionHooks: string[];
}
export interface CompanionStanceProfile {
trust: number;
warmth: number;
ideologicalFit: number;
fearOrGuard: number;
loyalty: number;
currentConflictTag?: string | null;
recentApprovals: string[];
recentDisapprovals: string[];
}
export interface StoryEngineMemoryState {
discoveredFactIds: string[];
activeThreadIds: string[];
resolvedScarIds: string[];
recentCarrierIds: string[];
}
```
同时更新:
- `src/types.ts`
`storyEngine.ts` 导出。
## 5.2 扩展 `src/types/customWorld.ts`
扩展:
```ts
interface CustomWorldRoleProfile {
narrativeProfile?: ActorNarrativeProfile;
}
interface CustomWorldProfile {
themePack?: ThemePack | null;
storyGraph?: WorldStoryGraph | null;
}
```
注意:
1. 这两个字段都要允许 `null` / 缺失
2. `normalizeCustomWorldProfile(...)` 必须能从旧档案平滑补 fallback
## 5.3 扩展 `src/types/runtimeItem.ts`
扩展:
```ts
interface RuntimeItemMetadata {
storyFingerprint?: CarrierStoryFingerprint;
}
```
同时扩展 AI 意图:
```ts
interface RuntimeItemAiIntent {
visibleClue?: string;
witnessMark?: string;
unfinishedBusiness?: string;
hiddenHook?: string;
reactionHooks?: string[];
namingPattern?: string;
}
```
## 5.4 扩展 `src/types/game.ts`
扩展:
```ts
interface GameState {
storyEngineMemory?: StoryEngineMemoryState;
}
```
用途:
1. 记录已发现事实
2. 记录当前激活线程
3. 记录已经回响过的旧伤
4. 记录最近拿到的重点叙事载体
## 5.5 扩展 `src/types/scene.ts`
扩展:
```ts
interface NpcPersistentState {
stanceProfile?: CompanionStanceProfile;
}
interface Encounter {
narrativeProfile?: ActorNarrativeProfile;
}
interface SceneNpc {
narrativeProfile?: ActorNarrativeProfile;
}
```
注意:
- 这里的 `stanceProfile` 不只给已入队同伴使用,重点 NPC 也可以先共享这套结构
## 5.6 扩展 `src/services/aiTypes.ts`
`StoryGenerationContext` 增加:
```ts
visibilitySlice?: VisibilitySlice | null;
sceneNarrativeDirective?: SceneNarrativeDirective | null;
encounterNarrativeProfile?: ActorNarrativeProfile | null;
activeThreadIds?: string[] | null;
```
`QuestGenerationContext` 增加:
```ts
activeThreadIds?: string[] | null;
issuerNarrativeProfile?: ActorNarrativeProfile | null;
```
## 6. 模块实现方案
## 6.1 `src/services/storyEngine/themePack.ts`
职责:
1. 根据 `customWorldProfile.templateWorldType``summary``tone` 生成题材适配层
2. 如果是预设世界,也能提供内置默认 `ThemePack`
3. 给后续命名、术语、禁忌词、物件类别提供统一词汇入口
建议导出:
```ts
buildThemePackFromWorldProfile(profile)
resolveFallbackThemePack(worldType)
```
本阶段要求:
- 先做 deterministic builder不强依赖额外 LLM 调用
## 6.2 `src/services/storyEngine/worldStoryGraph.ts`
职责:
1. 根据 `CustomWorldProfile` 现有字段生成或补全 `WorldStoryGraph`
2. 先从 `majorFactions / coreConflicts / landmarks / storyNpcs` 抽图谱
3. 缺失时允许走 LLM 辅助生成,但要有 deterministic fallback
建议导出:
```ts
buildFallbackWorldStoryGraph(profile, themePack)
generateWorldStoryGraphWithAi(profile, themePack)
normalizeWorldStoryGraph(value, fallback)
```
本阶段要求:
- 默认必须可离线 fallback
- 图谱生成失败不能阻塞整个自定义世界生成
## 6.3 `src/services/storyEngine/actorNarrativeProfile.ts`
职责:
1. 从角色的 `description / backstory / motivation / relationshipHooks / tags / backstoryReveal`
编译 `ActorNarrativeProfile`
2. 缺失时给出 fallback
3. 为 prompt 提供稳定的“首遇面具、当前压力、暗线钩子”
建议导出:
```ts
buildFallbackActorNarrativeProfile(role, graph)
generateActorNarrativeProfileWithAi(role, graph, themePack)
normalizeActorNarrativeProfile(value, fallback)
```
## 6.4 `src/services/storyEngine/visibilityEngine.ts`
职责:
1. 根据当前遭遇、好感、首遇状态、已解锁章节、故事记忆构造 `VisibilitySlice`
2. 明确哪些事实:
- 可以进入 prompt
- 只能作为推测
- 绝对不能进入本轮上下文
建议导出:
```ts
buildEncounterVisibilitySlice(params)
buildQuestVisibilitySlice(params)
buildCarrierVisibilitySlice(params)
```
本阶段关键约束:
1. 自定义世界 NPC 首遇时禁止注入完整 `backstory`
2. 未解锁章节禁止注入 `content`
3. 低披露阶段允许注入:
- `publicMask`
- `firstContactMask`
- `visibleLine`
- `immediatePressure`
- 已解锁章节的 `contextSnippet`
## 6.5 `src/services/storyEngine/sceneNarrativeDirector.ts`
职责:
1. 用当前场景、遭遇、最近行动、激活线程构造 `SceneNarrativeDirective`
2. 告诉 prompt 本轮更应该强调:
- 紧张
- 试探
- 情感深化
- 揭示
- 悬念
建议导出:
```ts
buildSceneNarrativeDirective(params)
```
本阶段先做 local director不新增额外 LLM 调用。
## 6.6 `src/services/storyEngine/carrierNarrativeCompiler.ts`
职责:
1. 根据 `WorldStoryGraph + relationAnchor + scene + actorNarrativeProfile`
编译 `CarrierStoryFingerprint`
2. 给运行时重点物件提供:
- 可见线索
- 见证痕
- 未完成问题
- 当前出现理由
- 后续反应钩子
建议导出:
```ts
buildRuntimeItemStoryFingerprint(params)
buildCarrierNarrativeName(params)
buildCarrierNarrativeDescription(params)
```
## 7. 现有文件改造方案
## 7.1 `src/services/customWorld.ts`
当前问题:
1. 角色生成偏设定卡
2. 没有先产题材适配层与世界线程图谱
3. 角色背景和章节没有统一挂到世界线程上
改造方案:
1. 保留现有多阶段生成结构
2. 插入两个新阶段:
- `theme_pack_and_story_graph`
- `actor_narrative_profile`
3. 最终输出时把:
- `themePack`
- `storyGraph`
- 每个 NPC 的 `narrativeProfile`
写回 `CustomWorldProfile`
建议新的顺序:
1. 世界基础框架
2. ThemePack
3. WorldStoryGraph
4. 角色基础字段
5. ActorNarrativeProfile
6. backstoryReveal / skills / initialItems
## 7.2 `src/services/prompt.ts`
这是第一阶段必须重点改的文件。
当前问题已经确认:
1. 自定义世界 NPC 遭遇会直接注入完整 `backstory`
2. 会直接注入所有章节摘要
3. `describeCustomWorldSection(...)` 会整体塞入太多 NPC 全量信息
改造方案:
1. 所有自定义世界 NPC prompt 统一先经过 `buildEncounterVisibilitySlice(...)`
2. 只允许读取 `visibilitySlice` 输出的事实
3. `describeCustomWorldSection(...)` 改成只注入:
- 世界摘要
- ThemePack 摘要
- StoryGraph 激活线程摘要
- 当前相关 NPC 的公开面与线程索引
禁止继续注入:
1. 完整 `backstory`
2. 未解锁 `backstoryReveal.content`
3. 多角色全量技能、初始物品、完整背景
## 7.3 `src/data/npcInteractions.ts`
改造目标:
1. 低好感角色从“更冷”改成“更有压力和错位”
2. 接入最小 `stanceProfile`
建议新增:
```ts
buildInitialStanceProfile(...)
applyStoryChoiceToStanceProfile(...)
describeNpcNarrativePressure(...)
```
本阶段只接这些行为的 stance 更新:
1. `npc_chat`
2. `npc_help`
3. `npc_gift`
4. `npc_recruit`
5. `npc_quest_accept`
先不做完整 approval UI只做
- 内部状态更新
- prompt 注入差异
- 文本反应差异
## 7.4 `src/hooks/useStoryGeneration.ts`
当前不要再往里塞更多内容逻辑,而是让它接新引擎组件。
改造方式:
1. 构造 `visibilitySlice`
2. 构造 `sceneNarrativeDirective`
3. 把这两者透传给 `generateInitialStory / generateNextStep`
4. 在回合结束时回写:
- `storyEngineMemory`
- `revealedFactIds`
- 最近激活线程
它在第一阶段里只做 orchestration不承担新的叙事规则实现。
## 7.5 `src/services/questDirector.ts`
当前它已经有:
- AI intent
- fallback builder
- compile to quest
第一阶段只补最小 thread awareness不把整个任务系统完全重做。
改造方式:
1. `QuestGenerationContext` 增加:
- `activeThreadIds`
- `issuerNarrativeProfile`
2. `buildQuestIntentPrompt(...)` 增加:
- 当前激活线程
- NPC 当前压力
- 可披露线索
本阶段不改:
- `QuestLogEntry` 主结构
- `questFlow.ts` 主编译方式
## 7.6 `src/services/runtimeItemAiPrompt.ts`
扩展当前物品意图 contract但不让它直接生成成品。
新增字段:
1. `visibleClue`
2. `witnessMark`
3. `unfinishedBusiness`
4. `hiddenHook`
5. `reactionHooks`
6. `namingPattern`
要求模型回答:
1. 这件物到底见证过什么
2. 它为什么现在出现
3. 谁以后会对它起反应
## 7.7 `src/data/runtimeItemNarrative.ts`
这是第一阶段另一个必须重点改的文件。
当前问题:
1. 名称偏词块拼接
2. 描述偏单模板句
改造方案:
1. 先从 `CarrierStoryFingerprint` 编译名称
2. 描述固定升级成三层式:
- 表面痕迹
- 旧事牵连
- 当前局势意义
3. `sourceReason` 继续保留,但不再是描述的全部中心
## 8. Prompt Contract 方案
## 8.1 自定义世界生成新增 contract
### 1. ThemePack Contract
输入:
- 世界 summary
- tone
- templateWorldType
- factions
- coreConflicts
输出:
- 题材词汇
- 冲突形式
- 载体种类
- 命名范式
### 2. WorldStoryGraph Contract
输入:
- 世界摘要
- major factions
- core conflicts
- landmarks
- story NPC 简要清单
输出:
- `visibleThreads`
- `hiddenThreads`
- `scars`
- `motifs`
### 3. ActorNarrativeProfile Contract
输入:
- 角色基础字段
- 角色 `backstoryReveal`
- 所属世界线程摘要
输出:
- `publicMask`
- `firstContactMask`
- `visibleLine`
- `hiddenLine`
- `contradiction`
- `debtOrBurden`
- `taboo`
- `immediatePressure`
- `reactionHooks`
## 8.2 运行时剧情生成 contract
运行时主 prompt 不再直接吃全量世界设定,而是吃:
1. `SceneNarrativeDirective`
2. `VisibilitySlice`
3. 当前遭遇公开信息
4. 已解锁章节摘要
5. 当前激活线程
## 8.3 运行时物件 contract
输入:
- 生成渠道
- 关系锚点
- 当前场景
- 当前激活线程
- 相关角色公开面与当前压力
输出:
- 物件叙事指纹字段
- 命名范式建议
- build 倾向字段
## 9. 迁移与兼容方案
## 9.1 旧自定义世界兼容
旧数据可能没有:
- `themePack`
- `storyGraph`
- `narrativeProfile`
策略:
1. 读取时用 `normalizeCustomWorldProfile(...)` 自动补 fallback
2. fallback 不阻塞运行时
3. 下次保存时按新结构写回
## 9.2 旧存档兼容
旧存档可能没有:
- `storyEngineMemory`
- `stanceProfile`
- `storyFingerprint`
策略:
1. `GameState` 初始化时补空结构
2. `NpcPersistentState` 初始化时补最小 stance
3. 旧物品没有 `storyFingerprint` 时,不报错,走旧描述逻辑 fallback
## 10. 测试方案
## 10.1 单元测试
建议新增:
1. `visibilityEngine.test.ts`
- 验证首遇和低披露阶段不会泄露完整背景
2. `worldStoryGraph.test.ts`
- 验证 fallback 图谱最少字段齐全
3. `actorNarrativeProfile.test.ts`
- 验证 fallback profile 至少包含压力、错位、钩子
4. `carrierNarrativeCompiler.test.ts`
- 验证重点物件能稳定产出指纹、名称和三层描述
## 10.2 集成测试
建议补这些集成检查:
1. 自定义世界生成后,`CustomWorldProfile.storyGraph``narrativeProfile` 存在
2. `prompt.ts` 在首遇自定义世界 NPC 时不含完整 `backstory`
3. `runtimeItemNarrative.ts` 重点物件输出包含故事指纹与升级描述
4. `questDirector.ts` 任务上下文已经能读取线程与角色叙事档案
## 10.3 手工验证场景
至少做这 4 条人工回归:
1. 初见低好感 NPC
2. 初见中高好感 NPC
3. 拿到 rare 级重点物件
4. 从某 NPC 处接到调查或关系类任务
## 11. 交付顺序
建议按下面顺序做,避免返工:
1. 类型与 fallback
- `storyEngine.ts`
- 现有类型扩展
- 旧档兼容
2. 自定义世界生成链
- `themePack`
- `worldStoryGraph`
- `actorNarrativeProfile`
3. prompt 可见性层
- `visibilityEngine`
- `prompt.ts` 裁剪
- `useStoryGeneration.ts` 接线
4. NPC 首遇和 stance 最小链
- `npcInteractions.ts`
- `StoryGenerationContext` 注入
5. 重点物件叙事链
- `runtimeItemAiPrompt.ts`
- `carrierNarrativeCompiler.ts`
- `runtimeItemNarrative.ts`
6. 任务线程感知最小接入
- `questDirector.ts`
7. 测试与内容回归
## 12. 风险与处理
## 风险 1阶段过大
处理:
- 第一阶段只强接 NPC 与重点物件两条链
- 营地事件、全支线线程化后置
## 风险 2prompt 体积继续膨胀
处理:
- 先做 `VisibilitySlice`
- 严禁继续直接注入全量背景
## 风险 3旧档与旧内容不兼容
处理:
- 所有新增字段必须有 normalize fallback
- 第一阶段不删除旧字段
## 风险 4AI 输出不稳定
处理:
- 所有新 contract 都必须配 deterministic fallback builder
- AI 只产意图,不直接产运行时成品
## 13. 第一阶段验收清单
做到以下几点,才算第一阶段可收口:
1. 新生成自定义世界可稳定带出 `ThemePack + WorldStoryGraph + ActorNarrativeProfile`
2. 首遇自定义世界 NPC 时prompt 中不再包含完整 `backstory`
3. 低好感 NPC 首轮文本能显著表现“压力、错位、钩子”
4. 稀有以上重点物件会稳定带出 `storyFingerprint`
5. 重点物件名称与描述不再只依赖固定模板句
6. 任务生成至少能读取激活线程和 NPC 当前叙事压力
7. 旧档读取正常
8. `lint / 相关测试 / check:encoding` 通过
## 14. 一句话结论
第一阶段不要追求“立刻做出所有经典 RPG 体验”,而要先把:
- 世界线程
- 角色叙事档案
- 信息可见性
- 重点物件叙事指纹
这四个底座接进当前仓库主链。
只要这一步做稳,后面无论是《仙剑》式角色关系、《轩辕剑》式历史神话、《古剑》式世界厚度、《黑神话》式空间残痕,还是《博德之门》式队友反应,都会开始有一个真正可持续生长的引擎底盘。

View File

@@ -0,0 +1,644 @@
# AI 原生剧情引擎第二阶段技术落地方案
更新时间:`2026-04-06`
## 0. 文档目的
这份方案建立在当前仓库已经基本完成的第一阶段能力之上,面向第二阶段的真实技术推进。
第一阶段已经把这些底座接进主链:
1. `ThemePack`
2. `WorldStoryGraph`
3. `ActorNarrativeProfile`
4. `VisibilitySlice`
5. `SceneNarrativeDirective`
6. `CarrierStoryFingerprint`
7. `storyEngineMemory`
同时也已经把这些链打通了:
1. 自定义世界扩展构建链
2. 自定义世界 NPC 首遇 prompt 裁剪
3. 运行时重点物件叙事编译
4. 任务 prompt 的最小线程感知
5. NPC 最小 stance 更新
第二阶段不再解决“底座有没有”,而是解决:
**这些底座如何从“静态骨架 + deterministic fallback”升级成“真正能持续驱动经典 RPG 体验的动态剧情引擎”。**
## 1. 第一阶段审计结论
先明确当前真实状态,再定义第二阶段范围。
## 1.1 已经落地的部分
按代码审计结果,以下内容已经可以判定为“已落地”:
1. 类型层已接入
- `src/types/storyEngine.ts`
- `src/types/customWorld.ts`
- `src/types/game.ts`
- `src/types/runtimeItem.ts`
- `src/types/scene.ts`
- `src/services/aiTypes.ts`
2. 自定义世界扩展构建已接入
- `src/services/customWorldBuilder.ts`
- `src/services/customWorld.ts`
3. Prompt 可见性裁剪已接入主链
- `src/services/prompt.ts`
- `src/hooks/useStoryGeneration.ts`
4. 重点物件叙事指纹已接入主链
- `src/services/storyEngine/carrierNarrativeCompiler.ts`
- `src/data/runtimeItemNarrative.ts`
5. 最小记忆回写已接入
- `src/hooks/story/progressionActions.ts`
- `src/services/storyEngine/echoMemory.ts`
6. 第一阶段关键测试已通过
- `prompt.test.ts`
- `customWorldBuilder.test.ts`
- `visibilityEngine.test.ts`
- `carrierNarrativeCompiler.test.ts`
- `runtimeItemDirector.test.ts`
- `npcInteractions.test.ts`
7. 工程门禁本轮检查通过
- `lint`
- `typecheck`
- `check:encoding`
## 1.2 仍然属于“部分落地”的部分
以下能力虽然已经有骨架,但还没达到第二阶段想要的经典 RPG 体验强度:
1. `WorldStoryGraph`
- 当前主要仍是 fallback 构建AI 版本还是 stub。
2. `ActorNarrativeProfile`
- 当前主要仍是 fallback 编译AI 版本还是 stub。
3. `CompanionStanceProfile`
- 当前只覆盖局部 NPC 行为,不覆盖全局选择反馈、队友插话、营地事件。
4. `storyEngineMemory`
- 当前已经回写,但消费端还很弱,回响还没有真正反过来改变世界表达。
5. `QuestDirector`
- 当前已经有线程感知,但任务本体还没有成为“线程合约”的实体。
6. `CarrierStoryFingerprint`
- 当前只强接运行时物件,还没扩到地点残痕、文书、证物、怪物掉落情报、场景调查结果。
## 1.3 当前进入第二阶段前,最值得注意的两个真实缺口
### 缺口 AAI 版世界线程 / 角色档案生成仍未真正接管主链
当前代码里虽然已经有:
- `generateWorldStoryGraphWithAi(...)`
- `generateActorNarrativeProfileWithAi(...)`
但它们还只是 fallback 包装,本质上没有真的调用独立 AI contract。
这意味着:
- 当前世界线程和角色叙事档案仍偏“本地启发式编译”
- 第一阶段解决了“结构没有”的问题
- 但还没有真正进入“AI 原生世界叙事图谱”阶段
### 缺口 B可见性虽然裁掉了完整背景但隐式泄露仍未完全收紧
当前 `prompt.ts` 里,对自定义世界 NPC 的:
- `relationshipHooks`
- `tags`
仍是无条件注入。
如果这些字段本身带有暗线名词、组织名、旧案对象名,那么:
- 首遇阶段仍有隐式越权泄露的风险
这说明第二阶段必须把“知识图谱”和“可见性切片”的颗粒度继续做细,不能只停留在章节级裁剪。
## 2. 第二阶段目标
第二阶段只做 5 件事:
1. 把世界线程和角色叙事档案从 fallback 编译升级成真正的 AI contract 驱动
2.`VisibilitySlice` 升级成可追踪的 `KnowledgeFact` 图谱
3.`CompanionStanceProfile` 从局部 NPC 状态升级成队友反应系统
4.`QuestDirector` 从“知道线程”升级成“线程合约推进器”
5. 把叙事载体从“重点物件”扩展成“物件 + 地点 + 文书 + 调查残痕”
一句话定义第二阶段:
**从“会组织故事骨架”升级到“会持续推进、反馈、回响和分化故事”。**
## 3. 第二阶段完成定义
第二阶段完成后,必须同时满足:
1. 自定义世界的 `ThemePack / WorldStoryGraph / ActorNarrativeProfile` 至少核心部分由独立 AI contract 生成,而不再只是 fallback。
2. 世界中的“事实”被显式建模成可发现、可说、可误判、可禁止的 `KnowledgeFact`
3. 队友会对关键选择给出稳定的认可 / 反对 / 沉默 / 紧张回避反馈。
4. 至少一类任务已经真正挂在 `StoryThread` 上推进,并能根据 `signal` 更新阶段。
5. 玩家获得重点物件、调查地点或读取文书后,后续 NPC 和剧情会产生回响。
6. “经典 RPG 感”开始明显来自系统联动,而不只是单次文本质量提升。
## 4. 第二阶段范围
## 4.1 纳入范围
- `src/services/customWorld.ts`
- `src/services/customWorldBuilder.ts`
- `src/services/prompt.ts`
- `src/services/questDirector.ts`
- `src/services/questPrompt.ts`
- `src/data/questFlow.ts`
- `src/data/npcInteractions.ts`
- `src/hooks/useStoryGeneration.ts`
- `src/hooks/story/npcEncounterActions.ts`
- `src/hooks/story/npcInteraction.ts`
- `src/services/storyEngine/*`
- `src/types/storyEngine.ts`
- `src/types/story.ts`
## 4.2 新增模块
- `src/services/storyEngine/knowledgeGraph.ts`
- `src/services/storyEngine/knowledgeContract.ts`
- `src/services/storyEngine/companionReactionDirector.ts`
- `src/services/storyEngine/threadContract.ts`
- `src/services/storyEngine/threadSignalRouter.ts`
- `src/services/storyEngine/sceneResidueCompiler.ts`
- `src/services/storyEngine/narrativeCarrierCatalog.ts`
## 4.3 明确不做
第二阶段仍不做:
1. 全量结局树编辑器
2. 全世界所有对象统一入图谱编辑器
3. 多周目专用 meta-story 系统
4. 完整 romance / betrayal / leave-party 大型队友事件网
5. 全 UI 层 approval feed 面板
原因:
第二阶段的核心仍是“让引擎开始动态驱动经典 RPG 体验”,而不是做内容工具大平台。
## 5. 第二阶段最小闭环
建议第二阶段最小闭环定义为:
```text
世界图谱 AI 生成
-> 角色叙事档案 AI 生成
-> KnowledgeFact 图谱
-> VisibilitySlice 2.0
-> 队友反应导演
-> 线程合约生成
-> signal 推进
-> 地点/文书/物件回响
-> 记忆回写
```
本阶段最关键的用户可感知落点有 3 条:
1. 队友 / 同伴反应链
2. 调查 / 任务推进链
3. 地点 / 物件 / 文书残痕链
## 6. 数据结构升级方案
## 6.1 `src/types/storyEngine.ts`
第二阶段新增:
```ts
export interface KnowledgeFact {
id: string;
title: string;
content: string;
ownerActorIds: string[];
relatedThreadIds: string[];
relatedScarIds: string[];
sourceType: 'actor' | 'item' | 'document' | 'scene' | 'monster' | 'quest';
visibility: 'public' | 'discoverable' | 'private' | 'forbidden';
sayability: 'direct' | 'indirect' | 'reactive_only';
aliases?: string[];
}
export interface ThreadContractStep {
id: string;
title: string;
revealText: string;
completionSignalIds: string[];
optionalFactIds: string[];
}
export interface ThreadContract {
id: string;
threadId: string;
issuerActorId?: string | null;
narrativeType: 'investigation' | 'escort' | 'hunt' | 'relationship' | 'trial' | 'recovery';
currentStepId: string | null;
visibleStage: number;
steps: ThreadContractStep[];
followupThreadIds: string[];
}
export interface StorySignal {
id: string;
signalType:
| 'enter_scene'
| 'leave_scene'
| 'talk_to_actor'
| 'obtain_carrier'
| 'inspect_scene'
| 'win_battle'
| 'give_item'
| 'accept_contract'
| 'resolve_contract_step';
actorId?: string | null;
sceneId?: string | null;
carrierId?: string | null;
threadIds?: string[];
}
export interface CompanionReactionRecord {
id: string;
characterId: string;
reactionType: 'approve' | 'disapprove' | 'concern' | 'silence' | 'curious';
reason: string;
relatedThreadIds: string[];
createdAt: string;
}
```
并扩展:
```ts
export interface StoryEngineMemoryState {
discoveredFactIds: string[];
inferredFactIds?: string[];
activeThreadIds: string[];
resolvedScarIds: string[];
recentCarrierIds: string[];
recentSignalIds?: string[];
recentCompanionReactions?: CompanionReactionRecord[];
}
```
## 6.2 `src/types/story.ts`
第二阶段建议扩展任务结构,而不是直接新起平行系统。
扩展:
```ts
interface QuestLogEntry {
threadId?: string | null;
contractId?: string | null;
discoveredFactIds?: string[];
relatedCarrierIds?: string[];
}
```
注意:
- 第二阶段仍继续复用 `QuestLogEntry`
- 不推翻当前任务系统,只增强其线程感知和推进能力
## 6.3 `src/types/scene.ts`
扩展:
```ts
interface ScenePresetInfo {
narrativeResidues?: SceneNarrativeResidue[];
}
interface SceneNarrativeResidue {
id: string;
title: string;
visibleClue: string;
linkedFactIds: string[];
linkedThreadIds: string[];
}
```
## 7. 模块实现方案
## 7.1 `knowledgeGraph.ts`
职责:
1.`WorldStoryGraph + ActorNarrativeProfile + backstoryReveal + carriers`
编译出全局 `KnowledgeFact[]`
2. 统一管理:
- 事实 ID
- 所属角色
- 所属线程
- 是否可直说
- 是否只能反应式表达
建议导出:
```ts
buildKnowledgeGraph(profile)
buildActorKnowledgeFacts(role, graph)
buildCarrierKnowledgeFacts(carrier, graph)
```
第二阶段关键要求:
- `VisibilitySlice` 不再只靠字符串标签推断
- 必须能落到真实事实节点
## 7.2 `knowledgeContract.ts`
职责:
1.`KnowledgeFact` 构造 `VisibilitySlice 2.0`
2. 支持:
- 可直接说的事实
- 只能暗示的事实
- 只会在反应中暴露的事实
- 玩家已经误判但系统不盖章的事实
建议导出:
```ts
buildVisibilitySliceFromFacts(params)
buildMisdirectionFacts(params)
```
## 7.3 `companionReactionDirector.ts`
职责:
1. 根据玩家选择、活跃线程、事实图谱、队友 stance 生成队友反应
2. 把当前只存在于 `stanceProfile` 内的数值,变成:
- 明确的认可 / 反对 / 担忧 / 沉默
- 可写入聊天、插话、任务后反馈的短反应
建议导出:
```ts
buildCompanionReactionBatch(params)
applyCompanionReactionToStance(params)
```
第二阶段要求:
1. 至少支持关键选择后队友短反应
2. 至少支持营地或旅途中一次补充评价
## 7.4 `threadContract.ts`
职责:
1.`StoryThread` 编译成可推进的 `ThreadContract`
2. 为调查、关系、试炼、追索等线程提供稳定步骤结构
建议导出:
```ts
buildThreadContract(params)
compileQuestFromThreadContract(params)
```
第二阶段目标:
- 不是重做任务系统
- 而是让任务成为线程推进器的一种表现
## 7.5 `threadSignalRouter.ts`
职责:
1. 接收运行时 signal
2. 判断哪些线程、哪些合约步骤应该推进
3. 触发:
- 任务步骤完成
- 新事实解锁
- 队友反应
- 新残痕 / 新物件回响
建议导出:
```ts
collectStorySignals(params)
resolveSignalsToThreadUpdates(params)
```
## 7.6 `sceneResidueCompiler.ts`
职责:
1. 给场景和调查结果补 `narrativeResidues`
2. 让场景本身开始承担《黑神话》《古剑》式残痕叙事
建议导出:
```ts
buildSceneNarrativeResidues(params)
buildResidueInspectResult(params)
```
第二阶段要求:
1. 至少在自定义世界 landmark 上生成残痕
2. 至少能在“观察痕迹 / inspect / observe_signs”时读出来
## 7.7 `narrativeCarrierCatalog.ts`
职责:
把当前只覆盖 `InventoryItem` 的载体,扩成统一的叙事载体目录:
1. 物件
2. 文书
3. 场景残痕
4. 怪物特殊掉落情报
5. 任务证据
建议导出:
```ts
buildNarrativeCarrierCatalog(state)
resolveCarrierById(id)
```
## 8. 现有文件改造方案
## 8.1 `src/services/customWorld.ts`
第二阶段要做的,不是继续堆 fallback而是把 AI contract 真正接进生成链。
改造目标:
1. `ThemePack` 允许 AI 细化词汇与命名模式
2. `WorldStoryGraph` 允许 AI 生成更像世界主线 / 暗线的线程图谱
3. `ActorNarrativeProfile` 允许 AI 生成更有作者性的角色命题与错位感
要求:
- 仍保留 fallback
- AI 失败时不阻塞生成
- AI 成功时优先写入结构化结果
## 8.2 `src/services/customWorldBuilder.ts`
第二阶段不再只是 normalize而要支持
1. 合并 AI 输出与 fallback
2. 校验线程、角色、场景之间的 ID 关联
3.`KnowledgeFact` 预编译结果一起挂回 profile
## 8.3 `src/services/prompt.ts`
这是第二阶段最重要的运行时改造点。
改造目标:
1. 彻底移除低披露阶段对 `relationshipHooks` / `tags` 的无条件直出
2. `VisibilitySlice` 改为基于 `KnowledgeFact` 组装
3. 引入 `recentCompanionReactions`
4. 引入 `recentCarrierEchoes`
第二阶段后prompt 不应再直接拼太多原始字段,而应该优先拼:
1. 可见事实
2. 可推测事实
3. 反应提示
4. 线程压力
## 8.4 `src/data/npcInteractions.ts`
第二阶段重点:
1.`stanceProfile` 从局部数值状态,升级成真正会改变文本与反应方向的关系模型
2. 增加:
- 审慎沉默
- 价值观反对
- 被触发的 taboo 反应
- 队友间互评
仍不做大 UI但要开始做
- 运行时差异反应文本
- 旅途中短插话
## 8.5 `src/hooks/useStoryGeneration.ts`
第二阶段继续保持 orchestrator 职责,不吞业务细节。
新增职责:
1. 收集 `StorySignal`
2. 路由到 `threadSignalRouter`
3. 收集队友反应批次
4. 把反应和回响写回 story history / memory
## 8.6 `src/services/questDirector.ts` + `src/data/questFlow.ts`
第二阶段目标:
1. 任务不再只是“任务意图 -> 任务”
2. 而是:
- `StoryThread -> ThreadContract -> Quest manifestation`
最低要求:
1. 调查类任务
2. 关系类任务
先完成线程化。
## 8.7 `src/data/runtimeItemNarrative.ts`
第二阶段这里不再是主攻点,但仍要扩:
1.`narrativeCarrierCatalog` 对齐
2. 支持非物件类叙事载体复用同一套描述语法
3. 支持 NPC 对重点物件产生反应
## 9. 第二阶段开发顺序
建议顺序如下:
1. `KnowledgeFact` 图谱
2. `VisibilitySlice 2.0`
3. Prompt 泄露收口
4. Companion reaction director
5. Thread contract / signal router
6. Scene residue / narrative carriers
7. 自定义世界 AI contract 真接入
8. 测试与内容回归
原因:
- 不先做知识图谱和可见性,后面所有反应系统都会继续飘
- 不先做 signal router线程化任务和回响都无法稳定推进
## 10. 测试方案
## 10.1 新增单元测试
建议新增:
1. `knowledgeGraph.test.ts`
2. `knowledgeContract.test.ts`
3. `companionReactionDirector.test.ts`
4. `threadContract.test.ts`
5. `threadSignalRouter.test.ts`
6. `sceneResidueCompiler.test.ts`
## 10.2 新增集成测试
建议补以下集成路径:
1. 关键选择 -> 队友反应 -> stance 更新
2. 获取重点物件 -> memory 回写 -> 后续 NPC 反应
3. 调查线索 -> signal -> thread contract step 推进
4. 自定义世界 AI 线程图谱 -> prompt 可见性 -> 首遇文本
## 10.3 第二阶段验收测试场景
至少人工回归这 5 条:
1. 队友对玩家价值观选择的分化反应
2. 调查类任务拿到线索后任务推进
3. 场景残痕被观察后触发新对话变化
4. 重点物件被某 NPC 识别并改变口风
5. 同一条暗线在人物、任务、地点、物件上多次回响
## 11. 第二阶段验收标准
做到以下几点,才算第二阶段收口:
1. 自定义世界线程图谱和角色叙事档案已真正支持 AI contract 生成
2. 首遇和低披露阶段不再通过 `relationshipHooks / tags` 等隐式字段泄露暗线信息
3. 队友会对关键选择给出差异化反应,且能写回关系状态
4. 至少一类任务已经通过 `ThreadContract + StorySignal` 推进
5. 地点调查、物件获取、对话推进之间开始形成回响闭环
6. `storyEngineMemory` 中的 `recentCarrierIds / resolvedScarIds / recentCompanionReactions`
已被运行时消费,而不只是存着
7. 相关测试通过,`lint` / `typecheck` / `check:encoding` 通过
## 12. 一句话结论
第一阶段解决的是“剧情引擎的骨架有没有”,第二阶段要解决的是:
**这些骨架能不能开始真正驱动选择后果、队友反应、调查推进和世界回响。**
只要第二阶段做稳,当前项目就会从“结构上像 AI 原生剧情引擎”,真正走到“体验上开始像经典单机 RPG”。

View File

@@ -0,0 +1,690 @@
# AI 原生剧情引擎第三阶段技术落地方案
更新时间:`2026-04-06`
## 0. 文档目的
这份方案建立在当前仓库第二阶段已经基本落地的前提上,面向第三阶段的技术推进。
按当前代码审计结果,第二阶段这些关键能力已经基本接入:
1. `KnowledgeFact`
2. `VisibilitySlice 2.0`
3. `CompanionReactionRecord`
4. `ThreadContract`
5. `StorySignal`
6. `SceneNarrativeResidue`
7. `narrativeCarrierCatalog`
8. `recentCompanionReactions / recentCarrierEchoes`
9. 自定义世界生成链中的 `ThemePack / StoryGraph / ActorNarrativeProfile` AI 生成阶段
同时,这些链已经形成了真实接线:
1. `customWorldBuilder` 会生成 `knowledgeFacts / threadContracts / narrativeResidues`
2. `useStoryGeneration` 会读取 `knowledgeFacts` 并构造新的可见性切片
3. `progressionActions` 会收集 `signals`、更新 `thread`、生成 `companion reactions`
4. `questFlow` 已开始挂接 `threadContract`
5. `prompt.ts` 已消费最近队友反应与载体回响
因此第三阶段不再解决:
- 引擎底层语法有没有
- 线程和事实能不能进主链
第三阶段要解决的是:
**如何让这些系统进一步长成“章节化、队友线、世界状态变化、旅程高光、长期回顾”这些真正构成经典单机 RPG 体验的中高层叙事能力。**
## 1. 第二阶段审计结论
## 1.1 可以判定为“基本落地”的部分
按代码和测试情况,第二阶段已经基本落地:
1. 第二阶段新增模块都已存在并有测试:
- `knowledgeGraph`
- `knowledgeContract`
- `companionReactionDirector`
- `threadContract`
- `threadSignalRouter`
- `sceneResidueCompiler`
- `echoMemory`
2. 关键主链已接入:
- `customWorldBuilder.ts`
- `useStoryGeneration.ts`
- `progressionActions.ts`
- `questFlow.ts`
- `prompt.ts`
3. 第二阶段相关测试通过:
- `knowledgeGraph.test.ts`
- `knowledgeContract.test.ts`
- `companionReactionDirector.test.ts`
- `threadContract.test.ts`
- `threadSignalRouter.test.ts`
- `sceneResidueCompiler.test.ts`
- `echoMemory.test.ts`
4. 工程门禁通过:
- `lint`
- `typecheck`
- `check:encoding`
所以,“第二阶段技术落地方案已经基本落地”这个判断是成立的。
## 1.2 第二阶段仍然留下的真实缺口
虽然第二阶段已经基本落地,但它目前更像“动态剧情中层骨架”,还没完全进入“经典 RPG 体验高层”。
当前最关键的 6 个缺口是:
1. `ThreadContract` 仍偏浅
- 目前主要还是两步式 contract更多是“线程感知任务”还不是多阶段主线/支线推进器。
2. `CompanionReactionDirector` 仍偏通用
- 现在队友反应能发生,但还主要是通用 approve/disapprove 级别,还没有真正进入角色个人命题、价值观冲突、营地事件、队友互评。
3. `KnowledgeFact` 虽然存在,但还缺“长期总结层”
- 现在事实能进可见性切片,但还缺章节摘要、世界回顾、角色关系归档、游玩 recap。
4. `SceneNarrativeResidue` 仍偏静态
- 场景开始能讲故事了,但场景还不会因为线程推进、事件完成、阵营变化而发生状态变异。
5. 世界状态变化还很弱
- 当前 `signal` 会推进记忆和 quest可是还不会稳定驱动
- 场景变更
- NPC 立场改口
- 商店库存风格变化
- 场景敌人/残痕刷新
6. 缺少章节 / 旅程 / 高光导演层
- 现在有线程、有事实、有反应,但还没有一个更高层的“章节推进器”来控制:
- 主线节奏
- 旅程段落
- 大事件前后
- 营地休整与情感释放
- 章节收束与下一章开启
## 1.3 结论
第一阶段解决的是“骨架有没有”,第二阶段解决的是“中层动态有没有”,第三阶段要解决的是:
**这些系统能不能组合出真正像经典单机 RPG 的章节感、队友线、旅程高光和世界变化。**
## 2. 第三阶段目标
第三阶段只做 5 件事:
1. 建立 `章节 / 旅程 / 高光导演层`
2. 建立 `队友个人线与营地事件层`
3. 建立 `世界状态变化与阵营温度层`
4. 建立 `叙事文书 / 档案 / 回顾摘要层`
5. 建立 `大事件 / 章节高潮 / Boss 前后叙事编排层`
一句话定义第三阶段:
**从“动态剧情系统”升级到“能持续制造章节记忆点和旅程余味的 RPG 叙事框架”。**
## 3. 第三阶段完成定义
第三阶段完成后,至少要同时满足:
1. 游戏运行中能形成 `章节感`
- 玩家明确感到自己经历了“第一章、第二章、转折、大事件、余波”。
2. 队友不再只是对选择做短反应
- 而是会有:
- 个人线推进
- 营地事件
- 队友互评
- 价值观冲突
- 忠诚变化
3. 世界会因为线程推进发生状态变化
- 某些场景描述、残痕、NPC 态度、敌对压力、商店风格、任务机会会改变。
4. 玩家会得到结构化回顾
- 包括:
- 当前章节摘要
- 已发现关键真相
- 队友关系变化
- 最近大事件
5. 至少一条主线或关键线程,已经能从“起线 -> 扩张 -> 转折 -> 高潮 -> 余波”完整走完。
## 4. 第三阶段范围
## 4.1 纳入范围
- `src/services/storyEngine/*`
- `src/hooks/useStoryGeneration.ts`
- `src/hooks/story/progressionActions.ts`
- `src/data/npcInteractions.ts`
- `src/data/questFlow.ts`
- `src/services/prompt.ts`
- `src/components/AdventureEntityModal.tsx`
- `src/components/CharacterPanel.tsx`
- `src/components/InventoryPanel.tsx`
- `src/components/AdventurePanel.tsx`
- `src/types/storyEngine.ts`
- `src/types/story.ts`
- `src/types/game.ts`
- `src/types/scene.ts`
## 4.2 新增模块
- `src/services/storyEngine/chapterDirector.ts`
- `src/services/storyEngine/journeyBeatPlanner.ts`
- `src/services/storyEngine/companionArcDirector.ts`
- `src/services/storyEngine/campEventDirector.ts`
- `src/services/storyEngine/worldMutationRouter.ts`
- `src/services/storyEngine/factionTensionState.ts`
- `src/services/storyEngine/documentCarrierCompiler.ts`
- `src/services/storyEngine/storyChronicle.ts`
- `src/services/storyEngine/recapDigest.ts`
- `src/services/storyEngine/setpieceDirector.ts`
## 4.3 第三阶段明确不做
第三阶段仍不做:
1. 全流程可视化剧情编辑器
2. 通用 mod 工具链
3. 全量配音/镜头脚本系统
4. 无限复杂分支树编辑器
5. 所有支线都拥有章节级演出
原因:
第三阶段目标是把当前系统推到“经典 RPG 体验层”,不是同时把制作工具也做到工业级。
## 5. 第三阶段最小闭环
建议第三阶段最小闭环为:
```text
ChapterDirector
-> JourneyBeatPlanner
-> ThreadContract / StorySignal
-> CompanionArcDirector
-> CampEventDirector
-> WorldMutationRouter
-> SetpieceDirector
-> StoryChronicle / RecapDigest
```
这条闭环对应玩家可感知的体验是:
1. 章节推进
2. 旅程段落变化
3. 队友关系与个人线变化
4. 场景 / 世界状态变化
5. 大事件 / 高潮回合
6. 章节后的回顾与余波
## 6. 数据结构升级方案
## 6.1 `src/types/storyEngine.ts`
第三阶段建议新增:
```ts
export interface ChapterState {
id: string;
title: string;
theme: string;
primaryThreadIds: string[];
stage: 'opening' | 'expansion' | 'turning_point' | 'climax' | 'aftermath';
chapterSummary: string;
}
export interface JourneyBeat {
id: string;
beatType: 'approach' | 'investigation' | 'camp' | 'conflict' | 'boss_prelude' | 'climax' | 'recovery';
title: string;
triggerThreadIds: string[];
recommendedSceneIds: string[];
emotionalGoal: string;
}
export interface CompanionArcState {
characterId: string;
arcTheme: string;
currentStage: 'closed' | 'guarded' | 'opening' | 'conflicted' | 'bonded' | 'resolved';
activeConflictTags: string[];
pendingEventIds: string[];
resolvedEventIds: string[];
}
export interface CampEvent {
id: string;
eventType: 'private_talk' | 'party_banter' | 'conflict' | 'comfort' | 'reveal' | 'decision';
title: string;
participantCharacterIds: string[];
triggerReason: string;
relatedThreadIds: string[];
}
export interface WorldMutation {
id: string;
mutationType: 'scene_text' | 'npc_attitude' | 'shop_style' | 'enemy_pressure' | 'route_lock' | 'route_unlock';
targetId: string;
reason: string;
relatedThreadIds: string[];
}
export interface FactionTensionState {
factionId: string;
temperature: number;
pressureSummary: string;
activeConflictThreadIds: string[];
}
export interface ChronicleEntry {
id: string;
category: 'chapter' | 'thread' | 'companion' | 'carrier' | 'scene' | 'world_event';
title: string;
summary: string;
relatedIds: string[];
createdAt: string;
}
```
并扩展:
```ts
export interface StoryEngineMemoryState {
currentChapter?: ChapterState | null;
currentJourneyBeatId?: string | null;
companionArcStates?: CompanionArcState[];
worldMutations?: WorldMutation[];
chronicle?: ChronicleEntry[];
}
```
## 6.2 `src/types/game.ts`
第三阶段建议新增:
```ts
interface GameState {
chapterState?: ChapterState | null;
}
```
说明:
- `chapterState` 放在 `GameState` 顶层,便于 UI 和主流程快速读取
- 详细历史仍留在 `storyEngineMemory`
## 6.3 `src/types/scene.ts`
第三阶段建议扩展:
```ts
interface ScenePresetInfo {
mutationStateText?: string | null;
currentPressureLevel?: 'low' | 'medium' | 'high' | 'extreme';
}
```
用于场景在章节推进后发生显式变化。
## 7. 模块实现方案
## 7.1 `chapterDirector.ts`
职责:
1. 根据主活跃线程、最近 signal、世界冲突温度决定当前章节处于哪个阶段
2. 生成:
- 章节标题
- 当前主题
- 当前主线线程
- 当前章节摘要
建议导出:
```ts
resolveCurrentChapterState(params)
advanceChapterState(params)
```
第三阶段目标:
- 让玩家的体验从“连续事件流”变成“章节化旅程”
## 7.2 `journeyBeatPlanner.ts`
职责:
1. 在章节内部规划短周期旅程段落
2. 给当前阶段分配:
- 接近
- 调查
- 休整
- 冲突
- 高潮前奏
- 余波
建议导出:
```ts
buildJourneyBeatQueue(params)
resolveCurrentJourneyBeat(params)
```
它是第三阶段对标《黑神话》旅程感和《仙剑》节奏起伏的关键模块。
## 7.3 `companionArcDirector.ts`
职责:
1. 把当前队友的 stance、thread、reaction、facts 组合成真正的个人线状态
2. 决定某个队友此刻更接近:
- 打开
- 回避
- 冲突
- 信任
- 和解
建议导出:
```ts
buildCompanionArcState(params)
advanceCompanionArc(params)
```
目标:
- 从“通用反应”进化到“每个队友都有正在发生的个人线”
## 7.4 `campEventDirector.ts`
职责:
1. 根据 `CompanionArcState + recentCompanionReactions + chapterState`
决定是否生成营地/旅途中事件
2. 生成:
- 私聊事件
- 队友互评
- 意见冲突
- 情绪缓和
- 个人秘密推进
建议导出:
```ts
evaluateCampEventOpportunity(params)
buildCampEvent(params)
```
这是第三阶段对标《仙剑》角色羁绊、《博德之门》营地戏的核心模块。
## 7.5 `worldMutationRouter.ts`
职责:
1.`StorySignal + ThreadContract + ChapterState` 转成世界状态变化
2. 更新:
- 场景描述
- NPC 口风
- 商店风格
- 敌人压力
- 路线开关
建议导出:
```ts
resolveWorldMutations(params)
applyWorldMutationsToGameState(params)
```
第三阶段目标:
- 世界开始“因为你做过的事而变”
## 7.6 `factionTensionState.ts`
职责:
1. 给 major factions 维护温度和压力摘要
2. 决定某些章节里哪条势力线正在升温
建议导出:
```ts
buildFactionTensionState(profile, memory)
applySignalToFactionTension(params)
```
它主要对标《轩辕剑》的大时代张力和《古剑》的世界推进感。
## 7.7 `documentCarrierCompiler.ts`
职责:
1. 把“文书、口供、记录、日志、残页、信件”等正式纳入叙事载体体系
2.`narrativeCarrierCatalog` 对齐
建议导出:
```ts
buildNarrativeDocument(params)
compileDocumentKnowledgeFacts(params)
```
目标:
- 第三阶段让叙事载体不再只限于物件和场景残痕
## 7.8 `storyChronicle.ts`
职责:
1. 把当前发生过的大事件、关键事实、角色转折写入 chronicle
2. 让玩家和系统都有一个更高层的“已发生过什么”的长期摘要
建议导出:
```ts
appendChronicleEntry(params)
buildChronicleSummary(params)
```
## 7.9 `recapDigest.ts`
职责:
1. 生成章节回顾、阶段摘要、下回合简报
2. 给 UI、存档恢复、继续游戏提供更强的 recap 文本
建议导出:
```ts
buildChapterRecap(params)
buildContinueGameDigest(params)
```
## 7.10 `setpieceDirector.ts`
职责:
1. 决定何时进入大事件、Boss 前奏、对峙、章节高潮
2. 给主链输出高光导演指令
建议导出:
```ts
evaluateSetpieceOpportunity(params)
buildSetpieceDirective(params)
```
第三阶段目标:
- 让剧情不只是“持续往前”,而是有真正高光和收束
## 8. 现有文件改造方案
## 8.1 `src/hooks/useStoryGeneration.ts`
第三阶段这里要继续保持 orchestrator 职责,但增加“高层导演”的接线:
新增接线:
1. `chapterDirector`
2. `journeyBeatPlanner`
3. `setpieceDirector`
4. `campEventDirector`
它要做的事情:
1. 读取当前章节状态
2. 读取当前旅程 beat
3. 判断本回合是否应该转入营地 / 高潮 / 余波
4. 把这些高层指令压入 prompt
## 8.2 `src/hooks/story/progressionActions.ts`
这里是第三阶段最重要的状态推进点。
新增职责:
1. 调用 `worldMutationRouter`
2. 调用 `companionArcDirector`
3. 调用 `storyChronicle`
4. 回写:
- `chapterState`
- `companionArcStates`
- `worldMutations`
- `chronicle`
## 8.3 `src/services/prompt.ts`
第三阶段改造目标:
1. 加入 `chapterState`
2. 加入 `journeyBeat`
3. 加入 `recentWorldMutations`
4. 加入 `recentChronicleSummary`
提示词不再只围绕“当前场景 + 当前遭遇 + facts”还要围绕
1. 当前章节主题
2. 当前旅程段落
3. 最近发生的世界变化
4. 队友当前情绪与线索包袱
## 8.4 `src/data/npcInteractions.ts`
第三阶段重点:
1. 支持由 `CompanionArcState` 决定对话气质
2. 支持队友互评与冲突事件
3. 支持同一选择在不同 arc stage 下触发不同态度
## 8.5 `src/data/questFlow.ts`
第三阶段目标:
1. 任务从“线程 manifest”继续升级为“章节与旅程服务”
2. 支持:
- 章节中期任务
- 高潮前置任务
- 余波任务
## 8.6 `src/components/*`
第三阶段不主打大 UI 重做,但建议最小补这些表现:
1. `AdventurePanel`
- 当前章节标题 / 当前旅程 beat 轻量显示
2. `CharacterPanel`
- 队友当前个人线阶段
3. `AdventureEntityModal`
- 最近与该角色相关的 chronicle / residue / carrier 片段
4. `InventoryPanel`
- 文书 / 证据 / 特殊载体的独立入口
## 9. 第三阶段开发顺序
建议顺序如下:
1. `chapterDirector`
2. `journeyBeatPlanner`
3. `companionArcDirector`
4. `campEventDirector`
5. `worldMutationRouter`
6. `documentCarrierCompiler`
7. `storyChronicle`
8. `recapDigest`
9. `setpieceDirector`
10. UI 最小接线
原因:
- 没有章节和旅程层,后面的营地事件和高潮都无从安放
- 没有 world mutation很多后续内容仍会像“文本在变世界没变”
## 10. 测试方案
## 10.1 新增单元测试
建议新增:
1. `chapterDirector.test.ts`
2. `journeyBeatPlanner.test.ts`
3. `companionArcDirector.test.ts`
4. `campEventDirector.test.ts`
5. `worldMutationRouter.test.ts`
6. `factionTensionState.test.ts`
7. `documentCarrierCompiler.test.ts`
8. `storyChronicle.test.ts`
9. `recapDigest.test.ts`
10. `setpieceDirector.test.ts`
## 10.2 新增集成测试
建议补这 5 类:
1. 线程推进到转折点后,章节状态发生变化
2. 队友在关键选择后推进个人线阶段
3. 获得关键文书后,营地事件或下一轮剧情出现新回响
4. 某条主线推进后,场景文本和 NPC 态度发生世界状态变化
5. 高潮前后prompt 中的章节、旅程、世界变化信息都能被正确注入
## 10.3 人工回归场景
至少做这 6 条:
1. 一条调查线程从起线推进到转折
2. 一个队友从 guarded 推到 conflicted / bonded
3. 一个营地事件被触发并影响后续关系
4. 一个重点物件 + 文书 + 场景残痕组成同一条暗线回响
5. 一个章节进入高潮前后,场景压力显著变化
6. 继续游戏时能看到结构化 recap而不是只靠最后几条 story history
## 11. 第三阶段验收标准
做到以下几点,才算第三阶段可收口:
1. 系统能稳定给出 `ChapterState`
2. 至少一条主线线程可以经历 `opening -> expansion -> turning_point -> climax -> aftermath`
3. 队友个人线能有明确阶段推进,并能触发营地或旅途事件
4. 世界状态会因为线程推进产生可见变化
5. 文书/证据类叙事载体正式进入主链
6. 玩家可以在运行时获得章节回顾和近期大事件摘要
7. 高潮节点会由 `setpieceDirector` 显式导演,而不是随机撞出来
8. 相关测试通过,`lint` / `typecheck` / `check:encoding` 通过
## 12. 一句话结论
第一阶段解决“骨架”,第二阶段解决“动态系统”,第三阶段要解决的是:
**这些动态系统能不能真正长出章节感、队友线、世界变化和章节高光。**
只有第三阶段做稳,当前项目才会从“已经很像 AI 原生剧情引擎”,真正走向“能稳定制造经典单机 RPG 旅程体验”的层级。

View File

@@ -0,0 +1,725 @@
# AI 原生剧情引擎第四阶段技术落地方案
更新时间:`2026-04-06`
## 0. 文档目的
这份方案建立在当前仓库第三阶段已经基本落地的前提上,面向第四阶段的技术推进。
按当前代码审计结果,第三阶段已经基本把这些中高层能力接进了主链:
1. `ChapterState`
2. `JourneyBeat`
3. `CompanionArcState`
4. `CampEvent`
5. `WorldMutation`
6. `FactionTensionState`
7. `ChronicleEntry`
8. `ContinueGameDigest`
9. `SetpieceDirective`
并且这些能力已经开始被:
- `useStoryGeneration`
- `progressionActions`
- `prompt.ts`
- `AdventurePanel`
- `CharacterPanel`
- `AdventureEntityModal`
- `InventoryPanel`
实际消费。
因此第四阶段不再解决:
- 底层图谱有没有
- 动态系统有没有
- 章节、旅程和高光导演有没有
第四阶段要解决的是:
**如何让当前已经具备的动态叙事系统,真正进入“可持续量产内容、可收束长线剧情、可形成多幕主线与结局体验、可进行作者性控制和质量校验”的阶段。**
一句话说:
**前三阶段把引擎“做起来”,第四阶段要把它“做完整、做可控、做可持续量产”。**
## 1. 第三阶段审计结论
## 1.1 可以判定为“基本落地”的部分
按代码和测试情况,第三阶段已经基本落地:
1. 第三阶段新增模块都已存在并有测试:
- `chapterDirector`
- `journeyBeatPlanner`
- `companionArcDirector`
- `campEventDirector`
- `worldMutationRouter`
- `factionTensionState`
- `documentCarrierCompiler`
- `storyChronicle`
- `recapDigest`
- `setpieceDirector`
2. 关键主链已接入:
- `useStoryGeneration.ts`
- `progressionActions.ts`
- `prompt.ts`
- `AdventurePanel.tsx`
- `CharacterPanel.tsx`
- `AdventureEntityModal.tsx`
- `InventoryPanel.tsx`
- `GameShell.tsx`
3. 第三阶段相关测试通过:
- `chapterDirector.test.ts`
- `journeyBeatPlanner.test.ts`
- `companionArcDirector.test.ts`
- `campEventDirector.test.ts`
- `worldMutationRouter.test.ts`
- `factionTensionState.test.ts`
- `documentCarrierCompiler.test.ts`
- `storyChronicle.test.ts`
- `recapDigest.test.ts`
- `setpieceDirector.test.ts`
4. 工程门禁通过:
- `lint`
- `typecheck`
- `check:encoding`
所以,“第三阶段技术落地方案已经基本落地”这个判断成立。
## 1.2 第三阶段留下的真实缺口
虽然第三阶段已经把“章节、旅程、队友线、世界变化、高光导演”这些高层能力接起来了,但它们还更像“运行时中高层系统”,还没有进入真正的“长线 campaign 完整度”和“内容生产可控性”阶段。
当前最关键的 7 个缺口是:
1. `ChapterState` 已有,但还缺 `Act / Campaign` 级结构
- 目前更像章节段落推进器,还不是完整的多幕主线架构。
2. 队友个人线已有,但还缺“收束态”
- 当前能推进 arc stage但还没有
- 个人线结局
- 决裂 / 离队 / 归队
- 忠诚锁定
- 决战前站队
3. 世界变化已有,但还缺“全局后果账本”
- 当前能改场景和口风,但还没有统一的:
- 关键选择后果台账
- 阵营态势累积
- 长线不可逆变化
4. 文书与 chronicle 已有,但还缺“玩家可管理的故事档案”
- 现在有内容生成和少量展示,但还缺真正的 codex / archive 层。
5. `SetpieceDirector` 已有,但还偏事件触发器
- 当前能识别高潮和余波,但还没有:
- 多阶段高潮编排
- 决战前准备段
- 决战后结算段
6. 缺少结局 / 尾声系统
- 当前可以推进 journey但没有明确的
- 线程结局
- 角色结局
- 世界结局
- 尾声摘要
7. 缺少作者性约束与质量门禁
- 当前系统很强,但如果要稳定产出“经典 RPG 级长线内容”,必须补:
- branch budget
- ending coverage
- contradiction checks
- pacing checks
- narrative QA 报告
## 1.3 结论
第一阶段解决“骨架”,第二阶段解决“动态系统”,第三阶段解决“章节和旅程感”,第四阶段要解决的是:
**这套引擎能不能稳定做出完整 campaign并且能被持续生产、校验、维护和扩张。**
## 2. 第四阶段目标
第四阶段只做 5 件事:
1. 建立 `Campaign / Act / Ending` 级主线结构
2. 建立 `Companion Resolution` 队友线收束系统
3. 建立 `Consequence Ledger` 全局后果账本
4. 建立 `Narrative Codex / Archive` 故事档案系统
5. 建立 `Authorial Constraint + Narrative QA` 内容生产与质量门禁体系
一句话定义第四阶段:
**从“能跑出经典 RPG 旅程感”升级到“能稳定完成一整部经典 RPG campaign”。**
## 3. 第四阶段完成定义
第四阶段完成后,至少要同时满足:
1. 系统能够维护多幕结构
- `Act I / II / III` 或等价 campaign 分段真正成立。
2. 至少一条完整主线能走到结局
- 并且结局由:
- 主线程结果
- 队友个人线结果
- 阵营态势
- 关键后果账本
共同决定。
3. 队友个人线能有明确收束
- 包括:
- 和解
- 坚定追随
- 决裂
- 离队
- 牺牲 / 缺席 / 旁观
4. 世界后果被系统记录并能影响结局和尾声
- 不只是局部场景文字变化。
5. 玩家可以查看已发生的主线、角色线、文书、关键真相和结局线索。
6. 生成链具备明确的作者性约束和 QA 报告,不再只靠人工抽样验证。
## 4. 第四阶段范围
## 4.1 纳入范围
- `src/services/storyEngine/*`
- `src/hooks/story/progressionActions.ts`
- `src/hooks/useStoryGeneration.ts`
- `src/services/prompt.ts`
- `src/data/questFlow.ts`
- `src/data/npcInteractions.ts`
- `src/components/AdventurePanel.tsx`
- `src/components/CharacterPanel.tsx`
- `src/components/InventoryPanel.tsx`
- `src/components/AdventureEntityModal.tsx`
- `src/components/GameShell.tsx`
- `src/types/storyEngine.ts`
- `src/types/game.ts`
- `src/types/story.ts`
## 4.2 新增模块
- `src/services/storyEngine/campaignDirector.ts`
- `src/services/storyEngine/actPlanner.ts`
- `src/services/storyEngine/endingResolver.ts`
- `src/services/storyEngine/epilogueComposer.ts`
- `src/services/storyEngine/companionResolutionDirector.ts`
- `src/services/storyEngine/consequenceLedger.ts`
- `src/services/storyEngine/narrativeCodex.ts`
- `src/services/storyEngine/authorialConstraintPack.ts`
- `src/services/storyEngine/branchBudgetPlanner.ts`
- `src/services/storyEngine/narrativeQaReport.ts`
- `src/services/storyEngine/narrativeConsistencyChecks.ts`
## 4.3 第四阶段明确不做
第四阶段仍不做:
1. 完整可视化剧情节点编辑器
2. 商业级本地化 pipeline
3. 全自动配音 / 镜头脚本工具链
4. 全量开放给 mod 作者的内容 DSL
5. 无上限多周目 meta-progression
原因:
第四阶段的任务是把 campaign 层做完整和可控,不是同时做全生产平台。
## 5. 第四阶段最小闭环
建议第四阶段最小闭环为:
```text
CampaignDirector
-> ActPlanner
-> Chapter / Journey / Thread systems
-> ConsequenceLedger
-> CompanionResolutionDirector
-> EndingResolver
-> EpilogueComposer
-> NarrativeCodex
-> NarrativeQaReport
```
这条闭环对应玩家可感知的体验是:
1. 这不是无限流局部冒险,而是一段完整 campaign
2. 你的选择有长期代价
3. 队友线会真正收束
4. 结局和尾声会回收之前埋下的线
5. 整个过程具有更强作者性和完成度
## 6. 数据结构升级方案
## 6.1 `src/types/storyEngine.ts`
第四阶段建议新增:
```ts
export interface CampaignState {
id: string;
title: string;
currentActId: string | null;
currentActIndex: number;
resolvedEndingId?: string | null;
}
export interface ActState {
id: string;
title: string;
actIndex: number;
theme: string;
primaryThreadIds: string[];
status: 'opening' | 'midgame' | 'late_game' | 'finale' | 'resolved';
}
export interface ConsequenceRecord {
id: string;
category: 'thread' | 'companion' | 'faction' | 'world' | 'ending_flag';
title: string;
summary: string;
weight: number;
relatedIds: string[];
irreversible: boolean;
}
export interface CompanionResolution {
characterId: string;
resolutionType: 'bonded' | 'reconciled' | 'estranged' | 'departed' | 'sacrificed' | 'neutral';
summary: string;
relatedThreadIds: string[];
}
export interface EndingState {
id: string;
title: string;
endingType: 'heroic' | 'tragic' | 'bitter_sweet' | 'fractured' | 'ascendant';
summary: string;
contributingThreadIds: string[];
companionResolutions: CompanionResolution[];
worldOutcomeSummary: string;
}
export interface AuthorialConstraintPack {
toneRules: string[];
noGoPatterns: string[];
branchBudget: {
maxMajorDivergences: number;
maxEndingFamilies: number;
};
mandatoryThemes: string[];
requiredPayoffs: string[];
}
export interface NarrativeQaIssue {
id: string;
severity: 'low' | 'medium' | 'high';
category: 'consistency' | 'pacing' | 'payoff' | 'branch_budget' | 'reveal_leak';
summary: string;
relatedIds: string[];
}
export interface NarrativeQaReport {
generatedAt: string;
issues: NarrativeQaIssue[];
summary: string;
}
```
并扩展:
```ts
export interface StoryEngineMemoryState {
campaignState?: CampaignState | null;
actState?: ActState | null;
consequenceLedger?: ConsequenceRecord[];
companionResolutions?: CompanionResolution[];
endingState?: EndingState | null;
authorialConstraintPack?: AuthorialConstraintPack | null;
narrativeQaReport?: NarrativeQaReport | null;
}
```
## 6.2 `src/types/game.ts`
扩展:
```ts
interface GameState {
campaignState?: CampaignState | null;
}
```
## 6.3 `src/types/story.ts`
扩展:
```ts
interface QuestLogEntry {
actId?: string | null;
consequenceIds?: string[];
}
```
目的:
- 让任务正式进入 campaign / act 结构
## 7. 模块实现方案
## 7.1 `campaignDirector.ts`
职责:
1. 建立整个 campaign 的总状态
2. 管理当前 act 与 campaign 收束进度
建议导出:
```ts
resolveCampaignState(params)
advanceCampaignState(params)
```
目标:
- 从章节推进升级到“整部故事”的推进
## 7.2 `actPlanner.ts`
职责:
1. 根据主线程、世界 tension、队友线推进情况划分 act
2. 决定何时进入:
- 第一幕铺陈
- 第二幕扩张
- 第三幕决战
建议导出:
```ts
buildActPlan(params)
resolveCurrentActState(params)
```
## 7.3 `consequenceLedger.ts`
职责:
1. 记录关键选择和线程推进的长期后果
2. 形成一个统一可回收的“后果账本”
建议导出:
```ts
appendConsequenceRecord(params)
buildConsequenceLedgerSummary(params)
```
这是第四阶段最重要的全局语义层之一。
## 7.4 `companionResolutionDirector.ts`
职责:
1. 根据 `CompanionArcState + reactions + key consequences`
决定队友线的最终收束状态
2. 输出:
- bonded
- reconciled
- estranged
- departed
- sacrificed
建议导出:
```ts
resolveCompanionResolution(params)
resolveAllCompanionResolutions(params)
```
## 7.5 `endingResolver.ts`
职责:
1. 综合:
- 主线程结局
- 队友收束
- faction tension
- consequence ledger
2. 生成最终 `EndingState`
建议导出:
```ts
resolveEndingState(params)
```
目标:
- 真正形成“经典 RPG 结局体验”
## 7.6 `epilogueComposer.ts`
职责:
1. 为结局后生成尾声摘要
2. 回收:
- 关键线程
- 队友去向
- 世界变化
- 玩家留下的长期后果
建议导出:
```ts
buildEpilogueSummary(params)
```
## 7.7 `narrativeCodex.ts`
职责:
1. 把当前已有的:
- facts
- residues
- carriers
- chronicle
- documents
组织成玩家可浏览的故事档案系统
建议导出:
```ts
buildNarrativeCodex(state)
buildCodexSections(state)
```
## 7.8 `authorialConstraintPack.ts`
职责:
1. 把当前题材和 campaign 级作者性要求结构化
2. 给 AI generation、ending、setpiece、epilogue 全部提供一致约束
建议导出:
```ts
buildAuthorialConstraintPack(params)
```
## 7.9 `branchBudgetPlanner.ts`
职责:
1. 控制 major divergence 数量
2. 控制 ending family 数量
3. 防止 campaign 后期分支爆炸
建议导出:
```ts
evaluateBranchBudget(params)
```
## 7.10 `narrativeQaReport.ts`
职责:
1. 汇总 consistency / pacing / payoff / leak / branch budget 等问题
2. 输出结构化 QA report
建议导出:
```ts
buildNarrativeQaReport(params)
```
## 7.11 `narrativeConsistencyChecks.ts`
职责:
1. 做规则化检查
2. 捕捉:
- 事实泄露
- payoff 缺失
- unresolved thread 过多
- 角色线断裂
- ending 收束不足
建议导出:
```ts
runNarrativeConsistencyChecks(params)
```
## 8. 现有文件改造方案
## 8.1 `useStoryGeneration.ts`
第四阶段这里新增 campaign 层接线:
1. `campaignDirector`
2. `actPlanner`
3. `authorialConstraintPack`
并把结果注入 prompt
1. 当前 act
2. 当前 campaign 目标
3. 当前分支预算压力
4. 当前必须回收的 payoff
## 8.2 `progressionActions.ts`
这是第四阶段最重要的状态推进点。
新增职责:
1. 维护 `CampaignState / ActState`
2. 回写 `ConsequenceLedger`
3. 解析 `CompanionResolution`
4. 在满足条件时触发 `EndingResolver`
5. 生成 `NarrativeQaReport`
## 8.3 `prompt.ts`
第四阶段改造目标:
1. prompt 不只是围绕当前章节和旅程
2. 还要围绕:
- 当前 act
- campaign 主命题
- 已积累的关键后果
- 还必须回收的 payoff
- 作者性 constraint pack
## 8.4 `questFlow.ts`
第四阶段目标:
1. 任务不只是 thread / chapter 服务
2. 还要进入 act/campaign 层的安排
至少新增:
1. act 关键任务
2. ending 前置任务
3. 队友个人线收束任务
## 8.5 `npcInteractions.ts`
第四阶段目标:
1. 队友/NPC 关系可以进入 resolution 判定
2. 支持队友去留和最终站队
3. 支持更高权重的不可逆关系变化
## 8.6 `components/*`
第四阶段不主打大规模 UI 重做,但建议最小补这些:
1. `AdventurePanel`
- 当前 act / chapter / ending pressure
2. `CharacterPanel`
- companion resolution progress
3. `InventoryPanel`
- narrative codex / document archive 入口
4. `AdventureEntityModal`
- 当前角色的关键 consequence / resolution 片段
## 9. 第四阶段开发顺序
建议顺序如下:
1. `campaignDirector`
2. `actPlanner`
3. `consequenceLedger`
4. `companionResolutionDirector`
5. `endingResolver`
6. `epilogueComposer`
7. `narrativeCodex`
8. `authorialConstraintPack`
9. `branchBudgetPlanner`
10. `narrativeConsistencyChecks`
11. `narrativeQaReport`
12. UI 最小接线
原因:
- 没有 campaign / act结局和 QA 都无从谈起
- 没有 consequence ledgerending 会继续偏表层组合
- 没有 authorial constraints 和 QA长线内容会越来越漂
## 10. 测试方案
## 10.1 新增单元测试
建议新增:
1. `campaignDirector.test.ts`
2. `actPlanner.test.ts`
3. `consequenceLedger.test.ts`
4. `companionResolutionDirector.test.ts`
5. `endingResolver.test.ts`
6. `epilogueComposer.test.ts`
7. `narrativeCodex.test.ts`
8. `authorialConstraintPack.test.ts`
9. `branchBudgetPlanner.test.ts`
10. `narrativeConsistencyChecks.test.ts`
11. `narrativeQaReport.test.ts`
## 10.2 新增集成测试
建议补这 6 类:
1. 主线程推进到 act 切换
2. 关键后果进入 ledger 并影响后续 companion resolution
3. 队友个人线收束进入 ending
4. ending state 正确聚合主线、队友线、世界状态
5. epilogue 能回收关键 threads / companions / world mutations
6. QA report 能检测未回收 payoff 或分支超预算
## 10.3 人工回归场景
至少做这 6 条:
1. 一条完整主线从开局跑到结局
2. 两名队友在同一 campaign 中走向不同 resolution
3. 一个重大选择改变结局基调
4. 一条暗线在结局中被正式回收
5. 玩家可以查看完整 codex / chronicle / documents
6. continue game / ending / epilogue 三个摘要层彼此一致
## 11. 第四阶段验收标准
做到以下几点,才算第四阶段可收口:
1. 系统能维护 `CampaignState + ActState`
2. 至少一条完整主线可稳定走到 `EndingState`
3. 队友线能稳定产出 `CompanionResolution`
4. `ConsequenceLedger` 能真实影响 ending 和 epilogue
5. `NarrativeCodex` 可供玩家查看关键故事档案
6. 系统能输出结构化 `NarrativeQaReport`
7. 分支预算和作者性约束已开始进入 generation 主链
8. 相关测试通过,`lint` / `typecheck` / `check:encoding` 通过
## 12. 一句话结论
前三阶段让当前项目拥有了“会生成、会推进、会分层、会回响、会制造章节感”的 AI 原生剧情引擎。
第四阶段要做的,是让它进一步成为:
**一套能稳定完成整部 RPG campaign、能回收长线伏笔、能产出多幕主线和结局、还能被持续生产和校验的完整叙事系统。**

View File

@@ -0,0 +1,676 @@
# AI 原生剧情引擎第五阶段技术落地方案
更新时间:`2026-04-06`
## 0. 文档目的
这份方案建立在当前仓库第四阶段已经基本落地的前提上,面向第五阶段的技术推进。
按当前代码审计结果,第四阶段已经基本把这些 campaign 级能力接进了主链:
1. `CampaignState`
2. `ActState`
3. `ConsequenceRecord`
4. `CompanionResolution`
5. `EndingState`
6. `NarrativeCodex`
7. `AuthorialConstraintPack`
8. `NarrativeQaReport`
并且这些能力已经开始被:
- `progressionActions`
- `useStoryGeneration`
- `prompt.ts`
- `AdventurePanel`
- `CharacterPanel`
- `InventoryPanel`
- `AdventureEntityModal`
实际消费。
因此第五阶段不再解决:
- campaign / act 有没有
- ending / epilogue 有没有
- codex / qa / constraint 有没有
第五阶段要解决的是:
**如何让这套已经能完成完整 campaign 的引擎,进一步成为一套可批量生产、可多 campaign 复用、可仿真评估、可玩家画像自适应、可发布运营的叙事平台。**
一句话说:
**前四阶段把引擎做成“一部完整 RPG 的叙事系统”,第五阶段要把它做成“可以持续生产很多完整 RPG 体验的叙事平台”。**
## 1. 第四阶段审计结论
## 1.1 可以判定为“基本落地”的部分
按代码和测试情况,第四阶段已经基本落地:
1. 第四阶段新增模块都已存在并有测试:
- `campaignDirector`
- `actPlanner`
- `consequenceLedger`
- `companionResolutionDirector`
- `endingResolver`
- `epilogueComposer`
- `narrativeCodex`
- `authorialConstraintPack`
- `branchBudgetPlanner`
- `narrativeConsistencyChecks`
- `narrativeQaReport`
2. 关键主链已接入:
- `useStoryGeneration.ts`
- `progressionActions.ts`
- `prompt.ts`
- `AdventurePanel.tsx`
- `CharacterPanel.tsx`
- `InventoryPanel.tsx`
- `AdventureEntityModal.tsx`
- `GameShell.tsx`
3. 第四阶段相关测试通过:
- `campaignDirector.test.ts`
- `actPlanner.test.ts`
- `consequenceLedger.test.ts`
- `companionResolutionDirector.test.ts`
- `endingResolver.test.ts`
- `epilogueComposer.test.ts`
- `narrativeCodex.test.ts`
- `authorialConstraintPack.test.ts`
- `branchBudgetPlanner.test.ts`
- `narrativeConsistencyChecks.test.ts`
- `narrativeQaReport.test.ts`
4. 工程门禁通过:
- `lint`
- `typecheck`
- `check:encoding`
所以,“第四阶段技术落地方案已经基本落地”这个判断成立。
## 1.2 第四阶段留下的真实缺口
虽然第四阶段已经把 campaign 层做出来了,但它还更像“单 campaign 可运行系统”,还没有进入真正的“生产平台”和“高重玩度生态”阶段。
当前最关键的 8 个缺口是:
1. `CampaignState / EndingState` 已有,但仍偏单线单实例
- 当前更像运行时主战役状态,还没有正式进入“多 campaign 包”和“多 ending family 策略”。
2. `AuthorialConstraintPack` 已有,但仍偏静态
- 目前更像运行时约束快照,还不是可以为不同 campaign / world pack / authorship style 配置的资产层。
3. `NarrativeQaReport` 已有,但仍偏单次运行内检查
- 还没有真正的批量仿真、回归矩阵、发布门禁。
4. `BranchBudgetPlanner` 已有,但仍偏轻量
- 当前更像局部预算检查,不是完整的 campaign 分支运营工具。
5. 缺少玩家画像与自适应导演
- 当前系统很强,但还没有回答:
- 这位玩家偏剧情、偏探索、偏队友、偏战斗、偏收集哪一种?
- 节奏和推荐内容是否应该因玩家风格而微调?
6. 缺少多 campaign / 多 scenario 资产化管理
- 现在能做出一部完整故事,但还没有正式的:
- scenario pack
- campaign registry
- world pack dependency
- reusable story modules
7. 缺少批量仿真和回放能力
- 当前以测试和局部运行验证为主,还没有:
- playthrough simulation
- branch matrix runner
- narrative regression playback
8. 缺少发布与迭代运营链路
- 当前系统适合开发,但还没有:
- telemetry
- release gate report
- save migration manifest
- content diff report
## 1.3 结论
第一阶段解决“骨架”第二阶段解决“动态系统”第三阶段解决“章节与旅程”第四阶段解决“campaign 完整度”,第五阶段要解决的是:
**这套引擎能不能从“一次做成一部作品”,升级到“可以持续生产、评估、复用、发布和运营很多部作品”。**
## 2. 第五阶段目标
第五阶段只做 5 件事:
1. 建立 `Scenario Pack / Campaign Registry` 多 campaign 资产体系
2. 建立 `Simulation Lab / Regression Matrix` 批量仿真与回放评估体系
3. 建立 `Player Style Model / Adaptive Narrative Tuner` 玩家画像与自适应导演体系
4. 建立 `Release Gate / Telemetry / Save Migration` 发布运营体系
5. 建立 `Narrative Production Platform` 内容复用、依赖管理和版本演化体系
一句话定义第五阶段:
**从“完整 campaign 引擎”升级到“可持续生产和运营 campaign 的叙事平台”。**
## 3. 第五阶段完成定义
第五阶段完成后,至少要同时满足:
1. 系统可以同时承载多个 `Scenario Pack / Campaign Pack`
2. 不同 campaign 能共享部分叙事模块、队友模板、载体模板、约束包
3. 发布前可以跑批量 narrative simulation而不只靠单点测试
4. 系统能识别不同玩家风格,并对节奏、事件权重、推荐内容做有限自适应
5. 系统有正式的 `Release Gate Report`
6. 版本更新时有 `Save Migration Manifest`
7. campaign 之间可以被复用、比较、回归和持续优化
## 4. 第五阶段范围
## 4.1 纳入范围
- `src/services/storyEngine/*`
- `src/hooks/story/progressionActions.ts`
- `src/hooks/useStoryGeneration.ts`
- `src/services/prompt.ts`
- `src/services/customWorldBuilder.ts`
- `src/services/customWorld.ts`
- `src/types/storyEngine.ts`
- `src/types/game.ts`
- `src/types/customWorld.ts`
## 4.2 新增模块
- `src/services/storyEngine/scenarioPackRegistry.ts`
- `src/services/storyEngine/campaignPackCompiler.ts`
- `src/services/storyEngine/contentDependencyGraph.ts`
- `src/services/storyEngine/storySimulationRunner.ts`
- `src/services/storyEngine/playthroughMatrixLab.ts`
- `src/services/storyEngine/narrativeRegressionReplay.ts`
- `src/services/storyEngine/playerStyleProfiler.ts`
- `src/services/storyEngine/adaptiveNarrativeTuner.ts`
- `src/services/storyEngine/narrativeTelemetry.ts`
- `src/services/storyEngine/releaseGateReport.ts`
- `src/services/storyEngine/saveMigrationManifest.ts`
- `src/services/storyEngine/contentDiffReport.ts`
## 4.3 第五阶段明确不做
第五阶段仍不做:
1. 大规模联网运营后台
2. 多人协作编辑器平台
3. 商业级可视化内容管理系统
4. 实时云端剧情编排服务
5. 全自动商业数据分析平台
原因:
第五阶段目标是把引擎推进到“可工业化生产和可持续运营”的层级,而不是直接变成完整 SaaS。
## 5. 第五阶段最小闭环
建议第五阶段最小闭环为:
```text
ScenarioPackRegistry
-> CampaignPackCompiler
-> StorySimulationRunner
-> PlaythroughMatrixLab
-> PlayerStyleProfiler
-> AdaptiveNarrativeTuner
-> NarrativeTelemetry
-> ReleaseGateReport
-> SaveMigrationManifest
```
对应到实际价值,就是:
1. campaign 可以被资产化管理
2. 发布前可以批量仿真
3. 上线后可以持续调优
4. 更新时不会轻易打坏旧存档
## 6. 数据结构升级方案
## 6.1 `src/types/storyEngine.ts`
第五阶段建议新增:
```ts
export interface ScenarioPack {
id: string;
title: string;
version: string;
worldPackIds: string[];
campaignIds: string[];
sharedConstraintPackIds: string[];
}
export interface CampaignPack {
id: string;
scenarioPackId: string;
title: string;
authoringStyle: string;
campaignStateSeed: CampaignState;
actTemplates: ActState[];
requiredCompanionIds: string[];
}
export interface PlayerStyleProfile {
id: string;
preferenceWeights: {
story: number;
exploration: number;
combat: number;
companion: number;
collection: number;
};
dominantStyle:
| 'story_first'
| 'explorer'
| 'combat_driver'
| 'companion_bond'
| 'collector';
}
export interface SimulationRunResult {
id: string;
scenarioPackId: string;
campaignPackId: string;
seed: string;
endingId?: string | null;
activeThreadCountPeak: number;
fracturedCompanionCount: number;
issueCount: number;
summary: string;
}
export interface ReleaseGateReport {
generatedAt: string;
status: 'pass' | 'warn' | 'block';
summary: string;
blockingIssues: string[];
simulationCoverage: number;
}
export interface SaveMigrationManifest {
version: string;
requiredTransforms: string[];
backwardCompatible: boolean;
}
```
并扩展:
```ts
export interface StoryEngineMemoryState {
playerStyleProfile?: PlayerStyleProfile | null;
simulationRunResults?: SimulationRunResult[];
releaseGateReport?: ReleaseGateReport | null;
saveMigrationManifest?: SaveMigrationManifest | null;
}
```
## 6.2 `src/types/customWorld.ts`
第五阶段建议扩展:
```ts
interface CustomWorldProfile {
scenarioPackId?: string | null;
campaignPackId?: string | null;
}
```
目的:
- 让世界档案正式进入 pack 体系
## 6.3 `src/types/game.ts`
第五阶段建议扩展:
```ts
interface GameState {
activeScenarioPackId?: string | null;
activeCampaignPackId?: string | null;
}
```
## 7. 模块实现方案
## 7.1 `scenarioPackRegistry.ts`
职责:
1. 维护多个 `ScenarioPack`
2. 让不同 world / campaign / constraint pack 成为正式资产
建议导出:
```ts
registerScenarioPack(pack)
resolveScenarioPack(id)
listScenarioPacks()
```
## 7.2 `campaignPackCompiler.ts`
职责:
1. 把现有 campaign 结构编译成标准 `CampaignPack`
2. 支持:
- 不同 authorial style
- 不同 required companions
- 不同 ending families
建议导出:
```ts
buildCampaignPack(params)
compileCampaignFromWorldProfile(params)
```
## 7.3 `contentDependencyGraph.ts`
职责:
1. 维护:
- campaign -> world
- campaign -> companion
- campaign -> thread
- campaign -> constraint pack
之间的依赖关系
建议导出:
```ts
buildContentDependencyGraph(params)
```
## 7.4 `storySimulationRunner.ts`
职责:
1. 跑单条 playthrough 仿真
2. 输出:
- 走到哪类 ending
- 多少线程未回收
- 队友收束情况
- QA 问题数量
建议导出:
```ts
runStorySimulation(params)
```
## 7.5 `playthroughMatrixLab.ts`
职责:
1. 用多组 seed、多种选择倾向跑批量仿真
2. 汇总:
- ending 分布
- unresolved thread 峰值
- fractured companion 分布
- branch budget 压力
建议导出:
```ts
runPlaythroughMatrix(params)
buildMatrixSummary(params)
```
## 7.6 `narrativeRegressionReplay.ts`
职责:
1. 记录关键 playthrough 样本
2. 在版本升级后回放,检查 narrative regressions
建议导出:
```ts
recordReplaySeed(params)
replayNarrativeRun(params)
```
## 7.7 `playerStyleProfiler.ts`
职责:
1. 根据玩家行为识别风格画像
2. 依据:
- 选项偏好
- 队友互动密度
- 探索行为
- 战斗投入
- 收集倾向
建议导出:
```ts
buildPlayerStyleProfile(state)
updatePlayerStyleProfileFromAction(params)
```
## 7.8 `adaptiveNarrativeTuner.ts`
职责:
1. 基于 `PlayerStyleProfile` 微调运行时导演参数
2. 允许有限自适应:
- 更偏队友戏
- 更偏探索残痕
- 更偏高压冲突
- 更偏调查展开
建议导出:
```ts
resolveAdaptiveNarrativeBias(params)
applyAdaptiveTuningToPromptContext(params)
```
注意:
- 这里必须是“有限微调”,不能破坏作者性和主命题
## 7.9 `narrativeTelemetry.ts`
职责:
1. 汇总关键 narrative runtime 指标
2. 至少包括:
- 平均活跃线程数
- 队友反应密度
- ending family 分布
- unresolved payoff 计数
建议导出:
```ts
captureNarrativeTelemetry(params)
buildTelemetrySnapshot(params)
```
## 7.10 `releaseGateReport.ts`
职责:
1. 把:
- QA report
- simulation results
- branch budget
- unresolved threads
汇总成正式发布门禁报告
建议导出:
```ts
buildReleaseGateReport(params)
```
## 7.11 `saveMigrationManifest.ts`
职责:
1. 为不同版本 story engine state 定义迁移要求
2. 确保多 campaign、多版本更新后旧存档还能继续用
建议导出:
```ts
buildSaveMigrationManifest(params)
applyStoryEngineMigration(params)
```
## 7.12 `contentDiffReport.ts`
职责:
1. 比较两个 campaign/world/constraint pack 版本的差异
2. 用于发布前评估改动面
建议导出:
```ts
buildContentDiffReport(params)
```
## 8. 现有文件改造方案
## 8.1 `useStoryGeneration.ts`
第五阶段新增:
1. 读取 `PlayerStyleProfile`
2. 应用 `AdaptiveNarrativeTuner`
3. 把 adaptive bias 注入 prompt
作用:
- 让同一套 campaign 在不破坏作者性前提下,对不同玩家风格有更好的适配
## 8.2 `progressionActions.ts`
第五阶段重点:
1. 回写 `PlayerStyleProfile`
2. 回写 `SimulationRunResult`(仅调试/实验模式)
3. 回写 `ReleaseGateReport`(构建或工具态)
4. 维护 `SaveMigrationManifest`
## 8.3 `prompt.ts`
第五阶段改造目标:
1. 增加 adaptive bias 提示
2. 增加 authoring style / scenario pack 提示
3. 继续控制不要让自适应破坏核心主题和 mandatory payoffs
## 8.4 `customWorldBuilder.ts` / `customWorld.ts`
第五阶段目标:
1. 正式支持 `ScenarioPack / CampaignPack` 资产化
2. 支持不同 pack 的约束包和版本号
3. 支持 build diff / migration 检查
## 8.5 `useGamePersistence.ts`
第五阶段重点:
1. 引入 `SaveMigrationManifest`
2. 对 story engine state 做版本迁移
3. 确保多 pack、多版本情况下 continue game 仍安全
## 9. 第五阶段开发顺序
建议顺序如下:
1. `scenarioPackRegistry`
2. `campaignPackCompiler`
3. `contentDependencyGraph`
4. `playerStyleProfiler`
5. `adaptiveNarrativeTuner`
6. `storySimulationRunner`
7. `playthroughMatrixLab`
8. `narrativeRegressionReplay`
9. `narrativeTelemetry`
10. `releaseGateReport`
11. `saveMigrationManifest`
12. `contentDiffReport`
原因:
- 先没有 pack 和依赖图,就无法进入平台化
- 先没有 player style profile就无法做自适应
- 先没有 simulation/regression就无法真正做 release gate
## 10. 测试方案
## 10.1 新增单元测试
建议新增:
1. `scenarioPackRegistry.test.ts`
2. `campaignPackCompiler.test.ts`
3. `contentDependencyGraph.test.ts`
4. `playerStyleProfiler.test.ts`
5. `adaptiveNarrativeTuner.test.ts`
6. `storySimulationRunner.test.ts`
7. `playthroughMatrixLab.test.ts`
8. `narrativeRegressionReplay.test.ts`
9. `narrativeTelemetry.test.ts`
10. `releaseGateReport.test.ts`
11. `saveMigrationManifest.test.ts`
12. `contentDiffReport.test.ts`
## 10.2 新增集成测试
建议补这 6 类:
1. 同一 scenario pack 下多 campaign 装载
2. 版本更新后旧存档迁移
3. 同一 campaign 不同 player style 下的有限自适应
4. playthrough matrix 跑出多种 ending family
5. release gate 正确拦截高风险版本
6. regression replay 能检测 narrative drift
## 10.3 人工回归场景
至少做这 6 条:
1. 同一套世界切两条不同 campaign 运行
2. 同一 campaign 用两种玩家风格跑出明显不同的节奏偏重
3. 更新版本后旧存档继续游戏
4. 运行一批 simulation 并生成 release gate report
5. narrative codex 在不同 campaign 间内容不串线
6. ending 和 epilogue 在 regression replay 中保持稳定
## 11. 第五阶段验收标准
做到以下几点,才算第五阶段可收口:
1. 系统支持 `ScenarioPack + CampaignPack`
2. 系统支持 `PlayerStyleProfile + AdaptiveNarrativeTuner`
3. 系统支持批量 `playthrough matrix simulation`
4. 系统支持 `ReleaseGateReport`
5. 系统支持 `SaveMigrationManifest`
6. 系统支持 `NarrativeTelemetry`
7. campaign 可以被复用、对比、回归和版本迁移
8. 相关测试通过,`lint` / `typecheck` / `check:encoding` 通过
## 12. 一句话结论
前四阶段让当前项目拥有了一套从世界图谱到 campaign 收束都能运转的 AI 原生剧情引擎。
第五阶段要做的,是让它进一步成为:
**一套能够持续生产多个 campaign、进行批量仿真评估、适配不同玩家风格、支持版本演化和发布门禁的叙事平台。**

View File

@@ -0,0 +1,559 @@
# AI 原生剧情引擎第六阶段技术落地方案
更新时间:`2026-04-06`
## 0. 是否需要第六阶段
结论先说:
**需要,但第六阶段不应该继续主要围绕“再加一层 runtime 叙事引擎能力”展开,而应该转向“内容生产、策划协同、仿真可视化、版本治理和持续调优”的平台层。**
原因很明确:
按当前代码审计结果,前五阶段已经基本把这些核心能力做出来了:
1. 世界图谱
2. 角色叙事档案
3. 信息可见性
4. 线程与信号推进
5. 队友反应与个人线
6. 章节 / 旅程 / 高光导演
7. campaign / act / ending / epilogue
8. codex / chronicle / QA report
9. scenario pack / campaign pack
10. simulation / regression / release gate / migration
这说明:
- “引擎能力不够”已经不是最核心的问题了
- 接下来最大的瓶颈会变成:
- 内容生产效率
- 策划可控性
- 多版本治理
- 调优闭环
- 让设计师和内容作者能真正驾驭这套系统
所以第六阶段不是 “story engine phase 6 = 再造一个新 runtime 层”,而是:
**让这套引擎从“强大的技术系统”,进化成“可被持续使用的剧情生产系统”。**
## 1. 第五阶段审计结论
## 1.1 可以判定为“基本落地”的部分
按代码和测试情况,第五阶段已经基本落地:
1. 第五阶段模块已存在并有测试:
- `scenarioPackRegistry`
- `campaignPackCompiler`
- `contentDependencyGraph`
- `storySimulationRunner`
- `playthroughMatrixLab`
- `narrativeRegressionReplay`
- `playerStyleProfiler`
- `adaptiveNarrativeTuner`
- `narrativeTelemetry`
- `releaseGateReport`
- `saveMigrationManifest`
- `contentDiffReport`
2. 关键主链已接入:
- `progressionActions.ts`
- `useStoryGeneration.ts`
- `prompt.ts`
- `customWorldBuilder.ts`
- `useGamePersistence.ts`
3. 第五阶段相关测试通过:
- `scenarioPackRegistry.test.ts`
- `campaignPackCompiler.test.ts`
- `contentDependencyGraph.test.ts`
- `storySimulationRunner.test.ts`
- `playthroughMatrixLab.test.ts`
- `narrativeRegressionReplay.test.ts`
- `playerStyleProfiler.test.ts`
- `adaptiveNarrativeTuner.test.ts`
- `narrativeTelemetry.test.ts`
- `releaseGateReport.test.ts`
- `saveMigrationManifest.test.ts`
- `contentDiffReport.test.ts`
## 1.2 当前真实缺口
虽然第五阶段已经把“平台化骨架”做出来了,但它还明显偏:
1. 后台能力
2. 内部结构
3. 代码级接口
还没有真正形成下面这些“生产工作台”能力:
1. 设计师 / 内容作者可视化地理解:
- 当前 world pack
- 当前 campaign pack
- 当前 branch budget
- 当前 unresolved payoff
2. 仿真结果可视化与比对
- 现在能跑 simulation但还缺
- matrix dashboard
- ending 分布图
- unresolved thread 热区
- companion fracture 热图
3. 人机协同编辑闭环
- 当前可以生成、回归、校验,但还缺:
- 人工批注
- 审核通过 / 驳回
- 局部重生成
- 受控覆盖
4. 内容治理体系
- 当前 pack 可以存在,但还缺:
- 版本状态
- 草稿 / 候选 / 已发布
- 回滚
- 依赖冲突提示
5. 面向策划的 narrative ops
- 当前 QA report 存在,但还缺:
- 每日 / 每版本比较
- 关键指标趋势
- 哪条线程最常断
- 哪个 ending 最少触发
## 1.3 额外需要注意的现实问题
本轮审计里还有一个工程事实需要单独记下:
- 第五阶段相关测试通过
- 但当前全仓 `lint` 仍不是完全绿色,存在 import 排序和未使用导入问题
这说明:
**从第六阶段开始,除了继续扩功能,更应该把“生产平台自己的门禁和治理”一起正式纳入。**
## 2. 第六阶段目标
第六阶段只做 5 件事:
1. 建立 `Narrative Studio Workspace` 剧情工作台
2. 建立 `Simulation Dashboard / Regression Review` 仿真与回归可视化
3. 建立 `Human-in-the-loop Authoring Flow` 人机协同创作流
4. 建立 `Pack Governance / Publish Workflow` 内容治理与发布流
5. 建立 `Narrative Ops` 指标、比较、告警与持续调优流
一句话定义第六阶段:
**从“叙事平台”升级到“叙事生产系统”。**
## 3. 第六阶段完成定义
第六阶段完成后,至少要同时满足:
1. 设计师不看代码,也能看懂当前 campaign 的结构状态。
2. 可以用可视化方式查看 simulation / regression / release gate 的结果。
3. 可以对 AI 产物做人工批注、重生成、局部覆盖和审批。
4. `ScenarioPack / CampaignPack` 有正式的版本状态与发布流。
5. narrative QA 和 telemetry 不只是生成结果,而是成为可比较、可追踪、可告警的运营资产。
## 4. 第六阶段范围
## 4.1 纳入范围
- `src/services/storyEngine/*`
- `src/components/*`
- `src/components/preset-editor/*`
- `src/components/CustomWorldGenerationView.tsx`
- `src/components/StateFunctionEditor.tsx`
- `src/components/SelectionCustomizationModals.tsx`
- `src/services/customWorld.ts`
- `src/services/customWorldBuilder.ts`
- `src/hooks/useGamePersistence.ts`
- `src/types/storyEngine.ts`
## 4.2 新增模块
- `src/services/storyEngine/narrativeStudioState.ts`
- `src/services/storyEngine/simulationDashboardModel.ts`
- `src/services/storyEngine/reviewQueue.ts`
- `src/services/storyEngine/regenerationPatchPlan.ts`
- `src/services/storyEngine/packPublishWorkflow.ts`
- `src/services/storyEngine/packRollbackPlan.ts`
- `src/services/storyEngine/narrativeOpsMetrics.ts`
- `src/services/storyEngine/narrativeAlerting.ts`
- `src/services/storyEngine/narrativeReviewNotes.ts`
- `src/services/storyEngine/qaTrendReport.ts`
## 4.3 第六阶段明确不做
第六阶段仍不做:
1. 全在线多人协同编辑器
2. 完整云端数据平台
3. 商业 BI 大盘系统
4. 全自动策划代理替代人工审核
5. 对外开放市场级内容生态
原因:
第六阶段的目标是让内部生产真正运转起来,而不是直接做成对外产品平台。
## 5. 第六阶段最小闭环
建议第六阶段最小闭环为:
```text
NarrativeStudioState
-> SimulationDashboardModel
-> ReviewQueue
-> RegenerationPatchPlan
-> PackPublishWorkflow
-> NarrativeOpsMetrics
-> QaTrendReport
-> NarrativeAlerting
```
对应到实际价值,就是:
1. 可以看到当前内容状态
2. 可以看 simulation 结果
3. 可以对问题内容提出修复
4. 可以受控发布和回滚
5. 可以持续观察质量变化
## 6. 数据结构升级方案
## 6.1 `src/types/storyEngine.ts`
第六阶段建议新增:
```ts
export interface NarrativeReviewNote {
id: string;
targetId: string;
targetType: 'thread' | 'chapter' | 'companion' | 'carrier' | 'ending' | 'pack';
note: string;
status: 'open' | 'addressed' | 'ignored';
}
export interface ReviewQueueItem {
id: string;
source: 'qa_report' | 'simulation' | 'manual';
priority: 'low' | 'medium' | 'high';
summary: string;
relatedIds: string[];
}
export interface PackPublishState {
packId: string;
version: string;
status: 'draft' | 'candidate' | 'released' | 'rolled_back';
lastPublishedAt?: string | null;
}
export interface NarrativeOpsSnapshot {
generatedAt: string;
activePackCount: number;
releaseGatePassRate: number;
unresolvedIssueCount: number;
topRiskAreas: string[];
}
export interface QaTrendPoint {
label: string;
issueCount: number;
blockingCount: number;
}
```
并扩展:
```ts
export interface StoryEngineMemoryState {
reviewNotes?: NarrativeReviewNote[];
reviewQueue?: ReviewQueueItem[];
publishStates?: PackPublishState[];
narrativeOpsSnapshot?: NarrativeOpsSnapshot | null;
qaTrend?: QaTrendPoint[];
}
```
## 7. 模块实现方案
## 7.1 `narrativeStudioState.ts`
职责:
1. 聚合当前:
- campaign 状态
- branch budget
- QA report
- ending 状态
- simulation 结果
建议导出:
```ts
buildNarrativeStudioState(params)
```
## 7.2 `simulationDashboardModel.ts`
职责:
1. 把 matrix / replay / telemetry 结果整理成可展示模型
2. 输出:
- ending 分布
- unresolved threads 排行
- fracture companion 排行
- regression failure 列表
建议导出:
```ts
buildSimulationDashboardModel(params)
```
## 7.3 `reviewQueue.ts`
职责:
1. 把 QA、simulation、手工批注统一收敛成 review queue
2. 支持优先级排序与状态流转
建议导出:
```ts
buildReviewQueue(params)
advanceReviewQueueItem(params)
```
## 7.4 `regenerationPatchPlan.ts`
职责:
1. 把 review item 转成局部重生成 / 局部 override 计划
2. 支持:
- 角色档案重生成
- 线程补偿
- ending 修复
- 文书 / 载体文本修复
建议导出:
```ts
buildRegenerationPatchPlan(params)
```
## 7.5 `packPublishWorkflow.ts`
职责:
1. 管理 pack 的发布状态
2. 要求:
- 发布前通过 release gate
- 生成 publish record
建议导出:
```ts
advancePackPublishState(params)
canPublishPack(params)
```
## 7.6 `packRollbackPlan.ts`
职责:
1. 对已发布 pack 生成回滚方案
2.`SaveMigrationManifest` 协作
建议导出:
```ts
buildPackRollbackPlan(params)
```
## 7.7 `narrativeOpsMetrics.ts`
职责:
1. 聚合 narrative ops 指标
2. 输出:
- pass rate
- issue density
- regression stability
- ending diversity
建议导出:
```ts
buildNarrativeOpsSnapshot(params)
```
## 7.8 `narrativeAlerting.ts`
职责:
1. 对:
- release gate blocking
- regression drift
- unresolved issue spike
发出告警
建议导出:
```ts
evaluateNarrativeAlerts(params)
```
## 7.9 `narrativeReviewNotes.ts`
职责:
1. 让人工可以对:
- chapter
- ending
- thread
- companion
记录审核笔记
建议导出:
```ts
appendNarrativeReviewNote(params)
resolveNarrativeReviewNote(params)
```
## 7.10 `qaTrendReport.ts`
职责:
1. 把多次 QA report 做趋势比较
2. 输出:
- issue 趋势
- block 趋势
- 最常出问题区域
建议导出:
```ts
buildQaTrendReport(params)
```
## 8. 现有文件改造方案
## 8.1 `progressionActions.ts`
第六阶段重点:
1. 回写 `reviewQueue`
2. 回写 `narrativeOpsSnapshot`
3. 回写 `qaTrend`
## 8.2 `useStoryGeneration.ts`
第六阶段重点:
1. 在 studio/debug 模式下暴露更多状态
2. 不污染正式运行时主链
## 8.3 `CustomWorldGenerationView.tsx`
建议成为第六阶段的第一个“工作台入口”,用于展示:
1. 当前 pack
2. 当前 release gate
3. 当前 QA trend
4. 当前 simulation 摘要
## 8.4 `StateFunctionEditor.tsx` / `preset-editor/*`
建议逐步增加 narrative review / patch plan 的入口,而不是只做底层数据编辑。
## 8.5 `useGamePersistence.ts`
继续强化:
1. pack version
2. migration status
3. rollback safety
## 9. 第六阶段开发顺序
建议顺序如下:
1. `reviewQueue`
2. `narrativeReviewNotes`
3. `simulationDashboardModel`
4. `narrativeOpsMetrics`
5. `qaTrendReport`
6. `packPublishWorkflow`
7. `packRollbackPlan`
8. `regenerationPatchPlan`
9. `narrativeAlerting`
10. `narrativeStudioState`
11. UI 工作台最小接线
原因:
- 第六阶段的重点是让“平台能力真正可操作”
- 所以先做 review / dashboard / publish flow比继续堆 runtime 更有价值
## 10. 测试方案
## 10.1 新增单元测试
建议新增:
1. `reviewQueue.test.ts`
2. `narrativeReviewNotes.test.ts`
3. `simulationDashboardModel.test.ts`
4. `narrativeOpsMetrics.test.ts`
5. `qaTrendReport.test.ts`
6. `packPublishWorkflow.test.ts`
7. `packRollbackPlan.test.ts`
8. `regenerationPatchPlan.test.ts`
9. `narrativeAlerting.test.ts`
10. `narrativeStudioState.test.ts`
## 10.2 新增集成测试
建议补这 5 类:
1. QA report -> review queue -> patch plan
2. simulation matrix -> dashboard -> release gate
3. pack candidate -> publish -> rollback
4. old save -> migration -> continue game
5. 多版本 QA trend 比较
## 10.3 人工回归场景
至少做这 5 条:
1. 打开 narrative 工作台能看懂当前 campaign 状态
2. 一次 regression drift 能正确进入 review queue
3. 一个 pack 通过 release gate 成功发布
4. 一个 pack 发布后可以生成 rollback plan
5. 一组 QA trend 能看出问题是在变好还是变坏
## 11. 第六阶段验收标准
做到以下几点,才算第六阶段可收口:
1. 系统具备可视化 narrative studio 状态模型
2. 系统具备 review queue 和 review note 流程
3. 系统具备 simulation dashboard 模型
4. 系统具备 publish / rollback workflow
5. 系统具备 narrative ops snapshot 和 QA trend
6. 人工审核与 AI 重生成之间形成闭环
7. 相关测试通过,`lint` / `typecheck` / `check:encoding` 通过
## 12. 一句话结论
如果前五阶段解决的是“把 AI 原生剧情引擎做成一套完整可运行、可发布、可复用的平台”,
那么第六阶段要解决的,就是:
**让这套平台真正变成团队可以长期驾驭、持续生产、持续审核、持续迭代的叙事生产系统。**

View File

@@ -0,0 +1,876 @@
# AI 原生任务驱动目标感增强 PRD
更新时间:`2026-04-07`
## 0. 目标
这份 PRD 面向当前仓库,解决的是一个已经被用户明确反馈出来的问题:
**当前游戏虽然已经具备任务、章节、旅程节拍、剧情线程等系统,但玩家在实际游玩里,仍然经常感受不到“我现在到底在朝什么目标推进”。**
这里要增强的,不是单纯“多做一些任务”,而是把现有系统重新组织成一条玩家可感知的目标驱动链路,让玩家在大多数时刻都能快速回答 3 个问题:
1. 我现在在做什么?
2. 为什么这件事值得我去做?
3. 我下一步应该去哪里、找谁、做哪件事?
一句话目标:
**把当前分散在任务、章节、旅程、线程里的推进信息,编译成玩家随时能感知到的“主目标 -> 当前委托 -> 下一步行动”体验。**
---
## 1. 当前问题定位
## 1.1 当前项目其实已经有不少“目标相关系统”
从现有仓库看,项目并不是没有目标系统,而是已经有了多套“部分成立”的目标表达:
- `src/data/questFlow.ts`
- 已经有 `QuestIntent -> QuestContract -> QuestStep -> QuestProgressSignal` 的任务闭环。
- `src/hooks/useStoryGeneration.ts`
- 已经在运行时维护 `chapterState``journeyBeat``storyEngineMemory.activeThreadIds``setpieceDirective` 等叙事推进信息。
- `src/components/AdventurePanel.tsx`
- 已经有任务入口、章节入口、任务完成提示。
- `src/components/adventure-panel/AdventurePanelOverlays.tsx`
- 已经能展示章节面板、任务面板、任务详情与奖励弹窗。
- `src/types/storyEngine.ts`
- 已经有 `ChapterState``JourneyBeat``ThreadContract``SetpieceDirective` 这些中长线推进结构。
这说明当前问题不是“系统完全缺失”,而是:
**这些系统还没有被编译成一套稳定、持续、前台可见的目标体验。**
## 1.2 为什么玩家仍然会觉得“没目标”
结合现有实现,当前目标感不足主要来自 6 个原因。
### 1.2.1 目标信息分散在多个系统里,但没有统一前台主语
目前玩家可能同时受到这些信息影响:
- 章节标题
- 当前旅程节拍
- 活跃任务
- 任务当前 step
- 活跃剧情线程
- 当前场景异动
但这些信息没有被统一编译成一句更强的玩家语义:
- “你这章在追什么”
- “你此刻最该先推进哪一件事”
- “如果你现在只做一步,最有价值的是哪一步”
结果就是后台系统知道很多,前台玩家却只感到“事情很多,但方向不够清楚”。
### 1.2.2 任务存在,但任务不等于持续目标感
当前任务系统已经能接受、推进、完成、交付,但它的可见性仍偏“日志型”:
- 任务主要在任务面板里看
- 任务完成时有提示,但完成前的存在感不够强
- 玩家在主冒险视图里,并不会持续被提醒“这就是你当前的核心目标”
这会导致:
- 任务更像“可选记录”
- 而不是“持续牵引当前行动的主线张力”
### 1.2.3 章节 / 旅程节拍更像背景摘要,不像可执行目标
现有 `chapterState``journeyBeat` 已经很接近“中长期目标骨架”,但当前更偏:
- 章节氛围说明
- 旅程阶段命名
- 剧情回顾面板内容
而不是:
- 此刻最该推进哪条线程
- 当前节拍对应的推荐行动
- 这一步不推进会错过什么
于是它们更像“叙事状态”,不够像“行动目标”。
### 1.2.4 选项列表没有稳定表达“哪些动作在推进当前目标”
当前 `StoryOption` 主要按 function 合法性和 priority 输出,玩家能看到:
- 可以做什么
但不总能一眼看出:
- 哪个选项是在推进当前主目标
- 哪个选项只是支线绕行
- 哪个选项是补给、社交、整理状态
当所有选项都以类似强度出现时,玩家会更容易进入“我每一步都像在随便试试”的体验。
### 1.2.5 目标完成后的“下一目标交接”不够强
当前一个任务完成后,系统能做的是:
- 显示完成提示
- 去任务日志领奖
但目标体验更关键的一步其实是:
**完成之后,系统要马上把下一段方向递到玩家手上。**
如果这一步缺失,玩家就会在“完成一个点”之后重新掉回目标真空。
### 1.2.6 探索和叙事已经有内容,但缺少“承诺感”
当前系统已经能提供:
- NPC 氛围
- 场景异常
- 宝藏调查
- 战斗奖励
- 关系推进
但玩家未必知道这些碎片最后会指向什么。
也就是说,项目已经有不少“局部有趣”,但还缺一层更明确的:
- 这一章我正在靠近什么
- 这一段我为什么继续走下去
- 现在这次调查、切磋、汇报,和后面的更大目标是什么关系
## 1.3 当前问题的根因总结
可以把根因压缩成一句话:
**项目已经有“任务系统”和“叙事阶段系统”,但还没有“玩家视角的统一目标导演层”。**
---
## 2. 设计原则
## 2.1 目标感增强不等于满屏任务文案
这个项目已经明确要求 UI 保持清爽、移动端优先,因此这次方案不能走:
- 左上角一大堆任务文字
- 常驻厚重任务列表
- 密密麻麻的规则说明
正确方向是:
- 前台只突出 1 个当前主目标
- 再给 1 个清晰的下一步
- 其余信息折叠到任务 / 章节 / 地图面板中
## 2.2 AI 负责叙事强化,本地规则负责目标裁决
目标系统继续遵循当前项目已经验证有效的边界:
AI 负责:
- 当前目标为什么重要
- 这一步在故事里的张力
- 目标推进时的氛围和话术
本地规则负责:
- 当前目标从哪里来
- 哪个目标优先级最高
- 哪个选项算推进目标
- 目标何时完成、阻塞、切换
## 2.3 玩家应始终看到“短中长”三层目标
真正稳定的目标感,不是只有任务,也不是只有主线,而是至少同时成立 3 层:
1. 长目标
- 这一章 / 这一幕到底在逼近什么
2. 中目标
- 当前正在处理哪条委托、哪条线程、哪段关系
3. 短目标
- 下一步具体要去哪里 / 找谁 / 做什么
## 2.4 至少保证一个明确前进方向,但保留探索自由
目标驱动不是把玩家锁死在唯一按钮上。
正确体验应该是:
- 大多数时刻都有一个清晰可前进的方向
- 但仍然允许补给、聊天、绕行、观察、整理 build
- 玩家知道自己是在“主动偏离”,而不是“系统根本没方向”
## 2.5 目标必须来自当前局面,而不是硬塞公告栏
这次不做传统 MMO 式的固定任务板,而要让目标继续从这些上下文里长出来:
- 当前章节主题
- 当前旅程节拍
- 活跃线程
- 当前场景压力
- 当前 NPC 关系
- 当前资源缺口
换句话说:
**目标感要更强,但目标来源仍然要像从当前叙事局面里自然长出来。**
---
## 3. 核心方案Goal Stack目标栈
建议在现有 `quest + chapter + journeyBeat + threadContract` 之上,新增一层统一的玩家目标结构:
**Goal Stack**
它不替代现有系统,而是把现有系统编译成玩家当前最容易理解的目标层级。
## 3.1 三层结构
### 3.1.1 North Star Goal章节承诺
这是玩家当前阶段最大的“为什么继续往前”的理由。
它来自:
- `chapterState`
- `actState`
- `setpieceDirective`
- 当前主线程组合
玩家可感知的表达应该像:
- 追查失踪背后的真正势力
- 逼近这一区域的核心威胁
- 弄清某位关键 NPC 为何始终在回避真相
它回答的问题是:
**这一章总体在往哪里去。**
### 3.1.2 Active Contract Goal当前主目标
这是当前最应该推进的一件事。
它通常来自:
- 当前活跃任务
- 当前线程合约
- 当前旅程节拍对应的调查 / 汇报 / 前往 / 对峙目标
它回答的问题是:
**此刻最值得优先推进的事情是什么。**
### 3.1.3 Immediate Step Goal下一步行动
这是玩家在当前回合、当前场景最容易执行的实际动作。
它通常来自:
- 当前任务 active step
- 当前推荐场景
- 当前推荐 NPC
- 当前可触发 signal
它回答的问题是:
**如果我现在就迈一步,最合理的是先做什么。**
## 3.2 支持目标
除了主目标外,再允许最多 `2` 个支持目标,作为轻量附属存在:
- 关系目标
- 补给目标
- 构筑目标
- 探索支线
它们应该存在,但不挤占主目标在前台的视觉优先级。
## 3.3 3 秒规则
Goal Stack 设计的核心验收标准是:
**玩家在任意正常游玩时刻,用 3 秒就能看懂当前主目标和下一步。**
---
## 4. 目标导演层Goal Director
建议新增 `Goal Director`,负责把现有多个系统编译成一份统一的前台目标。
## 4.1 输入来源
目标导演层的输入应至少包含:
- `chapterState`
- `journeyBeat`
- `storyEngineMemory.activeThreadIds`
- `setpieceDirective`
- `quests`
- `currentScene`
- `currentEncounter`
- `npcStates`
- 玩家资源状态
- 最近若干 `StorySignal` / `QuestProgressSignal`
## 4.2 输出目标
输出应是一个稳定的 `GoalStackState`
```ts
type GoalSourceKind =
| 'quest'
| 'chapter'
| 'journey_beat'
| 'thread_contract'
| 'setpiece'
| 'relationship'
| 'survival';
type GoalTrack = 'main' | 'side' | 'relationship' | 'survival' | 'exploration';
type GoalStatus =
| 'teased'
| 'active'
| 'blocked'
| 'ready_to_resolve'
| 'resolved'
| 'archived';
interface GoalStackEntry {
id: string;
sourceKind: GoalSourceKind;
sourceId: string;
layer: 'north_star' | 'active_contract' | 'immediate_step' | 'support';
track: GoalTrack;
title: string;
promiseText: string;
whyNow: string;
nextStepText: string;
sceneHint?: string | null;
npcHint?: string | null;
progressLabel?: string | null;
status: GoalStatus;
urgency: 'low' | 'medium' | 'high';
relatedThreadIds: string[];
}
interface GoalStackState {
northStarGoal: GoalStackEntry | null;
activeGoal: GoalStackEntry | null;
immediateStepGoal: GoalStackEntry | null;
supportGoals: GoalStackEntry[];
}
```
## 4.3 目标优先级裁决
建议 Goal Director 按下面顺序裁决前台主目标:
1. 若存在 `ready_to_turn_in` 的关键主目标任务,优先前台化“去交付”
2. 若存在活跃任务 step优先将该 step 作为 `immediate_step`
3. 若当前无明确任务,但 `journeyBeat` 有推荐场景或推进方向,则编译成临时主目标
4. 若当前有强 setpiece / showdown / boss_prelude则将其提升为主目标承诺
5. 若玩家资源严重不足,可生成支持型生存目标,但默认不覆盖主线目标
## 4.4 目标切换规则
目标切换不能随便抖动,建议满足以下规则:
1. 主目标默认保持稳定,直到完成、阻塞或被更高优先级事件接管
2. 支持目标可以进出,但不频繁替换主目标
3. 章节目标只在章内关键阶段变化时更新
4. 当前 step 完成后,必须立刻切到下一 step 或交付目标
5. 如果玩家连续若干轮没有明确目标,系统必须主动重新生成一份当前 lead
---
## 5. 核心体验闭环Promise -> Commit -> Advance -> Confirm -> Handoff
这次目标感增强的关键,不是“加一个 HUD”而是补齐完整闭环。
## 5.1 Promise先告诉玩家为什么值得追
每一阶段都要先有一句承诺,回答:
- 这件事背后有什么更大的意义
- 当前章节到底在逼近什么
这层主要来自:
- `chapterState`
- `journeyBeat`
- `setpieceDirective`
## 5.2 Commit把大目标落成当前可接的委托或 lead
大目标不能悬空,必须落到玩家当前能承接的一件事:
- 接受委托
- 去某处调查
- 找某 NPC 对话
- 回去交付
- 前往某场景验证异常
## 5.3 Advance推进时持续看到自己在接近目标
推进不能只在任务日志里发生。
推进感需要在主流程里被持续表达:
- 选项提示“推进当前目标”
- 场景文本回响“你正在靠近这条线”
- 进度提示明确“已完成哪一步”
## 5.4 Confirm完成后给明确确认
推进成功后,系统要立即确认:
- 你已经推进了
- 你推进的是哪条目标
- 这一步意味着什么
而不只是静默更新后台进度。
## 5.5 Handoff立刻交接下一目标
真正决定目标感是否持续的,是交接。
完成一件事后,系统要尽快把下一句说出来:
- 现在回去交付
- 线索已经到手,下一步去找谁
- 这一步已完成,更大的目标因此前进到了哪里
如果没有 handoff再好的任务系统也会出现“刚做完就空了”的断层。
---
## 6. UI 表达方案
UI 目标是:
**不增厚页面、不堆规则说明,但让目标在主冒险视图里持续可见。**
## 6.1 冒险页新增常驻 Goal Ribbon
建议在主冒险页增加一个轻量常驻的 `Goal Ribbon`,只展示当前最需要知道的目标信息。
推荐展示字段:
- 目标标题
- 目标 track 标签
- 一句 `nextStepText`
- 一行极短 `sceneHint / npcHint`
- 简短进度表达
表现要求:
- 默认只显示 1 个主目标
- 风格轻,不做厚重说明板
- 手机端优先单列、可折叠
- 不抢占剧情区和选项区的核心空间
## 6.2 主冒险视图要直接显示“下一步”
对玩家而言,最重要的一句不是任务标题,而是:
- 去哪里
- 找谁
- 做什么
因此 Goal Ribbon 里最该强化的是 `nextStepText`,而不是一堆背景说明。
例如:
- 去遗迹外缘确认异动,再回来和林朔对话
- 返回营地,把调查结果告诉同伴
- 前往北桥,追上刚刚提到的敌对角色
## 6.3 选项按钮增加目标关联标记
建议给 `StoryOption` 增加目标关联信息:
```ts
interface StoryOptionGoalAffordance {
goalId: string;
relation: 'advance' | 'support' | 'detour';
label: string;
}
```
然后在前台做极轻量表达:
- 推进当前目标
- 支持当前准备
- 暂时绕开目标
要求:
- 只对关键选项打标
- 不让所有按钮都挂一堆说明
- 至少保证存在主目标时,通常有一个 `advance` 选项
## 6.4 任务面板从“日志”转成“目标板”
当前任务面板基础可复用,但信息组织建议升级为:
1. 当前主目标
2. 正在推进
3. 可交付
4. 支持目标
5. 已归档
这样玩家打开任务页时,看到的不是一排同权列表,而是更明确的目标优先级结构。
## 6.5 章节面板只做“承诺 + 当前节拍 + 当前主目标”
章节面板不需要继续扩成说明书。
建议只保留:
- 当前章节标题
- 当前章节主题
- 当前旅程节拍
- 本章正在追的主问题
- 当前建议推进方向
## 6.6 任务完成提示要直接导向下一个动作
当前“任务完成,可前往日志领奖”已经比没有强,但还不够。
建议改成:
- 任务完成
- 现在去哪里交付 / 现在建议做什么
- 一键打开当前目标详情
这样完成提示本身也成为 handoff 的一部分。
---
## 7. 与叙事生成和选项生成的联动
目标感不是纯 UI 问题,还必须进入叙事与选项生成。
## 7.1 Prompt 上下文注入当前目标摘要
建议在 `buildStoryContextFromState(...)` 产出的上下文中,增加统一目标摘要:
```ts
interface GoalPromptContext {
northStarSummary?: string | null;
activeGoalTitle?: string | null;
activeGoalWhyNow?: string | null;
immediateStepText?: string | null;
supportGoalTitles?: string[];
}
```
AI 使用这层上下文的目的不是发明新目标,而是:
- 在剧情文本里强化当前推进感
- 在选项措辞里更明确表达“哪步是往前”
- 在阶段切换时自然回写 handoff 语气
## 7.2 本地规则保证前进选项存在
当存在主目标且当前场景允许推进时,本地规则应尽量保证:
- 至少一个选项能推进当前目标
- `换一换` 不应把所有前进方向都刷掉
换句话说:
**选项池可以多样,但不能把方向感洗掉。**
## 7.3 目标推进要进入剧情文本回响
当 step 被推进时,剧情文本应更常出现这些反馈:
- 你已经拿到了关键线索
- 这一步让某人对你的判断改变了
- 当前区域的异常已经被你确认
- 现在该回去把结果说清楚
这类文本能明显强化“我不是在原地刷新内容,而是在前进”。
---
## 8. 目标来源设计
为了避免只有“NPC 发任务”才有目标,建议目标来源拆成 6 类。
## 8.1 Quest Goal委托型目标
来自现有 `QuestContract / QuestStep`
适合表达:
- 讨伐
- 调查
- 切磋
- 回报
- 交付
## 8.2 Thread Goal叙事线程型目标
来自:
- `ThreadContract`
- `activeThreadIds`
适合表达:
- 当前章节的主要调查方向
- 某条持续存在但暂未显式任务化的追查线
## 8.3 Journey Goal旅程阶段型目标
来自:
- `JourneyBeat`
适合表达:
- 现在是调查阶段
- 现在该回营整备
- 现在正在逼近冲突前奏
## 8.4 Setpiece Goal高潮前奏型目标
来自:
- `SetpieceDirective`
适合表达:
- 决战前奏
- 对峙前整理
- 余波中的关键善后
## 8.5 Relationship Goal关系推进型目标
来自:
- NPC 好感阶段
- 同伴弧线
- 当前营地事件 / 私聊机会
适合表达:
- 找某人谈清楚
- 处理一次关系冲突
- 在营地承接一段角色剧情
## 8.6 Survival Goal生存补给型目标
来自:
- 资源紧张
- build 缺口
- 路线压力
适合表达:
- 先补给
- 先回营整理
- 先准备能支撑下一段推进的资源
但它默认只做支持目标,不轻易覆盖主线目标。
---
## 9. 数据结构与模块建议
## 9.1 建议新增类型
建议新增:
- `src/services/storyEngine/goalTypes.ts`
- 或直接扩展 `src/types/storyEngine.ts`
核心结构建议包括:
- `GoalStackEntry`
- `GoalStackState`
- `StoryOptionGoalAffordance`
- `GoalPulseEvent`
- `GoalHandoff`
其中 `GoalPulseEvent` 用于前台反馈:
```ts
interface GoalPulseEvent {
id: string;
goalId: string;
pulseType: 'progress' | 'ready_to_turn_in' | 'resolved' | 'handoff';
title: string;
detail: string;
}
```
## 9.2 建议新增模块
建议新增:
- `src/services/storyEngine/goalDirector.ts`
- `src/services/storyEngine/goalCompiler.ts`
- `src/services/storyEngine/goalSignals.ts`
职责如下:
- `goalDirector`
- 汇总章节 / 旅程 / 任务 / 线程 / 资源状态,裁决当前目标栈
- `goalCompiler`
- 把不同来源编译成统一 GoalStackEntry
- `goalSignals`
- 处理 progress、resolve、handoff 反馈事件
## 9.3 建议改动的现有区域
建议优先接入这些文件:
- `src/hooks/useStoryGeneration.ts`
- 在返回值中新增 `goalUi`
- `src/hooks/story/uiTypes.ts`
- 增加目标 UI 类型
- `src/components/AdventurePanel.tsx`
- 增加 Goal Ribbon 与选项目标标记
- `src/components/adventure-panel/AdventurePanelOverlays.tsx`
- 将任务 / 章节视图改成围绕主目标组织
- `src/types/story.ts`
- 扩展 `StoryOption` 目标标记字段
- `src/data/questFlow.ts`
- 暴露任务当前 step 与 handoff 所需摘要
---
## 10. MVP 落地顺序
## 阶段 A先做前台统一目标层不重写底层任务系统
先做:
- Goal Director
- Goal Stack 编译
- Adventure 主视图 Goal Ribbon
此阶段目标:
- 玩家打开主冒险页就能看到当前主目标和下一步
- 不要求任务生成逻辑大改
## 阶段 B补齐目标交接
重点做:
- 任务接受后的主目标接管
- step 完成后的下一步切换
- ready_to_turn_in 的前台提升
- 领奖后的下一目标 handoff
此阶段目标:
- 目标不再只在“开始接任务”时存在
- 完成后也能顺势接到下一步
## 阶段 C让选项和剧情文本都带目标感
重点做:
- `StoryOption.goalAffordance`
- 目标推进相关 prompt 上下文
- 目标推进反馈 pulse
此阶段目标:
- 玩家不仅在任务面板里看见目标
- 也能在每一回合的文本和选项里感到自己在朝目标前进
## 阶段 D补非任务型目标来源
重点做:
- `journeyBeat -> goal`
- `thread -> goal`
- `relationship -> support goal`
- `survival -> support goal`
此阶段目标:
- 即使没有显式任务,系统也仍然能给出清晰 lead
---
## 11. 验收标准
做到以下几点,才能说明“任务驱动目标感”真的提升了,而不是只多了一层 UI。
## 11.1 体验验收
1. 新开局 `3` 次有效交互内,玩家必须看到一个明确主目标。
2. 在存在主目标的正常游玩阶段,主冒险页必须持续可见“当前目标 + 下一步”。
3. 任一目标完成后,下一目标或交付动作必须在 `1` 次交互内被明确交接。
4. 玩家不打开任务面板,也能在多数时刻知道自己下一步该做什么。
## 11.2 交互验收
1. 有活跃目标时,选项池中应尽量存在至少 `1` 个推进当前目标的选项。
2. `换一换` 不应把唯一前进方向刷没。
3. 任务完成提示应直接导向当前后续动作,而不只是泛提示。
## 11.3 UI 验收
1. 手机竖屏下 Goal Ribbon 不应把主剧情区和底部操作区挤出首屏。
2. 前台目标信息应控制在轻量级,不堆规则文案。
3. 任务 / 章节 / 目标表达需保持当前项目的清爽游戏 UI 风格。
## 11.4 叙事验收
1. 当前章节承诺、当前主目标、下一步行动三层语义必须能同时成立。
2. 任务推进、调查推进、关系推进都应在剧情文本里有回响。
3. 玩家应明显感到“我正在逼近某件事”,而不只是“我又看了一段新文本”。
---
## 12. 为什么这套方案适合当前仓库
这套方案不是推翻重做,而是顺着仓库已经形成的系统继续往前走:
1. 当前仓库已经有任务 contract 和 step progression
- 所以短目标层并不是从零开始。
2. 当前仓库已经有章节、旅程节拍、线程与 setpiece
- 所以中长目标层已经有素材,只差统一导演。
3. 当前 Adventure UI 已有任务入口、章节入口和弹层体系
- 所以前台表达可以在现有壳层上增量升级。
4. 当前项目强调移动端优先与清爽 UI
- 所以本方案明确走“一个主目标 + 一个下一步”的轻量表达,而不是堆面板。
换句话说:
**当前项目最需要的,不是再造一套新任务系统,而是把已有的任务、章节、线程、旅程节拍编译成一条持续存在的玩家目标体验。**
---
## 13. 最后结论
用户反馈“缺乏任务驱动的目标感”,真正指向的问题不是“没有任务”,而是:
- 任务没有持续站在前台
- 章节和旅程没有转成行动承诺
- 完成后的下一步交接不够强
- 选项和剧情文本没有持续强化“你正在前进”
因此,这次 PRD 的核心不是“继续扩任务数量”,而是补上一个统一的 `Goal Director + Goal Stack`
1. 用章节承诺给玩家长期方向
2. 用当前主目标给玩家中程牵引
3. 用下一步行动给玩家即时清晰的操作方向
4. 用推进反馈与 handoff 把整条目标链接起来
这样之后,玩家感受到的就不再是“系统里有任务”,而会更接近:
**我知道自己为什么在这里、正在推进什么、下一步该去哪,这个世界也在不断回应我的前进。**

View File

@@ -0,0 +1,473 @@
# AI 原生任务系统主前台化调整方案
更新时间:`2026-04-07`
## 0. 背景
在当前迭代里,右上区域同时出现了:
- `目标`
- `章节`
- `任务`
从系统设计角度看,这 3 个概念分别对应:
- `目标`:当前应该优先推进的事情
- `章节`:当前叙事阶段与长期承诺
- `任务`:玩家可执行、可追踪、可交付的实际推进载体
但从玩家视角看,这 3 个入口被并列摆在同一层级时,会产生两个直接问题:
1. 概念重复
- `目标``任务` 都在告诉玩家“下一步做什么”。
2. 主次倒置
- 原本最该成为主前台的“任务系统”,反而被拆散到 `目标 / 章节 / 任务` 三个入口中,导致任务系统看起来像被边缘化。
一句话判断:
**当前不是“信息不够”,而是“前台概念过多,任务作为主推进载体没有站到 C 位”。**
---
## 1. 核心结论
建议把当前前台结构调整为:
**任务系统作为唯一主推进入口,目标与章节退到任务系统内部,成为任务的上层语义与背景语义。**
也就是说:
- `任务` 是玩家前台的主概念
- `目标` 是任务面板里的当前聚焦态
- `章节` 是任务面板里的背景上下文
而不是 3 个并列一级入口。
---
## 2. 当前问题拆解
## 2.1 三个并列入口会制造额外理解成本
玩家进入第一个场景时,本来最需要快速理解的是:
- 我当前接了什么事
- 下一步去哪
- 什么时候算推进
但现在 UI 让玩家先面对的是:
- 要不要看目标
- 要不要看章节
- 要不要看任务
这会把本来应该非常直接的“任务驱动”体验,变成一次概念选择题。
## 2.2 `目标` 和 `任务` 在玩家心智中高度重叠
当前 `目标` 弹窗展示的是:
- 当前主推进
- 下一步
`任务` 面板展示的是:
- 当前主目标任务
- 任务摘要
- 任务详情
这两者在玩家眼里并不是两套系统,而更像:
- 一个是“任务的简版”
- 一个是“任务的详版”
如果它们并列出现,只会让玩家觉得重复。
## 2.3 `章节` 不应与 `任务` 争夺同一前台优先级
章节的作用更接近:
- 给长期方向
- 给叙事承诺
- 给“这一章在讲什么”的理解坐标
它并不直接回答:
- 此刻去哪
- 找谁
- 做什么
因此章节不适合做和任务并列的常驻一级入口,更适合做任务面板里的背景信息,或二级展开信息。
## 2.4 移动端空间被重复入口浪费
项目本身是移动端优先。
当前右上连续摆 3 个入口,会带来:
- 视觉拥挤
- 首屏操作点过多
- 玩家频繁在 3 个高度相似的入口之间来回切
这类浪费在手机端尤其明显。
## 2.5 当前实现会削弱“任务系统正在驱动我”的感受
`目标` 被做成独立前台入口时,用户会更容易把“目标系统”理解成一个独立模块,而不是任务系统的前台头部。
结果就是:
- 任务系统负责记录
- 目标系统负责提醒
- 章节系统负责叙事
三个系统各做一部分,但没有一个系统真正完整承担“驱动玩家前进”的主责任。
---
## 3. 调整原则
## 3.1 前台只保留一个主推进概念:任务
玩家最容易理解、最容易执行、也最容易形成长期习惯的前台概念,应该只有一个:
**任务**
因为任务天然同时满足:
- 可接取
- 可追踪
- 可推进
- 可交付
- 可奖励
这正是“目标感”最需要的系统壳。
## 3.2 目标不是独立模块,而是任务的当前聚焦态
目标仍然有价值,但它在前台的正确位置应是:
- 任务面板顶部的“当前主任务”
- 任务更新时的提示弹窗
- 任务推进时的脉冲反馈
也就是说:
**目标是任务系统的呈现方式,不是另一个并列入口。**
## 3.3 章节不是行动入口,而是任务背景
章节保留,但它更适合表达:
- 本章主题
- 当前阶段
- 当前长期承诺
所以章节应该:
- 在任务面板里提供轻量背景卡
- 或在任务面板中提供“查看章节背景”二级展开
而不是右上一级按钮。
## 3.4 先让任务系统完整承担“承接、推进、反馈、交接”
如果想真正让任务驱动体验成立,就必须让任务系统自己完成完整闭环:
1. 接任务
2. 看任务
3. 推任务
4. 知道自己推进了
5. 知道什么时候可交付
6. 领奖后获得下一任务方向
只要这条链断在别的模块上,任务系统就会继续显得像“半个主系统”。
---
## 4. 新的信息架构
## 4.1 顶层前台结构
建议调整为:
- 保留:`任务`
- 保留:`设置`
- 视情况保留:`统计`
- 移除独立常驻入口:`目标`
- 移除独立常驻入口:`章节`
其中:
- `目标` 被并入任务面板头部与任务更新弹窗
- `章节` 被并入任务面板中的“章节背景卡”
## 4.2 任务面板的新结构
建议把当前任务面板重构为下面 4 层:
### 第一层:当前主任务
只展示玩家此刻最该看的内容:
- 任务标题
- 下一步
- 地点 / 人物提示
- 当前进度
这是原 `目标` 面板应该承载的内容,但要回收到 `任务` 面板头部。
### 第二层:活跃任务列表
展示:
- 当前主任务
- 其他活跃任务
- 可交付任务
排序规则应继续保留:
1. 当前主任务
2. 可交付任务
3. 其他活跃任务
4. 已归档 / 已完成
### 第三层:章节背景卡
只显示:
- 当前章节标题
- 当前段落
- 一句章节摘要
不要再显示:
- 近期回顾大段文本
- 营地风向
- 高光导演
- 其他偏后台式的叙事结构信息
这些信息可以保留在系统内部,但不应默认占据前台。
### 第四层:任务详情页
任务详情页继续保留,但内容也要收束为玩家信息:
- 任务简介
- 目标对象
- 当前步骤
- 奖励
- 交付动作
---
## 5. 弹窗策略调整
## 5.1 “目标弹窗”重命名为“任务更新弹窗”
当前独立的目标弹窗不应继续以“目标”名义存在。
建议改成:
- `任务更新`
- `已接取任务`
- `任务可交付`
- `下一步建议`
这样玩家会直接把它理解成任务系统的反馈,而不是另一套系统。
## 5.2 任务更新弹窗的触发时机
建议只在这些关键节点弹出:
1. 初次进入场景,生成当前主任务时
2. 接受新任务时
3. 当前任务关键步骤切换时
4. 当前任务变为可交付时
5. 领奖后 handoff 到下一目标时
不建议在普通小幅状态变化时频繁弹出。
## 5.3 任务更新弹窗展示内容
只保留:
- 当前任务标题
- 当前为什么值得推进
- 下一步做什么
- 如有必要,给出地点 / 人物提示
不要再展示:
- 支持目标
- 章节承诺大段说明
- 过多后台状态信息
---
## 6. 章节信息的前台降级方案
## 6.1 章节从一级入口降为任务系统内嵌信息
章节仍然重要,但前台地位应该调整为:
- 默认不单独抢入口
- 默认只在任务面板中出现
- 仅在必要时从任务面板中二级展开
## 6.2 章节面板的最小展示集
如果仍然保留章节面板,建议最小化到:
- 当前章节标题
- 当前阶段
- 当前段落
- 当前推进方向
不再默认展示:
- 近期回顾长文
- 营地事件
- setpiece 导演问题
- 其他后台语义分层
## 6.3 章节与任务的关系表达
章节信息应服务于任务理解,而不是独立存在。
推荐表达方式:
- 在任务面板中显示:
- `所属章节:封桥旧案`
- `当前段落:调查`
- `当前推进方向:继续追查桥上的异常来源`
让玩家知道:
**任务是我现在在做的,章节是这件事属于哪一章。**
---
## 7. 系统语义重排
建议把当前 3 层语义重新映射成:
### 前台玩家语义
1. 任务
- 玩家真正会去点击、追踪、推进的对象
2. 当前主任务
- 任务中的当前聚焦项
3. 章节背景
- 帮助理解任务所在的大方向
### 后台系统语义
1. `Quest`
- 主执行壳
2. `GoalStack`
- 任务前台聚焦编译层
3. `Chapter / JourneyBeat / Setpiece`
- 任务背景和长期语义来源
也就是说:
**Goal Stack 继续保留在系统内部,但在 UI 语义上不再和 Task 并列。**
---
## 8. 实现调整建议
## 8.1 第一阶段:入口收口
直接调整:
- 删除右上独立 `目标` 按钮
- 删除右上独立 `章节` 按钮
- 保留 `任务` 按钮
同时:
- 将当前目标弹窗改名为任务更新弹窗
- 从任务按钮进入任务面板
## 8.2 第二阶段:任务面板吸收目标信息
在任务面板中新增顶部区域:
- 当前主任务
- 下一步
- 简短提示
并用它替代当前独立 `目标` 入口的职责。
## 8.3 第三阶段:章节信息降级
调整章节信息展示为:
- 任务面板中的轻量背景卡
必要时:
- 在任务面板内再点“查看章节背景”进入二级详情
## 8.4 第四阶段:任务更新弹窗统一化
把当前各种与目标相关的弹窗统一命名和风格:
- 接取任务
- 任务推进
- 任务可交付
- 下一步建议
统一挂到任务系统语义下。
---
## 9. 对当前代码结构的建议映射
建议后续实现时主要改这些位置:
- `src/components/AdventurePanel.tsx`
- 去掉独立目标前台嵌入和独立章节入口
- `src/components/adventure-panel/AdventurePanelOverlays.tsx`
- 重做任务面板顶部和章节卡结构
- `src/services/storyEngine/goalDirector.ts`
- 保留 GoalStack但只作为任务聚焦编译层
- `src/hooks/useStoryGeneration.ts`
- 把 pulse / handoff 语义统一归到任务更新流
- `src/hooks/useStoryOptions.ts`
- 保持选项与当前主任务的关联标记
---
## 10. 验收标准
做到以下几点,才说明“任务系统为主”的调整真正成立:
1. 右上不再同时并列出现 `目标 / 章节 / 任务` 三个入口。
2. 玩家在前台只需要理解一个主推进概念:`任务`
3. 当前主任务、下一步、可交付状态,都能在任务系统内部闭环完成。
4. 章节信息仍然存在,但不再和任务抢夺一级前台入口。
5. 首个场景进入后,玩家首先感知到的是“接到了什么任务”,而不是“系统里还有一套目标模块”。
6. 移动端右上操作区明显更简洁,主剧情区不再被多套并列语义干扰。
---
## 11. 最后结论
当前右上同时摆 `目标 / 章节 / 任务`,本质上是在让三个语义层并列竞争前台注意力,这会直接削弱任务系统的主导感。
正确的调整方向不是“继续优化三个入口”,而是重新明确主次:
- **任务**:前台唯一主推进入口
- **目标**:任务系统内部的当前聚焦态
- **章节**:任务系统内部的背景语义
这样调整之后,玩家前台感受到的就不再是:
- “我该看目标、章节还是任务?”
而会更接近:
- “我当前的任务是什么,下一步去哪,章节只是告诉我这件任务属于哪一段故事。”

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,413 @@
# Build 系统重构 PRD标签-属性相似度模型
更新时间:`2026-04-02`
## 1. 背景
当前 Build 系统的核心实现位于:
- `src/data/buildDamage.ts`
- `src/data/buildTags.ts`
现状不是“标签各自独立生效”,而是:
1. 先收集角色标签、装备标签、套装标签、Buff 标签。
2. 再计算“每个标签与其他所有标签”的相似度。
3. 用标签之间的整体相互作用,得到最终 `buildDamageMultiplier`
这套机制已经能跑,但存在 4 个明显问题:
1. 解释成本高。玩家很难理解“为什么我多带一个标签,所有旧标签的贡献都变了”。
2. 平衡难度高。任意新增一个标签,都会对整个标签集合产生连锁影响。
3. 角色感不够强。当前倍率更像“标签团簇强度”,而不是“这个标签是否适合当前角色属性”。
4. 扩展不稳定。策划继续扩标签、套装、Buff 时,组合爆炸会越来越明显。
因此,本次重构目标是把 Build 系统从“标签互相影响”改为“标签分别匹配玩家扮演角色的属性画像”,让每个标签的收益来源更直观、更可控。
## 2. 目标
### 2.1 产品目标
建立一套新的 Build 计算模型:
- 不再计算标签与标签之间的互相影响。
- 改为计算“每个标签”和“角色每个属性”的相似度。
- 再根据角色属性分布,决定该标签的修正加成倍数。
- 所有标签的总收益由“单标签贡献求和”得到,而不是由“标签网络效应”得到。
### 2.2 设计目标
新系统需要满足:
1. 可解释:每个标签为什么强、强在哪个属性上,都能拆出来看。
2. 可控:新增一个标签,只影响它自己的贡献,不扰动全局。
3. 贴角色:敏捷型角色更容易吃满“突进/快剑/追击”类标签,智力/精神型角色更容易吃满“法修/法力/符阵”类标签。
4. 可扩展装备、Buff、套装仍然可以继续产出标签但标签结算方式统一且稳定。
### 2.3 非目标
本期不做:
1. 不重做掉落、锻造、拆解循环。
2. 不引入防御端 Build 抗性系统。
3. 不重新设计角色基础四维属性。
4. 不依赖运行时在线 embedding 服务。
## 3. 核心方案
## 3.1 基本思想
每个 Build 标签不再和其他标签比较,而是改为和以下 4 个角色属性做比较:
- `strength`
- `agility`
- `intelligence`
- `spirit`
每个标签都会拥有一个“属性亲和度向量”,表示它分别贴近哪类属性。
示例:
- `快剑`:更偏 `agility`,次偏 `strength`
- `重击`:更偏 `strength`
- `法修`:更偏 `intelligence`
- `护体`:偏 `spirit + strength`
- `符阵`:偏 `intelligence + spirit`
角色自身也有属性分布。系统将角色属性归一化后,与标签属性亲和度做匹配,得到该标签在当前角色身上的“适配度”。
最终伤害加成不再来自“标签互相增幅”,而来自“每个标签在当前角色上的适配度贡献”。
## 3.2 新公式
### 角色属性权重
```ts
roleAttributeWeight[attr] = character.attributes[attr] / totalAttributes
```
其中:
```ts
totalAttributes =
strength + agility + intelligence + spirit
```
### 标签属性亲和度
每个标签维护一个四维向量:
```ts
tagAttributeAffinity = {
strength: 0~1,
agility: 0~1,
intelligence: 0~1,
spirit: 0~1,
}
```
### 单标签适配度
```ts
tagFitScore(tag, character) =
sum(attr in [str, agi, int, spr])(
roleAttributeWeight[attr] * tagAttributeAffinity[attr]
)
```
`tagFitScore` 结果区间固定在 `0 ~ 1`
### 单标签加成倍数
```ts
tagBonusMultiplier =
1 + baseTagBonus * tagFitScore * sourceCoefficient
```
建议首版参数:
- `baseTagBonus = 0.12`
- `sourceCoefficient`
- Buff 标签:`1.0`
- 角色固有标签:`0.9`
- 武器标签:`0.85`
- 防具标签:`0.75`
- 饰品标签:`0.8`
- 套装合成标签:`0.9`
### 最终 Build 总倍率
为了避免标签过多时指数膨胀,首版采用“加法累计,再转倍率”的方式:
```ts
buildBonus =
clamp(sum(eachTagBonusDelta), 0, 0.6)
buildDamageMultiplier = 1 + buildBonus
```
其中:
```ts
eachTagBonusDelta = baseTagBonus * tagFitScore * sourceCoefficient
```
这意味着:
- 标签越多,总收益越高。
- 但每个标签只看自己和角色属性是否匹配。
- 新增一个标签,不会反向修改旧标签贡献。
## 3.3 示例
角色属性:
- `strength = 8`
- `agility = 10`
- `intelligence = 4`
- `spirit = 3`
归一化后:
- `strength = 0.32`
- `agility = 0.40`
- `intelligence = 0.16`
- `spirit = 0.12`
标签亲和度假设:
```ts
: { strength: 0.35, agility: 1.0, intelligence: 0.1, spirit: 0.05 }
: { strength: 0.45, agility: 0.95, intelligence: 0.0, spirit: 0.0 }
: { strength: 0.0, agility: 0.1, intelligence: 1.0, spirit: 0.6 }
```
则:
```ts
fit = 0.32*0.35 + 0.40*1.0 + 0.16*0.1 + 0.12*0.05 = 0.534
fit = 0.32*0.45 + 0.40*0.95 = 0.524
fit = 0.40*0.1 + 0.16*1.0 + 0.12*0.6 = 0.272
```
可以直观看到:
- 同样是标签,`快剑/突进` 对敏捷角色收益高。
- `法修` 在这名角色身上的收益明显偏低。
- 原因不再是“它和其他标签不合群”,而是“它和当前角色属性画像不匹配”。
## 4. 数据结构改造
## 4.1 `BuildTagDefinition` 扩展
当前 `src/types/build.ts` 中的 `BuildTagDefinition` 需要新增:
```ts
attributeAffinity: {
strength: number;
agility: number;
intelligence: number;
spirit: number;
};
```
完整建议:
```ts
interface BuildTagDefinition {
id: string;
label: string;
category: BuildTagCategory;
aliases: string[];
description: string;
attributeAffinity: {
strength: number;
agility: number;
intelligence: number;
spirit: number;
};
}
```
## 4.2 运行时明细结构
`src/data/buildDamage.ts` 需要将当前的 `BuildDamageBreakdown` 从“标签两两贡献表”改成“标签-属性贡献表”:
```ts
type BuildDamageBreakdown = {
tags: string[];
buildDamageBonus: number;
buildDamageMultiplier: number;
rows: Array<{
label: string;
source: 'buff' | 'character' | 'equipment' | 'set' | 'monster';
fitScore: number;
sourceCoefficient: number;
bonusDelta: number;
attributeContributions: {
strength: number;
agility: number;
intelligence: number;
spirit: number;
};
}>;
};
```
这样 UI 或调试日志能直接回答:
- 这个标签吃的是哪条属性
- 吃了多少
- 为什么它比另一个标签强
## 4.3 相似度来源
旧版曾生成过标签-标签相似度矩阵,但新方案不再以“标签-标签相似度矩阵”为主数据源。
建议改为新增:
- `src/data/buildTagAttributeAffinity.ts`
用于存放标签到四维属性的静态向量。
首版推荐手工维护,原因:
1. 标签总量不大,人工校准更稳定。
2. 当前目标是产品可控性,不是自动发现语义簇。
3. 四维属性向量远比标签两两矩阵更容易审表和平衡。
后续如果要半自动化,可再增加脚本从标签描述中生成建议值,但运行时仍只读取本地静态表。
## 5. 标签来源规则
标签来源不变,计算方式变化。
### 保留来源
1. 角色固有 `combatTags`
2. 装备 `buildProfile.tags`
3. 套装标签
4. Buff 标签
### 新规则
1. 所有标签统一做规范化和去重。
2. 每个标签独立计算与角色属性的适配度。
3. 不再计算标签与标签之间的 pair / product / cluster。
4. 套装标签本质上仍是标签,只是 `sourceCoefficient` 更高。
## 6. 伤害接入方式
当前 `calculateOutgoingDamage()` 的接法可以保留:
```ts
finalDamage =
round(
baseDamage
* functionMultiplier
* equipmentMultiplier
* buildDamageMultiplier
)
```
本次只替换 `buildDamageMultiplier` 的来源,不改整体伤害主链路。
## 7. 与旧系统的关键差异
| 维度 | 旧系统 | 新系统 |
| --- | --- | --- |
| 核心逻辑 | 标签之间互相影响 | 标签分别匹配角色属性 |
| 新增标签的影响范围 | 会扰动整个标签集合 | 只影响自身贡献 |
| 可解释性 | 低 | 高 |
| 平衡成本 | 高 | 低 |
| 角色属性参与感 | 弱 | 强 |
| 套装/装备/Buff 接入 | 已支持 | 继续支持 |
## 8. 实施方案
### 阶段 A数据层
1.`src/types/build.ts` 扩展 `BuildTagDefinition.attributeAffinity`
2.`src/data/buildTags.ts` 为所有规范标签补齐四维亲和度
3. 新增 `src/data/buildTagAttributeAffinity.ts` 或直接内联到标签注册表
### 阶段 B规则层
1. 重写 `src/data/buildDamage.ts`
2. 删除或下线标签两两 `contributionRows` 计算
3. 新增 `tagFitScore``bonusDelta``attributeContributions` 计算
### 阶段 C展示层
1. 调整 Build 面板展示文案
2. 从“标签协同”改成“标签适配度”
3. 为每个标签展示主属性来源,例如:
- `快剑:敏捷主导,少量力量修正`
- `法修:智力主导,精神辅助`
### 阶段 D平衡层
1. 补一份全标签四维向量审表
2. 选 5 个预设角色跑样例验证
3. 校准 `baseTagBonus``sourceCoefficient`
## 9. 验收标准
### 功能验收
1. 任意标签的贡献都可以拆解到四个属性。
2. 删除一个标签时,只减少它自己的收益,不应重算其他标签的贡献值。
3. 同一套装备给不同属性角色使用时Build 倍率应体现明显差异。
4. 套装标签、Buff 标签仍能正常进入最终 Build 倍率。
### 数值验收
1. 单标签弱匹配时收益接近 0。
2. 单标签强匹配时收益稳定且可预期。
3. 3 到 6 个高匹配标签可形成清晰 build 成型感。
4. 8 标签上限下,总 Build 加成不超过设计封顶值。
### 体验验收
1. 玩家能理解“为什么这个标签适合我当前角色”。
2. 策划能直接通过改四维向量调数,不需要反复查标签图谱。
3. 调试日志能一眼看出收益来源,而不是只能看到复杂的 pair 乘积。
## 10. 风险与对策
### 风险 1标签语义被压平
问题:
去掉标签-标签协同后Build 可能变得过于线性。
对策:
1. 保留套装标签和 Buff 标签作为高价值来源。
2.`sourceCoefficient` 区分来源权重。
3. 后续如需要,可增加“少量同流派奖励”,但必须是弱规则,不能回到全图互相影响。
### 风险 2四维向量定义主观
问题:
不同策划对“快剑更像敏捷还是力量”可能判断不同。
对策:
1. 首版先建立审表规范。
2. 每个标签必须附一句属性说明。
3. 先让预设角色覆盖主要 archetype再扩充长尾标签。
### 风险 3旧数据迁移成本
问题:
旧标签相似度矩阵已经不再作为主数据源。
对策:
1. 新逻辑只依赖标签定义中的属性亲和度。
2. 旧相似度矩阵生成产物已从主工程移除。
3. 后续若需要重新引入自动建议,也应输出为审表辅助数据,而不是运行时真相源。
## 11. 一句话结论
本次 Build 系统重构的核心,不是再优化“标签之间怎么互相放大”,而是把判断标准改成“这个标签和当前玩家角色的属性画像有多匹配”,从而让 Build 倍率从复杂的标签网络效应,变成可解释、可调优、可控的单标签属性适配模型。

View File

@@ -0,0 +1,147 @@
# “我的”Tab 历史浏览 PRD
更新时间:`2026-04-16`
## 0. 目标
把“历史浏览”从本地浏览记录升级成账号级内容回访能力,让玩家能找回最近看过的作品,并支持跨设备同步。
---
## 1. 当前现状与问题
当前仓库里 `platformBrowseHistory.ts` 采用 `localStorage` 方案,存在明显限制:
1. 仅本机可见
2. 浏览记录上限固定且不可运营
3. 删除缓存后全部丢失
4. 无法用于账号级推荐和召回
---
## 2. 本期范围
## 2.1 本期要做
1. 账号级历史浏览记录
2. 历史浏览列表接口
3. 浏览记录去重与排序
4. 清空历史入口
## 2.2 本期不做
1. 浏览历史搜索
2. 收藏夹合并
3. 基于历史的复杂推荐页
---
## 3. 详细设计
## 3.1 记录时机
用户进入公开作品详情页时写入浏览记录。
不写入的场景:
- 草稿世界
- 未真正打开详情的列表曝光
## 3.2 列表规则
每条记录展示:
- 世界名
- 作者名
- 摘要
- 封面
- 最近浏览时间
排序:
-`visitedAt` 倒序
去重:
- 同一用户对同一作品只保留最近一次
## 3.3 管理动作
支持:
1. 点击记录进入作品详情
2. 清空全部浏览历史
首期不做单条删除,避免交互复杂化。
---
## 4. 后端设计
## 4.1 数据模型
建议新增:
### `user_browse_history`
- `id`
- `user_id`
- `owner_user_id`
- `profile_id`
- `world_name`
- `subtitle`
- `summary_text`
- `cover_image_src`
- `theme_mode`
- `author_display_name`
- `visited_at`
并对 `user_id + owner_user_id + profile_id` 做唯一约束或 upsert。
## 4.2 接口
### `POST /api/profile/browse-history`
用途:
- 进入作品详情时写入记录
### `GET /api/profile/browse-history`
返回:
- 浏览历史列表
### `DELETE /api/profile/browse-history`
用途:
- 清空当前账号浏览历史
---
## 5. 迁移策略
为了兼容当前本地历史:
1. 用户首次登录后可尝试把本地历史批量上报一次
2. 服务端落库成功后,以服务端历史为主
3. 本地历史保留为短期兜底缓存,不再作为主数据源
---
## 6. 前端实现要求
1. “我的”页优先读服务端历史
2. 清空历史前给出确认
3. 空态保持轻量,不写规则说明
4. 失败时保留当前列表,不做闪断
---
## 7. 验收标准
1. 浏览详情后能在历史浏览中看到记录
2. 同一作品重复浏览只保留最新一条
3. 跨设备登录后可看到同一份历史
4. 清空后列表立即刷新

View File

@@ -0,0 +1,154 @@
# “我的”Tab 我的数据看板 PRD
更新时间:`2026-04-16`
## 0. 目标
把“剩余叙世币 / 总游戏时长 / 玩过作品”这一排信息卡,从静态数字展示升级成稳定的个人数据看板,让玩家在进入“我的”页时一眼知道自己的账号资产和游玩投入。
---
## 1. 当前现状与问题
当前三个数字来源并不统一:
1. 叙世币来自当前存档上下文,不等于账号总资产
2. 总游戏时长依赖当前快照,不代表全账号累计
3. 玩过作品当前几乎是硬编码推导,不是真实统计
这会导致“我的”页看到的数据不可信。
---
## 2. 本期范围
## 2.1 本期要做
1. 账号级数据聚合接口
2. 三张核心数据卡
3. 数据更新时间策略
4. 点击卡片查看明细的扩展位
## 2.2 本期不做
1. 成就系统
2. 排行榜
3. 全量行为分析页
---
## 3. 指标定义
## 3.1 剩余叙世币
定义:
- 当前账号可立即消费的叙世币余额
不使用:
- 当前单个存档里的临时货币数值
## 3.2 总游戏时长
定义:
- 当前账号下所有正式游玩会话累计时长
规则:
- 只累计进入有效游戏流程的时长
- 后台挂机超阈值后停止累计
## 3.3 玩过作品
定义:
- 当前账号实际进入过可游玩世界并产生有效游玩记录的去重作品数
去重键建议:
- `ownerUserId + profileId`
---
## 4. 详细设计
## 4.1 交互
三张卡片默认仅展示数字和标题。
点击行为:
1. 叙世币卡
- 打开资产流水抽屉
2. 总游戏时长卡
- 打开游玩统计抽屉
3. 玩过作品卡
- 打开玩过作品列表
如果本期不做明细页,点击可先无动作,但必须预留可扩展事件位。
## 4.2 展示规则
1. 数字过大时做单位缩略展示
2. 进入页面先展示骨架屏
3. 数据请求失败时展示降级文案,不展示假数字
---
## 5. 后端设计
## 5.1 聚合模型
建议新增账号聚合视图或服务:
- `wallet_balance`
- `total_play_time_ms`
- `played_world_count`
- `updated_at`
## 5.2 接口
### `GET /api/profile/dashboard`
返回:
- `walletBalance`
- `totalPlayTimeMs`
- `playedWorldCount`
- `updatedAt`
### `GET /api/profile/wallet-ledger`
返回:
- 叙世币流水列表
### `GET /api/profile/play-stats`
返回:
- 游玩时长分布
- 玩过作品列表摘要
---
## 6. 数据来源要求
1. 钱包余额从后端钱包台账聚合
2. 游戏时长从运行时会话日志或快照汇总
3. 玩过作品数从有效游玩记录去重计算
禁止继续采用:
- 仅从当前存档快照直接读取全部看板数据
---
## 7. 验收标准
1. 三个核心指标都能按账号稳定返回
2. 切换设备后看板数据一致
3. 没有存档时也能正常展示账号级数据
4. 数据加载失败时页面表现可控

View File

@@ -0,0 +1,105 @@
# “我的”Tab 功能 PRD 索引
更新时间:`2026-04-16`
## 0. 目标
基于当前仓库里 `src/components/game-shell/PlatformHomeView.tsx` 已经存在的 “我的” Tab 首屏结构,把页面内每个功能入口都拆成可独立开发、可独立排期、可直接进入编码的 PRD。
这次不是重新发明一个新的个人中心系统,而是遵守当前项目约束:
1. 尽量复用现有平台首页与账号体系
2. 前端只负责表现,逻辑、校验、数据归属全部交给 Express 后端
3. 移动端优先,桌面端兼容
4. UI 保持清爽,不在界面默认堆规则说明文案
---
## 1. 当前“我的”Tab 功能拆分
说明:
-`2026-04-19` 起,“最近游玩 / 历史浏览”已从“我的”页迁出,改为平台一级主 Tab“存档”。
- 对应母文档见 [PLATFORM_SAVE_TAB_PRD_2026-04-19.md](/E:/Repos/Genarrative/docs/prd/PLATFORM_SAVE_TAB_PRD_2026-04-19.md)。
当前“我的”页保留以下 `7` 个独立功能:
1. 账号资料与身份卡
2. 会员中心与充值
3. 我的数据看板
4. 邀请好友
5. 填邀请码
6. 玩家社区
7. 设置与账号安全
---
## 2. PRD 文件清单
1. [MY_TAB_PROFILE_IDENTITY_CARD_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_PROFILE_IDENTITY_CARD_PRD_2026-04-16.md)
2. [MY_TAB_MEMBERSHIP_CENTER_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_MEMBERSHIP_CENTER_PRD_2026-04-16.md)
3. [MY_TAB_DATA_DASHBOARD_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_DATA_DASHBOARD_PRD_2026-04-16.md)
4. [PLATFORM_SAVE_TAB_PRD_2026-04-19.md](/E:/Repos/Genarrative/docs/prd/PLATFORM_SAVE_TAB_PRD_2026-04-19.md)
5. [MY_TAB_INVITE_FRIENDS_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_INVITE_FRIENDS_PRD_2026-04-16.md)
6. [MY_TAB_INVITE_CODE_REDEMPTION_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_INVITE_CODE_REDEMPTION_PRD_2026-04-16.md)
7. [MY_TAB_PLAYER_COMMUNITY_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_PLAYER_COMMUNITY_PRD_2026-04-16.md)
8. [MY_TAB_SETTINGS_AND_SECURITY_PRD_2026-04-16.md](/E:/Repos/Genarrative/docs/prd/MY_TAB_SETTINGS_AND_SECURITY_PRD_2026-04-16.md)
---
## 3. 推荐开发顺序
建议按下面顺序推进,避免后续返工:
1. 账号资料与身份卡
2. 设置与账号安全
3. 我的数据看板
4. 平台存档 Tab
5. 会员中心与充值
6. 邀请好友
7. 填邀请码
8. 玩家社区
原因:
- `1 + 2` 复用现有账号系统最多,最容易先落地
- `3 + 4` 直接增强账号资产与回流体验,短期收益高
- `5 + 6` 涉及商业化和关系绑定,依赖结算与奖励台账
- `7` 最适合放在平台内容层能力稳定后再做
---
## 4. 模块边界约束
### 4.1 前端边界
- `PlatformHomeView` 继续作为“我的”Tab 首屏承载层
- 优先采用现有面板、抽屉、弹窗,不新建独立大系统
- 页面只展示后端返回的状态,不自行计算结论型业务状态
### 4.2 后端边界
- 用户资料、会员、资产、邀请、浏览历史、账号安全全部统一进 Express 后端
- 不允许继续把历史浏览、邀请码状态、会员权益状态仅存本地
- 用户相关聚合数据必须按账号隔离
### 4.3 数据边界
- 所有“我的”数据都必须与正式账号绑定
- 微信待绑定手机号状态下,只展示最小必要的账户与安全入口
- 涉及奖励、货币、权益的变更必须有流水
---
## 5. 结果要求
这组 PRD 交付后,开发层应能直接回答下面问题:
1. 这个功能入口点哪里打开
2. 用户看见什么
3. 前端调用什么接口
4. 后端存什么数据
5. 什么状态能操作,什么状态不能操作
6. 怎么验收算完成
如果后续继续扩写实现计划,建议直接以这 9 份 PRD 为母文档,不再重新发散一套新的“个人中心总方案”。

View File

@@ -0,0 +1,160 @@
# “我的”Tab 填邀请码 PRD
更新时间:`2026-04-16`
## 0. 目标
把“填邀请码”做成用户激活早期的一次性绑定动作,完成:
1. 输入邀请码
2. 校验邀请码是否可用
3. 绑定邀请关系
4. 发放被邀请奖励
---
## 1. 当前现状与问题
当前页面有“填邀请码”按钮,但没有成型规则。最容易踩坑的点是:
1. 什么时候还能填
2. 一个账号能不能改绑
3. 邀请人与被邀请人奖励何时发
如果不先写清楚,后续很容易出现刷奖励和投诉问题。
---
## 2. 本期范围
## 2.1 本期要做
1. 邀请码填写弹窗
2. 邀请关系校验
3. 一次性绑定规则
4. 绑定成功后的奖励发放
## 2.2 本期不做
1. 改绑邀请人
2. 申诉人工修正流程
3. 活动邀请码多类型扩展
---
## 3. 业务规则
## 3.1 填写时机
邀请码只允许在下面时间窗内填写:
1. 新账号注册后
2. 且尚未绑定过任何邀请码
3. 且未超过首个有效周期,例如 `7`
## 3.2 不允许情况
以下情况不可填写:
1. 已绑定过邀请码
2. 用自己的邀请码填写
3. 已超过填写时效
4. 邀请码失效或不存在
## 3.3 绑定结果
绑定成功后:
1. 写入邀请关系
2. 发放被邀请用户奖励
3. 更新邀请人待结算或已结算状态
邀请码绑定后不可撤销、不可修改。
---
## 4. 详细设计
## 4.1 页面结构
弹窗内容仅保留:
1. 输入框
2. 提交按钮
3. 当前可否填写状态
不默认写长篇规则说明。
必要提示采用短句:
- 已绑定,无法修改
- 该邀请码不可用
- 绑定成功
## 4.2 交互
1. 输入邀请码
2. 点击确认绑定
3. 服务端校验
4. 返回成功或失败状态
成功后:
- 按钮置灰
- 展示绑定的邀请人昵称或摘要
---
## 5. 后端设计
## 5.1 数据模型
复用:
- `user_invite_codes`
- `user_referral_relations`
- `user_reward_ledger`
并为被邀请方增加:
- `invited_by_user_id`
- `invite_bound_at`
## 5.2 接口
### `GET /api/referrals/redeem-status`
返回:
- 是否还能填写
- 已绑定邀请人摘要
- 填写截止时间
### `POST /api/referrals/redeem-code`
入参:
- `inviteCode`
出参:
- `ok`
- `inviterSummary`
- `rewardSummary`
---
## 6. 前端实现要求
1. 已绑定状态下直接展示结果,不再显示输入表单
2. 提交中不能重复点击
3. 服务端失败原因要原样映射成短提示
---
## 7. 验收标准
1. 符合条件的新账号可以成功绑定邀请码
2. 同一账号不能重复绑定
3. 不能填写自己的邀请码
4. 奖励发放结果可追踪

View File

@@ -0,0 +1,167 @@
# “我的”Tab 邀请好友 PRD
更新时间:`2026-04-16`
## 0. 目标
把“邀请好友”做成正式的拉新入口,首期目标是:
1. 用户能拿到自己的专属邀请码或邀请链接
2. 能方便地复制或分享
3. 邀请成功后双方奖励可核算
---
## 1. 当前现状与问题
当前“邀请好友”仅是快捷入口按钮,没有:
1. 专属邀请码
2. 分享载体
3. 邀请关系记录
4. 奖励发放规则
因此无法真正产生拉新闭环。
---
## 2. 本期范围
## 2.1 本期要做
1. 邀请好友弹窗
2. 专属邀请码与邀请链接
3. 复制、系统分享、二维码三种分享方式
4. 邀请进度与奖励状态
## 2.2 本期不做
1. 多级分销
2. 战队拉新活动
3. 社交平台深度回流分析
---
## 3. 业务规则
## 3.1 邀请主体
只有正式激活账号可以邀请好友。
待绑定手机号账号不可邀请。
## 3.2 邀请标识
每个账号拥有:
1. 一个固定邀请码
2. 一个可分享邀请链接
邀请码与账号一一绑定,不允许频繁重置。
## 3.3 邀请成功判定
被邀请用户满足以下条件才算成功:
1. 首次注册或首次完成正式激活
2. 首次绑定邀请码成功
3. 完成至少一次有效进入游戏或创建世界动作
这样可以过滤纯注册刷量。
## 3.4 奖励
首期奖励建议采用可控方案:
1. 邀请人获得叙世币
2. 被邀请人获得新手奖励
所有奖励必须走台账,不允许前端本地加值。
---
## 4. 详细设计
## 4.1 页面内容
邀请弹窗展示:
1. 我的邀请码
2. 复制按钮
3. 系统分享按钮
4. 二维码展示
5. 已邀请人数
6. 待达成奖励数量
7. 已到账奖励
## 4.2 交互
1. 点击复制
- 复制邀请码和邀请链接
2. 点击分享
- 触发浏览器分享或复制兜底
3. 点击二维码
- 放大查看
---
## 5. 后端设计
## 5.1 数据模型
建议新增:
### `user_invite_codes`
- `user_id`
- `invite_code`
- `status`
- `created_at`
### `user_referral_relations`
- `inviter_user_id`
- `invitee_user_id`
- `invite_code`
- `bound_at`
- `activated_at`
- `reward_status`
### `user_reward_ledger`
- `user_id`
- `reward_type`
- `amount`
- `source_type`
- `source_id`
- `created_at`
## 5.2 接口
### `GET /api/referrals/invite-center`
返回:
- 邀请码
- 邀请链接
- 分享二维码地址
- 邀请统计
- 奖励统计
---
## 6. 前端实现要求
1. 邀请入口采用轻量弹窗,不跳新系统页
2. 邀请码展示必须可直接复制
3. 二维码图片由后端或统一服务生成
4. 所有奖励数字以服务端返回为准
---
## 7. 验收标准
1. 用户能看到自己的邀请码与邀请链接
2. 可以一键复制或分享
3. 邀请成功后能看到正确统计
4. 奖励到账后叙世币余额同步变化

View File

@@ -0,0 +1,209 @@
# “我的”Tab 会员中心与充值 PRD
更新时间:`2026-04-16`
## 0. 目标
把顶部“会员充值”按钮落成正式可运营的会员中心最小闭环,首期只解决三件事:
1. 看清当前会员状态
2. 购买或续费会员
3. 理解会员能得到的实际权益
会员中心不做复杂商城,不做满屏促销文案,保持轻量、清爽、可直接支付。
---
## 1. 当前现状与问题
当前页面已有“会员充值”按钮,但本质上还是视觉占位,缺少:
1. 会员等级定义
2. 权益结构
3. 订单与支付状态
4. 到期时间与续费逻辑
这样会导致按钮可见但不可运营。
---
## 2. 本期范围
## 2.1 本期要做
1. 会员中心弹窗/抽屉
2. 当前会员状态展示
3. 可购买套餐展示
4. 下单与支付状态查询
5. 充值成功后的权益生效
## 2.2 本期不做
1. 积分商城
2. 限时活动页
3. 礼包组合购
4. 多级会员体系
---
## 3. 会员定义
首期只保留两种状态:
1. `普通用户`
2. `叙世会员`
会员权益首期建议控制在直接可编码的范围:
1. 每日额外叙世币领取额度
2. 高级世界模板或创作槽位
3. 更高的云存档上限
4. 会员专属标识
权益必须都是能被后端明确判定和下发的,不允许先写模糊营销描述。
---
## 4. 详细设计
## 4.1 入口与打开方式
点击“会员充值”按钮后:
1. 打开会员中心抽屉
2. 顶部显示当前会员状态
3. 中部显示权益卡片
4. 底部显示套餐与购买按钮
## 4.2 页面内容
页面展示模块:
1. 当前状态
2. 到期时间
3. 可用权益
4. 套餐列表
5. 最近订单状态
不展示:
- 大段充值说明
- 复杂规则 FAQ
- 无法立即购买的灰色功能墙
## 4.3 套餐结构
首期套餐建议:
1. `月卡`
2. `季卡`
3. `年卡`
每个套餐展示:
- 套餐名
- 价格
- 到账权益
- 生效周期
## 4.4 支付状态
订单状态至少支持:
- `pending`
- `paid`
- `failed`
- `closed`
- `refunded`
支付成功后:
1. 刷新会员状态
2. 刷新叙世币余额
3. 刷新权益标签
---
## 5. 后端设计
## 5.1 数据模型
建议新增:
### `membership_products`
- `product_id`
- `product_name`
- `duration_days`
- `price_cents`
- `status`
- `benefit_json`
### `user_memberships`
- `user_id`
- `membership_type`
- `started_at`
- `expires_at`
- `status`
### `membership_orders`
- `order_id`
- `user_id`
- `product_id`
- `amount_cents`
- `order_status`
- `payment_channel`
- `paid_at`
- `created_at`
## 5.2 接口
### `GET /api/membership/center`
返回:
- 当前会员状态
- 到期时间
- 套餐列表
- 权益列表
- 最近订单摘要
### `POST /api/membership/orders`
入参:
- `productId`
- `paymentChannel`
出参:
- `orderId`
- `payParams`
- `orderStatus`
### `GET /api/membership/orders/:orderId`
用途:
- 查询支付结果
---
## 6. 前端实现要求
1. 会员中心复用现有模态层,不新增独立系统页
2. 移动端默认单列套餐卡片
3. 支付中状态不能重复点单
4. 支付成功后从后端重新拉取状态,不靠前端假更新
---
## 7. 验收标准
1. 普通用户能看到可买套餐
2. 已开通会员能看到当前到期时间
3. 支付成功后权益立即生效
4. 续费不会覆盖错误时间
5. 没有空按钮和假入口

View File

@@ -0,0 +1,159 @@
# “我的”Tab 玩家社区 PRD
更新时间:`2026-04-16`
## 0. 目标
把“玩家社区”做成轻量社区入口,但不额外新造一个庞杂社交系统。首期目标是复用当前平台内容能力,提供:
1. 官方动态
2. 玩家讨论入口
3. 热门作品讨论聚合
---
## 1. 设计原则
这个社区功能必须遵守两个前提:
1. 优先复用已有平台作品与账号体系
2. 不在首期直接做完整好友社交网
所以首期社区不是“朋友圈”,而是“内容讨论与官方动态聚合层”。
---
## 2. 本期范围
## 2.1 本期要做
1. 社区入口页
2. 官方公告流
3. 玩家讨论话题流
4. 作品详情页下的讨论聚合跳转
## 2.2 本期不做
1. 好友私聊
2. 社区发帖富文本编辑器
3. 点赞排行榜
4. 群组系统
---
## 3. 信息架构
首期社区入口页建议拆成三个轻量分区:
1. 官方
2. 热门讨论
3. 最近作品讨论
点击“玩家社区”后,不跳全新站外页面,优先打开站内社区抽屉或二级视图。
---
## 4. 详细设计
## 4.1 官方区
展示:
- 官方公告
- 版本更新摘要
- 活动预告
每条内容只显示:
- 标题
- 摘要
- 时间
## 4.2 热门讨论区
展示:
- 讨论标题
- 关联作品
- 回复数
- 最近活跃时间
## 4.3 作品讨论区
当前平台已有作品广场与作品详情,因此社区首期优先绑定作品:
1. 每个公开作品可有讨论串
2. 社区页聚合热门作品讨论
3. 作品详情页可跳到该讨论串
---
## 5. 后端设计
## 5.1 数据模型
建议新增:
### `community_posts`
- `id`
- `author_user_id`
- `category`
- `related_profile_id`
- `title`
- `content_text`
- `status`
- `created_at`
- `updated_at`
### `community_replies`
- `id`
- `post_id`
- `author_user_id`
- `content_text`
- `status`
- `created_at`
### `community_announcements`
- `id`
- `title`
- `summary`
- `content_text`
- `published_at`
- `status`
## 5.2 接口
### `GET /api/community/home`
返回:
- 官方动态列表
- 热门讨论列表
- 最近作品讨论列表
### `GET /api/community/posts/:postId`
用途:
- 读取帖子与回复
---
## 6. 前端实现要求
1. 社区页保持内容导向,不做复杂社交关系页
2. 移动端优先采用流式卡片
3. 非登录用户只可浏览,发言必须登录
4. 敏感内容审核状态全部由后端控制
---
## 7. 验收标准
1. 用户可以从“我的”页进入社区入口
2. 可以看到官方动态和热门讨论
3. 作品讨论与作品详情存在双向跳转
4. 不需要新增独立社交系统就能跑通首期体验

View File

@@ -0,0 +1,212 @@
# “我的”Tab 账号资料与身份卡 PRD
更新时间:`2026-04-16`
## 0. 目标
把“我的”页顶部资料卡从一个静态展示块升级成正式的用户身份入口,承载:
1. 头像编辑
2. 昵称编辑
3. 叙世号展示与复制
4. 登录方式与绑定状态展示
5. 进入资料编辑抽屉
这个模块的作用不是做安全设置总入口,而是把“我是谁”展示清楚,并提供最轻量的资料编辑。
---
## 1. 当前现状与问题
当前页面已经展示:
- 头像占位
- 昵称
- 叙世号
- 登录方式
- 绑定状态
但存在几个问题:
1. 头像按钮和昵称编辑按钮都直接打开账号弹窗,信息架构混在一起
2. 头像当前只是视觉壳,没有真正的上传与裁剪能力
3. 昵称缺少明确的编辑规则与唯一性策略
4. 叙世号只是前端拼接值,不适合长期作为正式公开识别码
---
## 2. 产品范围
## 2.1 本期要做
1. 用户身份卡展示
2. 资料编辑抽屉
3. 头像上传、裁切、保存
4. 昵称编辑、校验、保存
5. 叙世号固定生成与复制
6. 登录方式与账号状态标签展示
## 2.2 本期不做
1. 个性签名
2. 主页装扮
3. 自定义头像框
4. 社交主页公开页
---
## 3. 信息架构
## 3.1 首屏卡片内容
资料卡固定展示:
- 用户头像
- 用户昵称
- `叙世号`
- 登录方式标签
- 账号状态标签
- 资料编辑入口
资料卡不展示:
- 大段规则说明
- 安全告警明细
- 设备管理
- 审计日志
这些内容统一放到“设置与账号安全”。
## 3.2 交互结构
点击区域行为如下:
1. 点击头像
- 打开“编辑资料”抽屉,并默认聚焦头像编辑区域
2. 点击昵称右侧编辑按钮
- 打开“编辑资料”抽屉,并默认聚焦昵称输入框
3. 点击叙世号复制按钮
- 直接复制,并给出轻提示
4. 点击登录方式/状态标签
- 不跳页,不弹复杂说明
---
## 4. 详细设计
## 4.1 头像
头像规则:
1. 默认使用系统首字头像
2. 用户上传后替换为正式头像
3. 上传后进入正方形裁切
4. 服务端生成 `256x256` 主图和 `96x96` 缩略图
5. 超过大小或格式限制时直接拦截
支持格式:
- `jpg`
- `png`
- `webp`
限制:
- 单文件最大 `5MB`
- 裁切结果统一为正方形
## 4.2 昵称
昵称规则:
1. 长度 `2-20` 个字符
2. 允许中文、英文、数字、下划线
3. 不允许空白昵称
4. 不要求全站唯一,但要允许后端做敏感词审核
5. 审核失败时返回明确错误
## 4.3 叙世号
叙世号规则:
1. 作为公开可复制识别码
2. 用户创建后固定生成,不允许用户修改
3. 格式统一,例如:`SY-8F29A13C`
4. 后端生成并返回,不再由前端临时拼接
## 4.4 账号状态标签
状态只显示短标签:
- `手机号登录`
- `微信登录`
- `待绑定手机号`
- `已激活`
不在资料卡里展开规则说明。
---
## 5. 后端设计
## 5.1 数据模型
建议扩展 `users` 或新增 `user_profiles`
- `user_id`
- `public_user_code`
- `display_name`
- `avatar_asset_id`
- `avatar_url`
- `avatar_thumb_url`
- `updated_at`
## 5.2 接口
### `GET /api/profile/me`
返回:
- `displayName`
- `avatarUrl`
- `avatarThumbUrl`
- `publicUserCode`
- `loginMethod`
- `bindingStatus`
### `PATCH /api/profile/me`
入参:
- `displayName`
- `avatarAssetId`
出参:
- 更新后的资料对象
### `POST /api/profile/avatar/upload-token`
用途:
- 获取头像上传凭证或上传地址
---
## 6. 前端实现要求
1. 资料编辑优先做成底部抽屉或轻量弹窗,不新开独立页面
2. 移动端头像、昵称、复制按钮必须单手可操作
3. 保存按钮固定在抽屉底部
4. 保存中展示明确 loading 态
5. 成功后即时回写顶部资料卡
---
## 7. 验收标准
1. 用户可以上传并保存头像
2. 用户可以修改昵称并实时看到更新
3. 叙世号由后端返回,复制后可正常使用
4. 未登录或待绑定状态下,不出现无效编辑入口
5. 页面不出现冗长规则说明文案

View File

@@ -0,0 +1,126 @@
# “我的”Tab 最近游玩 PRD
更新时间:`2026-04-16`
## 0. 目标
把“最近游玩”从单一继续游戏卡片扩成账号级最近游玩模块,让玩家可以快速回到最近推进过的作品和存档节点。
---
## 1. 当前现状与问题
当前“最近游玩”仅基于一个本地快照推导:
1. 只支持一个最近记录
2. 只要本地没有快照就没有内容
3. 无法跨设备同步
4. 无法区分多个世界和多个角色
这不符合平台化后的用户预期。
---
## 2. 本期范围
## 2.1 本期要做
1. 最近游玩列表
2. 继续游玩主动作
3. 进入作品详情或继续冒险
4. 跨设备同步最近记录
## 2.2 本期不做
1. 多存档槽管理全量页面
2. 手动置顶
3. 存档备注与重命名
---
## 3. 详细设计
## 3.1 展示结构
首屏展示 `1-5` 条最近游玩卡片。
每张卡片展示:
- 世界名
- 当前角色名
- 最近摘要
- 最近游玩时间
- 继续按钮
移动端优先横向滑动卡片,桌面端可显示为横向列表或双列卡片。
## 3.2 点击行为
1. 点击卡片主体
- 进入作品详情页,展示继续入口和存档摘要
2. 点击继续按钮
- 直接恢复最近游玩存档
如果该存档已失效:
- 给出“存档不可恢复”的明确提示
- 引导回到作品详情或重新开始
## 3.3 排序规则
`lastPlayedAt` 倒序。
若同一作品下存在多个存档:
- 只展示最近一次有效记录
---
## 4. 后端设计
## 4.1 数据模型
建议在存档或游玩记录层增加聚合:
- `user_id`
- `world_owner_user_id`
- `profile_id`
- `save_id`
- `world_name`
- `character_name`
- `continue_digest`
- `cover_image_src`
- `last_played_at`
- `is_resume_available`
## 4.2 接口
### `GET /api/profile/recent-plays`
返回:
- 最近游玩列表
### `POST /api/runtime/saves/:saveId/resume`
用途:
- 校验并恢复指定存档
---
## 5. 前端实现要求
1. 继续游玩动作必须走后端校验
2. 不允许前端自行拼装恢复上下文
3. 列表为空时展示轻量空态
4. 卡片摘要最多显示三行,保持“我的”页清爽
---
## 6. 验收标准
1. 最近游玩可以展示多个最近记录
2. 不同设备登录同一账号时列表一致
3. 点击继续后能恢复到正确存档
4. 无效存档不会让前端直接报错白屏

View File

@@ -0,0 +1,228 @@
# “我的”Tab 设置与账号安全 PRD
更新时间:`2026-04-20`
## 0. 目标
把“设置”入口正式定义为账号安全中心,统一承载:
1. 账号基础信息查看
2. 当前安全状态
3. 登录设备管理
4. 更换手机号
5. 最近账号操作记录
6. 退出登录与退出全部设备
这个模块直接建立在当前仓库已有的账号接口之上,是“我的”页最优先落地的正式功能。
---
## 1. 当前现状
当前仓库已具备以下基础能力:
1. `GET /api/auth/risk-blocks`
2. `GET /api/auth/sessions`
3. `GET /api/auth/audit-logs`
4. `POST /api/auth/phone/change`
5. `POST /api/auth/logout`
6. `POST /api/auth/logout-all`
7. `POST /api/auth/sessions/:sessionId/revoke`
说明当前账号安全不是从零开始,而是缺少稳定的信息架构和最终产品定义。
---
## 2. 产品范围
## 2.1 本期要做
1. 设置与账号安全弹窗
2. 安全状态展示
3. 登录设备管理
4. 更换手机号
5. 操作记录查看
6. 退出当前设备
7. 退出全部设备
## 2.2 本期不做
1. 修改密码正式入口
2. 实名认证
3. 邮箱绑定
4. 多因子认证
---
## 3. 信息架构
设置中心首层固定为两段:
1. 主题外观
2. 账号信息
其中“账号信息”二级面板固定承载以下内容:
1. 账号概况
2. 当前安全状态
3. 登录设备
4. 更换手机号
5. 账号操作记录
6. 退出登录
7. 退出全部设备
交互层级要求补充为:
1. 设置首页只展示“主题外观”“账号信息”两个分区入口,不在首页内联展开具体详情
2. 点击任一分区入口后,必须进入独立二级面板
3. 安全状态、登录设备、操作记录不再作为首页独立入口,统一归入“账号信息”二级面板
4. 更换手机号属于独立操作面板,不允许在账号信息面板内直接展开表单
5. 退出登录与退出全部设备统一归入“账号信息”二级面板,不再在设置首页单独占位
6. 设置首页头部只保留一套主标题,不允许在内容区再重复放置“设置首页”“选择要管理的内容”这类二次标题块
7. 子面板导航动作必须单一明确;同一层面板内有“返回”时,不再同时展示“关闭”
8. 子面板返回按钮固定摆在面板右上角
9. 设置首页与各级子面板都必须定义单一滚动容器,列表内容必须可稳定滚动,禁止外层与内层同时争夺滚动
10. 二级或三级面板打开后,下层内容必须进入不可交互状态,并把焦点主动转移到当前面板内;禁止对仍保留焦点的祖先节点使用 `aria-hidden`
---
## 4. 详细设计
## 4.1 账号概况
展示:
- 登录方式
- 手机号脱敏值
- 微信绑定状态
这里只看信息,不做大编辑动作。
标题约束:
- 设置首页标题固定表达“设置”或“设置与账号安全”
- 设置首页标题区域不展示手机号,也不允许把手机号当作主标题替代昵称
- 手机号只允许出现在账号概况信息项中,以脱敏值展示
## 4.2 当前安全状态
展示当前账号命中的风控保护:
- 手机号保护
- 当前网络保护
每条状态可执行:
- 解除保护
解除动作必须经过后端校验。
## 4.3 登录设备
每条设备展示:
- 设备类型
- 最近活跃时间
- 到期时间
- IP 脱敏信息
- 是否当前设备
非当前设备支持:
- 踢下线
## 4.4 更换手机号
流程:
1. 输入新手机号
2. 获取验证码
3. 如有需要,完成人机校验
4. 输入验证码
5. 提交修改
规则:
1. 新号码不能等于当前号码
2. 已被其他账号绑定的号码不可用
3. 风控命中时必须遵循现有保护逻辑
## 4.5 操作记录
展示最近账号行为:
- 登录
- 绑定手机号
- 更换手机号
- 退出登录
- 踢设备
- 触发图形验证码
- 风险保护
---
## 5. 前后端职责边界
## 5.1 前端职责
1. 展示状态
2. 收集输入
3. 呈现 loading / success / error
## 5.2 后端职责
1. 风控判断
2. 图形验证码触发
3. 会话列表返回
4. 设备撤销
5. 日志审计
6. 手机号换绑
前端不允许自己决定:
- 是否需要验证码
- 是否允许解除风控
- 是否允许换绑
---
## 6. 接口对齐
首期优先复用现有接口:
1. `GET /api/auth/me`
2. `GET /api/auth/risk-blocks`
3. `POST /api/auth/risk-blocks/:scopeType/lift`
4. `GET /api/auth/sessions`
5. `POST /api/auth/sessions/:sessionId/revoke`
6. `GET /api/auth/audit-logs`
7. `POST /api/auth/phone/change`
8. `POST /api/auth/logout`
9. `POST /api/auth/logout-all`
如需补充,只增加展示层所缺的聚合字段,不重建接口体系。
---
## 7. 前端实现要求
1. 设置继续采用当前账号弹窗基础形态即可
2. 移动端优先底部弹层,桌面端可居中弹窗
3. 设置首页只保留“主题外观”“账号信息”两个入口,不再单独展示安全状态、登录设备、操作记录入口
4. “账号信息”二级面板直接承载账号概况、安全状态、登录设备、操作记录与退出动作,移动端优先纵向滚动,桌面端保持同一面板内稳定扫读
5. 更换手机号必须通过独立操作面板完成,不再使用当前面板内联展开表单
6. 危险操作按钮与普通按钮必须明显区分
7. 设置首页标题处禁止展示手机号、脱敏手机号或手机号形态的 displayName
8. 设置首页不额外堆砌规则说明文案,标题下直接进入可操作内容
9. 子面板采用覆盖式独立面板承载详情,返回上一级时恢复首页,不在同层同时出现双导航动作
10. 面板切换必须保证键盘焦点始终停留在当前活跃面板内,返回上一级后焦点恢复到触发入口
---
## 8. 验收标准
1. 用户能看到当前账号安全信息
2. 能查看并管理登录设备
3. 能按规则更换手机号
4. 能查看最近账号操作记录
5. 退出登录和退出全部设备都能稳定生效

View File

@@ -0,0 +1,259 @@
# 平台“存档”Tab PRD
更新时间:`2026-04-20`
## 0. 目标
把原本堆在“我的”页中的“最近游玩 / 历史浏览”移出,新增平台一级主 Tab“存档”用于承载当前账号在平台里玩过的所有游戏留下的最近可恢复存档。
这次改动的核心目标不是做复杂多槽位存档系统,而是先落地一个稳定、可跨设备同步、可直接继续游玩的账号级存档入口。
---
## 1. 信息架构调整
## 1.1 平台主导航
平台主导航从:
- 首页
- 创作
- 我的
调整为:
- 首页
- 创作
- 存档
- 我的
移动端底部导航与桌面端左侧纵向导航都必须同步调整。
## 1.2 “我的”页调整
“我的”页删除以下内容块:
- 最近游玩
- 历史浏览
“我的”页保留:
- 账号资料与身份卡
- 数据看板
- 常用功能
- 设置与账号安全
说明:
- 历史浏览本期直接从“我的”页移除,不再占据个人页首屏空间。
- 存档能力统一收口到平台一级“存档”Tab不再同时在“我的”页重复展示。
---
## 2. 存档定义
## 2.1 本期存档口径
本期“存档”Tab 展示的是:
- 当前账号在每个已游玩游戏 / 世界下保留的最近一个可恢复存档
不是:
- 同一游戏下的完整多槽位存档管理页
- 手动重命名 / 置顶 / 删除存档系统
## 2.2 世界唯一键
服务端必须按 `worldKey` 聚合最近存档:
- 自定义世界:`custom:<profileId>`
- 内建世界:`builtin:<worldType>`
同一账号、同一 `worldKey` 只保留最近一次成功保存的可恢复存档。
## 2.3 生命周期
1. 玩家每次成功写入运行时快照时,同步刷新该世界的最近存档记录。
2. 删除当前活动快照时,不删除历史存档归档。
3. 点击“继续游玩”时,从该世界最近存档恢复为当前活动快照,再进入游戏。
---
## 3. 界面设计
## 3.1 存档 Tab 首屏结构
页面首屏直接展示存档列表,不再单独保留顶部“最近存档”摘要卡。
列表容器本身需要承担首屏入口作用:
- 用户进入“存档”Tab 后第一屏就看到可恢复存档列表
- 不额外重复展示首个存档的大卡摘要
- 存档数量、排序状态如需表达,应收敛在列表标题或轻量状态信息中
不要在 UI 中默认堆规则说明文案,只保留简洁的状态表达。
## 3.2 列表排序
列表按 `lastPlayedAt` 倒序。
最近更新的存档始终在最前面。
## 3.3 列表项字段
每个列表项必须展示:
- 游戏名称
- 最后游玩时间
- 游戏信息
### 3.3.1 移动端卡片布局约束
- 移动端列表卡片中的封面只能作为独立缩略图或弱化背景层使用,不能直接占满整张卡片并压在正文信息下方。
- 标题、时间、摘要所在的信息区必须保持 `min-width: 0` 的可收缩布局,长标题不能把正文挤出屏幕外。
- 世界名称最多展示 2 行,游戏信息最多展示 3 行,超出后截断,不允许横向溢出。
- 时间标签、状态标签在窄屏下必须允许换行或独立成行,不能为了保持单行导致卡片内容错位。
- 列表卡片缩略图区域比例固定,文本区与缩略图区在移动端需要保持稳定对齐,避免出现上下参差和视觉歪斜。
其中“游戏信息”优先级如下:
1. `continueGameDigest`
2. 当前故事文本摘要
3. 世界简介 / 场景简介
4. 若都没有则给出简洁兜底文案
可附带展示封面,但封面不是必填验收项。
## 3.4 点击行为
点击列表项后:
1. 调用后端恢复接口
2. 将所选存档切换为当前活动快照
3. 直接进入游戏继续游玩
前端不允许自行拼装恢复上下文。
## 3.5 空状态
### 已登录但无存档
- 展示轻量空态
- 引导去首页开始游玩
### 未登录
- 展示登录态空壳
- 不请求受保护的云端存档列表接口
---
## 4. 默认进入逻辑
当满足以下条件时玩家进入网站后的平台首页默认进入“存档”Tab
1. 当前处于登录状态
2. 当前账号至少存在一个存档
否则:
- 仍默认进入“首页”Tab
注意:
- 这个默认进入逻辑只在平台首屏初始化时执行,不能覆盖用户手动切换后的选择。
- 若平台首页的公开作品、个人数据、存档列表仍在异步加载中,用户已经手动切到“创作 / 存档 / 我的”时,请求完成后也不能把当前 Tab 回刷成默认 Tab。
---
## 5. 后端设计
## 5.1 新增数据表
建议新增 `profile_save_archives`
- `user_id`
- `world_key`
- `owner_user_id`
- `profile_id`
- `world_type`
- `world_name`
- `world_subtitle`
- `summary_text`
- `cover_image_src`
- `saved_at`
- `bottom_tab`
- `game_state_json`
- `current_story_json`
- `updated_at`
约束:
- 主键:`user_id + world_key`
- 排序索引:`user_id + saved_at desc`
## 5.2 写入规则
每次 `/api/runtime/save/snapshot` 成功写入后:
1. 正常更新当前活动快照
2. 同步 upsert 对应 `world_key` 的存档归档
3. 继续保留原有个人看板 / 已玩作品同步逻辑
## 5.3 列表接口
### `GET /api/runtime/profile/save-archives`
返回:
- 当前账号全部最近存档
字段至少包含:
- `worldKey`
- `worldName`
- `worldSubtitle`
- `summaryText`
- `coverImageSrc`
- `lastPlayedAt`
- `worldType`
- `profileId`
- `ownerUserId`
## 5.4 恢复接口
### `POST /api/runtime/profile/save-archives/:worldKey/resume`
用途:
- 将指定存档归档恢复为当前活动快照
- 返回恢复后的快照
限制:
- 恢复动作不能重复记账,不得再次累计个人资产流水
- 恢复动作不能重复累计已玩时长
- 恢复动作不能破坏现有快照水合逻辑
---
## 6. 前端实现要求
1. `PlatformHomeView` 新增 `存档` 主 Tab。
2. `PreGameSelectionFlow` 在平台数据加载时同时拉取存档列表。
3. 已登录且有存档时,平台首屏默认选中 `存档` Tab。
4. “我的”页删除“最近游玩 / 历史浏览”两个区块。
5. 点击存档列表项时必须经过后端恢复接口,恢复成功后直接进入游戏。
6. 移动端优先,列表项点击区域不能过小。
---
## 7. 验收标准
1. 已登录账号可以在“存档”Tab 看到所有已玩过世界的最近存档。
2. 列表按最近更新时间倒序。
3. 列表项可看到游戏名称、最后游玩时间和游戏信息。
4. 点击列表项后可直接继续对应游戏。
5. 已登录且至少有一个存档时进入网站默认打开“存档”Tab。
6. 未登录时不请求云端存档列表,也不会出现受保护接口报错。

View File

@@ -0,0 +1,486 @@
# 当前运行时物品生成系统设计整理
更新时间:`2026-04-02`
## 0. 目标
这份文档只回答一个问题:
**当前仓库里,运行时物品是怎么被“定义、生成、发放、使用、转化、进入 build 结算”的。**
它不是未来方案,而是对现状的结构化整理,方便后续继续扩展 AI 原生玩法。
## 1. 当前系统的总体判断
当前仓库里的运行时物品系统,不是“纯 AI 生成”,而是一个 **本地规则驱动 + 局部程序化生成 + AI 负责叙事文本** 的体系。
它大体由 5 层组成:
1. **物品骨架层**
-`InventoryItem``ItemStatProfile``ItemUseProfile``ItemBuildProfile` 承载运行时能力。
2. **基础生成层**
-`src/data/itemCatalog.ts` + `src/data/itemDesign.ts` 从素材路径推导出物品目录与设计元数据。
3. **运行时发放层**
- 在初始背包、NPC 库存、宝藏奖励、怪物掉落、拆解/锻造/重铸、自定义世界运行时生成等入口,把物品真正放进 `GameState`
4. **战斗/背包生效层**
- 装备通过 `equipmentEffects.ts` 生效,消耗品通过 `inventoryEffects.ts` 生效build 标签通过 `buildTags.ts` + `buildDamage.ts` 生效。
5. **叙事包装层**
- AI 负责把这些本地规则已经确定的结果写成剧情、聊天、宝藏描述、选项文案,但 **AI 当前并不直接产出结构化运行时物品**
一句话概括:
**当前系统已经有“运行时物品玩法骨架”,但还没有“与具体背景 / 当前 NPC / 当前事件强绑定的 AI 原生物品导演层”。**
## 2. 当前核心数据结构
### 2.1 `InventoryItem`
运行时所有物品最终都落到 `InventoryItem`
- 基础身份:`id``category``name``quantity``rarity`
- 通用标签:`tags`
- 世界/表现:`iconSrc``description``worldAffinity``worldProfiles`
- 装备信息:`equipmentSlotId`
- 数值能力:`statProfile`
- 使用能力:`useProfile`
- build 能力:`buildProfile`
- 经济能力:`value`
这意味着当前系统已经允许同一个物品同时具备:
- 装备加成
- 消耗品效果
- build 标签
- 世界观文案
- 经济价值
### 2.2 `ItemStatProfile`
当前可直接进入数值结算的字段主要是:
- `maxHpBonus`
- `maxManaBonus`
- `outgoingDamageBonus`
- `incomingDamageMultiplier`
这套结构已经足够支撑“少量直接数值提升”的物品设计。
### 2.3 `ItemUseProfile`
当前消耗品/可使用物品可提供:
- `hpRestore`
- `manaRestore`
- `cooldownReduction`
- `buildBuffs`
这意味着当前系统已经具备“限时 build 标签道具”的基础承载能力。
### 2.4 `ItemBuildProfile`
当前 build 相关物品数据包括:
- `role`
- `tags`
- `setId`
- `setName`
- `pieceName`
- `synergy`
- `craftTags`
- `forgeRank`
这说明当前物品系统已经不仅仅是“数值装备”,而是已经向 **build / 套装 / 锻造** 方向扩展。
## 3. 当前物品是如何被生成出来的
## 3.1 素材目录 -> 物品目录
`src/data/itemCatalog.ts` 负责把素材路径转成 `ItemCatalogEntry`
- 先从素材路径推导:
- `category`
- `rarity`
- `tags`
- `name`
- 再调用 `src/data/itemDesign.ts` 补充更完整的设计:
- `statProfile`
- `useProfile`
- `buildProfile`
- `value`
- 世界观名称/描述
也就是说,当前项目里相当一部分物品,不是手工逐个写死的,而是 **“素材驱动 + 规则推导”**。
## 3.2 `itemDesign.ts` 的设计角色
`src/data/itemDesign.ts` 是当前最重要的“物品规则设计器”。
它会按素材族系推导出不同风格物品:
- `Armory` 系列
- 生成武器/护甲
- 自动带 `buildProfile`
- 自动挂 `setId / setName / pieceName / synergy`
- `Jewelry` 系列
- 生成饰品
- 偏向 `relic` 与 build 补位
- `Potions` 系列
- 生成消耗品
- 可恢复 HP / Mana / 冷却
- 部分药剂会生成 `buildBuffs`
- `Gems` / `Skills` / `Librarium` 系列
- 生成稀有品、法器、技能相关物品
- 部分带 build 倾向
这层已经是“半程序化设计”,不是纯静态表。
## 3.3 自定义世界运行时程序化生成
`src/data/customWorldRuntime.ts` 提供了另一条明显不同的生成链:
- 输入:
- `CustomWorldProfile`
- `seedKey`
- 查询条件:`categories / preferredTags / keywords / rarityFloor / count`
- 输出:
- 运行时即时程序化物品
它的特点是:
- 基于世界档案与种子稳定生成
- 可以按角色、用途、标签、关键词筛选
- 能生成:
- 武器
- 护甲
- 饰品
- 消耗品
- 材料
- 稀有品
- 专属物品
当前它已经被用于:
- 自定义世界角色初始装备
- 自定义世界角色初始背包
- 自定义世界 NPC 角色库存
但这条链目前更像 **“主题化程序物品池”**还不是“事件级、NPC级、场景级实时定制物品”。
## 4. 当前运行时有哪些物品发放入口
## 4.1 玩家初始物品
玩家开局物品主要来自两条链:
1. `buildInitialPlayerInventory`
- 来自 `npcInteractions.ts`
- 普通世界走角色预设背包
- 自定义世界走 `buildCustomWorldStarterInventoryItems`
2. `buildInitialEquipmentLoadout`
- 来自 `equipmentEffects.ts`
- 根据角色预设初始装备,转成可装备的 `InventoryItem`
这说明玩家初始 build 其实已经部分依赖物品体系,而不是只靠角色裸属性。
## 4.2 NPC 库存
`buildInitialNpcState` 会给每个 NPC 建立运行时库存:
- 角色型 NPC
- 从角色装备 + 角色背包推导
- 怪物型 encounter
- 从怪物 preset 的 `lootTable` 推导
- 普通场景 NPC
- 从职业/身份模板库存推导
- 自定义世界 NPC
- 可走 `buildRuntimeCustomWorldInventoryItems`
因此当前 NPC 交易、赠礼、击败掉落,已经都能围绕同一套 `InventoryItem[]` 进行。
## 4.3 宝藏奖励
`src/data/treasureInteractions.ts` 负责宝藏奖励:
- 根据世界类型选择奖励池
- 根据 encounter 信息和 action 做 seed
- 产出:
- 稀有品
- 消耗品
- 材料
- HP / Mana 恢复
- 货币
这条链已经是运行时生成,但目前仍然是 **世界模板池级别**,不是“根据当前场景背景 / 当前 NPC / 最近事件”深度定制。
## 4.4 怪物掉落 / NPC 击败掉落
当前掉落主要有两种:
1. 怪物 preset 自带 `lootTable`
2. NPC 击败后,从 `npcState.inventory` 里按玩家收益排序取高价值物品
这里的核心是:
**当前系统已经把“掉落”统一成库存消费问题,而不是单独的一套特殊奖励系统。**
## 4.5 拆解 / 合成 / 锻造 / 重铸
`src/data/forgeSystem.ts` 已经形成第二类运行时物品生成入口:
- `executeDismantleItem`
- 把装备拆成基础材料 + 标签精粹
- `executeForgeRecipe`
- 消耗材料生成成品装备
- `executeReforgeItem`
- 保留原物品基础上重投 build 标签并增强数值
这说明运行时物品系统已经不只是“掉落 -> 使用”,而是进入了:
**掉落 -> 持有 -> 拆解 -> 再生产 -> build 迭代**
的循环。
## 5. 当前物品如何进入玩法结算
## 5.1 装备生效
`src/data/equipmentEffects.ts` 会把 `EquipmentLoadout` 汇总为:
- `maxHpBonus`
- `maxManaBonus`
- `outgoingDamageMultiplier`
- `incomingDamageMultiplier`
当前实现已经会优先读取 `statProfile`,没有时才走 rarity fallback。
这意味着:
- 装备的直接数值提升已经真实生效
- 不是只在 UI 显示
## 5.2 build 标签生效
`src/data/buildTags.ts` + `src/data/buildDamage.ts` 已经形成完整 build 入口:
- 角色 `combatTags`
- 装备 `buildProfile.tags`
- 套装标签
- 限时 `TimedBuildBuff`
会被统一整理为激活标签集,再计算 build 伤害乘区。
当前 build 标签来源已经包括:
- 角色
- 怪物
- 装备
- 套装
- 消耗品/技能 buff
## 5.3 消耗品生效
`src/data/inventoryEffects.ts` + `src/hooks/useInventoryFlow.ts` 会在使用物品时:
- 恢复 HP
- 恢复 Mana
- 推进技能冷却
- 追加 `activeBuildBuffs`
这意味着当前系统已经存在:
- **直接恢复型物品**
- **节奏调整型物品**
- **限时 build 强化型物品**
三种雏形。
## 6. 当前 AI 在物品系统里的角色
当前 AI 与物品系统的关系主要有两种:
## 6.1 自定义世界“离线式”生成
`src/services/customWorld.ts` + `src/services/customWorldBuilder.ts` 会让 AI 生成:
- 世界名
- playable NPC
- story NPC
- 关键物品样本
- 地标
然后本地再把这些骨架扩展成更大的世界档案。
这时 AI 的角色是:
**提供世界观语义骨架,而不是直接在单次 encounter 里临场造出一个可结算物品。**
## 6.2 运行时叙事包装
`prompt.ts` 和相关 story flow 里AI 主要负责:
- 剧情文本
- 对话
- 选项文案
- 氛围描述
但当前 AI 不负责:
- 直接返回结构化物品
- 决定物品数值是否合法
- 决定 build 标签是否合法
- 决定库存如何变更
这与仓库已有开发经验文档里的原则一致:
**AI 负责解释世界,本地规则负责改动世界。**
## 7. 当前系统的优点
## 7.1 已有统一物品骨架
`InventoryItem` 已经足够承载:
- 永久装备
- 消耗品
- build 标签
- 世界观描述
- 经济系统
后续不需要另起一套物品结构。
## 7.2 已有 build 玩法骨架
当前系统已经支持:
- 装备 build 标签
- 套装 build 标签
- 消耗品限时 build buff
- 角色/怪物 combatTags
这让“物品影响 build”不再只是概念。
## 7.3 已有多个运行时入口
当前物品已经能从这些入口进入游戏:
- 初始背包
- 初始装备
- NPC 库存
- 宝藏
- 怪物掉落
- 击败 NPC
- 合成
- 拆解
- 锻造
- 重铸
- 自定义世界程序化生成
系统入口已经比较完整。
## 7.4 本地规则边界明确
当前实现最大的稳定性来源,是物品最终由本地规则落库和结算:
- 可测试
- 可复现
- 可存档兼容
- 不依赖模型临场稳定性
这非常适合继续向 AI 原生玩法演化。
## 8. 当前系统的主要缺口
## 8.1 非自定义世界的运行时发放仍偏模板池
当前普通世界的宝藏、NPC 库存、基础奖励,更多还是:
- 世界模板
- 身份模板
- 怪物 preset
而不是根据以下上下文动态拼装:
- 当前场景背景
- 当前 NPC 动机
- 当前事件阶段
- 最近剧情行为
- 玩家当前 build 缺口
## 8.2 宝藏与物品的叙事绑定不够深
当前宝藏奖励会根据世界类型变化,但还没有强绑定:
- 地标
- scene preset
- treasure hint
- 相关 NPC
- 最近发生的事件
所以“玩法可用”,但“故事贴脸感”还不够强。
## 8.3 自定义世界运行时物品偏“主题生成”,还不是“关系生成”
`customWorldRuntime.ts` 已经能做:
- 世界主题相关
- 标签/关键词相关
- 角色用途相关
但还没有直接把以下关系结构编进物品:
- 这个物品和哪个 NPC 有关系
- 为什么在这个时刻出现
- 它与哪个任务/线索绑定
- 它是否属于某个 faction / 场景 / 地标
## 8.4 一些运行时奖励没有补足完整 build 元数据
例如部分宝藏奖励和 NPC 模板奖励,当前只是简单 `InventoryItem`
-`category / rarity / tags`
- 但未必有完整 `statProfile / useProfile / buildProfile`
这会导致它们更像资源或商品,而不是强 build 物品。
## 8.5 缺少“物品生成导演层”
当前系统缺的不是单个函数,而是一层明确的运行时物品导演:
- 输入当前上下文
- 决定掉落/奖励/商店/赠礼候选
- 决定叙事来源
- 决定 build 倾向
- 决定是永久收益还是限时收益
- 决定数值预算
这层目前分散在:
- `treasureInteractions.ts`
- `npcInteractions.ts`
- `customWorldRuntime.ts`
- `forgeSystem.ts`
之间,还没有统一起来。
## 9. 对当前系统的结论
当前仓库里的“运行时物品生成系统”已经不是空白,反而已经具备了很好的扩展前提:
- 有统一物品数据结构
- 有 build 标签体系
- 有限时 buff 体系
- 有装备/消耗品/材料/稀有品的分类
- 有宝藏、NPC、掉落、锻造等运行时入口
- 有自定义世界程序化物品能力
- 有明确的“AI 叙事、本地规则结算”边界
但它现在更像:
**“规则系统已经就位AI 原生上下文驱动物品导演还没补上。”**
后续如果要继续往 AI 原生游戏推进,最值得补的不是推翻现有系统,而是:
1. 在现有 `InventoryItem` 体系上增加上下文生成层。
2. 让物品生成同时读取场景、NPC、剧情、build 缺口。
3. 让 AI 负责物品语义与叙事来源,本地规则负责编译成可结算物品。
4. 把宝藏、NPC 交易、任务奖励、掉落统一接入同一套“运行时物品导演”。

View File

@@ -0,0 +1,412 @@
# TXT 模式核心玩法 PRD2026-04-20
更新时间:`2026-04-20`
## 0. 文档目的
这份 PRD 只定义 `Interactive-fiction-frontend` + `Interactive-fiction-backend` 中 TXT 模式在 `Genarrative` 落地时的**核心玩法闭环**。
这次明确**不讨论平台层功能**,包括但不限于:
1. 平台首页
2. 平台详情页
3. 平台广场
4. 平台作品库
5. 平台浏览历史
6. 平台钱包与扣费落地
7. 平台统一存档页
8. 平台账号与公开态策略
本稿只关心一件事:
**把外部仓库 TXT 模式最小可玩的创作与运行闭环原样迁入,形成一个可以独立验证的视觉小说核心玩法。**
---
## 1. 一句话定义
TXT 模式核心玩法是一个包含“创作编辑器 -> 测试体验 -> 正式运行 -> 多槽位存档 -> 历史重生成”的视觉小说玩法闭环。
---
## 2. 本次目标
本次只做下面这些核心目标:
1. 支持创建 TXT 模式作品。
2. 支持 TXT 模式作品的完整创作流程。
3. 支持创作者测试体验。
4. 支持玩家正式游玩。
5. 支持文本模式运行。
6. 支持双会话机制。
7. 支持 5 槽位存档。
8. 支持通过 `saveId` 读档创建会话。
9. 支持历史记录查看。
10. 支持历史重生成。
11. 保留外部 TXT 模式提示词正文与功能需求,不改词、不改规则。
12. 仅替换文本生成接口与生图接口为本项目现有能力。
---
## 3. 明确不做
本次 PRD 明确不做下面这些事:
1. 不做平台首页融合。
2. 不做平台详情页融合。
3. 不做平台广场、作品库、公开浏览。
4. 不做平台浏览历史。
5. 不做平台统一钱包与扣费实现。
6. 不做平台统一存档页。
7. 不做回放。
8. 不做平台层账户策略改造。
9. 不做其它玩法的统一抽象。
10. 不把 TXT 模式扩展成平台总线工程。
一句话约束:
**先把 TXT 模式本体做成,再谈平台层融合。**
---
## 4. 核心范围
## 4.1 创作链路
本次必须完整保留外部 TXT 模式创作主链:
1. 选择 TXT 模式。
2. 进入创作编辑器。
3. 通过以下方式之一创建底稿:
- 文档上传
- 一句话生成
- 空白创建
4. 编辑以下内容:
- 世界观
- 角色
- 场景
5. 发起测试体验。
6. 完成作品保存。
## 4.2 运行链路
本次必须完整保留外部 TXT 模式运行主链:
1. 新的开始
2. 继续体验
3. 读取存档
4. 进入运行时页面
5. 普通模式 / 文本模式
6. 历史记录
7. 存档管理
8. 设置
9. 属性面板白名单
10. 历史重生成
---
## 5. 核心玩法冻结边界
后续实现时,以下内容必须按外部 TXT 模式原样保留:
1. 编辑器步骤顺序。
2. 双会话机制。
3. 流式动作协议事件:
- `start`
- `raw_text`
- `step`
- `complete`
- `data`
- `error`
- `done`
4. 5 槽位存档。
5. 通过 `saveId` 读档创建会话。
6. 存档载荷中的:
- `stateLite`
- `historyTail`
7. 历史重生成语义。
8. 属性面板白名单。
9. 默认主 prompt 选择语义。
10. prompt 正文。
---
## 6. 创作编辑器需求
## 6.1 创建方式
编辑器必须支持 3 种创建方式:
1. 上传文档
2. 一句话生成
3. 空白创建
三者都必须进入同一套 TXT 模式编辑器,而不是三套分裂流程。
## 6.2 编辑器模块
编辑器至少必须包含以下模块:
1. 世界观编辑
2. 角色编辑
3. 场景编辑
4. 测试体验入口
5. 保存/发布前准备入口
## 6.3 前后端边界
编辑器侧遵守下面这条边界:
1. 前端只负责编辑器表现与输入采集。
2. 作品结构校验、编译、测试会话创建、正式数据写入由后端负责。
---
## 7. 双会话机制
TXT 模式核心玩法必须完整保留双会话机制。
## 7.1 玩家游玩会话
玩家游玩会话用于:
1. 正式开始作品
2. 正式继续体验
3. 正式游玩推进
## 7.2 创作者测试/读档会话
创作者测试/读档会话用于:
1. 编辑器内测试体验
2. 指定存档加载
3. 非正式发布态验证
## 7.3 禁止简化
禁止把这两类会话合并成一类“统一 session”。
---
## 8. 运行时页面需求
## 8.1 页面能力面
运行时页面至少要有:
1. 普通模式
2. 文本模式
3. 历史记录面板
4. 存档面板
5. 设置面板
6. 属性面板
## 8.2 文本模式
文本模式必须按外部 TXT 模式语义保留:
1. 独立于普通模式的显示区域
2. 与运行时主状态同步
3. 可消费流式动作结果
## 8.3 属性面板
属性面板必须保留外部 TXT 模式的白名单语义:
1. 白名单用户显示
2. 非白名单用户不显示
---
## 9. 流式动作协议
TXT 模式核心玩法必须保留外部流式动作协议。
## 9.1 事件类型
服务端必须推送下列事件:
1. `start`
2. `raw_text`
3. `step`
4. `complete`
5. `data`
6. `error`
7. `done`
## 9.2 前端职责
前端只负责:
1. 发起动作请求
2. 解析流式事件
3. 渲染逐步结果
前端不负责:
1. 本地推进正式运行状态
2. 本地拼接替代结果
---
## 10. 存档机制
## 10.1 槽位规则
每个作品最多保留 5 个槽位。
必须支持:
1. 新建存档
2. 覆盖存档
3. 读取指定槽位
## 10.2 存档载荷
存档内容不能只有摘要,至少必须包含:
1. `stateLite`
2. `historyTail`
## 10.3 读档语义
读取存档不是恢复前端本地状态,而是:
1. 传入 `saveId`
2. 由后端创建新的测试/读档会话
3. 前端消费会话结果
---
## 11. 历史机制
## 11.1 历史记录
运行时必须支持查看已有历史记录。
## 11.2 历史重生成
运行时必须支持历史重生成。
其语义必须是:
1. 用户选择某个历史节点
2. 服务端基于该节点上下文重新生成后续
3. 新结果成为新的有效运行轨迹
禁止把它简化成普通“再来一次下一步”。
---
## 12. 提示词与模型调用
## 12.1 Prompt 规则
后续实现时必须遵守:
1. 外部 TXT 模式 prompt 正文不改。
2. 外部 TXT 模式 prompt 规则不改。
3. 默认 prompt 选择语义不改。
## 12.2 允许替换的部分
只允许替换下面两项底层能力:
1. 文本生成接口
- 替换为 `server-node/src/services/llmClient.ts`
2. 生图接口
- 替换为 `server-node/src/services/sceneImageService.ts`
除此之外,不允许借“接入本项目能力”之名修改玩法需求。
---
## 13. 核心后端职责
TXT 模式核心玩法的正式运行真相必须在后端。
后端至少负责:
1. 会话创建
2. prompt 装载与上下文拼接
3. 流式动作生成
4. 存档读写
5. `saveId` 读档会话创建
6. 历史重生成
7. 属性白名单裁决
---
## 14. 核心前端职责
前端只负责:
1. 编辑器页面表现
2. 运行时页面表现
3. 文本模式显示
4. 流式事件解析
5. 历史/存档/设置面板打开与关闭
前端不负责:
1. 正式运行时结算
2. 会话语义判定
3. 存档内容拼接
4. 历史重生成裁决
---
## 15. 建议影响文件
本次核心玩法落地,优先会影响下面这些区域:
前端:
1. `src/components/game-shell/PlatformCreationTypeModal.tsx`
2. `src/services/aiService.ts`
3. 新增 TXT 模式编辑器页面或模块
4. 新增 TXT 模式运行时页面或模块
5. 新增 TXT 模式 SSE 解析模块
后端:
1. `server-node/src/routes/runtimeRoutes.ts`
2. `server-node/src/services/llmClient.ts`
3. `server-node/src/services/sceneImageService.ts`
4. `server-node/src/repositories/runtimeRepository.ts`
5. `server-node/src/prompts/`
6. 新增 TXT 模式 services / contracts / repository modules
---
## 16. 验收标准
满足下面这些结果时,视为核心玩法闭环成立:
1. 可以创建 TXT 模式作品。
2. 可以通过上传文档、一句话生成、空白创建进入同一编辑器。
3. 编辑器可编辑世界观、角色、场景。
4. 编辑器内可发起测试体验。
5. 可创建正式游玩会话。
6. 可创建测试/读档会话。
7. 运行时支持普通模式与文本模式。
8. 流式动作协议按外部事件名工作。
9. 可查看历史记录。
10. 可执行历史重生成。
11. 支持 5 槽位存档。
12. 支持通过 `saveId` 读档创建会话。
13. 存档包含 `stateLite + historyTail`
14. 属性面板白名单逻辑生效。
15. prompt 正文与功能需求未被改写。
---
## 17. 本稿结论
这次先不要把 TXT 模式做成平台工程。
先把下面这条链做通:
**创建 TXT 作品 -> 编辑世界/角色/场景 -> 测试体验 -> 正式游玩 -> 文本模式 -> 多槽位存档 -> 历史重生成**
只要这条链通了TXT 模式核心玩法就成立;平台层融合、详情页整合、钱包接入、统一存档页,都可以放到下一阶段再做。