Files
Genarrative/docs/adr/【ADR】画布Agent会话消息存OSS-2026-07-03.md
k88936 f5368c825f Editor agent refactored (#76)
重构了editor agent.
使得它能进行多轮工具调用, 把工具调用的结果嵌入到上下文里。
对于上下文的图片, 使用哈希后的id用来引用,不暴露细节信息to llm。
当前实现, 状态直接维护在json doc里, 需要对整个doc加锁,任务目前只能串行。
把SSE改成一个简单请求( 因为生图工具耗时需要二次确认, 不需要再实时展示给用户进度)。
增加确认/取消生图操作。
把tool的参数和错误情况做了反馈。

TODO:  工具调用的规范/prompt还可以改进。

改用external job来做素材生成, 针对来自editor agent 的生成会把生成资产的引用加入到结果json里,
客户端轮询 external job 确定生成状态, 发现结束了或者失败了就 重新get 会话,后端重新提供会话的时候把 结果插入回会话历史里,用来让 ai 引用 以及显示

---------

Co-authored-by: 段舒康 <kdletters@qq.com>
Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/76
Reviewed-by: 段舒康 <kdletters@qq.com>
Co-authored-by: 王德宇 <kvtodev@outlook.com>
Co-committed-by: 王德宇 <kvtodev@outlook.com>
2026-07-17 21:03:15 +08:00

3.9 KiB
Raw Permalink Blame History

【ADR】画布Agent会话消息存OSS-2026-07-03

状态:已接受

背景

画布Agent对话需要保存历史记录并支持新开会话。消息正文会随对话和工具结果持续增长;SpacetimeDB 是后端唯一结构化真相存储,但表行不适合承载不断增长的长文本;画布工程快照已有独立保存链路,对话消息也不应与布局保存互相竞争。

决策

  • SpacetimeDB 表 editor_agent_conversation 只存会话元数据:会话 ID、projectId、ownerUserId、标题、软删标记、聊天记录 OSS 对象引用、时间戳。
  • 完整消息内容以会话粒度 JSON 对象存 OSS(editor-agent/{conversationId}.json),追加消息即整体重写对象。
  • editor-agent/ 是服务端内部消息文档前缀,只保存 editor-agent/{conversationId}.json 形态的会话级 JSON 文档;它不是浏览器直传前缀,也不是公开 generated 资源前缀。
  • 浏览器禁止直接上传、覆盖或签名写入 editor-agent/ 对象;前端只通过 api-server 的会话接口创建会话、发送消息、读取历史,OSS 读写由服务端完成。
  • 消息文档序列化后的读写上限为 2 MiB;超过上限时后端拒绝继续读写该会话消息文档,并返回 payload too large 语义错误。
  • 同一会话内的消息追加采用 conversationId 级串行锁,避免同一会话的“读-改-写”整对象过程互相覆盖。
  • Agent 规划失败使用 role=system、正文以 ERROR 开头的消息持久化;首次响应和同 clientMessageId 重放都通过 deltaMessages 返回该消息,errorMessage 不重复携带。前端隐藏前缀并显示红色错误气泡,后端构建后续 LLM memory 时仍保留该消息,让 Agent 获取上一轮失败上下文。工具调用失败继续保留 status=failed 工具记录、模型和错误信息;失败记录都是会话历史的一部分。
  • 不把消息明细写入 SpacetimeDB 表,不把对话混入画布工程快照,不在 api-server 内存中保存会话真相。

备选方案与取舍

  1. 独立 message 表(逐条入 SpacetimeDB:查询灵活,但消息文本长、附件结构嵌套,行数与行体积随聊天无界增长,挤占 SpacetimeDB 订阅与快照成本;对话消息没有跨会话结构化查询需求,放表里收益低。
  2. 消息塞进画布工程快照 payload:省一张表,但每条消息都会触发整个工程快照保存,与画布布局保存互相竞争,流式期间冲突概率高。
  3. 每条消息一个 OSS 对象:追加成本最低,但加载历史需要 N 次取对象或额外清单维护;对话消息量级小,整体读写实现最简单。

选择"表存引用 + OSS 存整段 JSON":与仓库既有「画布资源」「敲击音效」等 OSS 对象引用模式一致,加载历史一次取对象即可。

影响

  • 消息写入是"读-改-写"整对象;当前由 api-serverconversationId 做会话内串行化,保证同一进程内同一会话不会并发覆写。若未来横向多实例部署,需要补充分布式锁、对象版本条件写或等价的跨实例并发控制。
  • 会话表仍只保存元数据和 messagesObjectKey;API 可以在读取时把 OSS 消息文档拼装为会话详情返回,但完整消息正文的持久化真相仍是 OSS JSON 文档。
  • 消息文档最大 2 MiB;该限制用于阻止单个会话无限增长。后续如果需要更长历史,应引入归档、分页对象或摘要压缩,不应把正文回填进 SpacetimeDB 表。
  • 会话软删只打表标记,OSS 对象保留,便于恢复与审计。
  • 规划或工具生成失败也必须写入消息文档:规划失败保存 ERROR system 消息,工具失败保存失败状态、模型和错误信息,便于用户回看失败原因和后续排障。
  • 若未来出现跨会话消息检索需求,需另建投影或索引,不回退为消息入表。