原文引发 Hacker News 广泛讨论(原文链接),本文做深度解读与扩展。
一、那个我们习以为常的假设
过去 20 年,Web 架构建立在一个几乎没人质疑的假设上:
状态存在数据库里,计算是无状态的。
如果你想扩展?垂直扩容数据库(换更大的机器),水平扩容应用服务器(加更多的盒子)。任何请求可以打到任何一台服务器上,负载均衡器不在乎,数据库是唯一的真相来源。
客户端 → 负载均衡器 → [无状态服务器 A/B/C] → 数据库(唯一状态)
这个架构优雅、简单、有效。HTTP 协议天生就是无状态请求-响应模型。RESTful API 的设计哲学也深深扎根于此。
直到 LLM Agent 出现了。
二、LLM 如何用三种方式”违规”
违规 1:长时运行(Long-Running Work)
一个 Agent 执行 10 分钟的任务,不是一个”请求”,而是一个长时异步进程。
传统架构中,一个 HTTP 请求的超时通常在 30 秒以内。但 Agent 可能需要:搜索 → 阅读 → 推理 → 调用工具 → 等待结果 → 再推理 → 再调用。这个过程动辄数分钟甚至数小时。
传统请求:GET /api/query → 200 OK (50ms)
Agent 任务:POST /api/run-agent → 等待 10 分钟???
违规 2:有状态计算(Stateful Compute)
Agent 在对话中运行多轮,处理多个工具调用,依赖累积的上下文。这个状态不是”数据库状态”,而是 Agent 的记忆。
它不像传统服务那样”读数据库 → 计算 → 返回结果”。它的中间状态(思考链、工具调用历史、上下文窗口)本身就是计算的一部分。
# 传统无状态服务
def handle_request(req):
data = db.query(req.params)
result = compute(data)
return result # 做完就忘
# Agent 的有状态计算
class AgentSession:
memory = [] # 对话历史
tool_results = {} # 工具调用结果
reasoning_chain = [] # 推理链
def step(self, input):
self.memory.append(input)
action = self.llm.generate(self.memory, self.reasoning_chain)
result = self.tools.execute(action)
self.tool_results[action.id] = result
self.reasoning_chain.append(result)
# 状态持续存在,不是"做完就忘"
违规 3:双向交互(Bi-Directional Interaction)
用户想看着 Agent 思考,想中断它、重定向它。这不是对一个无状态 API 的查询,而是与一个进程的对话。
用户:"帮我分析这个数据集"
Agent: "正在读取数据... [流式输出思考过程]"
用户:"等等,换个分析维度" ← 中断并重定向
Agent: "好的,切换到维度 B..."
传统的请求-响应模型根本不支持这种交互模式。
三、业界的当前答案:Durable Execution
面对这些问题,业界给出的答案是 Durable Execution(持久执行)。
代表项目:
| 项目 | Stars | 简介 |
|---|---|---|
| Temporal | ⭐20K+ | 持久工作流引擎,支持故障恢复 |
| Inngest | ⭐5.3K+ | 面向 serverless 的状态机与 AI 工作流 |
| Restate | ⭐3.8K+ | 容错应用平台,自动处理基础设施故障 |
| LangGraph | ⭐32K+ | 构建弹性 LLM Agent 的图框架 |
Durable Execution 解决了执行层面的问题:进程可以故障恢复、断点续跑、不丢失中间状态。
但它没解决交互问题。
四、缺失的路由原语
这才是核心论点:
HTTP + 负载均衡器 + 无状态服务器 无法路由到一个具体的进程。它只能路由到数据库。
所以当客户端想和一个在 Durable Execution 框架中运行的进程对话时,所有人都回到了同一个问题:怎么找到它?
于是所有人不约而同地选择了 轮询(Polling):
客户端 → 定时查询 /api/status?workflow_id=xxx → 数据库
↑
Durable Process 把结果写入数据库
这本质上是在把数据库当作消息总线。就像消息总线出现之前人们做的那样。
轮询的问题大家都清楚:
- 延迟取决于轮询频率
- 数据库负载无谓增加
- 大量空请求浪费资源
- UX 极差
轮询是你找不到该对话的”东西”时的无奈之举。 这是一个路由问题,不是数据问题。
五、缺失的路由原语到底是什么?
一个清晰的概念:
一个可路由的传输名称,不是服务器。
我们需要能说:”把这条消息发给正在为 workflow X 生产输出的那个进程”。而不需要知道它在哪个机器、哪个副本、哪个进程上。
方案对比
| 方案 | 优点 | 致命问题 |
|---|---|---|
| HTTP 轮询 | 简单、兼容性好 | 延迟、浪费、UX 差 |
| WebSocket | 双向、实时 | 是连接,不是地址;断开就丢失 |
| Pub/Sub Channel | 可寻址、持久、断开可重连 | 需要额外基础设施 |
Pub/Sub 通道是最佳候选:
客户端 → [Pub/Sub Channel: workflow-123] ← Agent 进程
↑
通道就是地址,不是连接
断开后可以重连到同一个通道
Pub/Sub 通道反转了所有权:服务器进程和客户端都不是可寻址的,传输本身是可寻址的。双方通过名称连接到通道,获得双向、有状态的通信。
通道就是地址。断开后可以重新连接,不会丢失数据或失去路由能力。
六、持久传输 + 持久执行
把两件事结合起来:
Durable Workflow Activity → 连接到 Pub/Sub Channel (按 workflow ID 命名)
客户端 → 连接到同一个 Channel
→ 获取更新、发送中断或转向指令
- Workflow 是持久的
- Channel 是持久的
- 即使进程或客户端断开,都能重连到同一个通道继续对话
不需要把每个 token 塞进数据库,不需要轮询,不需要担心无法定位那个真正在干活的进程。
七、这真的只是 LLM 的问题吗?
一句话总结:
这其实不完全是 LLM 的问题。LLM 只是让它更明显了。
以前,连接断开?重试就行了。请求便宜,响应确定。
但 LLM 不同:
- 响应不确定:同样的输入不一定得到同样的输出
- 代价昂贵:每个 token 都要花钱,不能随便重试
- 状态累积:中间状态本身就是价值
LLM 的非确定性和高昂成本,让我们现有架构的局限性变得肉眼可见。
八、扩展思考:更广泛的架构冲击
LLM 对系统设计的冲击远不止路由问题:
1. 存储模型的变化
| 维度 | 传统 | LLM 时代 |
|---|---|---|
| 数据类型 | 结构化 | 向量 + 图谱 + 非结构化 |
| 存储引擎 | RDBMS | 向量数据库(Chroma/Milvus) + 图数据库 |
| 查询方式 | SQL | 语义搜索 + 相似度匹配 |
2. API 设计范式转变
| 维度 | 传统 | LLM 时代 |
|---|---|---|
| 设计模式 | REST/gRPC | Tool Calling / MCP |
| 接口定义 | OpenAPI/Proto | JSON Schema Tool Definition |
| 调用方式 | 固定端点 | 模型自主选择和组合工具 |
3. 错误处理策略
| 维度 | 传统 | LLM 时代 |
|---|---|---|
| 重试机制 | 指数退避重试 | 幂等 + 语义校验 |
| 回滚策略 | 事务回滚 | 语义一致性检查 + 补偿操作 |
| 确定性 | 保证 | 概率性输出,需要护栏 |
4. 可观测性
传统三板斧:指标 + 日志 + 链路追踪
LLM 新增维度:
- Token 消耗追踪(成本控制)
- 推理链记录(可解释性)
- 工具调用审计(安全合规)
- 输出质量评分(效果监控)
5. 安全模型
传统安全:认证 + 授权 + 速率限制
LLM 新增挑战:
- Prompt 注入防御
- 工具调用权限细粒度控制
- 输出内容审查与过滤
- 多 Agent 之间的信任边界
九、总结
无状态 Web 没有错。它只是不适合 Agent 应用——那些需要长时运行、有状态、可交互的进程。
我们需要的不是推翻一切重来,而是承认:
HTTP + 无状态服务器 + 负载均衡 + 数据库 只是架构工具箱中的一种组合。对于 Agent 时代,我们需要加入新的原语:
- Durable Execution(处理进程持久化)
- Pub/Sub Channel(处理进程寻址和双向通信)
- 流式传输(处理实时输出)
- 向量/图谱存储(处理非确定性记忆)
LLM 没有破坏系统设计。它只是让我们重新审视那些我们以为理所当然的假设。
参考资料
- LLMs are breaking 20 year old system design – Zak Knill
- Temporal – Durable Execution
- Inngest – Serverless Workflow Orchestration
- Restate – Resilient Application Platform
- LangGraph – Resilient LLM Agent Framework
