← 工程化与 LLMOps

分布式大模型应用如何管理会话状态与并发更新?

高频 困难 第 14 / 28 题 更新于 2026/09/25
LLMOps会话状态乐观并发幂等
学习 AI 实战项目

简化版

会话状态不能只是一段不断追加的消息数组。生产系统应把不可变事件、当前任务状态、近期消息、派生摘要和业务事实分开:事件用于审计与重建,状态对象用于当前执行,摘要只是可丢弃的派生视图,订单等真值仍从权威系统读取。

多标签页、重试和异步工具会并发修改同一会话,因此写入要带 session_version 与幂等键,使用乐观并发或单会话串行队列解决冲突。模型只能提出状态补丁,控制器校验来源、权限和版本后提交;过期工具结果不得覆盖用户更新。最终验证重复请求不重复执行、乱序结果不回滚状态、摘要可从事件重建。

详细版

推荐采用“事件日志 + 物化状态”结构:用户消息、模型结果、工具开始/完成、审批和状态补丁形成只追加事件;物化器按因果顺序生成 goal、constraints、open_steps、artifacts 等当前状态。每次写入携带期望版本,若数据库中的版本已变化则重新读取、合并或要求用户确认。

append event(idempotency_key, expected_version)
 -> validate authority and transition
 -> compare-and-swap session_version
 -> update materialized state
 -> asynchronously refresh summary/index

不要持有数据库事务等待几十秒的模型或工具调用。长任务先记录 operation_id 和输入版本,外部完成后再校验会话是否仍处于可接受状态;结果过期时保存为 artifact,但不自动覆盖新决定。会话级顺序、跨会话并行,通常比全局锁更可扩展。

完整版教学

会话历史回答“发生过什么”,物化状态回答“现在是什么”,版本与幂等机制回答“并发时谁可以改”。

一、先把五类数据分开

原始事件包含消息与操作事实;近期消息服务指代消解;任务状态保存当前目标和约束;摘要压缩旧历史;业务事实来自订单、账户等权威系统。混成一个 Prompt 后,来源与生命周期都会丢失。

摘要可以重建,业务真值不能由摘要覆盖。长期记忆是否应保存属于产品记忆策略,本题重点是一次会话在分布式执行中的一致性与恢复。

二、为什么只存 messages 数组不够

两个浏览器标签可同时发送消息,客户端超时会重试,工具结果还可能在一分钟后返回。若所有进程都读旧数组、追加后整段覆盖,就会发生 Lost Update。

同时,消息到达顺序不等于因果顺序。一个旧工具结果晚到,不代表它应覆盖用户刚刚撤销的任务。

三、事件日志与物化状态怎样协作

事件使用稳定 event_id、actor、type、causation_id、timestamp 和 payload reference,只追加不原地改。物化状态带当前版本和处理到的最后事件位置。

events: e1(user_request) -> e2(tool_started) -> e3(user_cancelled)
                                      `------> e4(tool_finished, late)
state : cancelled; e4 retained for audit but cannot reopen automatically

物化器出错时可从事件重放。为控制成本可保存快照,但快照必须标注覆盖事件范围和 Schema 版本。

四、乐观并发如何防止覆盖

读取状态版本 v=12 后,写入使用 Compare-And-Swap:只有当前仍为 12 才提交并升级为 13。失败说明有人先修改,需要重新读取并判断能否合并。

假设 A 修改输出语言,B 同时撤销发送权限;若字段互不冲突可按规则合并,涉及同一约束或高风险动作则不能 Last-Write-Wins,应显式解决或询问用户。

五、幂等键解决什么

网络超时后客户端会重发同一消息,任务队列也可能至少一次投递。每个逻辑命令携带幂等键,状态库保存其处理结果;重复到达返回原结果而不是再次追加或执行工具。

工具写操作使用独立 operation_id 与业务幂等键。会话消息去重不能替代支付、发信等下游系统自己的幂等保护。

六、长时间调用为什么不能锁住事务

模型生成、人工审批和外部工具可能持续数秒到数小时。持有行锁等待会阻塞同会话其他操作,并在进程崩溃时难以恢复。

应先提交 operation_started(expected_state_version),释放事务,再异步执行。结果回来时检查操作是否仍有效、输入资产版本是否一致,以及用户是否已取消。

七、状态机如何限制非法跃迁

为关键流程定义显式状态,例如 draft -> awaiting_approval -> executing -> succeeded/failed。模型可以建议事件,但控制器根据权限和前置条件执行迁移。

当前状态事件允许结果
draftrequest_approvalawaiting_approval
awaiting_approvalapprovedexecuting
awaiting_approvaluser_cancelledcancelled
succeededretry_execute拒绝或查询原结果

这能防止模型跳过审批,也让恢复逻辑有确定边界。

八、摘要与索引怎样保持派生关系

摘要、向量索引和会话标题都是派生视图,可以异步更新但要记录 source_version。读取到落后摘要时,要么叠加其后事件,要么同步刷新,不能把旧摘要当完整当前状态。

关键数字、权限和待办保存在结构化状态;摘要只负责叙事背景。若摘要损坏,可从原事件重建而不会丢失真值。

九、多租户和删除边界

session_id 必须与认证后的 tenant/user 绑定,所有事件、快照、索引和 artifact 查询都先做权限过滤。不能依赖模型在 Prompt 中判断归属。

删除请求要传播到主存、搜索索引、缓存和派生摘要,并按政策处理审计墓碑。会话分享则创建明确授权关系,不是泄露一个可猜 URL。

十、如何测试与观测

构造双标签并发更新、客户端重复提交、工具乱序完成、取消与完成竞争、Worker 崩溃后重放、摘要滞后和跨租户访问。检查最终状态、事件数量、副作用次数和审计链。

监控 CAS 冲突率、重复事件命中、过期结果丢弃、状态迁移拒绝、摘要版本滞后和重放失败。若 1,000 次重试造成 1,005 次工具执行,幂等边界就没有守住。

十一、常见误区与追问

  • 误区:会话状态就是完整聊天记录。 当前任务状态、业务真值和事件审计具有不同语义。
  • 误区:按到达时间最后写入即可。 异步结果可能晚到但因果上已过期。
  • 误区:数据库事务应包住模型调用。 长事务会阻塞并难以恢复,应使用操作事件和版本检查。
  • 误区:模型输出的状态补丁可以直接保存。 需要 Schema、权限、来源和迁移规则校验。
  • 误区:有消息去重就不会重复付款。 下游副作用仍需业务幂等键与状态查询。
  • 追问:冲突时总能自动合并吗? 独立低风险字段可以;同一约束或高风险意图应拒绝静默合并。
  • 追问:摘要落后怎么办? 读取时叠加后续事件或重建,并用 source_version 防止冒充最新状态。

十二、加强记忆

会话状态管理记“事件留历史、状态供执行、摘要可重建、业务有真值”。并发写用版本 CAS,重复投递用幂等键,长操作用 operation_id 和完成时再校验;旧结果不能覆盖新决定。模型只提补丁,确定性状态机守权限与跃迁,最终用乱序、重试、崩溃和跨租户测试验收。