LLMに処理の一部を担わせるプロキシAPIの設計思想

要約
本番で使われるデータのサイズやLLM処理に要する時間を設計段階から意識し、最適なアーキテクチャを実装しよう
意見はこのエリアに表示されます
アイキャッチ画像

この記事は何?

LLM での処理を行うプロキシ API をどう作るか
自分の失敗から私なりの考えをまとめた記事です
本記事の内容を一言で表すならば

本番で使われるデータのサイズや LLM 処理に要する時間を設計段階から意識し、最適なアーキテクチャを実装しよう

です
当たり前の話ですが、LLM の出力は再現性が低いこともあり私は引っかかりましたね

Q: 誰に向けた記事?

A: LLM処理をプロダクトに取り入れたい方々に向けて書きました!

LLM に処理の一部を担わせるプロキシ API の設計思想

みなさんは Requests body を OpenAI や Claude, Gemini 等の AI に流し込み、返り値をクライアントに返すプロキシ API を作成する際、どのように設計しますか?
まずは下記のようなアーキテクチャを想像するのではないでしょうか

LLM にプロキシする API
LLM にプロキシする API

LLM にアクセスするための API キーの漏洩を防いだり、LLMOps を回すためにデータをストレージに送ったりと、プロキシ API を必要とするケースは多いはずです

私の失敗

多くの MVP 開発において、上図の構成で事足りると思います
しかし、上記の構成ではうまくいかない場合もあります
それは LLM 処理に時間がかかる場合やプロキシ API に送られた body の中身がデカすぎる場合です
AWS Lambda でプロキシ API を実装するケースを考えてみましょう
よくあるケースは LLM 処理が長すぎて API Gateway 側で30秒タイムアウトが発生する場合です
API 実装初期は数秒でレスポンスが返ってきていたので安心して開発を進めていたが、本番データが予想よりもデカく、処理に30秒以上かかることが判明しました

デカすぎる body にハングアップするプロキシ API
デカすぎる body にハングアップするプロキシ API

どうすればよかったのか?

「入力として想定されるデータとして、一番サイズが大きいケースは何か」これを最初に考えるクセをつけよう

タイムアウトの懸念があるなら非同期処理で実装しよう

入力値の上限ギリギリを攻めて開発に着手しましょう
また、データがなくともテストせずともタイムアウトを予期できるケースがあります
それはリストの要素一件一件に対して LLM 処理を実行する場合です
こちらはリストの要素数が多すぎる場合には簡単にタイムアウトしてしまいます(逐次実行の場合)

このようなケースでは Lambda ではなく AWS StepFunction や他のアーキテクチャを使用しましょう
非同期処理に切り替えることでタイムアウト問題を乗り越えられます

StepFunction で非同期処理を行う例
StepFunction で非同期処理を行う例

StepFunction を使うと作成するリソースを最小限に抑えることができるため、管理が楽になります
しかし、StepFunction でも受け付けられないパターンもあります
それはリクエストサイズが1MB を超える場合です
StepFuncrion のリクエストサイズ上限が1MB であるため、このようなケースでは SQS と DynamoDB を使うことで対応しましょう

AWS Lambda + SQS + DynamoDB で構成する例
AWS Lambda + SQS + DynamoDB で構成する例

SQS で LLM 処理をバッチで実行し DynamoDB に送り、ポーリングで DynamoDB から処理結果を取り出す方法です

おわりに

本記事では LLM に処理の一部を担わせるプロキシ API の設計思想について書きました
AWS を例に挙げて書きましたが、GCP や Cloudflare でも同じ考え方でアーキテクチャを組めるはずです!
ここまで読んでいただきありがとうございました🙌

Explore More
関連記事はありません。