1
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
# Custom World Agent 大模型对话恢复设计
|
||||
|
||||
日期:`2026-04-22`
|
||||
|
||||
## 1. 背景
|
||||
|
||||
当前 Rust `server-rs` 里的 Custom World Agent 聊天链路已经接上了会话、消息、operation 与 SSE 外壳,但**并没有真正调用大模型生成聊天回复**。
|
||||
|
||||
现状问题:
|
||||
|
||||
1. `submit_custom_world_agent_message` 在 `spacetime-module` 中直接写死 assistant 回复。
|
||||
2. `/api/runtime/custom-world/agent/sessions/:sessionId/messages/stream` 只是把最后一条 assistant 文案一次性回放给前端。
|
||||
3. 旧 `server-node` 已经实现过完整的大模型单轮推理链,包括:
|
||||
- 动态状态识别
|
||||
- 原样提示词拼装
|
||||
- 流式 `replyText` 截取
|
||||
- 回合结束后的 anchor / creator intent / readiness / clarification / suggested action 派生
|
||||
|
||||
用户本轮要求是:
|
||||
|
||||
1. 恢复 Agent 聊天对话使用大模型推理生成回复。
|
||||
2. 把之前 Node 的提示词和后台流程恢复到 Rust 后端。
|
||||
3. **禁止修改提示词正文。**
|
||||
|
||||
## 2. 目标
|
||||
|
||||
本轮只恢复 Custom World Agent 聊天主链的真实推理闭环:
|
||||
|
||||
1. 用户发消息后,assistant 回复必须来自大模型。
|
||||
2. SSE `reply_delta` 必须来自真实流式推理增量。
|
||||
3. 回合结束后要把 session 派生状态一次性回写到 SpacetimeDB。
|
||||
4. 旧 Node `eightAnchorPrompts.ts` 的提示词正文保持原样,不改中文文案。
|
||||
|
||||
## 3. 约束
|
||||
|
||||
### 3.1 SpacetimeDB 约束
|
||||
|
||||
SpacetimeDB reducer / procedure 必须保持确定性,因此:
|
||||
|
||||
1. 禁止在 `spacetime-module` 内直接发起 LLM 网络请求。
|
||||
2. LLM 调用必须放在 `api-server`。
|
||||
3. `spacetime-module` 只负责提交消息、记录 operation、回写最终结果。
|
||||
|
||||
### 3.2 提示词冻结约束
|
||||
|
||||
本轮严格复用旧 Node 的以下提示词内容:
|
||||
|
||||
1. `server-node/src/prompts/eightAnchorPrompts.ts`
|
||||
2. `BASE_SYSTEM_PROMPT`
|
||||
3. `GLOBAL_HARD_RULES`
|
||||
4. `MODE_RULES`
|
||||
5. `USER_SIGNAL_RULES`
|
||||
6. `QUICK_FILL_EXTRA_RULES`
|
||||
7. `STATE_INFERENCE_SYSTEM_PROMPT`
|
||||
8. `STATE_INFERENCE_OUTPUT_CONTRACT`
|
||||
9. `OUTPUT_CONTRACT_REMINDER`
|
||||
|
||||
允许做的只有:
|
||||
|
||||
1. Rust 字符串字面量搬运
|
||||
2. Rust 函数式重组
|
||||
3. Rust/Serde 语法等价改写
|
||||
|
||||
不允许:
|
||||
|
||||
1. 修改提示词正文
|
||||
2. 调整规则措辞
|
||||
3. 替换成新的 prompt 版本
|
||||
|
||||
## 4. 目标链路
|
||||
|
||||
恢复后的消息链路改成两阶段:
|
||||
|
||||
### 4.1 阶段 A:提交消息
|
||||
|
||||
`submit_custom_world_agent_message`
|
||||
|
||||
职责:
|
||||
|
||||
1. 校验 session / message / operation id。
|
||||
2. 只写入 user message。
|
||||
3. 创建 `process_message` operation。
|
||||
4. operation 初始状态写为 `running`。
|
||||
5. 不直接写 assistant message。
|
||||
6. 不直接推进 progress / stage / current_turn。
|
||||
|
||||
### 4.2 阶段 B:完成单轮推理
|
||||
|
||||
`finalize_custom_world_agent_message_turn`
|
||||
|
||||
职责:
|
||||
|
||||
1. 校验 session 与 operation 所属关系。
|
||||
2. 追加 assistant message。
|
||||
3. 回写 session 聚合字段:
|
||||
- `current_turn`
|
||||
- `progress_percent`
|
||||
- `stage`
|
||||
- `focus_card_id`
|
||||
- `anchor_content_json`
|
||||
- `creator_intent_json`
|
||||
- `creator_intent_readiness_json`
|
||||
- `anchor_pack_json`
|
||||
- `draft_profile_json`
|
||||
- `last_assistant_reply`
|
||||
- `pending_clarifications_json`
|
||||
- `suggested_actions_json`
|
||||
- `recommended_replies_json`
|
||||
- `quality_findings_json`
|
||||
- `asset_coverage_json`
|
||||
3. 更新对应 operation 为 `completed` 或 `failed`。
|
||||
|
||||
## 5. `api-server` 责任
|
||||
|
||||
`api-server` 新增 Custom World Agent turn service,负责:
|
||||
|
||||
1. 读取当前 session 快照。
|
||||
2. 按旧 Node 逻辑构造 chat history。
|
||||
3. 先走“动态状态识别”推理。
|
||||
4. 再走“正式单轮输出”推理。
|
||||
5. 流式阶段从 JSON 片段里增量截取 `replyText`,持续往 SSE 发 `reply_delta`。
|
||||
6. 回合结束后派生:
|
||||
- creator intent
|
||||
- readiness
|
||||
- pending clarifications
|
||||
- suggested actions
|
||||
- anchor pack
|
||||
- draft profile
|
||||
- quality findings
|
||||
- asset coverage
|
||||
7. 最后调用 SpacetimeDB finalize procedure 回写真相。
|
||||
|
||||
## 6. 旧 Node 逻辑恢复范围
|
||||
|
||||
本轮恢复以下旧 Node 行为:
|
||||
|
||||
1. `eightAnchorPrompts.ts`
|
||||
2. `eightAnchorSingleTurnService.ts`
|
||||
3. `customWorldAgentMessageTurnService.ts`
|
||||
4. `customWorldAgentClarificationService.ts`
|
||||
5. `customWorldAgentIntentExtractionService.ts`
|
||||
6. `customWorldAgentSuggestedActionService.ts`
|
||||
7. `eightAnchorCompatibilityService.ts` 中聊天链需要的 anchor / progress 派生
|
||||
|
||||
本轮不强制一比一恢复整条结果页重编译链,只恢复聊天链真正依赖的最小派生结果。
|
||||
|
||||
## 7. SSE 口径
|
||||
|
||||
恢复后 `/messages/stream` 必须按以下顺序输出:
|
||||
|
||||
1. 多个 `reply_delta`
|
||||
2. 一个 `session`
|
||||
3. 一个 `done`
|
||||
|
||||
错误时输出:
|
||||
|
||||
1. `error`
|
||||
|
||||
要求:
|
||||
|
||||
1. `reply_delta.text` 来源于 `platform-llm.stream_text(...)` 的真实增量。
|
||||
2. `session` 必须来自 finalize 完成后的最新 session 真相。
|
||||
|
||||
## 8. 验收
|
||||
|
||||
1. 用户发一条 Agent 消息后,assistant 回复不再是固定文案。
|
||||
2. `quickFillRequested=true` 时,推理结果仍遵循旧 Node 的 `force_complete` 逻辑。
|
||||
3. SSE 能先看到逐步增长的 `reply_delta`,而不是一次性整段返回。
|
||||
4. finalize 完成后,前端拿到的 session 中:
|
||||
- `lastAssistantReply`
|
||||
- `messages`
|
||||
- `currentTurn`
|
||||
- `progressPercent`
|
||||
- `stage`
|
||||
- `pendingClarifications`
|
||||
- `suggestedActions`
|
||||
已被真实更新。
|
||||
5. 提示词正文未被改写。
|
||||
|
||||
@@ -99,10 +99,9 @@
|
||||
这次实际是前后端两层边界叠加:
|
||||
|
||||
1. Node 代理路由 `server-node/src/routes/puzzleProxyRoutes.ts` 已经完成外层 JWT 校验,并把用户 id 通过内部转发头带给 Rust API。
|
||||
2. Rust API `server-rs/crates/api-server/src/auth.rs` 之前只允许 `big-fish` 路径信任这类内部转发头,没有把 `/api/runtime/puzzle/**` 纳入白名单。
|
||||
3. 因此拼图代理链路会在 Node 首层通过后,Rust 二跳再次因为“缺少 Bearer”返回 `401`。
|
||||
4. 前端 `fetchWithApiAuth(...)` 在“首个 401 -> refresh 成功 -> 重试后的业务请求仍 401”时,又会把刚刷新到的 token 清掉并广播一次全局鉴权变更。
|
||||
5. `AuthGate` 监听到事件后重新 hydrate,平台入口又重新预取拼图作品列表,于是形成循环。
|
||||
2. Rust API `server-rs/crates/api-server/src/auth.rs` 现已允许 `/api/runtime/puzzle/**` 复用内部已鉴权转发头;如果本地进程未重启到新代码,仍可能出现旧行为。
|
||||
3. 前端 `fetchWithApiAuth(...)` 在“首个 401 -> refresh 成功 -> 重试后的业务请求仍 401”时,旧实现会把刚刷新到的 token 清掉并广播一次全局鉴权变更。
|
||||
4. `AuthGate` 监听到事件后重新 hydrate,平台入口又重新预取拼图作品列表,于是形成循环。
|
||||
|
||||
### 6.3 修复策略
|
||||
|
||||
@@ -110,7 +109,8 @@
|
||||
- `/api/runtime/big-fish/**`
|
||||
- `/api/runtime/puzzle/**`
|
||||
2. 前端 `fetchWithApiAuth(...)` 调整 401 后置处理:
|
||||
- 只有“尚未尝试 refresh”的 401,才清 token 并广播鉴权变化
|
||||
- refresh 成功后不再立即广播全局鉴权变化
|
||||
- 只有“尚未尝试 refresh 且最终确认登录态失效”的 401,才清 token 并广播鉴权变化
|
||||
- 若 refresh 已成功,但重试请求仍返回 401,则保留新 token,把失败收敛为当前业务请求自身错误
|
||||
3. 补充请求层回归测试,覆盖“refresh 成功但重试仍 401”的场景。
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
## 文档列表
|
||||
|
||||
- [CUSTOM_WORLD_AGENT_LLM_REPLY_RESTORE_2026-04-22.md](./CUSTOM_WORLD_AGENT_LLM_REPLY_RESTORE_2026-04-22.md):恢复 Custom World Agent 聊天必须走大模型推理的 Rust 落地方案,冻结 submit/finalize 两阶段职责、旧 Node 提示词原样搬运、SSE 流式回复与 session 回写边界。
|
||||
- [CREATION_HUB_CARD_ACTIONS_2026-04-22.md](./CREATION_HUB_CARD_ACTIONS_2026-04-22.md):冻结创作中心作品卡“体验 / 删除”入口的最小落地语义,明确 RPG 已发布作品软删除、卡片直达运行时,以及暂不扩草稿 / 拼图删除契约。
|
||||
- [CREATION_CATEGORY_OPENING_TIMEOUT_GUARD_FIX_2026-04-22.md](./CREATION_CATEGORY_OPENING_TIMEOUT_GUARD_FIX_2026-04-22.md):记录创作中心点击类别后长时间停留在“正在开启”的根因与修复口径,收口前端创建会话启动超时、中文错误提示以及 Big Fish / 拼图代理上游超时兜底。
|
||||
- [RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md](./RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md):冻结 Rust 本地一键联调脚本与 Ubuntu 发布包构建脚本的执行口径,覆盖 `npm run dev:rust`、`npm run build:rust:ubuntu`、Vite release、Linux `api-server`、SpacetimeDB wasm、启动停止脚本、默认 scp 上传和安全清库开关。
|
||||
|
||||
Reference in New Issue
Block a user