Files
Genarrative/docs/technical/PUZZLE_AGENT_LLM_REPLY_INTEGRATION_2026-04-23.md
kdletters cbc27bad4a
Some checks failed
CI / verify (push) Has been cancelled
init with react+axum+spacetimedb
2026-04-26 18:06:23 +08:00

6.9 KiB
Raw Permalink Blame History

拼图 Agent 聊天接入大模型设计

日期:2026-04-23

1. 背景

当前拼图创作链已经具备:

  1. PuzzleAgentWorkspace 前端聊天壳层
  2. Rust api-serversubmit / stream / action HTTP facade
  3. spacetime-modulepuzzle_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. PuzzleAnchorPackPuzzleCreatorIntentPuzzleResultDraft 纯领域模型
  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

{
  "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-serverpuzzle_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 回复