3.9 KiB
3.9 KiB
AI 生成过程草稿持久化设计(2026-04-24)
1. 背景
当前创作类模板已经具备 session / message / operation 级别的最终态落库能力,但部分流式生成只把模型增量推给前端。若 HTTP/SSE 连接、浏览器页面或 LLM 请求在最终解析前中断,用户只能看到短暂流式文本,服务端缺少可恢复的生成中间态。
本设计补齐“生成过程中已经生成的内容必须持续持久化”的机制,并要求该机制对所有创作模板统一生效。
2. 目标
- 每次模板生成开始前创建或绑定一个
ai_task。 - 模型每次产出可见文本增量时,写入
ai_text_chunk,并同步更新ai_task.latest_text_output与对应 stage 的text_output。 - 生成失败或连接中断时,不丢弃已经落库的 chunk;后续可用
ai_task.latest_text_output作为续写上下文。 - 成功解析并 finalize 后,将最终结构化结果继续写回各模板原有 session 表,保持现有业务快照不变。
3. 统一落库边界
3.1 真相表
ai_task:记录一次模板生成任务的业务来源、状态、最新聚合文本、结构化结果。ai_task_stage:记录模板生成阶段状态;当前创作对话统一使用DraftGeneration。ai_text_chunk:按sequence追加保存模型增量文本,是断点恢复的最小粒度。
3.2 适用模板
- 自定义世界创作 Agent。
- 解谜游戏创作 Agent。
- 大鱼吃小鱼创作 Agent。
- 后续新增模板必须复用同一生成草稿持久化工具,不允许只在 UI 内存保存流式文本。
4. 续写策略
- 发起生成时,后端根据
template_key + session_id + operation_id创建稳定task_id。 - LLM 流式回调收到
replyText的最新可见文本后,计算相对上一次文本的增量;只有非空增量写入ai_text_chunk。 - 写入失败不应阻断当前生成主流程,但必须记录 warn 日志,避免因持久化瞬时失败导致用户生成直接失败。
- 若最终解析失败,
ai_task保持Running或显式Failed,已写入的latest_text_output仍可作为下一轮 prompt 的“已生成草稿”。 - 下一轮续写 prompt 应优先带上最近未完成任务的
latest_text_output;本次先落地服务端 chunk 持久化能力,后续模板 prompt 可逐步消费该草稿。
5. 编码要求
- 持久化逻辑放在
server-rs/crates/api-server的通用工具中,由各模板路由接入。 - 不引入
server-node兼容分支。 - SpacetimeDB 写入必须通过
spacetime-client已生成绑定,不在 reducer 中访问网络或文件系统。 - 所有新增 Rust 代码保留中文注释,且只做局部修改,避免重写包含中文的大文件。
6. 失败排查原文日志
- RPG 草稿生成链路的模型输入与模型输出原文日志统一收口在
platform-llm网关层,避免每个模板调用点重复实现。 - 只有发生请求失败、上游非 2xx、响应读取失败、JSON/SSE 解析失败或空响应时,才将本次模型输入与已拿到的模型输出原文分别写入文件;正常成功生成不默认落盘原文,避免日志体积不可控。
- 日志目录默认使用仓库运行目录下的
logs/llm-raw,可通过LLM_RAW_LOG_DIR覆盖;每次失败写成同一 trace 前缀下的*.input.json与*.output.txt两个 UTF-8 文件。 *.input.json记录 provider、model、stream、attempt、maxTokens 与完整 messages;*.output.txt记录上游 HTTP 原文、非流式响应原文、SSE 原始事件文本,或请求尚未到达上游时的错误摘要。- 文件名只使用时间戳、进程号、递增序号与安全化错误阶段,不包含用户输入、sessionId 或 API key;输入 JSON 不写入 API key。
- 文件日志失败只写 warn,不影响草稿生成主错误返回;该日志仅用于本地开发与排障,不作为 SpacetimeDB 真相态。