5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Django】AIチャットアプリをASGI分離した話

Last updated at Posted at 2025-12-20

この記事はPython Advent Calendar 2025 の24日目の記事です。

はじめに

あるDjangoプロジェクトにAIエージェント機能を導入することになり、langChainを用いたReActエージェントを実装した。開発環境では問題なく動作していたのだが、本番環境(Render)にデプロイしたところtimeoutエラーが出てしまった...

WSGIとASGI

まず、djangoプロジェクトに存在するwsgi.pyとかasgi.pyの役割を見ていく。

wsgi asgi
名前 Web Server Gateway Interface Asynchronous Server Gateway Interface
それは何 Pythonにおいて、WebサーバとWebアプリケーションが通信するための、標準化されたインタフェース定義 WSGIの精神的な後継仕様であり、asyncioを介して非同期で動作するように設計されたインターフェース定義
できること 同期処理(同期的なHTTP req/res) 非同期処理(http, websocket, SSE..)  長時間接続
動作環境例 gunicorn uvicorn

なるほど。つまり、WSGIでは1リクエスト1プロセス前提であり、WebSocketやSEEなどの継続接続に対応していないということだ。

では、WSGIなんて使わずに同期・非同期どちらも扱えるASGIを使った方がいいのでは..?

ASGIは万能?

0から開発するのであれば、ASGI選定はほぼ最適解といえるだろう。しかし、WSGI対応で開発されたプロジェクトのASGIへのリプレイスコストや開発メンバの学習コストを考えたとき、それは最適解とならないかもしれない。

実際、自身のチームでは開発経験の浅いメンバがいたこともあり、WSGIを選定していた。

AIチャットの導入

先述した通り、私たちのプロジェクトはWSGI想定で開発されており、Renderでもgunicornで運用していた。そこに、ReActエージェントを用いたAIチャットの導入が企画された。実装の詳細は省くが、langChain + OpenAIで開発し、開発環境では安定した動作を見せていた。

しかし、デプロイのときになってエラーが我らを襲った。gunicornのtimeoutエラーである。エラーログを辿るとOpenAIなどの重いモジュールをimportするときにtimeoutしているらしかった。

ASGI分離

前項のエラーに対して、lazy importやtimeoutの延長などの対策を行ったが解消されず、最終的にAIチャット機能だけASGIに逃がす選択をした。ASGIは非同期処理ができるだけでなく、長時間接続が可能であることからtimeoutエラーを解消できると考えたからである。

この改修によって、プロジェクトはWSGI+ASGIの形態となりエラーは解消された。
また、Renderにおいてgunicornuvicornを併用して実現できた。

副作用

timeoutエラー解消のためにASGI分離をしたことで、それまでWSGI故に諦めていたAIチャットのStreamingレスポンス処理が視野に入ってきた。SSEプロトコルを使ってAIエージェントからの回答をトークン単位でリアルタイムでフロントエンドに表示することで、回答待ちの体感時間が大幅に改善した。

まとめ

どちらかを採用するということではなく、状況に合わせて柔軟に選定することで安定性と革新を同時に満たすことができるとわかる、よい経験だった。Python以外でのインターフェースも見てみたいと思う。

5
0
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
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?