# 拼图 Agent 聊天接入大模型设计 日期:`2026-04-23` ## 1. 背景 当前拼图创作链已经具备: 1. `PuzzleAgentWorkspace` 前端聊天壳层 2. Rust `api-server` 的 `submit / stream / action` HTTP facade 3. `spacetime-module` 的 `puzzle_agent_session / puzzle_agent_message` 真相表 4. `module-puzzle` 的锚点推断、草稿编译、发布校验与运行态规则 但 `submit_puzzle_agent_message` 仍然是 deterministic 占位逻辑: 1. 用户发言后,`spacetime-module` 直接推断 `anchor_pack` 2. 同一事务里直接写入固定 assistant 总结文案 3. SSE `/messages/stream` 只是把 `last_assistant_reply` 一次性回放给前端 这导致拼图 Agent 看起来有聊天面板,但没有真实 LLM 共创能力。 ## 2. 目标 本轮只恢复拼图 Agent 聊天主链的真实 LLM 接入,不扩到图片模型和复杂多阶段编排: 1. 用户发消息后,assistant 回复必须来自 LLM 2. LLM 输出必须同时产出: - `replyText` - `progressPercent` - `nextAnchorPack` 3. SSE `reply_delta` 必须来自真实流式增量解析 4. finalize 后一次性回写最新 session 真相 5. LLM 不可用或解析失败时,不再写固定 assistant 假回复 ## 3. 分层边界 ### 3.1 `module-puzzle` 只负责: 1. `PuzzleAnchorPack`、`PuzzleCreatorIntent`、`PuzzleResultDraft` 纯领域模型 2. 锚点清洗、草稿编译、发布校验 3. 运行态拼图规则 明确不负责: 1. 网络请求 2. LLM prompt 组织 3. SSE 推流 ### 3.2 `spacetime-module` 只负责: 1. `submit_puzzle_agent_message` - 校验 session / ownership / message id - 只写入 user message - 不再直接写 assistant message - 不再直接推进 `current_turn / progress_percent / anchor_pack_json` 2. `finalize_puzzle_agent_message_turn` - 追加 assistant message - 覆盖 `anchor_pack_json` - 回写 `current_turn / progress_percent / stage / last_assistant_reply / updated_at` ### 3.3 `api-server` 负责: 1. 读取拼图 session 快照 2. 组织 LLM prompt 3. 流式截取 `replyText` 4. 回合结束后组装 finalize 输入 5. 调用 SpacetimeDB finalize procedure ## 4. 目标链路 ### 4.1 阶段 A:提交消息 `submit_puzzle_agent_message` 职责: 1. 写入 user message 2. 返回 submit 后的 session 快照 3. 该快照中尚未新增 assistant message 4. 该快照中的 `anchorPack / progressPercent / currentTurn` 保持提交前真相 ### 4.2 阶段 B:完成单轮推理 `finalize_puzzle_agent_message_turn` 职责: 1. 追加 assistant message 2. 回写: - `current_turn` - `progress_percent` - `stage` - `anchor_pack_json` - `last_assistant_reply` - `updated_at` 3. 若已存在 `draft_json`,允许继续保留,不在聊天 finalize 中改写结果页草稿 ## 5. LLM 输出契约 拼图聊天不需要复刻 Custom World 那么重的多层结构,本轮冻结为单个 JSON: ```json { "replyText": "我已经收住画面方向了,接下来你更想强调夜雨反光,还是猫咪本身的奇幻感?", "progressPercent": 46, "nextAnchorPack": { "themePromise": { "key": "themePromise", "label": "题材承诺", "value": "雨夜中的奇幻探索", "status": "confirmed" }, "visualSubject": { "key": "visualSubject", "label": "画面主体", "value": "发光猫咪站在遗迹台阶上", "status": "confirmed" }, "visualMood": { "key": "visualMood", "label": "视觉气质", "value": "潮湿、梦幻、带轻微悬疑", "status": "confirmed" }, "compositionHooks": { "key": "compositionHooks", "label": "拼图记忆点", "value": "台阶透视、倒影、远处遗迹门洞", "status": "inferred" }, "tagsAndForbidden": { "key": "tagsAndForbidden", "label": "标签与禁忌", "value": "雨夜、猫咪、神庙遗迹;禁止文字水印", "status": "inferred" } } } ``` 要求: 1. 只能输出 JSON 2. `progressPercent` 范围固定 `0..100` 3. `nextAnchorPack` 必须是完整对象,不允许只给增量 patch ## 6. Prompt 设计 本轮不追求“复杂创作状态识别器”,只做拼图场景最小可用 prompt: 1. system prompt 明确模型角色是“拼图视觉共创策划” 2. 明确 5 个锚点: - 题材承诺 - 画面主体 - 视觉气质 - 拼图记忆点 - 标签与禁忌 3. 明确回复必须: - 自然中文 - 一次只推进一个最关键问题 - 不提“字段”“锚点”“JSON 结构”等内部词 4. user prompt 携带: - 当前 turn / progress - 当前 anchor pack - 最近聊天记录 - 输出 JSON 契约 ## 7. SSE 口径 `POST /api/runtime/puzzle/agent/sessions/:sessionId/messages/stream` 成功时按顺序输出: 1. 多个 `reply_delta` 2. 一个 `session` 3. 一个 `done` 失败时输出: 1. `error` 要求: 1. `reply_delta.text` 来自真实流式累计 `replyText` 2. `session` 必须来自 finalize 后重新读取的最新 session ## 8. 错误策略 1. 如果 `llm_client` 未配置: - 普通接口返回 `502` - SSE 返回 `error` - 不写 assistant message 2. 如果 LLM 响应解析失败: - 普通接口返回 `502` - SSE 返回 `error` - 只保留 user message 3. 如果 finalize 失败: - 普通接口返回 `502` - SSE 返回 `error` - 以前端重新拉 session 为准 ## 8.1 anchor pack 解析边界 `nextAnchorPack` 是 LLM 输出契约的一部分,字段名固定采用前端与 prompt 侧一致的 `camelCase`: 1. `themePromise` 2. `visualSubject` 3. `visualMood` 4. `compositionHooks` 5. `tagsAndForbidden` Rust 领域模型 `PuzzleAnchorPack` 仍保持 `theme_promise / visual_subject / visual_mood / composition_hooks / tags_and_forbidden`,不把 LLM 契约命名扩散到 `module-puzzle`。因此 `api-server` 的 `puzzle_agent_turn.rs` 必须在 LLM 边界显式把 `camelCase` anchor pack 翻译为 Rust 领域结构,再序列化给 SpacetimeDB finalize。 验收补充:真实 LLM 返回符合本文 `nextAnchorPack` 示例时,不应再触发“拼图 anchor pack 解析失败,请稍后重试。”。 ## 9. 实现清单 1. `module-puzzle` - 新增 `PuzzleAgentMessageFinalizeInput` 2. `spacetime-module/src/puzzle.rs` - 新增 `finalize_puzzle_agent_message_turn` - 修改 `submit_puzzle_agent_message` 3. `spacetime-client` - 刷新 Rust bindings - 新增 `finalize_puzzle_agent_message(...)` 4. `api-server` - 新增 `puzzle_agent_turn.rs` - `puzzle.rs` 的普通消息与 SSE 改接 turn service 5. `docs/technical/README.md` - 补入本文档索引 ## 10. 验收 1. 拼图 Agent 普通发送接口不再返回固定 assistant 文案 2. 拼图 Agent SSE 可看到逐步增长的 `reply_delta` 3. finalize 后 `session.messages` 中新增 assistant chat 消息 4. `session.anchorPack / progressPercent / currentTurn / lastAssistantReply` 已真实更新 5. LLM 关闭时不会再写入伪造 assistant 回复