超越无状态:为什么 LLM 正在挑战传统系统设计
超越无状态:为什么 LLM 正在挑战传统系统设计
二十年来,可扩展 Web 架构的蓝图一直非常一致:状态存储在数据库中,而计算是无状态的。在这种模型中,任何请求都可以命中负载均衡器背后的任何服务器,而数据库则作为绝对的单一事实来源。这种设计通过将应用服务器视为可丢弃的商品,使得互联网能够扩展到数十亿用户。
然而,大语言模型 (LLM) 和自主代理 (autonomous agents) 的出现正在开始瓦解这一长期存在的假设。虽然“无状态计算”模型适用于传统的 CRUD 应用,但它越来越不适合智能体 AI (agentic AI) 的需求。
无状态架构的三大裂痕
智能体工作流引入了传统无状态请求-响应循环无法高效处理的三个特定挑战:
- 长时运行工作:执行复杂任务(例如研究一个主题并编写报告)的 AI 代理可能会花费十分钟才能完成。这在 HTTP 意义上不再是一个“请求”;它是一个长时运行的异步过程。
- 有状态计算:代理依赖于累积的上下文、对话中前几轮的记忆,以及多次工具调用的结果。这种状态不仅仅是“数据库状态”(例如用户配置文件);它是运行中过程的活跃记忆。
- 双向交互:用户不仅想要最终答案;他们还希望实时观察代理“思考”,中断其进度,或实时重定向其轨迹。这使得交互从向无状态 API 发送查询转变为与运行中过程的实时对话。
路由问题:为什么轮询是不够的
为了处理这一问题的执行部分,业界已经转向“持久化执行”框架(例如 Temporal, Inngest 或 Restate)。这些工具使过程具有韧性,确保如果服务器崩溃,工作流可以从中断处恢复。
但持久化执行解决的是过程问题,而不是交互问题。由于标准的负载均衡器和 HTTP 无法将请求路由到特定的运行中过程,开发人员通常会退回到轮询。客户端通过轮询数据库端点来查看持久化过程是否已写入更新。
正如原文资料所述,这本质上是将数据库视为消息总线——这是对根本性路由缺陷的一种权宜之计。轮询会引入延迟,增加数据库负载,并为流式数据带来糟糕的用户体验。
寻求新的路由原语
为了超越轮询,我们需要一种能够针对“过程”而非仅仅针对服务器或数据库进行寻址的路由原语。目标是能够实现如下指令:“将此消息传递给当前正在为工作流 X 生成输出的任何人,” 而无需知道具体的服务器副本或 IP 地址。
为什么 WebSockets 不是答案
WebSockets 提供双向通信,但它们是一种连接,而不是一种地址。如果 WebSocket 连接断开(例如,因为用户进入了隧道),地址就会丢失。如果没有外部路由机制,就没有原生方式可以重新连接到完全相同的过程状态。
支持 Pub/Sub 通道的理由
一种更稳健的解决方案是使用命名的 pub/sub 通道。在这种模型中,客户端和服务器过程都不是地址;传输通道才是地址。客户端和服务器都连接到命名的通道。如果连接断开,客户端只需重新连接到同一个命名的通道并恢复数据流。
通过将持久化执行与持久化传输(pub/sub)相结合,开发人员可以创建智能体应用,其中工作流具有韧性,且通信是无缝的,从而消除了为了韧性而将每个 token 穿透数据库的必要性。
反对观点与行业视角
向有状态路由的转变并非没有批评者。一些工程师认为这些“问题”并非新鲜事。长时运行任务、webhooks 和 job IDs 已经被用于处理异步工作数十年了。批评者认为,数据库中的“单一事实来源”是一个经过验证的模式,应该继续作为系统设计的核心。
其他人则指向了已经解决这些问题的现有技术,例如:
- Virtual Actors:Actor 模型(见于 Elixir 或 Azure Orleans)提供了一种寻址特定有状态实体的途径。
- Durable Objects:Cloudflare 的 Durable Objects 提供了一种在单一位置协调状态和计算的方式。
- Session Pinning:一种确保客户端保持连接到特定服务器的传统方法。
为什么 LLM 使其变得紧迫
如果这些模式以前就存在,为什么现在变得重要了?区别在于 LLM 的本质:它们是非确定性的且昂贵的。
在传统系统中,如果连接断开,你通常可以重试请求并获得相同的结果。使用 LLM 时,重试请求可能会产生不同的答案并消耗更多的 token。你不能因为网络闪烁而浪费昂贵的计算资源,或丢失一个复杂、非确定性思维链的状态。
LLM 并没有发明这些问题,但它们放大了它们,使得 20 年前的无状态 Web 架构的权衡变得比以往任何时候都更加痛苦且显而易见。