news 2026/9/24 17:47:55

Agent 消息与事件工程笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent 消息与事件工程笔记

摘要:LLM 无状态,状态要在端点攒起来、过程要流出去——攒起来的是 Message,流出去的是 Event,这是 agent loop 上两个最基本的数据面。本文把它们拆开讲:各是什么、一轮 loop 里怎么流动、四家框架怎么实现、跨边界怎么靠 MCP / A2A / AG-UI 统一,最后落到工程上怎么用、三条边界怎么划。


《Agent 工程笔记》系列

  1. Agent Loop 工程笔记
  2. Agent 状态管理工程笔记
  3. Agent 消息与事件工程笔记(本篇)
  4. Agent 中间件工程笔记
  5. Agent 工具调用工程笔记
  6. Agent MCP 工程笔记
  7. Agent Skill 工程笔记

LLM 每次调用都是无状态的,状态要靠 harness 在端点自己攒起来,过程要靠 harness 流出去。攒起来的是 Message,流出去的是 Event——这是 agent loop 上两个最基本的数据面。实际项目里这俩常被当成一回事,通信层从第一天就埋了坑。下面把两件事拆开讲:先说清它们分别是什么,再看一轮 loop 里怎么流动、各家怎么实现、跨边界怎么靠协议统一,最后落到工程上怎么用。


图1:Message 和 Event 都在数据层,中间件在机制层,MCP / A2A / AG-UI 在边界层做翻译。

一、Message 与 Event 是两件事

1.1 Message:通信 / 状态单元

承载内容的单元,进入 state,是以后可以重放的真相。从事件溯源的角度看,message log 才是真相,当前 state 只是它的一个投影——《Agent 状态管理工程笔记》§2.2 已经铺过:历史消息序列叫 transcript / message history,它不是 state 本身,而是 state 里的一个字段。

同一个"消息",其实跨三层作用域,讨论时得先说清说的是哪层:

  • LLM 对话消息(transcript,进 state):OpenAI 的messages[]、Anthropic 的messages(system 单独放顶层)、Gemini 的contents、LangGraph 的BaseMessage、AgentScope 的UserMsg / AgentMsg
  • 跨 agent 消息(A2A 的Message,带Parts:TextPart / FilePart / DataPart)。
  • 传输消息(JSON-RPC / SSE 帧,线路上的格式)。

LLM 对话消息和 A2A 消息形状完全不同,拿一层去套另一层是最常见的谬误。

Message 长什么样

一个 Message 对象大致长这样(以 OpenAImessages[]为基准,各家字段名不同但骨架一致):

字段作用
role说话方:system / user / assistant / tool
content内容体:纯文本,或 block 数组(Anthropic 的 text / tool_use / thinking),或 parts(A2A 的 TextPart / FilePart / DataPart)
id消息 id,稳定唯一,用于关联与重放
tool_calls模型发起的工具调用(assistant 侧)
tool_call_id工具结果回写时绑定到哪个调用(tool 侧)
metadata时间戳、来源 agent 等附加信息

几个要点:有稳定 id、进 state、是 transcript 的一员、可重放——这是它和 Event 最根本的区别。

{"id":"msg_01","role":"assistant","content":"我先查一下天气","tool_calls":[{"id":"call_abc","type":"function","function":{"name":"get_weather","arguments":"{\"city\":\"北京\"}"}}]}

Anthropic 的content是 block 数组、A2A 的MessageParts装多模态——形状各异,但 role / content / id 这套骨架每个框架都有。

1.2 Event:通知 / 流单元

描述状态变化或生命周期进展的瞬态信号,出边界,用来驱动 UI 和可观测性。它通常可以丢、需要幂等、也最好能重放。

各家分法不同,但大致归三桶:流式增量(delta,文本或工具参数逐块到达)、生命周期(run / task 开始、步开始/结束、完成/失败)、中断与错误(human-in-the-loop interrupt、error、cancel)。

Event 长什么样

一个 Event 对象通常包含这些字段:

字段作用
type/event事件类型名,如TEXT_MESSAGE_CONTENTresponse.output_text.deltaTaskStatusUpdateEvent,常带点号命名空间
id事件自身 id,可选——MCP 的 Notification 就没有 id(单向、接收方不回);有 id 才能做幂等去重
run_id/thread_id/parent_run_id/task_id关联到哪次运行 / 会话,用来拼 append-only 轨迹、支持分支与时间旅行
source/origin谁发的,多 agent 时区分来源
data/payload/delta事件体:delta 事件里是这一小块内容,lifecycle 事件里是状态,state 事件里是快照或 patch
timestamp/sequence时序,用于重放排序

内容裹在data/delta里,不像 Message 的content直接挂顶层。

{"type":"TEXT_MESSAGE_CONTENT","messageId":"msg_123","runId":"run_abc","threadId":"thread_xyz","delta":"你好"}
event: response.output_text.delta data: {"type":"response.output_text.delta","response_id":"resp_...", "item_id":"...","content_index":0,"delta":"你好"}

两者都是type标明是什么、delta是这一块内容、再带血缘字段把事件绑到某次 run / 某条 message 上。


