php curl 接收 claude sse 流式响应需手动解析:设 curlopt_buffersize=>1、curlopt_returntransfer=>false 和 curlopt_writefunction 回调,逐行提取 data: 后 json 并 json_decode;仅处理 type 为 content_block_delta 的事件,取 delta.text;laravel http client 不原生支持 sse,仍需自行解析;遇 tool_use 须立即捕获并中断流。

PHP cURL 怎样接收 Claude 的 SSE 流式响应
PHP 原生 curl_init() 无法自动解析 Server-Sent Events(SSE)格式,必须手动按行读取、识别 data: 前缀并剥离换行和空行。直接用 curl_exec() 拿完整响应会卡住或返回空,因为流式连接不会主动关闭。
关键操作点:
- 必须设置
CURLOPT_BUFFERSIZE => 1和CURLOPT_RETURNTRANSFER => false,让 cURL 逐块吐出数据,而不是等结束 - 启用
CURLOPT_WRITEFUNCTION回调,自己处理每一块到达的数据 - 每行以
event:或data:开头,真正文本在data:后面,需用substr($line, 6)提取并json_decode() - 遇到
event: message_stop或空行时,可安全终止循环
如何从 SSE 数据中提取 text_delta 内容
Claude 的流式事件不是 OpenAI 那种扁平的 delta.content,而是嵌套结构:每个有效文本片段都在 content_block_delta 事件的 delta.text 字段里。漏掉类型判断,就会把 message_start 或 content_block_start 当成内容打印出来。
实操建议:
- 先检查
$event['type'] === 'content_block_delta',再取$event['delta']['text'] - 忽略
message_start、content_block_start、message_stop这类控制事件 - 注意
delta可能为null(比如工具调用前的空占位),要加isset($event['delta']['text'])判断 - 不要拼接原始 JSON 行,必须
json_decode($data_line, true)后再取字段
Laravel HTTP Client 能不能直接支持 Claude 流式
不能。Laravel 的 Http::stream() 是为 chunked transfer 编写的,不兼容 SSE 协议。它会把整条 data: {...} 当作一个 chunk 返回,而不会帮你按行切分——你拿到的还是带 data: 前缀的字符串,还得自己 parse。
所以即使用了 Laravel,也得退回到原生 cURL 或封装一个 SSE 解析器。常见错误是:
- 误以为
Http::timeout(30)->stream(...)就能自动 yield 文本,结果只收到一次大 blob - 没设
Accept: text/event-stream头,导致服务端降级为非流式响应 - 没传
anthropic-version: 2023-06-01,返回406 Not Acceptable
流式响应里怎么处理 tool_use 请求
当 Claude 决定调用工具时,会在流中插入一个 tool_use 类型事件,包含 name 和 input。它**不会等你执行完工具再继续流**,而是立刻发下一个事件(比如 message_stop),整个流就结束了。这意味着你必须在流未结束前就捕获并中断处理。
操作要点:
- 监听
$event['type'] === 'tool_use',立即保存$event['name']和$event['input'] - 调用完工具后,要构造新请求,把
tool_result作为新消息发回去,不能往原 stream 里塞数据 - 别等
message_stop才开始处理 tool_use —— 它可能根本不会来,尤其在超时或网络断开时 - 前端展示上,
tool_use事件不该渲染成用户可见文本,而是触发后台动作
text_delta 都会偏移,而且没有重传机制。大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











