Claude API

Streaming với Claude API: SSE, các loại sự kiện và xử lý lỗi giữa chừng

Tóm tắt

Streaming trả kết quả dần qua SSE, vừa cải thiện trải nghiệm vừa tránh timeout với max_tokens lớn. Dùng helper SDK, gom delta theo index, chỉ parse JSON tool khi khối đóng và luôn xử lý sự kiện error giữa stream.

Người dùng nhìn màn hình trắng 20 giây chờ câu trả lời dài, hoặc request với max_tokens lớn bị đứt vì timeout HTTP. Cả hai đều được giải quyết bằng streaming: đặt "stream": true và Claude API trả kết quả dần dần qua server-sent events (SSE). Chữ hiện ra ngay khi model sinh, còn kết nối được giữ sống suốt thời gian xử lý. Bài này giải thích luồng sự kiện, cách dùng SDK và những bẫy khi xử lý lỗi giữa chừng.

Dùng SDK: cách đơn giản nhất

with client.messages.stream(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Giải thích SSE trong 3 câu"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
    final = stream.get_final_message()   # Message đầy đủ, có usage

Không cần hiển thị dần? Vẫn nên dùng stream rồi gọi get_final_message(). Tài liệu nêu rõ cách này đặc biệt hữu ích khi max_tokens lớn, vì SDK yêu cầu streaming để tránh timeout HTTP.

Thứ tự sự kiện

Sự kiệnÝ nghĩa
message_startMở message, chứa object Message rỗng nội dung
content_block_startBắt đầu một khối (text, tool_use, thinking) với index
content_block_deltaTừng mảnh nội dung của khối
content_block_stopKết thúc khối
message_deltaCập nhật cấp message: stop_reason, usage cộng dồn
message_stopKết thúc stream
ping / errorGiữ kết nối / báo lỗi giữa chừng

Các loại delta

  • text_delta: mảnh văn bản, nối lại để hiển thị.
  • input_json_delta: tham số tool dưới dạng chuỗi JSON chưa hoàn chỉnh. Phải gom đủ đến content_block_stop mới parse được.
  • thinking_delta + signature_delta: khi bật thinking; signature đến ngay trước khi khối đóng, dùng để xác thực khối thinking.
event: content_block_delta
data: {"type":"content_block_delta","index":1,
       "delta":{"type":"input_json_delta","partial_json":"{\"location\": \"San Fra"}}

Lỗi giữa stream

Stream đã trả về HTTP 200 vẫn có thể nhận sự kiện error, ví dụ overloaded_error lúc tải cao (tương đương HTTP 529 khi không stream). Code của bạn phải xử lý trường hợp này, không thể chỉ kiểm tra status code ban đầu.

Rủi ro và lưu ý

  • Parse JSON tool quá sớm: lỗi kinh điển. Chỉ parse khi khối đóng, hoặc dùng helper tích luỹ của SDK.
  • Bỏ qua index: một message có nhiều khối; gộp delta theo index, không theo thứ tự đến.
  • Proxy/buffer chặn SSE: nginx hay gateway có thể buffer làm mất hiệu ứng streaming; tắt buffering cho endpoint này.
  • Đứt kết nối giữa chừng: phần đã nhận có thể dùng được, nhưng phải quyết định gửi lại hay tiếp tục; với UX chấp nhận được, gửi lại request là đơn giản nhất.
  • Bỏ qua sự kiện lạ: API có thể thêm loại sự kiện mới; code nên bỏ qua loại không biết thay vì crash.

Áp dụng thế nào?

  • Dev: Mặc định dùng messages.stream() cho mọi request dài; lưu get_final_message() vào log để có usage chính xác.
  • Tech Lead: Viết một lớp adapter duy nhất xử lý SSE, lỗi giữa stream và retry, thay vì mỗi service tự làm.
  • PM: Đo "thời gian tới chữ đầu tiên" thay vì tổng thời gian; đây là chỉ số người dùng cảm nhận rõ nhất.

Nguồn & tham khảo

  1. Streaming messages — Claude Docs