Потоковая передача сообщений
Получайте ответы Messages API инкрементально с помощью server-sent events, включая дельты текста, использования инструментов и расширенных размышлений.
При создании сообщения (Message) вы можете установить "stream": true, чтобы инкрементально получать ответ в режиме потоковой передачи с помощью server-sent events (событий, отправляемых сервером), или SSE.
Потоковая передача с помощью SDK
Python SDK и TypeScript SDK предлагают несколько способов «streaming» (потоковой передачи). PHP SDK обеспечивает потоковую передачу через createStream(). Python SDK поддерживает как синхронные, так и асинхронные потоки. Подробности см. в документации каждого SDK.
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
model="claude-opus-5-5",
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)Получение итогового сообщения без обработки событий
Если вам не нужно обрабатывать текст по мере его поступления, SDK предоставляют способ использовать потоковую передачу внутренне, возвращая при этом полный объект Message, идентичный тому, что возвращает .create(). Это особенно полезно для запросов с большими значениями max_tokens, где SDK требуют потоковой передачи, чтобы избежать тайм-аутов HTTP.
client = anthropic.Anthropic()
with client.messages.stream(
max_tokens=128000,
messages=[{"role": "user", "content": "Write a detailed analysis..."}],
model="claude-opus-5-5",
) as stream:
message = stream.get_final_message()
for block in message.content:
if block.type == "text":
print(block.text)Вызов .stream() поддерживает HTTP-соединение активным с помощью server-sent events, после чего .get_final_message() (Python) или .finalMessage() (TypeScript) накапливает все события и возвращает полный объект Message. В Go вы вызываете message.Accumulate(event) внутри цикла потока, чтобы собрать такой же полный Message. В Java используйте MessageAccumulator.create() и вызывайте accumulator.accumulate(event) для каждого события. В C# дождитесь выполнения метода расширения .Aggregate() потока, чтобы получить полный Message, или передайте MessageContentAggregator в .CollectAsync(), чтобы выполнять агрегацию одновременно с обработкой событий. В Ruby вызовите .accumulated_message у потока. В PHP SDK вы вручную перебираете события потока, чтобы накопить ответ.
Типы событий
Каждое событие server-sent event включает именованный тип события и связанные с ним данные JSON. Каждое событие использует имя события SSE (например, event: message_stop) и включает соответствующий type события в своих данных.
Каждый поток использует следующую последовательность событий:
message_start: содержит объектMessageс пустымcontent. При использовании бета-заголовкаthinking-binding-controls-2026-08-01этот объектMessageтакже содержит массивinput_transformations. После резервного переключения на стороне сервера в середине потока финальное событиеmessage_deltaснова содержит этот массив с записями обслуживающей модели.- Серия блоков контента, каждый из которых имеет событие
content_block_start, одно или несколько событийcontent_block_deltaи событиеcontent_block_stop. Каждый блок контента имеетindex, соответствующий его индексу в массивеcontentитогового Message. Одно исключение: во время ответов с резервным переключением на стороне сервера блок контентаfallbackпоступает на каждой границе модели в виде парыcontent_block_startиcontent_block_stopбез дельт между ними. - Одно или несколько событий
message_delta, указывающих на изменения верхнего уровня в итоговом объектеMessage. - Финальное событие
message_stop.
События ping
Потоки событий также могут включать любое количество событий ping.
События ошибок
API может время от времени отправлять ошибки в потоке событий. Например, в периоды высокой нагрузки вы можете получить overloaded_error, что в контексте без потоковой передачи обычно соответствовало бы HTTP 529:
event: error
data: {"type": "error", "error": {"type": "overloaded_error", "message": "Overloaded"}}Другие события
В соответствии с политикой версионирования могут добавляться новые типы событий, и ваш код должен корректно обрабатывать неизвестные типы событий.
Типы дельт блоков контента
Каждое событие content_block_delta содержит delta определённого типа, которая обновляет блок content по заданному index.
Текстовая дельта
Дельта блока контента text выглядит так:
event: content_block_delta
data: {"type": "content_block_delta","index": 0,"delta": {"type": "text_delta", "text": "ello frien"}}Дельта входного JSON
Дельты для блоков контента tool_use соответствуют обновлениям поля input блока. Для обеспечения максимальной детализации дельты представляют собой частичные строки JSON, тогда как итоговый tool_use.input всегда является объектом.
Вы можете накапливать строковые дельты и разбирать JSON после получения события content_block_stop, используя библиотеку вроде Pydantic для частичного разбора JSON, либо используя SDK, которые предоставляют вспомогательные средства для доступа к разобранным инкрементальным значениям.
Дельта блока контента tool_use выглядит так:
event: content_block_delta
data: {"type": "content_block_delta","index": 1,"delta": {"type": "input_json_delta","partial_json": "{\"location\": \"San Fra"}}}Примечание: текущие модели поддерживают выдачу только одного полного свойства «ключ-значение» из input за раз. Поэтому при использовании инструментов между событиями потоковой передачи могут возникать задержки, пока модель работает. Как только ключ и значение input накоплены, они выдаются в виде нескольких событий content_block_delta с разбитым на части частичным JSON, чтобы формат мог автоматически поддерживать более тонкую детализацию в будущих моделях.
Дельта размышлений
При использовании размышлений с включённой потоковой передачей вы будете получать содержимое размышлений через события thinking_delta. Эти дельты соответствуют полю thinking блоков контента thinking.
Для содержимого размышлений непосредственно перед событием content_block_stop отправляется специальное событие signature_delta. Эта подпись используется для проверки целостности блока размышлений.
Если в конфигурации размышлений задано display: "omitted", текст размышлений не передаётся. Блок размышлений открывается, получает thinking_delta с пустой строкой thinking, затем одно событие signature_delta и закрывается. При display: "updates" (бета) блоки рассуждений передаются так же. Текст содержат только события thinking_delta с обновлениями о ходе работы, которые некоторые модели пишут между вызовами инструментов. См. раздел Управление отображением размышлений.
Типичная дельта размышлений выглядит так:
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": "signature_delta", "signature": "EqQBCgIYAhIM1gbcDa9GJwZA2b3hGgxBdjrkzLoky3dl1pkiMOYds..."}}Полный HTTP-ответ потока
Используйте клиентские SDK при работе в режиме потоковой передачи. Однако если вы создаёте прямую интеграцию с API, вам необходимо обрабатывать эти события самостоятельно.
Ответ потока состоит из:
- События
message_start - Потенциально нескольких блоков контента, каждый из которых содержит:
- Событие
content_block_start - Потенциально несколько событий
content_block_delta - Событие
content_block_stop
- Событие
- Одного или нескольких событий
message_delta - События
message_stop
По всему ответу также могут быть рассредоточены события ping. Подробнее о формате см. в разделе Типы событий.
Базовый запрос с потоковой передачей
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5-5",
messages=[{"role": "user", "content": "Hello"}],
max_tokens=256,
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)event: message_start
data: {"type": "message_start", "message": {"id": "msg_1nZdL29xx5MUA1yADyHTEsnR8uuvGzszyY", "type": "message", "role": "assistant", "content": [], "model": "claude-opus-5-5", "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"}
Запрос с потоковой передачей и использованием инструментов
Этот запрос просит Claude использовать инструмент, чтобы сообщить погоду.
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-5",
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)event: message_start
data: {"type":"message_start","message":{"id":"msg_014p7gG3wDgGV9EUtLvnow3U","type":"message","role":"assistant","model":"claude-opus-5","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_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"}Запрос с потоковой передачей и размышлениями
Этот запрос включает размышления с потоковой передачей. Настройка display: "summarized" передаёт сжатое резюме рассуждений Claude, а не полную цепочку мыслей.
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5-5",
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":
delta = event.delta
match delta.type:
case "thinking_delta":
print(delta.thinking, end="", flush=True)
case "text_delta":
print(delta.text, end="", flush=True)event: message_start
data: {"type": "message_start", "message": {"id": "msg_01...", "type": "message", "role": "assistant", "content": [], "model": "claude-opus-5-5", "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"}Запрос с потоковой передачей и использованием инструмента веб-поиска
Этот запрос просит Claude найти в интернете актуальную информацию о погоде.
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-5-5",
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)event: message_start
data: {"type":"message_start","message":{"id":"msg_01G...","type":"message","role":"assistant","model":"claude-opus-5-5","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"}Восстановление после ошибок
Claude 4.5 и более ранние версии
Для моделей Claude 4.5 и более ранних вы можете восстановить запрос с потоковой передачей, прерванный из-за сетевых проблем, тайм-аутов или других ошибок, возобновив его с того места, где поток был прерван. Такой подход избавляет вас от повторной обработки всего ответа.
Базовая стратегия восстановления включает:
- Сохранение частичного ответа: сохраните весь контент, который был успешно получен до возникновения ошибки.
- Формирование запроса на продолжение: создайте новый запрос к API, включающий частичный ответ ассистента в качестве начала нового сообщения ассистента.
- Возобновление потоковой передачи: продолжайте получать оставшуюся часть ответа с того места, где он был прерван.
Claude 4.6 и более поздние версии
Для моделей Claude 4.6 и более поздних применяется та же стратегия сохранения и возобновления, но шаг 2 меняется: вместо размещения частичного ответа в сообщении ассистента добавьте сообщение пользователя, которое инструктирует модель продолжить с того места, где она остановилась.
- Сохранение частичного ответа: сохраните весь контент, который был успешно получен до возникновения ошибки.
- Формирование запроса на продолжение: создайте новый запрос к API с сообщением пользователя, содержащим частичный ответ и инструкцию продолжить, например:
Sample prompt
Your previous response was interrupted and ended with [previous_response]. Continue from where you left off. - Возобновление потоковой передачи: продолжайте получать оставшуюся часть ответа с того места, где он был прерван.
Лучшие практики восстановления после ошибок
- Используйте возможности SDK: задействуйте встроенные в SDK возможности накопления сообщений и обработки ошибок.
- Учитывайте типы контента: помните, что сообщения могут содержать несколько блоков контента (
text,tool_use,thinking). Блоки использования инструментов и расширенных размышлений не могут быть восстановлены частично. Вы можете возобновить потоковую передачу с самого последнего текстового блока.
Следующие шаги
Обрабатывайте каждое значение stop_reason после завершения потока.
Передавайте входной JSON инструментов без буферизации на стороне сервера для снижения задержки.
Передавайте вывод размышлений с помощью событий thinking_delta и signature_delta.
Используйте официальные SDK, которые берут на себя потоковую передачу, накопление и повторное подключение.
Обрабатывайте большие объёмы запросов асинхронно, когда вам не нужны ответы в реальном времени.
Was this page helpful?