はじめに
Claude等の生成AIに質問する際、一度に回答が画面に表示されるわけではなく、順次回答が表示されていますね。
あれどんな技術なんだろう?って思い調べてみた記事です。
ご本人に聞くと、ストリーミングって技術を使っているみたい。
今回は好きなLambdaでストリーミングをやってみよう!って記事です。
なぜストリーミング?
ストリーミングの何が良いか?については以下のページに書いてましたが、以下に2点がありそうです。特に生成AIには大きなメリットがありそうですね!(今までてっきり演出なんかと思ってました。)
- レスポンス性能
- レスポンスの一部が準備できた時点でクライアントに応答を返し始めるので、ユーザーの待機時間が短縮される
- メモリ効率
- レスポンス全体をメモリに保持する必要がないため、メモリ使用量を削減できる
Lambda 関数 URL を設定して、レスポンスペイロードをクライアントにストリーミングで返すようにできます。レスポンスストリーミングは、最初のバイトまでの時間 (TTFB) のパフォーマンスを向上させることで、レイテンシーの影響を受けやすいアプリケーションに役立ちます。これは、レスポンスの一部が利用可能になったときにクライアントに返送できるためです。さらに、レスポンスストリーミングを使用して、より大きなペイロードを返す関数を構築できます。レスポンスストリームのペイロードには、バッファされるレスポンスの 6 MB と比較して 20 MB のソフトリミットがあります。応答をストリーミングするということは、関数が応答全体をメモリに収める必要がないことも意味します。応答サイズが非常に大きい場合は、関数に設定する必要のあるメモリ量を減らすことができます。
料金
メモリは節約できるんだけど、追加の料金はかかるみたいです。
以下ページを確認すると、USD 0.008000 per GBとのことでした。
作ってみる!
早速作ってみます。
Lambdaの作成
Lambdaの場合は、以下のとおり、基本はNode.jsで作るのが手っ取り早そうです。
Lambda は Node.js マネージドランタイムでのレスポンスストリーミングをサポートしています。その他の言語の場合は、カスタムランタイム API 統合を備えたカスタムランタイムを使用してレスポンスをストリーミングするか、Lambda Web Adapter を使用することができます。
Claud Codeさんに簡単に書いてもらいました。
awslambda.streamifyResponseの引数responseStreamに100msec毎、文字をPushする仕組みです。
/* global awslambda */
export const handler = awslambda.streamifyResponse(async (event, responseStream, _context) => {
const text = "Hello, this is character-by-character streaming! 🚀";
// 直接 responseStream に書き込む
for (const char of text) {
responseStream.write(char);
await new Promise(resolve => setTimeout(resolve, 100));
}
responseStream.end();
});
作ったLambdaの関数URLをPostmanで叩いてみると、Content-Typeがapplication/octet-streamになっていることや、Transfer-Encoringがchunkedになっていることがわかります。
この方法とは別に、SSE(Server-Sent Events)という方式があるみたいですが、こちらはPOSTメソッドが使えなかったりと少し制約があったりするみたいです。
Webクライアントで動かしてみる。
ストリーミングの関数URLをブラウザで表示しても、ファイルダウンロードになってしまうので以下のような感じなクライアントを作ってみます。
ストリームリーダでデータを1文字ずつテキストにしながら、DOM操作で文字を加えていく感じです。
<!DOCTYPE html>
<html>
<head>
<title>Character Stream Test</title>
<style>
#output {
font-family: monospace;
font-size: 18px;
line-height: 1.5;
white-space: pre-wrap;
}
</style>
</head>
<body>
<div id="output"></div>
<script>
async function startCharacterStream() {
const response = await fetch('https://xxxxxxx .lambda-url.ap-northeast-1.on.aws/');
const reader = response.body.getReader();
const decoder = new TextDecoder();
const output = document.getElementById('output');
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chars = decoder.decode(value, { stream: true });
output.textContent += chars;
}
}
startCharacterStream();
</script>
</body>
</html>
今回はAmplify Hostingを使ってホスティングしてみました。
こんな感じで動きます!
最後に
Lambdaのストリーミング、ストリーミングの技術を知ることができてよかったです。
Bedrock AgentCoreのところにも導入したいなぁと思いましたが、一旦ここまでにします。


