Hermes Agent 流式输出架构解析 一个支持多消费者、多平台的实时流式输出设计前言在 AI 对话应用中实时流式输出Streaming Output能显著提升用户体验——用户无需等待完整响应即可看到正在生成的内容。Hermes Agent 采用了一套精心设计的流式输出架构支持同时向 CLI、TUI、第三方平台等多个目标推送内容。本文将深入解析这一架构的设计思路和实现细节。一、整体架构Hermes 的流式输出采用回调机制 多消费者模式┌─────────────────────────────────────────────────────────────┐ │ Agent (核心引擎) │ │ │ │ run_conversation() → 流式调用 → stream_callback() │ └───────────────────────────┼─────────────────────────────────┘ │ ┌───────────────┼───────────────┐ ▼ ▼ ▼ ┌───────────────┐ ┌──────────────┐ ┌──────────────────┐ │ CLI │ │ TUI Gateway │ │ Gateway │ │ 终端输出 │ │ Web UI 接口 │ │ 多平台消费者 │ └──────────────┘ └──────────────┘ └──────────────────┘ │ │ │ ▼ ▼ ▼ 本地终端显示 WebSocket推送 第三方平台编辑核心思想Agent 只需产生一次流式内容通过回调分发到多个消费者。二、核心组件详解2.1 Agent 层 —— 内容生产者Agent 是流式输出的起点负责调用 LLM 的流式 API 并将内容通过回调分发。工作流程接收用户消息和回调函数调用流式 API逐 token 获取响应每获取一个 token调用一次回调响应结束时调用回调并传入None表示结束关键设计回调函数作为参数传入实现解耦Agent 不需要知道有多少消费者支持可中断的流式调用2.2 CLI 消费者 —— 本地终端CLI 是最直接的消费者负责将流式内容输出到终端。工作流程接收增量文本一个或多个 token过滤推理/思考标签如think等进行行缓冲逐行输出到终端使用 prompt_toolkit 实现兼容终端的实时打印关键设计行缓冲避免逐字符输出导致的闪烁标签过滤用户只看最终内容不看推理过程KawaiiSpinner加载动画提升体验2.3 TUI Gateway —— Web UI 桥接TUI Gateway 提供 Web/桌面 UI 的 JSON-RPC 接口。工作流程接收增量文本可选实时 Markdown 渲染通过 WebSocket 发送message.delta事件前端收到事件后更新显示关键设计JSON-RPC 协议支持多种前端可选渲染字段平衡性能和显示效果2.4 Gateway Stream Consumer —— 多平台分发这是支持多平台的核心组件使用异步队列管理分发。工作流程接收增量文本加入线程安全队列异步任务持续消费队列将内容分发到所有已注册的平台各平台使用自己的方式编辑消息如 Telegram 的edit_message_text关键设计线程安全队列同步 Agent 和异步 UI 的桥接统一接口不同平台实现相同接口自适应退避API 调用失败时自动重试三、多消费者设计3.1 消费者列表消费者用途输出方式CLI本地命令行终端实时打印TUI GatewayWeb/桌面 UIWebSocket 推送TelegramTelegram 机器人编辑消息 APIDiscordDiscord 机器人编辑消息 APISlackSlack 机器人编辑消息 API3.2 平台桥接机制所有平台消费者都实现统一的接口核心只有两个方法edit_message(delta)编辑已发送的消息追加新内容finalize_message(text)消息完成后调用进行最终处理以 Telegram 为例发送初始消息后获得 message_id每次收到增量调用 Telegram API 编辑该消息由于 Telegram 限制编辑间隔不能太频繁1.5秒左右3.3 消息累积策略由于各平台 API 的限制如编辑间隔、字符数限制消费者不会每收到一个 token 就调用 API而是累积缓冲收集一定量文本后再编辑定时刷新每隔固定时间如 1.5 秒编辑一次光标提示在消息末尾显示▉表示正在输入四、事件协议4.1 流式增量事件{type:message.delta,session_id:会话ID,payload:{text:正在分析...,rendered:渲染后的文本// 可选}}4.2 消息完成事件{type:message.complete,session_id:会话ID,payload:{text:完整响应内容,reasoning:推理过程,// 可选status:complete// 或 interrupted/error}}4.3 推理块过滤AI 响应中可能包含reasoning.../reasoning等推理标记这些对用户不可见需要过滤打开标签think时开始过滤关闭标签时恢复输出过滤后的内容不显示给用户五、设计亮点5.1 回调机制实现解耦Agent ──回调──▶ 多个消费者Agent 不需要知道有多少消费者只需调用stream_callback(text)。新增消费者只需注册回调无需修改 Agent 代码。5.2 线程安全队列Agent 运行在独立线程而 UI 需要在主线程更新。通过线程安全队列桥接Agent 线程 ──Queue.put()──▶ 队列 ──Queue.get()──▶ UI 线程5.3 自适应退避当平台 API 调用失败如频率限制时自动增加重试间隔第1次失败 → 等待 1.5 秒 第2次失败 → 等待 3 秒 第3次失败 → 等待 6 秒5.4 Markdown 流式渲染部分消费者支持实时 Markdown 渲染接收增量文本逐步更新渲染结果用户看到逐步格式化的内容六、借鉴要点如果要在其他项目中实现类似的流式输出架构需要关注以下几点6.1 回调接口设计定义统一的流式回调接口参数只需一个增量文本结束时应传入None。6.2 行缓冲输出不要逐字符输出应该累积到换行符或一定长度后再输出避免终端闪烁。6.3 多消费者管理使用列表管理所有注册的消费者广播式调用即可。6.4 线程安全如果涉及多线程确保队列操作的原子性。6.5 平台适配不同平台有不同的 API 限制需要针对性处理如编辑间隔、消息长度。七、总结Hermes Agent 的流式输出架构展示了如何优雅地处理实时内容分发特性实现方式解耦回调机制 多消费者线程安全Queue 队列桥接跨平台统一接口 各自实现容错自适应退避美观行缓冲 Markdown 渲染这种设计使得同一个 AI 响应可以同时服务于 CLI、Web UI、第三方平台等多种场景极大提升了架构的灵活性和可扩展性。本文档基于 Hermes Agent 项目源码分析编写