1. 从一个让我寝食难安的痛点说起:Agent 的"记忆"到底该放哪
过去一年多,我一直在和 Agent 基础设施打交道。一开始做的还是那种"输入一段话,调一次大模型,返回一段话"的简单应用,后来慢慢过渡到多步推理、工具调度、多角色协作,问题就来了:Agent 的状态到底由谁管理?
这个问题听起来像架构师在咬文嚼字,但在工程上它是绕不过去的坎。举个例子,一个能做深度调研的 Agent,第一步搜索资料,第二步阅读网页,第三步写摘要,第四步汇总成报告。前三步的中间结果如果只靠大模型上下文里那几万 token 硬塞,第一步产生的内容全丢给第二步去"续写",那你很快会撞上两个天花板:上下文长度不够、以及每次调用都是无状态请求导致的关键信息重复计算。我当时为了解决这类问题,给每个 Agent 实例设计了一套"会话快照"机制,本质上就是把每一步的中间产物序列化后丢进 Redis。可这么干的问题也明显:Agent 的逻辑和状态存储强耦合在业务代码里,状态流更像是"手工搬运",而不是运行时自然维护的东西。
后来我看到了一个叫 CaveAgent 的新方向,它的口号很直接:把 Agent 当成一种面向对象的运行时实体来看待,而不仅仅是"模型加 Prompt"。它提出的有状态运行时管理,正好打在我踩过的坑上。
这篇文章我不打算照着官方文档复述,我想以自己的工程实践为主线,拆解 CaveAgent 背后的设计思想、我落地时做的关键取舍、以及使用它之后对 Agent 基础设施的重新理解。如果你正被"Agent 状态混乱、上下文不可控、多 Agent 协作难以追踪"折磨,这篇文章应该能给你一些直接的参考。
2. 先想清楚:Agent Infra 说的"面向对象"到底是在对标什么
2.1 从函数式调用到对象式驻留:范式转换的本质
要理解 CaveAgent 为什么把"面向对象"作为关键词,得先回顾我们的 Agent 系统是怎么演化的。
最早期大家写的 Agent 工具,本质上是一个函数:runAgent(prompt) -> answer。你做一次对话、一次总结、一次翻译,它像一个计算器,按一下出一个结果,不保存中间的寄存器状态。这个模式简单、无状态、容易水平扩展,但无法处理复杂任务链。
稍微成熟一点的系统,引入了"会话"概念。后台维护一个数组,把所有历史消息按顺序存起来,每次请求把整个数组拼接成 Prompt 塞给模型。这就是所谓的"带着记忆的调用"。但严格讲,这依然是函数式调用,只不过参数里多了一个历史列表。模型的注意力是有限的,状态其实仍然散落在调用方手里。
CaveAgent 的思路更像是:把 Agent 从"函数"升级为"对象",对象有属性、有方法、有生命周期,并由一个专门的运行时来统一管理属性(状态)和方法(行为)。这里面的关键不是"对象"这个名词,而是由此带来的一系列基础设施变化。比如:
- Agent 的"记忆"不再是消息列表,而是结构化的属性字段。模型只关注当前任务相关的状态子集,而不是全量历史。
- Agent 之间的协作变成了"对象方法调用",而不是"把一段文本丢给对方"。一个 Agent 向另一个 Agent 请求结果,底层是那个 Agent 在自己的状态基础上执行了一段逻辑,再返回结构化输出。
- 系统可以优雅地停掉、恢复一个 Agent。只要状态被持久化,重启后 Agent 能回到上次执行的位置,而不是从头再来。
这套范式的价值,我在一次长时间运行的客服分流 Agent 上感触特别深。传统方案里,用户聊了十轮后,如果中间流程出错需要重放,你得重算所有历史。而 CaveAgent 这种有状态运行时,每个处理阶段的状态都是独立可访问的,出问题只需要修正当前阶段的状态,然后继续执行,不需要把整棵流程树重跑一遍。
2.2 状态管理的"所有权"之争:谁该为 Agent 的记住负责
这里有个必须点破的工程现实:很多号称管理状态的系统,其实并没有真正拥有状态。
我看过不少团队的实现。它们把对话历史、工具调用记录、用户偏好全部存进数据库,表面上数据是落盘了,但读出来之后呢?状态变回 Prompt 里的字符串,Agent 的运行逻辑并不理解"哪些字段是当前决策的关键依据",它只是在上下文里"看到"了很多文字。这种情况下,状态的所有权其实属于数据库,属于调用方,不属于 Agent 本身。
CaveAgent 的有状态运行时把所有权收回到运行时。Agent 的生命周期由运行时统一把控,状态作为一等公民被管理,核心表现有几点:
- 显式状态协议:Agent 怎么接收状态、怎么修改状态、怎么提交状态,都由运行时规定的接口约束,而不是随意在 Prompt 里加一句"请记住用户姓名"。
- 状态快照与恢复:运行时可以随时冻结当前状态,之后按需恢复。这对于长时间运行、断点续跑、以及任务回滚都非常重要。
- 状态隔离:多实例 Agent 之间状态天然隔离,互不污染。这一条我在做多租户系统时感触极深,因为一旦 Agent 状态混在一起,轻则串数据,重则引发安全事件。
有了这一层理解,"面向对象"就不再是营销话术,而是一套切切实实改变 Agent 生命周期管理方式的基础设施设计。
3. CaveAgent 的运行时模型拆解:对象、实例、状态的三角关系
3.1 三层模型:定义类、创建实例、维护状态
从工程实现角度看,CaveAgent 的运行时模型可以拆成三个抽象层次,我称之为"类—实例—状态"三角关系。
类(CaveAgent Class)定义 Agent 的行为模式。比如一个"搜索型 Agent"的类,它包含工具列表(搜索、读取网页)、能力描述、默认参数、以及它在不同阶段如何调用模型的规则。这类定义是静态的,如同传统编程里的类定义。
实例(Agent Instance)是运行时创建的具体对象。每次"创建一个专门调研苹果公司最新动态的 Agent",你就实例化了一个对象,这个实例继承了类的所有能力,但拥有自己独立的身份标识和状态空间。
状态(Agent State)是实例在运行过程中不断变化的数据集合。包括当前任务目标、已获取的信息、中间推理记录、工具调用结果、置信度评分等。状态被运行时持久化管理,并且可以通过接口随时读取和修改。
我在实验项目里用这套三层模型重写了我早前那个"手工状态搬运"的调研 Agent。过程很直接:先定义类时把工具绑定进去,运行时自动为每个调研任务生成独立实例,每个实例维护自己的进度和结果。我不再需要"设计一个表来存中间结果",因为状态字段本身就是运行时的一部分。
下面是我搭建模拟项目时定义 Agent 类的一个简化骨架:
# 简化的 CaveAgent 类定义示意(非完整库代码) from caveagent import CaveAgentBase, state_field class ResearchAgent(CaveAgentBase): name = "research_agent_v1" description = "进行多步骤调研并输出结构化报告" # 显式声明状态字段,运行时负责持久化 task_goal = state_field(str, default="") collected_notes = state_field(list, default_factory=list) tools_called = state_field(list, default_factory=list) confidence_scores = state_field(dict, default_factory=dict) async def run(self, goal: str): self.task_goal = goal # 第一步:工具调用 search_results = await self.call_tool("web_search", query=goal) self.collected_notes.extend(search_results[:5]) self.log_progress("完成搜索阶段") # 第二步:进入模型推理 summary = await self.llm_call("summarize_notes", notes=self.collected_notes) self.confidence_scores["summary"] = 0.9 return {"summary": summary, "state": self.get_state()}这段代码看着简单,但它背后有几个值得玩味的点:
- 状态字段是强类型的,不是一段含糊的 JSON blob。这意味着你可以在运行时对状态做约束、校验、甚至自动迁移。
get_state()可以随时导出当前实例快照,配合持久化层,就构成了断点续跑的基础。- 类定义和实例创建分离,多个任务可以共享一套行为模板,但状态完全独立。
3.2 有状态运行时的落点:持久化、生命周期、断点续跑
光有状态字段的抽象还不够,运行时必须真正参与状态的存储和恢复。CaveAgent 在这方面做了一个非常工程化的决策:运行时不假设存储后端,而是定义一套持久化接口,允许你接入 Redis、数据库或者文件系统。
生命周期管理方面,CaveAgent 的运行时好比一个"容器编排系统"的缩小版。实例可以被启动、暂停、恢复、销毁。暂停时状态被完整导出;恢复时从导出的快照重建实例,继续从上次的节点往下执行。这个设计对于某些长周期任务价值巨大。
举个例子,我做过一个模拟的代码审查助手。它需要看完一个仓库的多个文件,然后逐文件输出审查意见并汇总。如果按照传统做法,每次模型调用都要重新发送"前面所有文件的审查摘要"作为上下文。文件一多,上下文膨胀得很快,模型性能也下降。改用 CaveAgent 后,每个文件的审查状态被显式保存在实例里,需要汇总时只需要让模型读取结构化的状态字段,而不是逐字重读历史,上下文消耗直接下降了一个数量级。
断点续跑的体验也让我印象深刻。有一次模拟项目里,审查助手在处理到第 7 个文件时,因为模型服务超时被中断了。传统方案下我得重新从第 1 个文件开始;CaveAgent 下,我只需要从实例快照中恢复,运行时自动知道"已处理了前 6 个文件,当前正在处理第 7 个",然后重新触发第 7 个文件的处理即可。中间几乎没有状态丢失。
3.3 与消息历史模式的关键差异
| 维度 | 传统消息历史模式 | CaveAgent 有状态运行时 |
|---|---|---|
| 状态载体 | 完整对话消息列表 | 结构化状态字段 |
| 上下文控制 | 全量历史拼接,易膨胀 | 按需读取相关字段 |
| 恢复机制 | 重放所有历史消息 | 加载状态快照直接续跑 |
| 实例隔离 | 靠会话 ID 手工隔离 | 运行时原生隔离 |
| 协作方式 | 文本互相传,模型再理解 | 方法调用,状态驱动 |
| 调试手段 | 看 Prompt 日志 | 查看状态流转记录 |
这个表不是我拍脑袋总结的,是我在重构时把两种实现都写了一遍之后得出的差异。传统方式"实现起来简单,扩展起来痛苦";有状态模式"前期抽象成本高,一旦跑通了,后续的维护和扩展体验完全不同"。
4. 多 Agent 协作场景:状态运行时如何改变 Agent 间的交互方式
4.1 对象方法调用替代自由文本传递
多 Agent 协作是当前 Agent 应用的热门场景,也是问题最多的地方。以前常用的方式是"黑板上写字"式协作:Agent A 把自己的输出写到共享内存或数据库,Agent B 定期去看有没有新内容,然后接着处理。这种方式很像程序员之间通过共享文档协作——你写完一段,另一个人再编辑,很容易出现覆盖、冲突、理解偏差。
CaveAgent 的运行时把协作提升到"方法调用"级别。如果 Agent A 需要一个"摘要",它不是往共享区丢一段文本,而是直接调用 Agent B 的"生成摘要"方法,并传入结构化参数。Agent B 在自己的状态上下文中执行该方法,返回结构化的结果。这就像程序里的函数调用替代了共享全局变量,程序结构清晰了,数据流也明确了。
我做的模拟实验是一个双 Agent 协作的写作工作流:一个"调研 Agent"负责收集资料,一个"写作 Agent"负责成文。传统模式下,调研 Agent 会输出"我今天找到了以下资料:……"这样一坨文本,写作 Agent 需要用自己的语言理解能力去 parse 这坨文本,提取要点。CaveAgent 模式下,写作 Agent 直接调用调研 Agent 的get_notes()方法,拿到的是一个结构化的笔记列表,包含标题、来源、摘要和置信度。两者之间的传递不再依赖自然语言的模糊性,而是近乎程序接口的精确性。
4.2 状态可见性与权限控制:协作不再是"黑箱"
另一个让我意外的价值是状态可见性。传统协作中,Agent A 怎么工作的、中途状态如何,对于 Agent B 来说是个黑箱。Agent B 只能看到 A 最终输出的结果,如果结果不理想,B 也没有办法去追溯 A 处理过程中哪一步出了问题。
CaveAgent 的有状态运行时让实例状态可以被选择性暴露。协作时,Agent B 不仅可以调用 A 的方法,还能按权限读取 A 的部分状态字段。例如写作 Agent 可以查看调研 Agent 的"已收集资料数量"和"关键来源列表",以此判断调研是否充分,再决定是开始写作还是要求补充调研。
这个能力踩中了我在实际项目中另一个痛点:多 Agent 协作的"可观测性"和"可干预性"。以前遇到协作结果不对,我只能去看两边的完整对话日志,人工判断哪一步偏了。现在直接检查状态字段,问题定位时间从小时级压缩到分钟级。而且因为状态是可修改的,我甚至能在调试时手工修改某个状态字段,让 Agent 从修正后的状态继续执行——相当于你可以在程序运行中直接改变量值然后继续调试。
这给我的启发是,面向对象范式在 Agent 领域之所以有生命力,不只是因为它"像编程",而是因为它带来的调试和控制能力,正是 Agent 从玩具走向工程化所必需的。
5. 我的工程实践:用 CaveAgent 重写一个多步骤运维诊断 Agent
5.1 场景背景与原始实现的问题
过去我们在内部维护着一个模拟的"半夜线上故障自动诊断系统"。它的任务很简单:收到一条告警消息后,自动分析日志、检查相关服务状态、推断可能原因、给出建议。听起来不复杂,但真正落地时状态管理问题很多。
原始实现是基于"多轮调用的链式编排":告警进来了,第一阶段调用日志分析,把结果拼进 Prompt;第二阶段把日志分析结论再加上服务状态信息,继续调模型;第三阶段把前两轮结果合成最终诊断建议。每个阶段之间靠一个大上下文接力,相当于不论第一阶段的结果有没有用,第二阶段都会看到完整信息,第三阶段也一样。
这个方案有几个典型毛病:
- 上下文过载:日志分析阶段如果产生了大量原始日志,那第二阶段整个 Prompt 会被日志占据,模型更容易"迷失重点"。
- 阶段回溯困难:如果第三阶段发现第一个阶段分析错了,你没法单独重跑第一个阶段然后保持后面不变,你只能全流程重来。
- 并行性差:有些诊断步骤其实是独立的(比如同时检查日志和检查服务状态),链式编排只能串行执行,白白浪费了时间窗口。
5.2 重写后的架构与实现要点
用 CaveAgent 重构后,我的设计变成了这样:
Agent 类定义:定义了一个"故障诊断基类",包含状态字段:alert(告警详情)、log_analysis(日志分析结果)、service_status(服务状态快照)、diagnosis(最终诊断结论)、current_stage(当前执行阶段)。
运行时实例:每一条告警消息,运行时自动创建一个诊断实例。实例拥有独立的current_stage,不同实例互不干扰。
方法拆分:把"日志分析""服务状态检查""诊断推断"拆成三个独立方法。这三个方法可以并行执行,也可以按依赖顺序执行,完全由编排逻辑决定。
状态流转:诊断进入第二阶段时,运行时自动把第一阶段写好的log_analysis和service_status作为输入传递给第二阶段,不需要再把原始日志、服务检查命令输出这些中间信息全塞到模型上下文里。
这一版代码在结构上清晰非常多。我特别想强调一个细节:阶段之间的状态传递不再是字符串拼接,而是动态读取已写入的状态字段。这意味着什么?意味着我可以随时写一个独立脚本,只要求诊断 Agent 进入某个特定状态,然后调试后续逻辑,不需要构造一整套前置 Prompt 来"逼"模型进入某个状态。这个开发调试体验是质的变化。
下面是重构后模拟项目的运行时组装示意(并非实际库的完整代码,仅表达工程组织方式):
async function runDiagnosis(alertPayload) { // 运行时创建实例,注入初始状态 const instance = await caveRuntime.createInstance("diagnosis_agent_v1", { alert: alertPayload, current_stage: "initialized" }); // 阶段一:并行收集两个独立维度的信息 await Promise.all([ instance.callMethod("analyzeLogs"), instance.callMethod("checkServiceStatus") ]); // 阶段二:基于已写入的状态执行推理 instance.callMethod("inferDiagnosis"); // 阶段三:返回结构化诊断结果(含完整状态快照) return instance.getState(); }5.3 实测效果:显式状态管理省下的不只是 token
这个重写项目上线试跑后,有几个数据我记得很清楚:
- 上下文 token 消耗大约下降为原来的 30-40%。因为不再把无关中间产物全部拼接进后续 Prompt,模型每次只需要读取跟自己当前任务直接相关的状态字段。
- 故障定位时间明显缩短。以前出问题时我需要读三个阶段的完整 Prompt 和输出来判断哪一步有问题,现在直接看状态字段——
log_analysis明显不合理,那就只重跑日志分析,其余不动。 - 并行执行的收益很直接。告警诊断的日志分析和服务状态检查本就互不依赖,并行后整体诊断耗时下降了约 40%(模拟环境中)。
当然,它也引入了一些"新成本"。比如类定义和状态字段设计需要提前规划,比"随手写链式调用"要多动脑;比如调试时你要关注状态是否符合预期,而不能只盯着返回文本。但这些成本换来的是长期可维护性和可观测性,在我看来非常值得。
6. 底层工程问题:持久化、序列化与失败恢复的经验
6.1 状态字段的序列化策略
要把 Agent 状态持久化并且能恢复,第一道坎就是序列化。我实践中踩过的最大的坑是:想当然地把状态序列化成"通用 JSON 对象",然后发现字段类型、嵌套结构、以及里面塞的不可序列化对象(比如文件句柄、数据库连接)全成了阻碍。
CaveAgent 的思路之所以让我觉得设计得稳,是因为它在一开始就要求状态字段声明类型,等于在序列化之前就建立了 schema。实践中,我建议状态字段遵守几条原则:
- 状态字段只放可序列化数据。所有无法持久化的对象都应该挂在运行时外部的资源池上,通过 ID 引用,不要直接放进状态。
- 嵌套层级不要太深。状态字段是给人看也给模型读的,三到四层以内的嵌套结构刚刚好,再深就要考虑重建读取索引。
- 每次状态变更记录版本号。这个我强烈推荐。它不光是调试利器,更是未来做状态回滚的基础。某次状态变更把字段写坏了,你能快速定位到是哪一版引入的问题。
6.2 快照恢复时的"偏移重建"
"断点续跑"听起来很美好,但真正实现时有个细节不能忽略:Agent 恢复时,它的外部资源环境可能已经变了。比如诊断 Agent 之前调用过某个日志服务,恢复时那个服务的访问凭证可能过期了;或者之前读取过某台服务器的状态,恢复时那台服务器已经下线了。
在这种场景下,单纯恢复"内部状态"是不够的。我之前的经验是,恢复逻辑还需要把状态中引用的外部资源重新校验一遍。CaveAgent 包含的持久化接口可以自定义恢复钩子(hook),允许你在快照恢复时重新建立外部依赖。我强烈建议所有生产级 Agent 都要设计这一层,否则断点续跑只是"看起来能用"。
我在实际项目中设计了一个简单的恢复校验函数:
# 恢复钩子示意:恢复时验证外部资源是否仍然有效 def on_restore(instance_state): # 检查外部凭证是否过期 if instance_state.credential_id: verify_credential(instance_state.credential_id) # 检查外部数据库连接是否健康 if instance_state.db_session_ref: session = resource_pool.ping(instance_state.db_session_ref) if not session.is_alive(): # 重建连接并更新状态引用 instance_state.db_session_ref = resource_pool.reconnect() return instance_state6.3 失败重试与状态回滚的边界
有状态系统的另一大话题是失败重试。并不是所有失败场景都能靠"原地重试"解决,有些必须做状态回滚。我的经验是,状态的每次修改都应当是可回滚的,至少要能回滚到上一个"阶段快照"。
实际操作中,我是这样做的:在 Agent 的每个执行阶段入口处,自动保存一个"阶段开始状态快照"。如果该阶段执行途中出现不可恢复的错误,就自动回滚到阶段开始时的状态,然后重新尝试。这比整体快照回滚更精确,因为只影响了当前阶段应该产生的状态变化,不会把之前已经正确生成的结果也一起抹掉。
有人可能担心"回滚再重跑"和"全量重放"有什么区别。区别在于,回滚之后,Agent 不需要重新执行前面所有阶段,它只需要重新执行当前阶段的方法逻辑。对于每个阶段都可能调用大模型、执行时间很长的 Agent 来说,这个设计能省下大量时间和费用。
7. 引入 CaveAgent 之后的取舍与踩坑记录
7.1 抽象成本不是免费的,别把简单任务硬拗成对象
我必须说句公道话。CaveAgent 这套范式不是万金油,如果你做的只是"单轮问答"或者"无需状态的轻量工具调用",强行引入有状态运行时就是过度设计。
我见过有人把"天气查询 Agent"也做成有状态实例,状态字段里存了"上次查询城市"和"最近一次天气结果",理由是"希望 Agent 记住用户偏好"。说实话,这类记忆用一个简单的 Key-Value 表就能解决,没必要动用运行时管理。
我的判断标准很简单:
- 如果 Agent 的流程超过三个步骤,并且步骤之间存在明确的输入输出依赖,适合用有状态运行时。
- 如果 Agent 需要在长时间内持续跟踪多个任务的状态,适合。
- 如果 Agent 任务之间需要协作并传递结构化结果,适合。
- 如果只是"用户问一句模型答一句",那传统无状态调用更划算。
7.2 状态与 Prompt 的边界:别让模型"看到"所有状态
引入状态字段后,新手最容易犯的错是:把所有状态一股脑塞进 Prompt,让模型"参考"全部状态。这等于把有状态运行时降级成了"结构化的消息历史",没有发挥出状态按需引用的优势。
正确做法是:只把当前阶段决策所需的关键状态字段暴露给模型,其他状态继续留在运行时里。举个例子,写作 Agent 写作时,没必要让它看到调研 Agent 全部的搜索日志,只需要给它"标题、摘要、关键来源"三个字段。其他状态在需要时才按需注入。
这一条我用一个直白的话来记:状态是数据源,Prompt 是视图。视图应该聚焦,数据源才能完整。
7.3 踩坑实录:状态会被并发实例"无意间共享"吗?
有状态运行时最需要小心的坑之一就是并发安全。我在模拟项目中曾经定义了一个类级别的缓存变量,原本希望用它来加速某些计算。结果发现所有基于该类的实例竟然共享了这个缓存,导致两个实例同时修改时互相污染。
这让我意识到一个原则:状态字段一定要归属于实例,而不是类。如果确实需要共享某些全局资源(比如共享配置、公共缓存),应该显式标注为共享资源,并且通过运行时提供的专门机制去访问,不能默认放在实例状态里。CaveAgent 的运行时对"实例私有状态"和"类共享资源"是区分管理的,但你自己得在建模时就想清楚哪些是哪种。
7.4 状态膨胀控制:不要让状态变成新的"无限上下文"
有状态系统还有个隐藏风险:状态本身也会膨胀。如果你设计的 Agent 不断往notes、history、intermediate_results里追加内容,而且从不清理,那到后期状态文件会越来越大,不仅持久化开销高,恢复时加载也会变慢,更危险的是模型读取状态时又会面临上下文过载。
我的做法是:在状态字段上设计"裁剪策略"。比如只保留最近 N 条工具调用记录,更早的摘要聚合后存放;中间过程日志按等级保留,关键节点留详情,普通节点只留一行摘要。这跟操作系统的日志轮转(log rotation)是一个思路,只不过作用在 Agent 状态上。
下表是我在项目中用的状态字段裁剪经验,供参考:
| 状态字段 | 保留策略 | 备注 |
|---|---|---|
| 长期目标 | 永久保留 | Agent 行为基准 |
| 关键决策记录 | 全部保留 | 可审计、可追溯 |
| 工具调用明细 | 最近 20 条 + 关键调用详情 | 防止状态无限膨胀 |
| 原始日志 | 只保留摘要和告警级明细 | 原始数据归档到外部存储 |
| 中间推理草稿 | 只保留最终版 | 中间草稿不回放 |
8. 写在最后的实战建议:如果你想在自己的项目里尝试这套范式
8.1 从"一个长流程任务"改造起,不要一开始就铺大摊子
如果你读了前面部分,想尽快在自己的代码里试水 CaveAgent 这类有状态运行时,我给的第一条建议是:挑一个明确的、有状态的长流程任务作为试点,比如"周期性的数据汇总分析"或者"多步内容处理流水线",不要一上来就重构整个 Agent 体系。
我当初就是从"运维诊断 Agent"这个单一场景开始的。即使只是这一个场景,我依然经历了状态字段设计、序列化策略调整、恢复钩子编写等一堆工作。试点场景跑通了,你才积累起足够的心得,再推广到其他场景时才不会手足无措。
8.2 状态字段就是你的数据模型,值得早规划
别把状态字段当成"临时变量"随意添加。加字段看起来容易,但每一次字段变更都涉及到序列化兼容、历史快照迁移、恢复逻辑改造。我的经验是,先列出现有 Agent 流程里所有需要跨阶段传递的信息,把这些信息按"生命周期长短"和"共享范围"分类,再设计字段。宁可最开始多花三四个小时做规划,也不要在上线后再补窟窿。
8.3 把调试工具建立在状态之上,而不是日志之上
传统 Agent