8月29日、Soner Yıldırımが「Connecting My LangGraph AI Agent to Postgres」と題した記事を公開した。LangGraphベースのAIエージェントはデフォルトではインメモリで状態を管理するため、アプリを再起動すると会話の進行状態がすべて消える。予約システムとして実用するには、状態をDBに永続化する仕組みが不可欠だ。本記事では、そのPostgres接続を実現する具体的な手順と、2つのブラウザウィンドウで予約の重複が正しく弾かれるという印象的な動作検証が紹介されている。
LangGraphエージェントとは
このプロジェクトはシリーズ記事の第4弾にあたる。Soner Yıldırımは過去3本の記事(第1弾・第2弾・第3弾)で、清掃サービスの予約対応を自動化するLangGraphベースのAIエージェントを段階的に構築してきた。エージェントは以下の処理を自律的にこなす。
- 顧客の問い合わせへの応答と要件の把握
- サービス料金の計算と提示
- 承諾・拒否の処理
- 最適な時間帯の提案(既存予約との重複を避ける)
- 予約の確定とデータベースへの記録
会話の進行状況はAgentStateとして管理される。AgentStateとはLangGraphが各ノード間でやり取りする状態オブジェクトで、会話履歴・予約情報・処理フラグなどを一括して保持する。この状態をチェックポイントとして保存することで、会話の途中からでも処理を再開できる。
LangGraphのチェックポイント機構はlanggraph-checkpointライブラリが担い、バックエンドとしてインメモリ(MemorySaver)またはPostgres(AsyncPostgresSaver / PostgresSaver)を選択できる。Postgres接続にはpsycopg2(同期)またはpsycopg(非同期)ドライバが必要で、今回の実装ではpsycopg2が依存関係として追加されている。
時間帯を提案する際はDBから既存予約を読み込み、重複しない枠だけを提示する。予約が確定すると、担当者・時間帯・住所・料金の1行が書き込まれる。
エージェントの構造(グラフワークフロー)は以下のとおりだ。

2つの永続化モード
アプリにはインメモリとPostgresの2つの永続化モードがある。
DATABASE_URLが未設定の場合 →InMemoryBookingRepositoryとMemorySaverを使用。テーブルは作成されないDATABASE_URLを設定した場合 → Postgresに接続し、予約データを永続化する
MemorySaverはLangGraphが標準で提供するインメモリ用チェックポインター実装で、開発・テスト用途に向いている。本番運用でデータを保持したい場合はPostgres接続が必要になる。インメモリモードではStreamlit UIで予約を完結できるが、アプリを再起動すると会話状態が消える。これが今回の記事が解決する課題の核心だ。
Dockerによる検証がフックになる理由
記事の最大の読みどころは、2つのブラウザウィンドウを使った重複予約の弾き方の実証だ。最初のウィンドウで予約を完了した後、別のブラウザで同じ時間帯を要求すると、エージェントは既に埋まっているスロットを提案しなかった。

この挙動はDBへの書き込みと読み込みが正しく連動していることを直感的に示す。2セッション間でデータが共有されているという事実は、インメモリ実装では絶対に再現できない。この検証シナリオを用意している点が、本記事の実践的な価値を高めている。
DockerでPostgresをローカル検証する
なぜDockerか
- ローカルにPostgresをインストールせずに、本番相当のDBでテストできる
docker-compose.ymlでURL・認証情報が固定されるため、誰でも同じ環境を再現できる- コンテナを
docker compose downで停止、docker compose down -vでデータごと削除でき、ホストマシンへの影響がない
docker-compose.yml
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: booking
POSTGRES_PASSWORD: booking
POSTGRES_DB: booking_agent
ports:
- "5432:5432"
volumes:
- booking_pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U booking -d booking_agent"]
interval: 5s
timeout: 5s
retries: 10
volumes:
booking_pgdata:
PostgreSQL 16(Alpine版)を使用。データはDockerボリュームbooking_pgdataに書き込まれるため、RAMではなくディスクに永続化される。healthcheckにより、Postgresが起動完了するまでアプリ側が接続を試みないよう制御されている。
手順
まず依存関係をインストールして.envを準備する。
poetry install
cp .env.example .env
.envにOPENAI_API_KEYとDATABASE_URLを設定する。
DATABASE_URL=postgresql://booking:booking@localhost:5432/booking_agent
Docker Desktopを起動し、コンテナを立ち上げてからStreamlitを起動する。
poetry run streamlit run customer_service_agent/streamlit_app.py
プロセスの独立性
StreamlitとDockerのPostgresは別プロセスとして動作する。Streamlitを再起動してもコンテナは停止しないため、予約データはそのまま残る。データが消えるのは、明示的にボリュームを削除したときだけだ。
docker compose down -v
# ✔ Container customer-service-agent-postgres-1 Removed
# ✔ Volume customer-service-agent_booking_pgdata Removed
# ✔ Network customer-service-agent_default Removed
クラウドホストのPostgresに接続する
SupabaseやAWS RDSなどのクラウドPostgresを使う場合は、Dockerは不要だ。プロバイダーのダッシュボードでDBを作成し、接続文字列を取得して.envに設定するだけでよい。
DATABASE_URL=postgresql://USER:PASSWORD@HOST:PORT/DATABASE
起動コマンドはDockerの場合と同じで、アプリの動作はDockerと完全に同一。違いはPostgresが動作する場所だけだ。接続文字列を差し替えるだけで本番環境へ移行できる設計になっており、ローカル検証から本番運用までの流れがスムーズに繋がる。
ソースコード
プロジェクトの全ソースコードはGitHub(customer-service-agent)で公開されており、クローンしてそのまま試すことができる。
今後の課題としてWhatsAppチャンネルへの対応、プロンプトインジェクション対策のセーフティレイヤー追加が挙げられており、シリーズはまだ続く予定だ。
詳細はConnecting My LangGraph AI Agent to Postgresを参照していただきたい。