Files
Genarrative/docs/prd/AI_NATIVE_QUEST_SYSTEM_PRD_2026-04-02.md
高物 c49c64896a
Some checks failed
CI / verify (push) Has been cancelled
初始仓库迁移
2026-04-04 23:57:06 +08:00

21 KiB
Raw Blame History

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 任务上下文采样层

先从当前运行时抽取一个统一的任务上下文:

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 只返回“任务意图”,而不是最终任务实例:

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 编译出真正可执行的任务合约:

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 任务运行时推进层

运行时只认本地任务合约和事件。

建议新增统一的任务推进事件:

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 新增任务元数据

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

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 扩展任务状态

建议未来把任务状态扩展为:

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 返回格式建议如下:

{
  "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

type QuestOpportunity = {
  shouldOffer: boolean;
  reason: string;
  suggestedIssuerNpcId?: string;
  suggestedThreatType?: "monster" | "treasure" | "relationship" | "travel";
};

这层先判断“该不该生成”,再决定“交给 AI 生成什么”。

这样能避免模型过度产出任务。

8. 任务推进设计

8.1 从“单字段进度”升级到“步骤机”

当前任务推进是:

  • 一个 objective
  • 一个 progress

建议升级为:

  • 多 step
  • 每个 step 自己推进
  • active step 决定当前 UI 展示

例如:

[
  {
    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 原生游戏真正该有的任务结构