第 2 章 消息流与会话界面
消息是统一展示协议,不是 UI 装饰
Claude Code 的界面看起来像聊天,但它的消息不是普通聊天消息。工具调用、文件变更、权限拒绝、diff、后台任务通知——所有这些都必须变成消息才能显示出来。
这个设计的关键在于:工具不是"返回数据,然后让 UI 猜怎么画",而是工具协议本身就包含展示方式。每个工具都要声明三件事:调用时显示什么、结果怎么显示、失败时显示什么。消息层和工具层之间有明确的协议边界,不是松散的耦合。
这就是为什么 Claude Code 的界面更像任务控制台:你能持续看到 agent 在做什么,而不是只看到最终答案。
消息到达界面之前经历了什么
原始消息和你看到的消息之间,有一个处理管道:
- normalize:把不同来源、不同格式的消息统一成标准结构
- reorder:调整显示顺序——某些消息在逻辑时序上和生成时序不一样
- grouping:把相关消息归组,比如一次工具调用和它的结果放在一起
- collapse:搜索结果、读取内容、后台任务通知这类输出默认折叠,不撑开界面
Brief 模式还有额外的过滤逻辑,会把很多中间过程的文本内容丢掉,只保留关键输出。
这个管道的存在说明一件事:显示给用户的会话轨迹是经过整理的,不是原始执行过程的直接映射。整理的目的是让人看得清楚,而不是完整记录每一个细节。
为什么要做成统一消息流
不这么做的后果是:每类功能都得自己搭 UI 状态,各搭各的,维护成本高,体验也会碎片化。
做成统一消息流的好处很实际:会话可以回放,因为所有执行历史都在消息里;状态可以审计,权限拒绝、工具调用、diff 都有记录;工具不需要自己实现展示逻辑,复用同一套容器就行。
还有一个间接好处:消息流的设计让 remote viewer 场景成为可能——另一个客户端可以订阅同一条消息流,实时看到 agent 在做什么,不需要重新执行任何东西。