29
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

API Gatewayのストリーミング機能を試してみました

29
Last updated at Posted at 2025-11-29

はじめに

Amazon API Gatewayがストリーム応答をサポートするアップデートがありました。

いきなりですが、下はストリーミングと非ストリーミングの比較です。
めっちゃ見やすくなってますよね。

今回は動作検証をしながら、どのようなアップデートなのか紹介できればと思います。

何が変わった?

API Gateway はこれまで、バックエンドがレスポンスをすべて生成し終わってからまとめて返す “バッファ方式” が基本でした。
そのため、処理が重い API や、生成系の処理(例:Bedrock で文章を生成する API)では 最初のレスポンスが返ってくるまで待ち時間が長くなる という課題がありました。また、レスポンス全体をまとめて返す都合上、10MB のレスポンスサイズ制限 や 29 秒のタイムアウト の影響もあり、大きな出力や長時間処理には工夫が必要でした。

今回追加された「レスポンス・ストリーミング(Response Streaming)」は、バックエンドが生成したデータをそのまま 逐次クライアントへ送れるようになった新機能です。

Bedrock のような「トークン単位で徐々に出力が進む」モデルとは相性が良く、ユーザーは“最初の一文字目”をすぐに見ることができるようになります。これにより、チャットボットや文章生成系 API の体感速度(UX)は大きく改善されます。

作ってみる

本記事では、この新しいストリーミング機能を Amazon Bedrockをバックエンドに使った構成 で検証します。

  • API Gateway
  • Lambda
  • Bedrock
    という構成を用意し、
  • 従来のバッファ方式とどう変わるのか
  • Bedrock の出力がどのようにストリーミングされるのか
  • UI 側ではどのタイミングでデータが到達するのか

を確認しながらまとめていきます。

構成図

AWSの公式ブログから構成図を拝借し、以下のような構成で今回検証します。

image.png

Lambda関数

Lambdaのストリーミング関数ですが、現在Node.jsにしか対応していないようでした😭
なので、今回はNode.jsで実施していきます。

コードは以下になります!また、Lambdaのタイムアウト時間も30秒くらいにしています。

index.mjs
import {
  BedrockRuntimeClient,
  ConverseStreamCommand,
} from "@aws-sdk/client-bedrock-runtime";

// Lambda Response Streaming
export const handler = awslambda.streamifyResponse(
  async (event, responseStream, _ctx) => {
    // ---------------------------
    // 1. API Gateway 用のメタデータ
    // ---------------------------
    const httpStream = awslambda.HttpResponseStream.from(responseStream, {
      statusCode: 200,
      headers: {
        "Content-Type": "text/plain; charset=utf-8",
        "x-api-gw-streaming": "true",
      },
    });

    try {
      // ---------------------------
      // 2. 入力取得(POST body)
      // ---------------------------
      let userPrompt = "あなたのAWSの推しサービスを教えて";

      if (event?.body) {
        try {
          const body = JSON.parse(event.body);
          userPrompt = body.message ?? body.prompt ?? userPrompt;
        } catch (_) {
          /* malformed JSON → デフォルトで進む */
        }
      }

      // ---------------------------
      // 3. Bedrock クライアント
      // ---------------------------
      const client = new BedrockRuntimeClient({
        region: process.env.BEDROCK_REGION ?? "us-west-2",
      });

      // Claude 4.5 Haiku(Inference Profile)
      const modelId =
        "global.anthropic.claude-haiku-4-5-20251001-v1:0";

      // ---------------------------
      // 4. ConverseStream 呼び出し
      // ---------------------------
      const command = new ConverseStreamCommand({
        modelId,
        messages: [
          {
            role: "user",
            content: [
              { type: "text", text: userPrompt },
            ],
          },
        ],
      });

      const response = await client.send(command);

      // ---------------------------
      // 5. Bedrock のチャンクを逐次処理 → API Gateway へ流す
      // ---------------------------
      for await (const item of response.stream) {
        if (!item?.contentBlockDelta) continue;

        const delta = item.contentBlockDelta.delta;
        const text = delta?.text;

        if (text) {
          httpStream.write(text);
        }
      }

      // ---------------------------
      // 6. 完了
      // ---------------------------
      httpStream.end();
    } catch (e) {
      // ---------------------------
      // 7. エラー時もストリームを閉じる
      // ---------------------------
      console.error("Lambda Error:", e);

      httpStream.write("\n[ERROR]\n");
      httpStream.write(String(e));
      httpStream.end();
    }
  }
);

Lambda関数の実行ロールにBedrockのポリシーをつけるのも忘れずに!

image.png

API Gateway

LambdaのトリガーとなるAPI Gatewayは設定欄から追加することができます。

image.png

ここは「REST API」を選択します。
image.png

API Gateawyの統合リクエストを設定します。
image.png

レスポンス転送モードで「ストリーム」を選択します。
image.png

あとは、APIをデプロイするだけです。

動作確認

ステージのツリーを開いて、URLをコピーします。
image.png

以下のコマンドターミナルから実行できます。

curl --no-buffer {URL}

実行時は以下のようなイメージです!
やはり処理がストリーミングされてくるといいですね。

2025-11-2913.33.19-ezgif.com-video-to-gif-converter.gif

さいごに

今回はAPI Gateawayのストリーミング処理を試してみました。
今回はシンプルにモデル呼び出しでしたが、AgentCoreやStrandsと組み合わせるとより面白そうではありますね。
機会があれば試してみたいと思います。

29
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?