# Runtime NPC 聊天 LLM 迁移设计(2026-04-25) ## 背景 当前 `server-rs/crates/api-server/src/runtime_chat.rs` 已承接 `POST /api/runtime/chat/npc/turn/stream`,但只返回确定性兜底文本。实际游戏聊天里,NPC 回复、下一轮建议、好感变化和限轮收束都应该沿用旧 Node 服务器的 LLM 编排。 ## 迁移源 本轮只参考旧 Node 已冻结实现,不恢复 `server-node` 服务,也不把前端切回 Express: 1. `server-node/src/prompts/chatPromptBuilders.ts` 2. `server-node/src/modules/ai/chatOrchestrator.ts` 3. `server-node/src/services/chatService.ts` 4. `packages/shared/src/contracts/rpgRuntimeChat.ts` 提示词常量必须原样迁移,禁止改写: 1. `NPC_CHAT_TURN_REPLY_SYSTEM_PROMPT` 2. `NPC_CHAT_TURN_SUGGESTION_SYSTEM_PROMPT` ## 本轮落地边界 1. Rust `api-server` 在同一路由内优先调用 `platform-llm`。 2. LLM 回复使用旧 Node 的 `buildNpcChatTurnReplyPrompt(...)` 等价构造逻辑,保持输入字段和中文上下文组织一致。 3. LLM 建议使用旧 Node 的 `buildNpcChatTurnSuggestionPrompt(...)` 等价构造逻辑,解析规则保持“最多 3 行、去掉编号/项目符号”。 4. 好感变化沿用旧 Node 的关键词打分规则: - 正向与负向关键词计分。 - 首聊无明显关键词时给 `+1`。 - 单轮变化限制在 `[-3, 3]`。 5. `chatDirective.forceExitAfterTurn / closingMode=foreshadow_close` 时不生成建议,返回空数组,并在 `complete.chatDirective.forceExit` 中显式告知前端退出。 6. LLM 未配置或失败时继续返回后端兜底 SSE,保证相遇和点击聊天链路不断。 7. 在 Node 已完成平台账号鉴权并通过内部密钥转发到 Rust API 的链路中,`/api/runtime/chat/` 必须纳入 Rust 内部转发鉴权白名单;否则 NPC 主动开场会在进入 `runtime_chat` handler 前被 401 拒绝,前端只能收到“NPC 聊天续写失败”。 ## 暂不落地 1. 暂不迁移 `maybeBuildPendingNpcQuestOffer(...)` 的完整 quest 生成链。 2. 暂不新增 SpacetimeDB reducer;本路由属于 Axum 侧 LLM 编排,SpacetimeDB reducer 仍保持确定性。 3. 暂不扩展前端 UI 文案。 ## 工程落点 1. 新增 `server-rs/crates/api-server/src/runtime_chat_prompt.rs` - 承载旧 Node 提示词常量。 - 承载 NPC 聊天 prompt builder 与轻量 JSON 读取 helper。 2. 修改 `server-rs/crates/api-server/src/runtime_chat.rs` - 注入 `State`。 - 优先 `LlmClient.stream_text(...)` 生成 `reply_delta`。 - 再调用 `request_text(...)` 生成建议。 - 计算 `affinityDelta / affinityText / chatDirective` 后输出 `complete`。 - SSE stream 返回给 Axum 时要求 `'static`,进入 stream 的玩家输入必须先转成 owned `String`,不能把 handler 栈上的 `&str` 借入 stream。 3. 修改 `server-rs/crates/api-server/src/auth.rs` - `allows_internal_forwarded_auth(...)` 允许 `/api/runtime/chat/`,与 big-fish、puzzle 的内部转发鉴权策略保持一致。 - 单测覆盖 `/api/runtime/chat/npc/turn/stream`,防止后续新增 runtime 路由时再次遗漏内部转发白名单。 4. 修改 `server-rs/crates/api-server/src/main.rs` - 注册 `runtime_chat_prompt` 模块。 ## 验收 1. `cargo fmt -p api-server` 2. `cargo check -p api-server` 3. `node scripts/check-encoding.mjs docs/technical/RUNTIME_NPC_CHAT_LLM_MIGRATION_2026-04-25.md server-rs/crates/api-server/src/auth.rs server-rs/crates/api-server/src/runtime_chat.rs server-rs/crates/api-server/src/runtime_chat_prompt.rs server-rs/crates/api-server/src/main.rs`