教程

Claude API 流式输出完全指南:Server-Sent Events 实时响应实战

Claude API 流式输出(Streaming)完整教程:为什么用流式输出(用户体验提升50%+)、Server-Sent Events 协议原理、Python/Node.js/curl 三种实现方式、stream=True 的事件类型(message_start/content_block_delta/message_stop)、流式 Tool Use 的特殊处理、在 FastAPI/Express/Next.js 中实现流式 API 端点,以及流式输出的错误处理和超时配置。

2026/3/204分钟 阅读ClaudeEagle

流式输出让用户看到 Claude 「边想边说」,而不是等待整个回复生成完再显示, 大幅提升交互体验——尤其是长回复时效果最明显。

为什么用流式输出?

对比普通请求流式请求
用户等待时间完整生成才显示(可能 10s+)几百毫秒内开始看到文字
感知响应速度快(提升 50%+ 主观体验)
适合场景程序批处理聊天界面、代码生成
实现复杂度简单略复杂(需处理 SSE 事件流)

Python 流式输出

方式一:with_streaming_response(推荐)

python
import anthropic

client = anthropic.Anthropic()

with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=2048,
    messages=[{"role": "user", "content": "写一个完整的 Python 爬虫示例"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

# 获取最终消息(含 usage 统计)
final = stream.get_final_message()
print(f"

共消耗 {final.usage.input_tokens} 输入 + {final.usage.output_tokens} 输出 tokens")

方式二:raw 事件流

python
with client.messages.stream(...) as stream:
    for event in stream:
        if event.type == "content_block_delta":
            if event.delta.type == "text_delta":
                print(event.delta.text, end="", flush=True)
        elif event.type == "message_stop":
            print("\n[生成完毕]")

异步版本(async/await)

python
import asyncio
import anthropic

async def stream_response(prompt: str):
    client = anthropic.AsyncAnthropic()
    async with client.messages.stream(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": prompt}],
    ) as stream:
        async for text in stream.text_stream:
            print(text, end="", flush=True)

asyncio.run(stream_response("解释什么是协程"))

Node.js / TypeScript 流式输出

typescript
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

async function streamChat(prompt: string) {
  const stream = await client.messages.stream({
    model: "claude-sonnet-4-6",
    max_tokens: 2048,
    messages: [{ role: "user", content: prompt }],
  });

  // 方式一:async iterator
  for await (const chunk of stream) {
    if (
      chunk.type === "content_block_delta" &&
      chunk.delta.type === "text_delta"
    ) {
      process.stdout.write(chunk.delta.text);
    }
  }

  // 方式二:事件监听
  stream.on("text", (text) => process.stdout.write(text));
  stream.on("message", (msg) => console.log("
使用量:", msg.usage));
  await stream.done();
}

SSE 事件类型完整说明

流式响应由多个 SSE 事件组成:

event: message_start ← 消息开始,包含 message_id 和初始 usage data: {"type": "message_start", "message": {"id": "msg_xxx", ...}} event: content_block_start ← 内容块开始(文本或工具调用) data: {"type": "content_block_start", "index": 0, "content_block": {"type": "text"}} event: content_block_delta ← 增量文本(核心事件,持续发送) data: {"type": "content_block_delta", "delta": {"type": "text_delta", "text": "你好"}} event: content_block_stop ← 内容块结束 data: {"type": "content_block_stop", "index": 0} event: message_delta ← 消息结束,包含 stop_reason 和最终 usage data: {"type": "message_delta", "delta": {"stop_reason": "end_turn"}, "usage": {...}} event: message_stop ← 流结束 data: {"type": "message_stop"}

在 Web 框架中实现流式 API

FastAPI(Python)

python
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import anthropic

app = FastAPI()
client = anthropic.Anthropic()

@app.get("/chat/stream")
async def chat_stream(prompt: str):
    async def generate():
        with client.messages.stream(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            messages=[{"role": "user", "content": prompt}],
        ) as stream:
            for text in stream.text_stream:
                # SSE 格式
                yield f"data: {json.dumps({'text': text})}\n\n"
        yield "data: [DONE]\n\n"

    return StreamingResponse(generate(), media_type="text/event-stream")

Next.js App Router(Edge Runtime)

typescript
// app/api/chat/route.ts
import Anthropic from "@anthropic-ai/sdk";

export const runtime = "edge";

export async function POST(req: Request) {
  const { messages } = await req.json();
  const client = new Anthropic();

  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      const anthropicStream = await client.messages.stream({
        model: "claude-sonnet-4-6",
        max_tokens: 2048,
        messages,
      });

      for await (const chunk of anthropicStream) {
        if (
          chunk.type === "content_block_delta" &&
          chunk.delta.type === "text_delta"
        ) {
          controller.enqueue(
            encoder.encode(`data: ${JSON.stringify({ text: chunk.delta.text })}\n\n`)
          );
        }
      }
      controller.enqueue(encoder.encode("data: [DONE]\n\n"));
      controller.close();
    },
  });

  return new Response(stream, {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
    },
  });
}

前端消费 SSE

typescript
// 使用 EventSource API
const evtSource = new EventSource("/api/chat/stream?prompt=你好");
evtSource.onmessage = (event) => {
  if (event.data === "[DONE]") {
    evtSource.close();
    return;
  }
  const { text } = JSON.parse(event.data);
  setResponse((prev) => prev + text);
};

// 或使用 fetch + ReadableStream(支持 POST)
const resp = await fetch("/api/chat", {
  method: "POST",
  body: JSON.stringify({ messages }),
  headers: { "Content-Type": "application/json" },
});
const reader = resp.body!.getReader();
const decoder = new TextDecoder();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const chunk = decoder.decode(value);
  // 解析 SSE 数据
}

