ストリーミング & マルチターン会話
- レスポンスをトークンごとにストリーミングし、ユーザーがすぐ出力を見られるようにする
- API がなぜステートレスなのか、そして会話履歴を自分で持ち運ぶ方法を理解する
- 直前のやり取り全体を再送してマルチターン会話を続ける
- 長い会話がコンテキストウィンドウとコストを膨張させないようにする
API でチャットのような体験を構築することは、2つの実務的な現実に集約されます:ユーザーがすぐ出力を見られるようストリーミングすること、そして API がステートレスなので履歴を自分で管理すること。両方を使いこなせば、チャットの UX は速く感じられ、すべてを覚えてくれます。
ストリーミング
ストリーミングなしでは、ユーザーは返信全体を待ちます。ストリーミングありなら、生成されるそばからトークンが届きます——体感速度がはるかに良くなります。
- 生のイベントを手で解析する代わりに、SDK のストリーミングヘルパーを使ってください——イベントのライフサイクルを代わりに管理してくれます。
- Python
- TypeScript
with client.messages.stream(
model="claude-sonnet-5", max_tokens=1024,
messages=[{"role": "user", "content": "Explain RAG in two sentences."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
const stream = client.messages.stream({
model: "claude-sonnet-5", max_tokens: 1024,
messages: [{ role: "user", content: "Explain RAG in two sentences." }],
});
for await (const event of stream) {
if (event.type === "content_block_delta") process.stdout.write(event.delta.text ?? "");
}
マルチターン:履歴はあなたが持つ
API は呼び出し間で記憶を持ちません(なぜか)。会話を続けるには、毎回直前のやり取り全体を送り返します。
Guided walkthrough1 of 4
- 最初のユーザーメッセージを messages リストに入れて送ります。
- 結果からアシスタントの応答テキストを読みます。
- アシスタントの返信と次のユーザーメッセージを同じ messages リストに追加します。
- 完全な messages リストを再び送ります——これが Claude がやり取りを「覚えている」仕組みです。
messages = [{"role": "user", "content": "Hi, I'm planning a trip."}]
# ... get assistant reply, then append both turns:
messages.append({"role": "assistant", "content": assistant_text})
messages.append({"role": "user", "content": "Make it 3 days."})
# send the full `messages` list again
長い会話はウィンドウを満たす
履歴が増えるとコンテキストウィンドウを食い、コストが上がります。抑えるための戦略:
- 古いターンを短い要約に要約/圧縮して持ち越す。
- 無関係な以前のターンを切り詰める。
- 安定したプレフィックスを再び払わずに済むよう、**プロンプトキャッシュ**と組み合わせる。
- 毎回の呼び出しが履歴全体を再送します——長い会話はコストが増え、圧縮や切り詰めをしなければ最終的にコンテキストウィンドウを超える可能性があります。
- 体感速度のためにトークンをストリーミングする;SDK ヘルパーがイベントのライフサイクルを処理する。
- API はステートレス——呼び出し間で記憶を持たない。
- 各ターンを追加し messages リスト全体を再送することで会話を続ける。
- 圧縮、切り詰め、キャッシュで長い会話のコストとサイズを制御する。