自我改进型 Agent(Self-improving agents)和事件溯源(Event Sourcing)放在一起,乍看像是一个架构洁癖者的个人偏好。真正把一个会从经验里学习的 Agent 跑起来之后,我发现这句话其实是一个很实际的产品结论:Agent 要改进自己,前提是它必须能看到自己过去到底做了什么、在什么条件下做的、结果是什么。事件溯源做的事情,恰恰就是把这一整条因果链原封不动地保存下来。适合正在做 Agent 记忆、反思、经验复用的开发者,也适合想从架构层面理解 Agent 自我进化的读者。下面我会先讲清楚为什么事件溯源是这个问题的自然答案,再给出一套可以照着落地的字段设计、闭环流程和排查顺序。
1. 先拆清楚:自我改进型 Agent 到底缺什么
1.1 “自我改进”不等于“多跑几次”
很多 Agent 项目所说的自我改进,其实只是“这次失败了,下次换个 prompt 再试”。这不算自我改进,这算人工调参。真正的自我改进,是 Agent 能在无人介入的情况下,从过往的决策序列和结果里提炼出规律,然后在下一次面对相似任务时改变自己的策略。
要做到这一点,Agent 需要四种能力:
- 精确认知:知道某一次任务中,自己在哪一步做了哪个选择。
- 因果判断:知道哪个选择直接导致了哪个结果。
- 跨任务对比:能比较多次任务之间的差异,找出模式和异常。
- 策略更新:把规律转写成新的指令、新的偏好、新的工具使用方式。
这四种能力有一个共同前提:Agent 必须拥有一份不会丢失、不会改写的“过程记录”。结果记录不够,因为结果不包含过程;记忆摘要不够,因为摘要在生成那一刻就已经丢了细节。只有按时间追加、逐条保存的事件,才能同时满足上面的四种能力。
1.2 事件溯源解决的是“经验可回放”问题
事件溯源是一种很成熟的软件架构模式,核心规则不复杂:不直接修改当前状态,而是把每一个状态变更记录成一条不可变事件,追加写入事件流;当前状态只是这些事件投射出来的视图。
普通业务系统使用事件溯源,更多是为了审计、追溯、重放。但放到自我改进型 Agent 的场景里,事件溯源的价值被放大了:它让 Agent 的经验从“模糊的记忆”变成了“可以重放的录像”。录像可以一帧一帧看,也可以跳着看;可以单条看,也可以统计着看。这正是分析和改进需要的原材料。
换句话说,这句话的准确理解是:自我改进型 Agent 不是“应该”用事件溯源,而是“本质上”就是事件溯源系统。Agent 的每一次决策、每一次工具调用、每一次反馈,都是一个不可变事件。Agent 的当前策略只是这些事件的一个投影。理解到这个层面,后面的设计就有方向了。
2. 为什么记忆库和状态快照撑不起自我改进
2.1 快照丢失因果链
很多团队给 Agent 做记忆的时候,第一版都是“跑完任务,把结果保存下来”。这个方案看起来省事,但它有一个致命问题:你只保存了最终状态,没有保存状态之间的因果链。
例如一个 Agent 先调了检索工具,拿到一段不相关的资料,然后犯了一个推理错误,最后输出失败。如果你只保存“任务失败”这个结论,事后你不知道失败是因为检索词不准、工具返回格式异常、还是推理环节出了问题。你也不可能回去做对比实验,因为对比实验需要知道当时每一步到底发生了什么。
事件溯源会强制你把每一步都写成事件,于是因果链天然存在。失败不再是一个孤立结果,而是一串事件里的一个节点,前因后果都能回放。
2.2 向量库擅长联想,不擅长还原决策过程
现在 Agent 记忆的主流方案是向量数据库:把对话、文档、反思结果向量化,然后按语义相似度检索。这个东西适合做“联想”,不适合做“还原”。
一个很典型的场景:你希望 Agent 从过去 100 次失败里找出“每当我调用某个解析工具时,输入编码不一致导致崩溃”的规律。向量检索可以帮你找到语义相近的几条失败记录,但很难帮你按时间顺序还原每一次完整执行过程。因为向量库本身不保存顺序结构,也通常不保存事件之间的关系。
我不是说向量库没用,而是说它应该用在事件日志之上:先用事件溯源保证完整性和顺序性,再用向量库做记忆查询。两者不是替代关系,是上下游关系。先把原料完整存下来,再谈怎么检索和联想。
2.3 会话日志有记录,但没有“事件结构”
第三种常见做法是直接记录日志,比如把 Agent 的每次 prompt 和 response 写入一个日志文件。这比快照好一点,但还差关键的“事件结构”。
普通日志的问题是:每条日志是独立的,没有统一的事件类型,没有 task_id、attempt_id、cause 这些关联字段,也没有把工具调用、环境反馈、人类反馈、策略版本区分开来。结果就是,日志能用于“人工排查”,但很难用于“自动学习”。程序不知道哪条日志是决策动作,哪条日志是结果信号,更不知道哪些条目应该被聚合到同一次反思里。
事件溯源强制的就是这个结构:先定义事件类型,再按类型写入标准字段。有了结构,后续的统计分析、失败聚类、策略更新才有自动化基础。
3. 从“完整事件日志”到“经验资产”的最小落地设计
3.1 事件类型和字段怎么设计
如果要从零开始设计一个 Agent 事件溯源方案,我建议先定一组最小事件类型,不要一上来就做几十种。最少可以先包含这样几种:
| 事件类型 | 记录内容 | 关键字段 |
|---|---|---|
| attempt_started | 一次任务尝试开始 | task_id, attempt_id, 输入摘要, 策略版本 |
| decision_made | Agent 做了一个关键决策 | 决策内容, 候选选项, 理由摘要, 时间戳 |
| tool_called | 调用了一个工具 | 工具名, 入参摘要, 调用顺序号 |
| tool_result_received | 拿到工具返回 | 工具名, 出参摘要, 耗时, 是否有错误 |
| feedback_received | 收到外部反馈 | 反馈来源, 反馈类型(成功/失败/纠正), 内容摘要 |
| reflection_completed | 完成一次反思 | 反思结论, 待改进项, 引用的决策事件 ID |
统一的事件结构比“多”更重要。每个事件都必须带 task_id 和 attempt_id,这是后续跨任务对比的基础。没有这两个字段,事件再多也拼不成经验链。
简单起见,第一版可以用 JSONL 文件或数据库追加表来做事件存储,不需要直接上 EventStoreDB 这样的重型组件。关键是保证“只追加、不修改、不删除”,并且每条事件有唯一的 event_id。一个典型的工具返回事件大概长这样:
{ "event_id": "evt_10023", "event_type": "tool_result_received", "task_id": "task_8842", "attempt_id": "task_8842_attempt_3", "timestamp": "2025-01-12T09:30:22Z", "tool_name": "document_parser", "input_summary": "file_id=doc_337, encoding=auto", "error": "unsupported_encoding", "elapsed_ms": 1423 }这种结构看起来简单,但已经足够支撑大多数复盘分析。
3.2 用投影按需生成记忆和指标
事件溯源里有一个概念叫投影:从事件流里派生出一个视图。对 Agent 来说,投影可以是多种形式:
- 最近 N 次失败分析:把失败事件聚类,看哪些步骤最常出问题。
- 工具稳定性报告:按 tool_called 和 tool_result_received 统计错误率、平均耗时。
- 长期语义记忆:把关键事件向量化,写入向量库,供后续检索使用。
- 策略草稿:把反思结论汇总成待更新的系统指令。
投影的好处是:原始事件日志永远不变,你可以随时用新的视角重新生成视图,不需要改动历史数据。今天你认为“耗时”不重要,以后想优化速度了,重新算一次投影就能得到新指标,历史事件还在那里。这就把“经验”从一个静态结论变成了一套可反复挖掘的数据资产。
3.3 一个最小闭环示例
最小闭环可以这样设计:
- 每跑完一个任务,把一个 attempt_id 下的所有事件收集起来。
- 运行一个反思脚本,读事件序列,找出“失败结果之前最近的 3 个事件”。
- 判断失败原因:是工具报错、输入不对,还是决策不合理。
- 把反思结论作为一条 feedback_received 或 reflection_completed 事件写回事件流。
- 下一次遇到相似任务时,先检索最近相关反思,把它拼进系统指令。
这个闭环里,第 2 步和第 4 步都依赖同一份事件源。没有完整事件日志,反思就没有输入;没有反馈事件,改进就没有闭环。整个系统的“原料”和“产物”都是事件,所以说自我改进型 Agent 本质上就是事件溯源系统。先跑通这个最小闭环,再扩展成批量任务和更细粒度的事件类型。
4. 从自我改进到元进化:事件溯源为什么是必经之路
4.1 自我改进和元进化的区别
最近关于 Agent 演进方向的讨论里,有一个说法很有代表性:现在的 Agent 正在进入一个以“经验”为核心资产的阶段,研究热点正从自我改进逐步走向“自我到元进化”(self-to meta evolution)。这两个层次的区别可以这样理解:
- 自我改进:Agent 在同一个任务类型上越做越好,比如写代码的 Agent 通过反思,减少重复犯的错误。
- 元进化:Agent 改进“改进机制本身”,比如发现自己当前的反思频率太低、反思粒度太粗、策略更新太激进,于是调整反思策略和更新策略。
简单说,自我改进是业务能力提升,元进化是学习能力提升。真正持久的 Agent 系统,最终一定会走向元进化。因为只要业务任务变了,原来那套反思方式和 prompt 更新规则就可能失效,Agent 需要有能力调整自己的“学习方式”。
4.2 观察“改进过程”本身也需要事件日志
元进化有一个很关键的隐含要求:你不仅要记录 Agent 执行任务的事件,还要记录 Agent 进行反思和改进的事件。也就是说,反思本身也必须事件化。
举个例子。如果一个 Agent 每次失败后都立刻重写一遍系统 prompt,短期内可能有效,但长期看很危险:频繁更新会让行为变得不稳定,今天改好的问题可能把昨天能跑通的场景又弄坏。这个“频繁更新导致不稳定”的规律,Agent 自己是看不到的,除非它把每一次反思和每一次策略更新都记录成事件。有了这些事件,更高一层的元进化分析才能回答:哪些反思方式在哪些任务上更有效,策略更新应该激进还是保守。
这就像老师不知道学生用了什么学习方法,只看考试分数,很难判断是方法好还是运气好。事件溯源天然支持这个要求,因为事件流里什么都可以追加:任务事件、反思事件、策略更新事件,全都在同一条链路上。
4.3 三层事件流:任务层、反思层、策略层
落地时可以按层级划分事件,但共用同一条事件流:
| 事件层级 | 示例事件 | 主要用途 |
|---|---|---|
| 任务层 | attempt_started, decision_made, tool_called, feedback_received | 复盘单次任务 |
| 反思层 | reflection_completed, improvement_proposal_created | 生成改进建议 |
| 策略层 | strategy_updated, strategy_rollback | 管理和回滚策略 |
三层事件流都追加在同一个序列里,用 event_type 区分。这样元进化分析就能回答:某次策略更新产生的好效果,到底来自哪次反思,而那次反思又参考了哪些任务事件。链路完整,收益归因才能做。所以我倾向于认为,事件溯源不只支撑自我改进,更是从自我改进走向元进化的地基。没有这个地基,Agent 只能靠人工反复调 prompt,谈不上自我进化。
5. 落地时最容易被忽视的边界和坑
5.1 日志不是越多越好
一提到事件溯源,很多人会走极端,恨不得把模型内部每一层、每一个 token 都记录下来。这是成本陷阱。事件记录也有代价:存储成本、写日志耗时、后续分析时的计算消耗和 token 成本。
我的建议是分级记录:任务级事件全量记录,工具调用记录入参摘要和出参摘要,不记录完整大文本;只有失败或关键节点才追加完整上下文。先跑通,再逐步加细。如果一上来就追求“全量无损”,系统会被日志拖垮。
可以引入一个定量判断:单条任务的完整事件流应当在一次 LLM 调用可处理的长度范围内,并且增长速度要可控。一旦发现事件流比任务本身还大好几倍,就要考虑字段精简和事件聚合。
5.2 重放要小心外部副作用
事件溯源经常提到的能力是“重放历史”,但对 Agent 来说,重放不等于重新执行。工具调用是有副作用的:发送消息、写文件、扣费、访问外部服务。这些操作不能无脑重放。
安全做法是:事件重放只用于“分析”和“推导”,不用于“重新执行”。你可以重放事件流,复盘当时的决策;但不要为了验证某个新策略,就把历史事件里的工具调用原样再执行一遍。重新验证应该使用隔离环境、模拟工具或幂等接口。这一点建议在架构设计阶段就想清楚,否则很容易踩到线上事故。
5.3 改进策略必须版本化
自我改进最怕的是“越改越差”还发现不了。如果 Agent 根据一些失败案例修改了自己的系统指令,随后整体效果下降,你必须能快速回答:是哪个版本引入了变化,基于哪些事件做的修改,修改前后各是什么。
这要求策略本身带版本号,策略更新记录本身也是事件。strategy_updated 事件至少要包含:旧策略版本、新策略版本、触发原因的反馈事件引用、更新人(人工或 Agent 自动)。这样当效果回退时,你可以在事件流里精确定位,甚至回滚到上一个策略版本。没有版本化,改进就变成不可逆的赌博;版本化之后,改进才变成可实验、可回滚、可对比的工程行为。
5.4 先跑通单任务,再谈批量经验挖掘
很多团队一上来就做“全局经验挖掘”,想从几万条事件里自动产出策略改进建议。这个目标很大,但很容易失败,因为事件质量还没验证。
我建议的顺序是:先用一条任务跑通事件记录和单任务反思,确认事件字段完整、因果链清晰;再扩大到几十条任务,验证跨任务对比和失败聚类;最后才考虑自动化生成策略更新。如果跳过前两步,后面所有分析都会建立在脏数据上,算法再好也没用。低配置、小规模环境也能先跑通这套流程,关键是先把链路理顺。
6. 排查链路和推荐实践顺序
6.1 四个常见问题的排查顺序
如果自我改进系统表现不符合预期,建议按这个顺序排查:
- 先看事件是否完整:是否缺少 decision_made 或 tool_result_received,事件顺序是否被破坏,task_id 和 attempt_id 是否错乱。
- 再看输入和日志:Agent 当前的上下文是从事件流投影出来的,投影本身可能过滤掉了关键历史,导致反思看不到原始因果链。
- 再看策略版本:当前策略版本是什么,上次更新是基于哪些事件,是否把单次失败误当成了普遍规律。
- 最后看评估方式:成功标准是否一致,是不是把不同难度的任务混在一起比较,导致改进效果被掩盖。
这四个问题里,前三步都依赖事件溯源。事件完整性和策略版本化做好之后,大部分“改着改着变差了”的情况都能快速定位。
6.2 从零开始落地的最小路线
最后给一份更通用的落地清单:
- 定义 6 到 10 个核心事件类型,先保住任务、决策、工具调用、反馈四类。
- 用 JSONL 或数据库追加表实现一个事件存储,保证只追加不修改。
- 为每个任务生成 task_id 和 attempt_id,所有事件都关联这两个字段。
- 实现至少一种投影:失败分析视图、工具错误率视图、或反思记忆视图。
- 跑通单任务反思闭环:从事件流生成反思,把反思写回事件流。
- 加上策略版本号和策略更新事件,建立可回滚机制。
- 每天或每个批次跑一次跨任务分析,观察改进率。
- 再考虑向量库、自动策略更新、元进化。
这一套做完之后再回头看那句话:自我改进型 Agent 是事件溯源的,其实已经不需要争论了。你需要的不是更多记忆插件,而是一份从第一秒开始就没有丢失、没有改写、可以随时分析的事件日志。把这条地基打稳,Agent 的每一步改进才真正有据可依。