来源:Anthropic 官方文档 - docs.anthropic.com/en/api/messages-streaming

相关文章推荐

教程Claude Cache Diagnostics 教程:定位 Prompt Cache Miss 的真正原因Claude Cache Diagnostics 解决 prompt cache miss 难排查问题。通过传入上一次 response id,API 会比较请求 fingerprint,告诉你 model/system/tools/messages 哪个部分破坏了缓存 prefix。2026/6/6教程Claude MCP Tunnels 指南:不用开放入站端口,也能把私有 MCP 服务接给 ClaudeMCP Tunnels 是 Anthropic 面向企业内网 MCP 服务的 beta 能力,通过 outbound-only 连接、cloudflared、proxy、inner TLS 和 OAuth,让 Claude 安全访问私有工具与数据源。2026/6/6教程Claude Mid-conversation System Messages 使用指南:长会话不再破坏 Prompt CacheClaude Opus 4.8 新增 mid-conversation system messages,可在长会话中途追加系统级指令,不改顶层 system prompt,从而保持缓存 prefix 命中,降低 Agent 循环成本。2026/6/6教程Claude Citations 完整指南:让 AI 回答带可验证引用,适合 RAG 与文档问答Claude Citations 官方能力中文整理:如何启用 citations.enabled、支持的文档类型、PDF 页码引用、文本字符索引、custom content block 索引、RAG chunk 粒度控制、与 Prompt Caching 兼容性和 Structured Outputs 不兼容限制。2026/5/21教程Claude Batch Processing 完整指南:批量处理任务如何节省 50% API 成本Claude Batch Processing 官方能力中文整理:为什么批处理能省钱、如何创建 batch、custom_id 设计、轮询状态、下载结果、处理失败请求,以及适合大规模分类、摘要、翻译、数据清洗的任务模式。2026/5/21教程Claude Prompt Caching 完整指南:降低长上下文成本与延迟的 API 实战Claude Prompt Caching 官方能力中文整理:适合缓存的内容、cache_control 使用方法、缓存断点策略、长文档和工具定义复用、成本/延迟收益、常见坑和生产环境落地建议。2026/5/21