AI 应用后端工程化:从原型到可交付系统 · 第 17 篇 · 第四章 · 会话与安全
把正在编辑、已经发布和历史版本分开,让配置既能频繁修改,又能稳定对外提供服务。
可配置应用往往同时服务两类人:编辑者希望随时修改 Prompt、模型和工具,最终用户希望线上行为稳定。如果每次编辑都直接覆盖生产配置,半成品会立即影响用户;如果发布后不能回看历史,事故也无法快速回退。
草稿、发布版本和调试会话的分离,是内容系统、规则引擎和 AI 应用都适用的版本化方法。
三种状态,三种承诺
stateDiagram-v2
[*] --> Draft
Draft --> Draft: 编辑与调试
Draft --> Published: 发布快照
Published --> Draft: 复制历史版本回草稿
Published --> Unpublished: 停止对外服务
Unpublished --> Draft: 继续编辑
Published --> Published: 发布新版本
草稿是可变工作区,不承诺稳定;发布版本是不可变快照,线上请求必须绑定具体版本;历史版本用于审计和回滚。回滚更适合把旧快照复制成新草稿,确认后再发布,而不是修改历史记录。
快照要完整
只在版本表保存“Prompt 修改了”无法重现行为。快照应包含模型标识与参数、Prompt、工具版本、知识库引用和关键运行策略。外部引用也要考虑可变性:工具当前版本变化后,旧应用版本是否仍能找到当时定义?
{
"version": 7,
"model": {"provider": "openai", "name": "gpt-4o", "temperature": 0.2},
"prompt": {"template": "answer-with-citations", "revision": 3},
"tools": [{"id": "tool_weather", "version": 2}],
"datasets": [{"id": "ds_policy", "version": 5}]
}
如果选择绑定“当前数据集”而非固定版本,应在产品上明确:配置回滚不能保证知识内容同步回滚。重现性和内容新鲜度之间需要显式取舍。
发布是状态转换,不是 update
发布过程通常包含校验、生成快照、写发布记录、切换当前版本和发失效事件。并发点击发布时要保证只有一个版本成为当前,可以使用数据库锁或比较草稿修订号。
发布前校验不仅检查字段存在,还要确认模型可用、工具有权限、工作流连通、知识库属于当前账号。否则一份结构合法但无法运行的配置会进入生产。
取消发布也应保留历史和访问结果。公开 API 遇到未发布应用返回稳定错误,而不是退回草稿或默认配置。
调试会话属于草稿
编辑者需要在发布前测试,调试会话应明确绑定草稿修订。草稿变化后,可以开启新会话或标记旧会话使用旧配置,不能让同一会话中途悄悄切换模型与工具。
长期记忆也要区分调试和真实用户。调试时写入的偏好不能污染生产终端用户;清空调试记忆不应删除生产会话。命名空间至少包含应用、环境、配置版本和会话身份。
回滚不是时间旅行
回滚配置无法撤销已经发送的邮件、创建的订单或写入的记忆。它只能改变后续请求使用的版本。事故处理还要检查历史副作用并执行补偿。
数据库迁移同样可能让旧代码无法运行,因此应用配置回滚与服务部署回滚要分别设计。真正的发布记录应同时关联代码版本和配置版本,排查才能复现完整环境。
容易发生的数据竞争
编辑者 A 打开草稿版本 12,编辑者 B 先保存成 13,A 随后提交旧页面并覆盖 B。通过 revision 乐观锁可以返回冲突,让 A 合并差异,而不是最后写入者静默获胜。
另一个问题是线上请求先读当前版本 ID,再读取快照时版本被删除。发布快照应不可物理删除,读取通过单个稳定引用完成,缓存按版本号而非“current”键存储。
举一反三到规则与内容平台
价格规则、功能开关、CMS 页面和数据报表都需要草稿、审核、发布与回滚。练习:设计两名编辑者并发修改同一草稿的测试,再发布两个版本,让十个请求分别记录实际版本。执行回滚后确认新请求使用新发布的旧内容快照,历史请求记录不变。
九次提交呈现了完整版本周期
ae09642:增加示例环境配置,为可运行配置建立入口。06bd6e5:定义应用、草稿与版本模型。2e02b82:实现创建和获取,草稿生命周期开始。0d3ec23:支持读取与更新草稿配置。65cc4b2:加入发布和取消发布。b6fb0e1:增加发布历史与回退到草稿。74d5b1c:管理调试会话的长期记忆。c374564:重构 Agent 与会话路径并加入调试聊天。b7a73fa:补充推理记录访问并整理队列表达。
这九步并不是孤立 CRUD,而是一条从编辑、测试、发布、历史到调试状态的产品化主线。