Anthropic API Streaming Messages Implementation Guide
Trust: ★★★☆☆ (0.90) · 0 validations · factual
Published: 2026-05-09 · Source: crawler_authoritative
Tình huống
Developer integrating with Anthropic Claude API, needs to implement real-time streaming responses using server-sent events (SSE). Supports multiple SDKs including Python, TypeScript, PHP, Java, Go, C#, and Ruby.
Insight
The Anthropic Messages API supports streaming via server-sent events (SSE) when setting stream: true in the request. The streaming event flow follows this sequence: 1) message_start (empty content), 2) content_block_start, 3) multiple content_block_delta events, 4) content_block_stop, 5) message_delta, 6) message_stop. Ping events may appear throughout. Token counts in usage field of message_delta are cumulative. The SDKs provide multiple streaming approaches: Python offers .stream() with .text_stream for iteration or .get_final_message() to accumulate the complete Message object. TypeScript uses .stream() with .finalMessage(). Go requires manual accumulation via message.Accumulate(event). Java uses MessageAccumulator.create() with accumulate method. PHP uses createStream(). Ruby uses .accumulated_message. For large max_tokens values (e.g., 128000), streaming is required to avoid HTTP timeouts. Error events like overloaded_error may appear during high usage periods. Content block delta types include: text_delta for text content, input_json_delta for partial JSON strings (for tool_use input fields), thinking_delta for extended thinking, and signature_delta for verifying thinking block integrity. When using display: ‘omitted’ with thinking, no thinking_delta events are sent. When using display: ‘summarized’, a condensed reasoning summary is streamed. For tool_use blocks, deltas are partial JSON strings that must be accumulated and parsed after content_block_stop using libraries like Pydantic. The CLI’s —stream flag emits one event per line in JSONL format and does not accumulate into a final Message.
Hành động
- Set stream: true in message creation request. 2. Use SDK-appropriate method: Python client.messages.stream(), TypeScript client.messages.stream(), Go client.Messages.NewStreaming(), Java createStreaming(), PHP createStream(), Ruby messages.stream(). 3. Iterate over text_stream or handle content_block_delta events to process text incrementally. 4. To get complete Message object, use .get_final_message() in Python, .finalMessage() in TypeScript, .accumulated_message in Ruby, or accumulate events manually in Go/Java. 5. For tool use streaming, enable eager_input_streaming per tool. 6. Handle error events gracefully (e.g., overloaded_error returns HTTP 529). 7. For error recovery with Claude 4.5 and earlier: capture partial response, construct continuation request with partial assistant message, resume streaming. 8. For Claude 4.6: add user message instructing model to continue from previous response. 9. Use anthropic-version: 2023-06-01 header and x-api-key header for API requests.
Kết quả
Response is streamed incrementally via SSE events, reducing perceived latency for large responses and avoiding HTTP timeouts for requests with high max_tokens values.
Điều kiện áp dụng
Streaming is required for requests with large max_tokens values (128000+) to avoid HTTP timeouts. Error recovery strategies differ between Claude 4.5/earlier and 4.6 models. Tool use and extended thinking blocks cannot be partially recovered; only text blocks support resumption from interruption point.
Nội dung gốc (Original)
Streaming messages
When creating a Message, you can set "stream": true to incrementally stream the response using server-sent events (SSE).
Streaming with SDKs
The Python and TypeScript SDKs offer multiple ways of streaming. The PHP SDK provides streaming via createStream(). The Python SDK allows both sync and async streams. See the documentation in each SDK for details.
```python Python hidelines={1..2}
import anthropic
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
model="claude-opus-4-7",
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
```
```typescript TypeScript hidelines={1..2}
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
await client.messages
.stream({
messages: [{ role: "user", content: "Hello" }],
model: "claude-opus-4-7",
max_tokens: 1024
})
.on("text", (text) => {
console.log(text);
});
```
```csharp C#
using Anthropic;
using Anthropic.Models.Messages;
class Program
{
static async Task Main(string[] args)
{
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus4_7,
MaxTokens = 1024,
Messages = [new() { Role = Role.User, Content = "Hello" }]
};
await foreach (var msg in client.Messages.CreateStreaming(parameters))
{
Console.Write(msg);
}
}
}
```
```go Go hidelines={1..11,-1}
package main
import (
"context"
"fmt"
"log"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 1024,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Hello")),
},
})
for stream.Next() {
event := stream.Current()
switch eventVariant := event.AsAny().(type) {
case anthropic.ContentBlockDeltaEvent:
switch deltaVariant := eventVariant.Delta.AsAny().(type) {
case anthropic.TextDelta:
fmt.Print(deltaVariant.Text)
}
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
}
```
```java Java hidelines={1..6,-2..}
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.MessageCreateParams;
public class StreamingExample {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model("claude-opus-4-7")
.maxTokens(1024L)
.addUserMessage("Hello")
.build();
try (var streamResponse = client.messages().createStreaming(params)) {
streamResponse.stream().forEach(event -> {
event.contentBlockDelta().ifPresent(deltaEvent ->
deltaEvent.delta().text().ifPresent(td ->
System.out.print(td.text())
)
);
});
}
}
}
```
```php PHP hidelines={1..4}
<?php
use Anthropic\Client;
$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));
$stream = $client->messages->createStream(
maxTokens: 1024,
messages: [
['role' => 'user', 'content' => 'Hello']
],
model: 'claude-opus-4-7',
);
foreach ($stream as $message) {
echo $message;
}
```
```ruby Ruby hidelines={1..2}
require "anthropic"
client = Anthropic::Client.new
stream = client.messages.stream(
model: "claude-opus-4-7",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }]
)
stream.text.each { |text| print(text) }
```
Get the final message without handling events
If you don’t need to process text as it arrives, the SDKs provide a way to use streaming under the hood while returning the complete Message object, identical to what .create() returns. This is especially useful for requests with large max_tokens values, where the SDKs require streaming to avoid HTTP timeouts.
```python Python hidelines={1..2}
import anthropic
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=128000,
messages=[{"role": "user", "content": "Write a detailed analysis..."}],
model="claude-opus-4-7",
) as stream:
message = stream.get_final_message()
print(message.content[0].text)
```
```typescript TypeScript hidelines={1..2}
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const stream = client.messages.stream({
max_tokens: 128000,
messages: [{ role: "user", content: "Write a detailed analysis..." }],
model: "claude-opus-4-7"
});
const message = await stream.finalMessage();
const textBlock = message.content.find((block) => block.type === "text");
if (textBlock && textBlock.type === "text") {
console.log(textBlock.text);
}
```
```csharp C# nocheck
using System;
using System.Threading.Tasks;
using Anthropic;
using Anthropic.Models.Messages;
class Program
{
static async Task Main()
{
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus4_7,
MaxTokens = 128000,
Messages = [new() { Role = Role.User, Content = "Write a detailed analysis..." }]
};
var fullText = "";
await foreach (var msg in client.Messages.CreateStreaming(parameters))
{
fullText += msg;
}
Console.WriteLine(fullText);
}
}
```
```go Go hidelines={1..11,-1}
package main
import (
"context"
"fmt"
"log"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 128000,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Write a detailed analysis...")),
},
})
message := anthropic.Message{}
for stream.Next() {
event := stream.Current()
if err := message.Accumulate(event); err != nil {
log.Fatal(err)
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
fmt.Println(message.Content[0].Text)
}
```
```java Java hidelines={1..2,4..9,-2..}
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.helpers.MessageAccumulator;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
public class StreamingExample {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_7)
.maxTokens(128000L)
.addUserMessage("Write a detailed analysis...")
.build();
MessageAccumulator accumulator = MessageAccumulator.create();
try (var streamResponse = client.messages().createStreaming(params)) {
streamResponse.stream().forEach(accumulator::accumulate);
}
Message message = accumulator.message();
message.content().get(0).text().ifPresent(tb -> System.out.println(tb.text()));
}
}
```
```php PHP hidelines={1..4}
<?php
use Anthropic\Client;
$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));
$stream = $client->messages->createStream(
maxTokens: 128000,
messages: [
['role' => 'user', 'content' => 'Write a detailed analysis...']
],
model: 'claude-opus-4-7',
);
$fullText = '';
foreach ($stream as $event) {
if ($event->type === 'content_block_delta') {
$fullText .= $event->delta->text;
}
}
echo $fullText;
```
```ruby Ruby hidelines={1..2}
require "anthropic"
client = Anthropic::Client.new
message = client.messages.stream(
model: "claude-opus-4-7",
max_tokens: 128000,
messages: [{ role: "user", content: "Write a detailed analysis..." }]
).accumulated_message
puts message.content.first.text
```
The .stream() call keeps the HTTP connection alive with server-sent events, then .get_final_message() (Python) or .finalMessage() (TypeScript) accumulates all events and returns the complete Message object. In Go, you call message.Accumulate(event) inside the stream loop to build the same complete Message. In Java, use MessageAccumulator.create() and call accumulator.accumulate(event) on each event. In Ruby, call .accumulated_message on the stream. In the PHP SDK, you iterate over stream events manually to accumulate the response.
Event types
Each server-sent event includes a named event type and associated JSON data. Each event uses an SSE event name (e.g. event: message_stop), and includes the matching event type in its data.
Each stream uses the following event flow:
message_start: contains aMessageobject with emptycontent.- A series of content blocks, each of which have a
content_block_start, one or morecontent_block_deltaevents, and acontent_block_stopevent. Each content block has anindexthat corresponds to its index in the final Messagecontentarray. - One or more
message_deltaevents, indicating top-level changes to the finalMessageobject. - A final
message_stopevent.
Ping events
Event streams may also include any number of ping events.
Error events
The API may occasionally send errors in the event stream. For example, during periods of high usage, you may receive an overloaded_error, which would normally correspond to an HTTP 529 in a non-streaming context:
event: error
data: {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}Other events
In accordance with the versioning policy, new event types may be added, and your code should handle unknown event types gracefully.
Content block delta types
Each content_block_delta event contains a delta of a type that updates the content block at a given index.
Text delta
A text content block delta looks like:
event: content_block_delta
data: {"type": "content_block_delta","index": 0,"delta": {"type": "text_delta", "text": "ello frien"}}Input JSON delta
The deltas for tool_use content blocks correspond to updates for the input field of the block. To support maximum granularity, the deltas are partial JSON strings, whereas the final tool_use.input is always an object.
You can accumulate the string deltas and parse the JSON once you receive a content_block_stop event, by using a library like Pydantic to do partial JSON parsing, or by using the SDKs, which provide helpers to access parsed incremental values.
A tool_use content block delta looks like:
event: content_block_delta
data: {"type": "content_block_delta","index": 1,"delta": {"type": "input_json_delta","partial_json": "{\"location\": \"San Fra"}}}Note: Current models only support emitting one complete key and value property from input at a time. As such, when using tools, there may be delays between streaming events while the model is working. Once an input key and value are accumulated, they are emitted as multiple content_block_delta events with chunked partial json so that the format can automatically support finer granularity in future models.
Thinking delta
When using extended thinking with streaming enabled, you’ll receive thinking content via thinking_delta events. These deltas correspond to the thinking field of the thinking content blocks.
For thinking content, a special signature_delta event is sent just before the content_block_stop event. This signature is used to verify the integrity of the thinking block.
When display: "omitted" is set on the thinking configuration, no thinking_delta events are sent. The thinking block opens, receives a single signature_delta, and closes. See Controlling thinking display.
A typical thinking delta looks like:
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "I need to find the GCD of 1071 and 462 using the Euclidean algorithm.\n\n1071 = 2 × 462 + 147"}}The signature delta looks like:
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "signature_delta", "signature": "EqQBCgIYAhIM1gbcDa9GJwZA2b3hGgxBdjrkzLoky3dl1pkiMOYds..."}}Full HTTP stream response
Use the client SDKs when using streaming mode. However, if you are building a direct API integration, you need to handle these events yourself.
A stream response consists of:
- A
message_startevent - Potentially multiple content blocks, each of which contains:
- A
content_block_startevent - Potentially multiple
content_block_deltaevents - A
content_block_stopevent
- A
- A
message_deltaevent - A
message_stopevent
There may be ping events dispersed throughout the response as well. See Event types for more details on the format.
Basic streaming request
ant messages create --stream --format jsonl \
--model claude-opus-4-7 \
--max-tokens 256 \
--message '{role: user, content: Hello}'import anthropic
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-4-7",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=256,
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const stream = client.messages.stream({
model: "claude-opus-4-7",
messages: [{ role: "user", content: "Hello" }],
max_tokens: 256
});
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
process.stdout.write(event.delta.text);
}
}using System;
using System.Threading.Tasks;
using Anthropic;
using Anthropic.Models.Messages;
class Program
{
static async Task Main(string[] args)
{
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus4_7,
MaxTokens = 256,
Messages = [new() { Role = Role.User, Content = "Hello" }]
};
await foreach (var msg in client.Messages.CreateStreaming(parameters))
{
Console.Write(msg);
}
}
}package main
import (
"context"
"fmt"
"log"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 256,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Hello")),
},
})
for stream.Next() {
event := stream.Current()
switch eventVariant := event.AsAny().(type) {
case anthropic.ContentBlockDeltaEvent:
switch deltaVariant := eventVariant.Delta.AsAny().(type) {
case anthropic.TextDelta:
fmt.Print(deltaVariant.Text)
}
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
}import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
public class StreamingExample {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_7)
.maxTokens(256L)
.addUserMessage("Hello")
.build();
try (var streamResponse = client.messages().createStreaming(params)) {
streamResponse.stream().forEach(event -> {
event.contentBlockDelta().ifPresent(deltaEvent ->
deltaEvent.delta().text().ifPresent(td ->
System.out.print(td.text())
)
);
});
}
}
}<?php
use Anthropic\Client;
$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));
$stream = $client->messages->createStream(
maxTokens: 256,
messages: [
['role' => 'user', 'content' => 'Hello']
],
model: 'claude-opus-4-7',
);
foreach ($stream as $message) {
echo $message;
}require "anthropic"
client = Anthropic::Client.new
stream = client.messages.stream(
model: "claude-opus-4-7",
messages: [{ role: "user", content: "Hello" }],
max_tokens: 256
)
stream.text.each { |text| print(text) }event: message_start
data: {"type": "message_start", "message": {"id": "msg_1nZdL29xx5MUA1yADyHTEsnR8uuvGzszyY", "type": "message", "role": "assistant", "content": [], "model": "claude-opus-4-7", "stop_reason": null, "stop_sequence": null, "usage": {"input_tokens": 25, "output_tokens": 1}}}
event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "text", "text": ""}}
event: ping
data: {"type": "ping"}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "Hello"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "!"}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 0}
event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence":null}, "usage": {"output_tokens": 15}}
event: message_stop
data: {"type": "message_stop"}
Streaming request with tool use
This request asks Claude to use a tool to report the weather.
ant messages create --stream --format jsonl <<'YAML'
model: claude-opus-4-7
max_tokens: 1024
tools:
- name: get_weather
description: Get the current weather in a given location
input_schema:
type: object
properties:
location:
type: string
description: The city and state, e.g. San Francisco, CA
required:
- location
tool_choice:
type: any
messages:
- role: user
content: What is the weather like in San Francisco?
YAMLimport anthropic
client = anthropic.Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get the current weather in a given location",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
}
},
"required": ["location"],
},
}
]
with client.messages.stream(
model="claude-opus-4-7",
max_tokens=1024,
tools=tools,
tool_choice={"type": "any"},
messages=[
{"role": "user", "content": "What is the weather like in San Francisco?"}
],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const tools: Anthropic.Tool[] = [
{
name: "get_weather",
description: "Get the current weather in a given location",
input_schema: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA"
}
},
required: ["location"]
}
}
];
const stream = client.messages.stream({
model: "claude-opus-4-7",
max_tokens: 1024,
tools: tools,
tool_choice: { type: "any" },
messages: [
{
role: "user",
content: "What is the weather like in San Francisco?"
}
]
});
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
process.stdout.write(event.delta.text);
}
}using System;
using System.Text.Json;
using System.Threading.Tasks;
using Anthropic;
using Anthropic.Models.Messages;
class Program
{
static async Task Main(string[] args)
{
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus4_7,
MaxTokens = 1024,
Tools = [
new ToolUnion(new Tool()
{
Name = "get_weather",
Description = "Get the current weather in a given location",
InputSchema = new InputSchema()
{
Properties = new Dictionary<string, JsonElement>
{
["location"] = JsonSerializer.SerializeToElement(new { type = "string", description = "The city and state, e.g. San Francisco, CA" }),
},
Required = ["location"],
},
}),
],
ToolChoice = new ToolChoiceAny(),
Messages = [
new() { Role = Role.User, Content = "What is the weather like in San Francisco?" }
]
};
await foreach (var msg in client.Messages.CreateStreaming(parameters))
{
Console.Write(msg);
}
}
}package main
import (
"context"
"fmt"
"log"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 1024,
Tools: []anthropic.ToolUnionParam{
{OfTool: &anthropic.ToolParam{
Name: "get_weather",
Description: anthropic.String("Get the current weather in a given location"),
InputSchema: anthropic.ToolInputSchemaParam{
Properties: map[string]any{
"location": map[string]any{
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
},
Required: []string{"location"},
},
}},
},
ToolChoice: anthropic.ToolChoiceUnionParam{OfAny: &anthropic.ToolChoiceAnyParam{}},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What is the weather like in San Francisco?")),
},
})
for stream.Next() {
event := stream.Current()
switch eventVariant := event.AsAny().(type) {
case anthropic.ContentBlockDeltaEvent:
switch deltaVariant := eventVariant.Delta.AsAny().(type) {
case anthropic.TextDelta:
fmt.Print(deltaVariant.Text)
}
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
}import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
import com.anthropic.models.messages.ToolChoice;
import com.anthropic.models.messages.ToolChoiceAny;
import com.anthropic.models.messages.Tool;
import com.anthropic.core.JsonValue;
import java.util.Map;
import java.util.List;
public class StreamingToolUse {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_7)
.maxTokens(1024L)
.addTool(Tool.builder()
.name("get_weather")
.description("Get the current weather in a given location")
.inputSchema(Tool.InputSchema.builder()
.properties(JsonValue.from(Map.of(
"location", Map.of(
"type", "string",
"description", "The city and state, e.g. San Francisco, CA"
)
)))
.putAdditionalProperty("required", JsonValue.from(List.of("location")))
.build())
.build())
.toolChoice(ToolChoice.ofAny(ToolChoiceAny.builder().build()))
.addUserMessage("What is the weather like in San Francisco?")
.build();
try (var streamResponse = client.messages().createStreaming(params)) {
streamResponse.stream().forEach(event -> {
event.contentBlockDelta().ifPresent(deltaEvent ->
deltaEvent.delta().text().ifPresent(td ->
System.out.print(td.text())
)
);
});
}
}
}<?php
use Anthropic\Client;
$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));
$stream = $client->messages->createStream(
maxTokens: 1024,
messages: [
['role' => 'user', 'content' => 'What is the weather like in San Francisco?']
],
model: 'claude-opus-4-7',
toolChoice: ['type' => 'any'],
tools: [
[
'name' => 'get_weather',
'description' => 'Get the current weather in a given location',
'input_schema' => [
'type' => 'object',
'properties' => [
'location' => [
'type' => 'string',
'description' => 'The city and state, e.g. San Francisco, CA'
]
],
'required' => ['location']
]
]
],
);
foreach ($stream as $message) {
echo $message;
}require "anthropic"
client = Anthropic::Client.new
tools = [
{
name: "get_weather",
description: "Get the current weather in a given location",
input_schema: {
type: "object",
properties: {
location: {
type: "string",
description: "The city and state, e.g. San Francisco, CA"
}
},
required: ["location"]
}
}
]
stream = client.messages.stream(
model: "claude-opus-4-7",
max_tokens: 1024,
tools: tools,
tool_choice: { type: "any" },
messages: [
{ role: "user", content: "What is the weather like in San Francisco?" }
]
)
stream.text.each { |text| print(text) }event: message_start
data: {"type":"message_start","message":{"id":"msg_014p7gG3wDgGV9EUtLvnow3U","type":"message","role":"assistant","model":"claude-opus-4-7","stop_sequence":null,"usage":{"input_tokens":472,"output_tokens":2},"content":[],"stop_reason":null}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: ping
data: {"type": "ping"}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Okay"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" let"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"'s"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" check"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" weather"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" for"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" San"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Francisco"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":","}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" CA"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":":"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: content_block_start
data: {"type":"content_block_start","index":1,"content_block":{"type":"tool_use","id":"toolu_01T1x1fJ34qAmk2tNTrN7Up6","name":"get_weather","input":{}}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"location\":"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" \"San"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" Francisc"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"o,"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" CA\""}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":", "}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"\"unit\": \"fah"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"renheit\"}"}}
event: content_block_stop
data: {"type":"content_block_stop","index":1}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"output_tokens":89}}
event: message_stop
data: {"type":"message_stop"}Streaming request with extended thinking
This request enables extended thinking with streaming. The display: "summarized" setting streams a condensed summary of Claude’s reasoning rather than the full chain of thought.
ant messages create --stream --format jsonl \
--model claude-opus-4-7 \
--max-tokens 20000 \
--thinking '{type: adaptive, display: summarized}' \
--message '{role: user, content: What is the greatest common divisor of 1071 and 462?}'import anthropic
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-4-7",
max_tokens=20000,
thinking={"type": "adaptive", "display": "summarized"},
messages=[
{
"role": "user",
"content": "What is the greatest common divisor of 1071 and 462?",
}
],
) as stream:
for event in stream:
if event.type == "content_block_delta":
if event.delta.type == "thinking_delta":
print(event.delta.thinking, end="", flush=True)
elif event.delta.type == "text_delta":
print(event.delta.text, end="", flush=True)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const stream = client.messages.stream({
model: "claude-opus-4-7",
max_tokens: 20000,
thinking: { type: "adaptive", display: "summarized" },
messages: [
{
role: "user",
content: "What is the greatest common divisor of 1071 and 462?"
}
]
});
for await (const event of stream) {
if (event.type === "content_block_delta") {
if (event.delta.type === "thinking_delta") {
process.stdout.write(event.delta.thinking);
} else if (event.delta.type === "text_delta") {
process.stdout.write(event.delta.text);
}
}
}using Anthropic;
using Anthropic.Models.Messages;
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus4_6,
MaxTokens = 20000,
Thinking = new ThinkingConfigEnabled(budgetTokens: 16000),
Messages = [new() { Role = Role.User, Content = "What is the greatest common divisor of 1071 and 462?" }]
};
await foreach (var msg in client.Messages.CreateStreaming(parameters))
{
Console.Write(msg);
}package main
import (
"context"
"fmt"
"log"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_6,
MaxTokens: 20000,
Thinking: anthropic.ThinkingConfigParamOfEnabled(16000),
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What is the greatest common divisor of 1071 and 462?")),
},
})
for stream.Next() {
event := stream.Current()
switch eventVariant := event.AsAny().(type) {
case anthropic.ContentBlockDeltaEvent:
switch deltaVariant := eventVariant.Delta.AsAny().(type) {
case anthropic.ThinkingDelta:
fmt.Print(deltaVariant.Thinking)
case anthropic.TextDelta:
fmt.Print(deltaVariant.Text)
}
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
}import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
public class ExtendedThinkingStreaming {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_6)
.maxTokens(20000L)
.enabledThinking(16000L)
.addUserMessage("What is the greatest common divisor of 1071 and 462?")
.build();
try (var streamResponse = client.messages().createStreaming(params)) {
streamResponse.stream().forEach(event -> {
event.contentBlockDelta().ifPresent(deltaEvent -> {
deltaEvent.delta().thinking().ifPresent(td ->
System.out.print(td.thinking())
);
deltaEvent.delta().text().ifPresent(td ->
System.out.print(td.text())
);
});
});
}
}
}<?php
use Anthropic\Client;
$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));
$stream = $client->messages->createStream(
maxTokens: 20000,
messages: [
['role' => 'user', 'content' => 'What is the greatest common divisor of 1071 and 462?']
],
model: 'claude-opus-4-7',
thinking: ['type' => 'adaptive', 'display' => 'summarized'],
);
foreach ($stream as $message) {
echo $message;
}require "anthropic"
client = Anthropic::Client.new
stream = client.messages.stream(
model: "claude-opus-4-7",
max_tokens: 20000,
thinking: { type: "adaptive", display: "summarized" },
messages: [
{ role: "user", content: "What is the greatest common divisor of 1071 and 462?" }
]
)
stream.each do |event|
if event.type == :content_block_delta
if event.delta.type == :thinking_delta
print(event.delta.thinking)
elsif event.delta.type == :text_delta
print(event.delta.text)
end
end
endevent: message_start
data: {"type": "message_start", "message": {"id": "msg_01...", "type": "message", "role": "assistant", "content": [], "model": "claude-opus-4-7", "stop_reason": null, "stop_sequence": null}}
event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "thinking", "thinking": "", "signature": ""}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "I need to find the GCD of 1071 and 462 using the Euclidean algorithm.\n\n1071 = 2 × 462 + 147"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\n462 = 3 × 147 + 21"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\n147 = 7 × 21 + 0"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "thinking_delta", "thinking": "\nThe remainder is 0, so GCD(1071, 462) = 21."}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "signature_delta", "signature": "EqQBCgIYAhIM1gbcDa9GJwZA2b3hGgxBdjrkzLoky3dl1pkiMOYds..."}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 0}
event: content_block_start
data: {"type": "content_block_start", "index": 1, "content_block": {"type": "text", "text": ""}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 1, "delta": {"type": "text_delta", "text": "The greatest common divisor of 1071 and 462 is **21**."}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 1}
event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn", "stop_sequence": null}}
event: message_stop
data: {"type": "message_stop"}Streaming request with web search tool use
This request asks Claude to search the web for current weather information.
ant messages create --stream --format jsonl \
--model claude-opus-4-7 \
--max-tokens 1024 \
--tool '{type: web_search_20250305, name: web_search, max_uses: 5}' \
--message '{role: user, content: What is the weather like in New York City today?}'import anthropic
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-4-7",
max_tokens=1024,
tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 5}],
messages=[
{"role": "user", "content": "What is the weather like in New York City today?"}
],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const stream = client.messages.stream({
model: "claude-opus-4-7",
max_tokens: 1024,
tools: [{ type: "web_search_20250305", name: "web_search", max_uses: 5 }],
messages: [{ role: "user", content: "What is the weather like in New York City today?" }]
});
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
process.stdout.write(event.delta.text);
}
}using Anthropic;
using Anthropic.Models.Messages;
AnthropicClient client = new();
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus4_7,
MaxTokens = 1024,
Tools = [new ToolUnion(new WebSearchTool20250305() { MaxUses = 5 })],
Messages = [new() { Role = Role.User, Content = "What is the weather like in New York City today?" }]
};
await foreach (var msg in client.Messages.CreateStreaming(parameters))
{
Console.Write(msg);
}package main
import (
"context"
"fmt"
"log"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus4_7,
MaxTokens: 1024,
Tools: []anthropic.ToolUnionParam{
{
OfWebSearchTool20250305: &anthropic.WebSearchTool20250305Param{
MaxUses: anthropic.Int(5),
},
},
},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What is the weather like in New York City today?")),
},
})
for stream.Next() {
event := stream.Current()
switch eventVariant := event.AsAny().(type) {
case anthropic.ContentBlockDeltaEvent:
switch deltaVariant := eventVariant.Delta.AsAny().(type) {
case anthropic.TextDelta:
fmt.Print(deltaVariant.Text)
}
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
}import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;
import com.anthropic.models.messages.WebSearchTool20250305;
public class WebSearchStreaming {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_4_7)
.maxTokens(1024L)
.addTool(WebSearchTool20250305.builder()
.maxUses(5L)
.build())
.addUserMessage("What is the weather like in New York City today?")
.build();
try (var streamResponse = client.messages().createStreaming(params)) {
streamResponse.stream().forEach(event -> {
event.contentBlockDelta().ifPresent(deltaEvent ->
deltaEvent.delta().text().ifPresent(td ->
System.out.print(td.text())
)
);
});
}
}
}<?php
use Anthropic\Client;
$client = new Client(apiKey: getenv("ANTHROPIC_API_KEY"));
$stream = $client->messages->createStream(
maxTokens: 1024,
messages: [
['role' => 'user', 'content' => 'What is the weather like in New York City today?']
],
model: 'claude-opus-4-7',
tools: [
['type' => 'web_search_20250305', 'name' => 'web_search', 'max_uses' => 5]
],
);
foreach ($stream as $message) {
echo $message;
}require "anthropic"
client = Anthropic::Client.new
stream = client.messages.stream(
model: :"claude-opus-4-7",
max_tokens: 1024,
tools: [
{
type: "web_search_20250305",
name: "web_search",
max_uses: 5
}
],
messages: [
{
role: "user",
content: "What is the weather like in New York City today?"
}
]
)
stream.text.each { |text| print(text) }event: message_start
data: {"type":"message_start","message":{"id":"msg_01G...","type":"message","role":"assistant","model":"claude-opus-4-7","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":2679,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":3}}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"I'll check"}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the current weather in New York City for you"}}
event: ping
data: {"type": "ping"}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"."}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: content_block_start
data: {"type":"content_block_start","index":1,"content_block":{"type":"server_tool_use","id":"srvtoolu_014hJH82Qum7Td6UV8gDXThB","name":"web_search","input":{}}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"query"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"\":"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" \"weather"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":" NY"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"C to"}}
event: content_block_delta
data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"day\"}"}}
event: content_block_stop
data: {"type":"content_block_stop","index":1 }
event: content_block_start
data: {"type":"content_block_start","index":2,"content_block":{"type":"web_search_tool_result","tool_use_id":"srvtoolu_014hJH82Qum7Td6UV8gDXThB","content":[{"type":"web_search_result","title":"Weather in New York City in May 2025 (New York) - detailed Weather Forecast for a month","url":"https://world-weather.info/forecast/usa/new_york/may-2025/","encrypted_content":"Ev0DCioIAxgCIiQ3NmU4ZmI4OC1k...","page_age":null},...]}}
event: content_block_stop
data: {"type":"content_block_stop","index":2}
event: content_block_start
data: {"type":"content_block_start","index":3,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":"Here's the current weather information for New York"}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":" City:\n\n# Weather"}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":" in New York City"}}
event: content_block_delta
data: {"type":"content_block_delta","index":3,"delta":{"type":"text_delta","text":"\n\n"}}
...
event: content_block_stop
data: {"type":"content_block_stop","index":17}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":10682,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":510,"server_tool_use":{"web_search_requests":1}}}
event: message_stop
data: {"type":"message_stop"}Error recovery
Claude 4.5 and earlier
For Claude 4.5 models and earlier, you can recover a streaming request that was interrupted due to network issues, timeouts, or other errors by resuming from where the stream was interrupted. This approach saves you from re-processing the entire response.
The basic recovery strategy involves:
- Capture the partial response: Save all content that was successfully received before the error occurred
- Construct a continuation request: Create a new API request that includes the partial assistant response as the beginning of a new assistant message
- Resume streaming: Continue receiving the rest of the response from where it was interrupted
Claude 4.6
For Claude 4.6 models, you should add a user message that instructs the model to continue from where it left off. For example:
Your previous response was interrupted and ended with [previous_response]. Continue from where you left off.Error recovery best practices
- Use SDK features: Leverage the SDK’s built-in message accumulation and error handling capabilities
- Handle content types: Be aware that messages can contain multiple content blocks (
text,tool_use,thinking). Tool use and extended thinking blocks cannot be partially recovered. You can resume streaming from the most recent text block.
Liên kết
- Nền tảng: Claude
- Nguồn: https://platform.claude.com/docs/en/build-with-claude/streaming.md
Xem thêm:
- [[entries/source-url-https-platform-claude-com-docs-en-api-beta-messages-md-title-messages|Source URL: https://platform.claude.com/docs/en/api/beta/messages.md Title: Messages]]
- Fine-grained Tool Streaming cho Claude API
- Anthropic Files API Documentation: Upload, Manage, and Reference Files
- Message Batches API - Xử lý hàng loạt yêu cầu API với chi phí giảm 50%
- Context Windows in Claude API: Token Management Strategies and Limits