图2:Message 进 state 成为可重放的真相,Event 出边界驱动 UI 和可观测性,方向相反。

1.3 为什么要把它们分开

Message 进 state,Event 出边界。混为一谈会带来两类典型 bug:

  • 反模式 A:把 tool result 当 event 流式推掉,没写回 message / state,结果崩溃后没法从 checkpoint 续跑(见《Agent 状态管理工程笔记》§5.5 审计与重放)。
  • 反模式 B:只流式推 message delta(本质是 event),不保留 message 全量,UI 看着爽,但 state 里没有真相,无法重放与审计。

AG-UI 把两者都标准化了还分得清:TEXT_MESSAGE_CONTENT是 message delta,可以重放拼回 message;RUN_STARTED是 event,不进 state。这是"分开"的工业级范例,也是后面各家对照时的标杆。

1.4 和前面两篇的关系

Message 是 state 的肉身:transcript 住在 state 里(《Agent 状态管理工程笔记》§2.1 / §2.2)。Event 是 checkpoint 和可观测性的血脉:state 每步快照加上事件流,就是一条完整的可重放轨迹(同篇 §5.5 审计)。

二、它们在 loop 里怎么走

2.1 从 harness 哑路由看两个数据面

《Agent Loop 工程笔记》里给 harness 的定位是个哑路由:每轮就四件事,组装 messages、调 LLM、执行 tool、把结果写回 messages;控制流在模型输出里,不在 harness 里。但还有第五件事常被忽略:把"过程"流出去给调用方和 UI。

这件事正好暴露出两个基本数据面:

  • 进 state 的 Message(说了什么):对话内容、工具调用、工具结果,最终落进 session / state,是可重放的真相。
  • 出边界的 Event(发生了什么):文本在流式吐、某步开始了、工具调完了、出错了,这些瞬态信号要实时推给前端和可观测系统。

消息和事件不是附加功能,是 loop 的两个基本 I/O 面。这篇接《Agent Loop 工程笔记》的"哑路由"和《Agent 状态管理工程笔记》的"Session 第二含义 = 通讯连接"——通讯连接落下来,就是 Message / Event 的传输层。

2.2 一轮 loop 里的两条路径

拆开看一轮 loop,Message 和 Event 走的是两条方向相反的路径:

  1. 入(Message 沉淀):上一轮的 message 历史从 state 读出,组装成这次 LLM 的输入messages[];LLM 产出的 tool_call 也作为 Message 进入同一序列。
  2. 出(Even
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 17:46:38

第 3 篇 · p2m 内存类型分类

p2m 表项不只记"对应哪个 MFN",还带一个类型标签(p2m_type),决定访问它时的行为。这一篇把 Xen 的 p2m 类型讲透:完整枚举 各自用例,以及它们之上两个容易混淆的"分组/空间"概念——类…

作者头像 李华
网站建设 2026/9/24 17:46:25

Zoom视频会议软件电脑版下载安装教程

概述 Zoom 是一款跨平台云视频会议软件,支持 Windows、macOS、Linux、iOS、Android,提供高清视频会议、屏幕共享、文字聊天、会议录制、虚拟背景等功能。本文讲清电脑版下载安装、权限设置与核心功能。 一、下载与安装 从 Zoom 下载入口 获取安装包&…

作者头像 李华
网站建设 2026/9/24 17:45:28

【AI大模型进阶】整理你的 AI 工具集:构建属于你自己的 AI 开发百宝箱

【AI大模型进阶】整理你的 AI 工具集:构建属于你自己的 AI 开发百宝箱 这是【AI大模型进阶】系列第一百五十课,也是本系列算力工程、云端开发、模型训练运维板块的收官总结课。在前序149节课程中,我们从零入门,逐一掌握了云端算力租赁、SSH远程开发、Tmux终端保活、GPU状态…

作者头像 李华
网站建设 2026/9/24 17:44:20

函数:写一次代码,用一万次

如果你连函数都写不出来, 那么你根本就没有进入到这门学问的门槛里面去。函数, 它是编程里面的那个核心的抽象。你现在去写一个函数, 这就等于你去发明了一个新的动词。那其他的人, 包括那个未来的你自己在内, 也只需要去知道它是做什么事情的就行了。至于说它到底是怎么去做的…

作者头像 李华
网站建设 2026/9/24 17:40:38

ben skills

代码开发规范 不要为了测试便利在主业务代码中加入测试专用的注入点、分支或参数;应优先在测试代码中通过 mock 依赖或替换模块实现测试,保持主业务代码的可读性和职责纯粹。 开发前端代码时默认不添加无障碍属性(role、aria-* 等&#xff09…

作者头像 李华
网站建设 2026/9/24 17:40:38

春晚机器人火爆背后:AI大模型点燃黄金赛道,普通人也能抓住机遇!

春晚的机器人表演引发了人们对AI技术的关注。文章指出,AI和机器人已经进入普通人的生活,并推动了“机器人租赁”等新产业的发展。同时,AI行业的薪资水平也在不断提高,因为市场上对AI人才的需求远远大于供给。普通人可以通过学习实…

作者头像 李华