前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Anthropic 流式事件类型 message_start content_block_delta
AIAI 全栈流式交互

Anthropic Messages API 流式响应中 message_start、content_block_delta、message_stop 等事件各自携带什么信息?

message_start提供整条消息的初始元数据,content_block_delta给出指定索引块的内容增量,message_stop仅标记流结束。

前端进阶之旅 · 一题精讲更新于 2026.09.05
AI 全栈#流式交互#流处理
先看核心答案
理解线索

事件流处理分工

  1. message_start创建全局消息状态,获得id、model等
  2. content_block_delta针对单个块追加或拼接增量内容
  3. message_stop无数据字段,作为流终止的哨兵事件

stop_reason和usage在message_delta中出现,而不是message_stop。

核心回答

先记住这个答案

流式响应以SSE事件序列推进:先收到message_start(内含content为空数组的Message对象,携带id、model、role等元数据);随后每个内容块经历content_block_start、多个content_block_delta(按index定位,delta含具体文本、工具JSON片段或思考)和content_block_stop;接着可能有message_delta调整顶层stop_reason、usage,最后message_stop表示正常结束。

  • message_start携带消息级元数据,content为空数组
  • content_block_delta按index携带文本或工具JSON增量
  • message_stop只表示正常结束,不携带业务数据

三种事件在事件流中的定位与顺序

message_start是流中第一个事件,其data.message携带Message对象的元数据,包括id、model、role和初始为null的stop_reason,而content字段固定为空数组。前端应在此处创建消息记录,初始化一个空的块集合和消息级标志位,后续所有增量都基于该记录的上下文更新。

随后每个内容块会先收到content_block_start声明index和类型。content_block_delta携带相同的index和增量delta,delta.type决定解析方式:text_delta直接提供字符串,input_json_delta给出partial_json分片,thinking_delta记录扩展思考。客户端必须按到达顺序把分片拼到属于该index的缓冲中,而不是直接当作完整内容使用。

当一个块内所有增量完成,content_block_stop标记该块结束。所有内容块处理完毕后,可能出现一个或多个message_delta用于更新顶部对象,例如补充最终stop_reason和usage统计。真正收尾的是message_stop,它不带任何业务字段,只是表示整个消息已完整输出;因此若需要读取最终状态,必须在message_delta里进行,而不是等message_stop。

同时渲染文本和工具参数的实时界面

假设需要实现一个聊天前端,模型在一次响应里既输出解释文字,又要调用get_weather工具,即返回一个文本内容块和一个tool_use内容块。收到message_start后界面创建一条消息记录;收到content_block_start时按index为0初始化文本缓冲区,为1初始化工具输入缓存,并记录两者的类型。

随后content_block_delta持续到达,前端根据index路由:索引0的text_delta把delta.text追加到可编辑的文本区域,索引1的input_json_delta把partial_json片段拼进字符串缓冲区,用于后续解析。注意不能对每个partial_json单独调用JSON.parse,因为模型可能一次只输出半个键值;这里采用实时解析器:尝试对累积的字符串做JSON解析,失败就等待下一次追加,成功则刷新工具参数预览。由于文本追加是原生的,渲染不会卡顿;工具预览也只在完整JSON出现后更新一次。

当流接近尾声,message_delta携带的stop_reason变为tool_use。此时前端应立刻隐藏“生成中”的旋转指示,并允许用户点击“执行工具”按钮,同时保留文本与工具块。最后message_stop到来时只触发清理临时缓冲的finally逻辑,不在此处读取stop_reason,因为该值已经在上一步的message_delta中拿到并保存到消息状态里。

中断、分片不完整与多事件交错的处理边界

如果网络断开或收到error事件(例如overloaded_error),流正常不会出现message_stop。任何已显示的文本增量都可以保留,但应标记为“响应被中断”;未完成的tool_use块其partial_json碎片如果没有收全,不能直接解析,应丢弃该块或置为“工具调用失败”状态,防止前端尝试执行不完整的参数。

另一个失效点是多个内容块可能交错产生事件,且同一SSE连接的TCP分片可能把不同事件的JSON数据拆散到同一帧中。客户端必须先用行缓冲切分data:字段,再将一个完整事件交给分发器;如果某块只有content_block_start而一直没等到对应的content_block_stop,允许保留已显示的文本,但工具块的内容则不适合做部分恢复,因为JSON必须完整才能获得对象值。

还要注意message_delta可能不止出现一次,当服务端发生模型切换或补充usage时,会发送多个此类事件。因此客户端不能假设第一条message_delta之后必然紧接message_stop,而应当每次都把顶层字段更新到最新;只有收到message_stop才允许把整个消息标记为已完成并提交数据库,这能避免中途意外状态覆盖。

回答前,多想一步

容易答错的地方

认为message_stop携带最终usage和stop_reason
错误的来源是混淆了事件名称。message_delta负责顶层字段的最终更新,包括stop_reason和usage,并且可能多次发送;message_stop只发送一个不附加业务数据的空对象。若要取最终状态必须在message_delta中累计。
将content_block_delta视为单一文本增量
delta类型不只text_delta,还可能有input_json_delta和thinking_delta。若不检查delta.type直接取text访问会得到undefined,工具输入的partial_json也不能被当作完整JSON来解析。必须根据类型维护不同的拼接逻辑,否则工具参数显示会损坏。
试着用自己的话回答

面试官还会怎么问?

流式响应过程中如何判断生成被截断而没收到message_stop?

正常流结束会收到message_stop。如果连接因网络错误或收到error事件而断开,就不会有message_stop,此时应视为中断。可依据应用需求设置超时或使用AbortController主动取消,但不应预设一个固定秒数。已显示的文本可保留,但未完成的工具块需作废。无需额外检查stop_reason,因为message_stop缺失本身即为异常。

多个content_block_delta的index是如何确定对应块的?

每个块的content_block_start设定固定index,后续所有content_block_delta都携带该index值,范围从0到块总数减一。前端可用数组作为容器,index就是数组下标,事件到达时直接定位到目标块并追加增量。

message_start里为什么content是空数组,而不是直接放好完整消息?

因为流式模式的核心目的是让客户端尽快开始渲染首段文本,而不是等待整个Message组装完毕。如果首个事件就带完整内容就失去了增量意义;空content也声明了后续需要动态构造块的顺序。

从一道题,走向一组知识

把知识连起来

流式交互

如何用 AbortController 正确取消一个正在进行的 fetch 流式请求?

同属「流式交互」专题,接着看 AbortController 取消 fetch 流式请求实践 在具体场景中的处理方式。

流式交互

在 AI 聊天场景中,Server-Sent Events 和 WebSocket 该如何选型?

同属「流式交互」专题,接着看 SSE 与 WebSocket 在 AI 流式对话中的选型对比 在具体场景中的处理方式。

参考资料

  • Streaming messages - Claude Platform Docs

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 三种事件在事件流中的定位与顺序
  3. 同时渲染文本和工具参数的实时界面
  4. 中断、分片不完整与多事件交错的处理边界
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