1.2. 从无状态调用到有状态智能体是一场范式迁移
从无状态调用到有状态智能体是一场范式迁移
去年冬天,我接了一个给内部运维系统加“智能诊断”功能的活。本质上就是做一个能自己查日志、调监控、翻文档,最后给出“根因分析报告”的智能体。我上来就按直觉干:选了个大模型,写了几段 prompt,用 Function Calling 把查日志、调 API、搜知识库串成一条工具链。Demo 跑通了——也就是“用户问一句、系统回一句”这种走法——演示的时候掌声也有了。
但上线第一周就崩了。用户不是只会问一次问题的人。一个真实的排障流程动辄要来回十几轮:先查告警,再扩范围,过程中发现新线索,推翻了上一步的假设,重新检索,最终才敢下结论。而我的“一锤子买卖”调用模型每轮都从零开始,上一轮的计算结果、检索到的关键日志、已经排除的疑点——什么都没留住。用户每多问一句,系统就多一分“失忆”的痛苦。最后用户跟我说的一句话扎心了:“它能回答眼前的问题,但它永远理解不了我正在处理的事。”
那个月我真正明白了一件事:把智能体设计成一次 API 调用,和让智能体活过一段完整的任务生命周期,是两套完全不同的范式。
REST 思维在对话智能体中的失败
如果你过去几年写后端、调 API,你对“无状态”这个词肯定不陌生。REST 架构把“每个请求包含所有必要信息”当成一种美德:服务器不记历史,状态要么在客户端,要么在数据库。这种设计让系统扩容没有心理负担,一个请求挂掉也不影响下一个。
但当你把同样的思维直接搬到对话智能体上,灾难就开始了。
我们来看一个完整的排障任务——一个用户要排查某条业务线的订单延迟问题——如果套用无状态设计,会发生什么。
| 轮次 | 用户输入 | 需要的上下文 | 无状态设计的实际表现 | 作者的结论 |
|---|---|---|---|---|
| 1 | "帮我查一下昨天晚上 8 点到 10 点订单服务的错误日志" | 时间范围、服务名 | 调用日志工具,返回结果 | 正常完成 |
| 2 | "只看和支付网关相关的超时" | 前一步的查询结果、服务拓扑关系 | 不知道前一步查了什么,重新查询或凭空猜测,大概率信息冗余或缺失 | 上下文丢失,用户被迫重复提供信息 |
| 3 | "把这段时间内所有支付重试超过 3 次的订单找出来,看看和前面的超时有没有关系" | 前两轮的时间范围、服务名、过滤条件、已检索到的超时日志 | 完全失忆,要么重新查所有日志再过滤,要么直接给出一个看似合理的错误回答 | 重复计算、信息泄漏、结论不可靠 |
| 4 | "等一下,我先确认一下那段日志里面有没有包含 Redis 连接超时的记录" | 前三轮累积的所有检索快照、中间结果 | 无法“回溯”,必须从头再查,上下文窗口可能已被无关信息撑爆 | 用户体验崩溃,任务不可持续 |
这张表里,每一行都在揭示同一个深层问题:当任务的生命周期跨越多次交互时,“每次调用独立计算”变成了一种根本性的架构误配。 这不是 prompt 写得不够好,也不是模型不够聪明——这是系统没给模型任何“记住自己刚才在干什么”的机会。
现在我们把上述失败归纳成三项致命后果:
- 重复计算:每一轮都要重新调用相同的工具、拉取相同的日志、扫描相同的文档。延迟上升、Token 消耗飙升、下游系统被重复请求打爆。
- 信息泄漏:无状态调用为了“怕漏掉重要信息”,往往倾向于把能拿到的数据全塞进上下文窗口。这正好把上一章讲过的那个魔鬼召唤出来了:窗口被无效信息占满,真正关键的线索反而被模型“忽略”或“遗忘”。
- 低效重试:一个复杂任务必然包含试错。但无状态模型没有“我已经试过 A、B、C 都失败了”的记忆能力,它可能在同一个死胡同里反复横跳。而在高 Token 消耗的推理模型中,每一次重试都在烧钱。
经验框:我曾在凌晨三点排障时,看着无状态 agent 把同一段 200 行的日志在 5 轮对话里反复检索了 3 遍,每次都告诉用户“建议检查该日志段”。用户当场放弃了系统,自己打开 grep 和 less 处理。那一刻我意识到:让一个“没有记忆的诊断师”去看病,它给出的每个建议都孤立于之前的检查结果,这不是辅助,是负担。
REST 思维的美妙之处在于“不记历史”换来的扩展性;对话智能体的致命之处恰好也在这里——它的价值恰恰来自于对历史的累积理解和持续推理。
智能体的生命周期不等于一次 API 调用
要跳出无状态的坑,首先要重新定义“智能体的一次执行”到底从哪到哪。
在无状态设计下,智能体的生命周期就是“一次 HTTP 请求 + 一次模型响应”。模型收到用户输入、调用工具、生成输出,然后进程内存释放、上下文销毁。这是“对话回合”级别的存在。
而有状态智能体的生命周期是一段连续的任务弧——我把它称为长时智能体(Long-Running Agent)。它的生命周期至少包含四个阶段:
- 启动(Activation):任务被触发,智能体建立初始状态快照。这个状态不仅包含当前用户问题的文本,还包括任务目标、角色声明、可用的工具列表、组织知识图谱的入口指针。
- 执行与感知(Execution & Perception):智能体根据需要调用工具、检索文档、查询数据库。这里的关键变化是:每次工具调用的结果并不直接抛回给“调用端”,而是写入智能体的持久化状态空间。 状态成为所有后续推理的基础层。
- 等待与反馈(Suspension & Feedback):真实世界中,一个任务常常需要“等”——等审核、等人来确认某个假设、等外部事件触发。长时智能体能够挂起自己,保持状态,在收到异步反馈后从断点处恢复推理。这是无状态调用根本做不到的事情:它连“我还在处理一个未完成的任务”这个事实都记不住。
- 自我修正与收敛(Reflection & Convergence):长时智能体在状态中积累每一步的“尝试-结果”对。当后续推理发现前序假设有误时,它可以回看状态历史,纠正路线,而不是像无状态调用那样,只能基于当前轮次的 prompt 做“局部最优”的猜测。最终,智能体沿着状态轨迹收敛到结论,而不是凭空给出一次性的快照答案。
如果你过去用过 LangChain 早期的 AgentExecutor,你应该能立刻感受到差异。早期 LangChain agent 本质上是无状态的:agent 每执行一步(take_action → observation → decide_next),虽然在一个循环里,但其状态管理极度脆弱,多轮对话间更是一片空白。这也解释了为什么后来 LangGraph 要明确定义 State 对象,并将其作为图节点之间循环流转的核心数据结构。这不是一个技术迭代,这是一个范式补丁。
核心建议框:如果你今天要设计一个智能体,请画两条时间线。第一条是“无状态调用时间线”:它只有“接收-响应”这一个原子事件。第二条是“长时智能体时间线”:它从任务目标建立开始,历经多个工具调用、人类反馈、子目标修正,直到结果收敛。然后问自己:用户的实际任务落在哪条线上?如果答案是后者,就不要用前者的架构去硬套。架构选择不在技术炫酷,而在是否匹配任务的时间结构。
状态管理的工程代价与收益
每次谈到“有状态”,工程师的第一反应往往是——延迟、内存、复杂度、状态一致性。
这些担心是真实的。有状态架构当然有代价,但它带来的收益对于长时任务而言,已经从一个“可选项”变成了“必须项”。
我们先把核心的 trade-off 摊在桌面上看。
| 维度 | 无状态调用 | 有状态智能体 | 作者的结论 |
|---|---|---|---|
| 延迟 | 每轮调用独立,延迟稳定可预测 | 首次调用需要加载状态,长任务中状态读写引入微秒级 overhead,但整体可优化 | 有状态在单轮延迟上略高,但避免“重复计算”后,端到端任务延迟大幅降低 |
| Token 成本 | 每轮注入全量上下文,token 消耗线性甚至指数增长 | 仅注入与当前推理最相关的状态片段(语义检索),token 曲线趋于平缓 | 有状态在实践中通常显著降低中后期成本,尤其在任务超过 5 轮后 |
| 可控性与可观测性 | 调用之间隔离,出问题容易归因,但终局行为不可控 | 状态轨迹提供了完整的“决策历史”,可回溯、可审计、可纠正,但调试工具链要求更高 | 有状态通过状态快照与轨迹回放实现了无状态永远做不到的事情:理解智能体为什么会做出某个决策 |
| 移植与恢复 | 无状态天然易水平扩展,实例挂掉无感 | 需要持久化后端(DB 或向量库)支持状态快照与恢复,架构更重 | 对于长时任务,“崩溃恢复”是有状态的刚需,也是它相对于无状态的绝对优势——无状态在此场景下根本没有状态可恢复 |
我曾在内部做一个实验:同样的排障任务——排查支付网关间歇性超时——分别用无状态调用链和有状态智能体跑 10 轮交互。无状态方案在第二轮之后 token 消耗就开始飙升,因为每轮都要重新拉取全量日志并重述全部前置结论。到第五轮时,上下文窗口已被占满 85%,之后的推理质量显著下降。而有状态方案在第三轮达到状态快照的稳定态后,每轮只需注入增量更新和状态摘要,token 消耗保持平缓,到第八轮时仍然能够准确回溯最初排除的假设。
这里的关键收益不是省钱,是让模型“想得更久、更稳”。
从工程角度看,有状态架构也给上下文治理带来了质的飞跃。上一章我们讨论的“上下文窗口是智能体最重要的稀缺资源”,在有状态架构下有了截然不同的解法:你不再需要在每一轮调用里把“前情提要”全塞进窗口,而是可以通过状态管理,在持久化层做语义检索,只注入与当前子任务紧密相关的历史片段。这就是主动调度信息,而非被动堆砌信息。
当然,代价不能回避。状态持久化引入了新的基础设施依赖(PostgreSQL / Redis / 向量数据库),状态一致性问题(工具调用写回状态失败怎么办)、状态垃圾回收问题(过期的中间假设什么时候清除)都需要在设计早期就明确策略。但根据当前调研资料中的工程实践,这些挑战都是成熟的分布式系统问题,有现成的模式(WAL、事务性写回、TTL 清理)可以借鉴。真正的风险不在于“有状态难做”,而在于“把有状态的事情硬按无状态的方式做”。
适合谁?不适合谁?
读到这里,你可能会问:那我到底该不该把现有系统迁到有状态架构?
以下结论基于当前已观察到的工程实践。
适合有状态智能体架构的场景:
- 诊断、调查、规划类任务:需要多步推理、中途修正假设,且有明确“任务终局”定义。
- 需要中途等待或人机协同的任务:智能体发起查询后等待外部事件或人类确认,然后继续执行。
- 上下文敏感、需要累积知识的长对话:用户在一次对话中持续深入一个主题,后面的问题高度依赖前面的结论。
不适合或者暂不需要的场景:
- 独立问答、简单信息检索:用户问“北京今天天气怎么样”,回答结束,任务完成。有状态的 overhead 毫无意义。
- 严格的幂等性要求、无状态的合规约束:某些金融或合规场景要求每个决策可独立审计、不可跨请求污染。
- 团队尚不具备状态基础设施运维能力:如果要强行上,可能先被 Redis 脑裂和持久化延迟打趴下。
一张自我检测清单,用来判断你是否正卡在“该迁但不自知”的状态里:
- 你的用户是否经常在对话中重复提供前面已经说过的信息?
- 你的系统是否在超过 5 轮交互后,回答质量肉眼可见地下降?
- 你是否发现每轮调用的 token 消耗在不可遏止地增长?
- 你的智能体是否经常在同一个错误的推理路径上循环?
如果以上任一项回答“是”,那么你的系统正在承受“把有状态任务塞进无状态架构”的痛苦。迁移不是技术升级,是给系统止血。
从范式迁移到记忆设计
当我们决定把智能体从“一锤子买卖”的调用变成“活着完成任务”的有状态执行体时,一个更根本的问题随之浮现:状态里到底存什么、怎么存、什么时候用? 这就不再只是一个工程层面的“加个数据库”的问题,而是智能体记忆系统的完整设计——记忆到底应该像档案库一样被动存储,还是像操作系统的页表一样,主动调度、预加载、参与推理?
这正是下一章要解决的问题——记忆不是存储,而是智能体的操作系统。
上下文治理:AI Agent 系统设计
关于 LearnKu