はじめに:なぜ「状態保持」エージェントなのか
ソファのクリーニング見積もりを取るために業者に連絡したことはありますか?サイズ、素材、写真、住所をやり取りし、見積もり確認後に日程調整まで…気づけば15分もかかってしまいます。このプロセスをAIに任せられたらどうでしょうか。
単なるチャットボットと真のAIエージェントの違いは**「状態(State)」**にあります。顧客が「2LDKで冷蔵庫内部の清掃もお願いします。火曜と水曜なら可能です」と一度に伝えた場合、エージェントは不足情報を判断し、価格を計算し、予約まで一貫して処理する必要があります。
本記事では、PythonとLangGraphを使用して、マルチステップの予約ワークフローを処理する状態ベースのエージェントを構築します。さらにLangfuseを組み込み、可観測性(Observability)を確保する実践的なアプローチを解説します。(なお、エージェントの完全なソースコードはGitHubで公開されています。)

核心実装:LangGraphで状態マシンを構築する
LangGraphの核心は**共有状態(Shared State)**です。複数の顧客メッセージにわたって会話を継続する必要があるため、TypedDictで状態スキーマを定義します。
from typing import TypedDict, Optional
class BookingDetails(TypedDict):
service_type: Optional[str]
size: Optional[str]
address: Optional[str]
preferred_dates: Optional[list[str]]
price: Optional[float]
class AgentState(TypedDict):
messages: list
booking_details: BookingDetails
next_step: str
次にグラフビルダーを生成し、ノードを追加します。例えば価格計算ノードは以下のように状態を読み取り、部分的な更新を返します。
from langgraph.graph import StateGraph, END
def calculate_price_node(state: AgentState):
details = state["booking_details"]
# 実際の価格計算ロジック(例:サービス種別、サイズに基づく)
price = calc_price(details)
return {"booking_details": {**details, "price": price}, "next_step": "confirm"}
graph = StateGraph(AgentState)
graph.add_node("gather_info", gather_info_node)
graph.add_node("calculate_price", calculate_price_node)
graph.add_node("book_appointment", book_node)
情報収集後、条件付きルーティング関数が十分な情報があるか判断します。
def route_after_gather(state: AgentState):
if is_complete(state["booking_details"]):
return "calculate_price"
return END # 追加の顧客メッセージを待機
graph.add_conditional_edges("gather_info", route_after_gather)
graph.add_edge("calculate_price", "book_appointment")
graph.add_edge("book_appointment", END)
最後にチェックポインタと共にグラフをコンパイルすると、状態が自動保存され、会話が途切れても続行できます。
from langgraph.checkpoint.memory import MemorySaver
app = graph.compile(checkpointer=MemorySaver())
この構造の利点は明確です。LLMの柔軟な対話能力と決定論的なビジネスルール(価格計算、予約ロジック)を分離することで、予測可能かつ自然なユーザー体験を提供できます。

注意事項と深掘り:可観測性(Observability)の確保
プロダクション環境でAIエージェントを運用する際に最も重要なのは**「何が起きているかを把握すること」**です。LangfuseはオープンソースのLLM観測プラットフォームで、プロンプト、入出力、トークン使用量、コストを追跡できます。
from langfuse.callback import CallbackHandler
langfuse_handler = CallbackHandler(
public_key="pk-lf-...",
secret_key="sk-lf-...",
host="https://cloud.langfuse.com"
)
# グラフ実行時にコールバックを渡す
app.invoke(inputs, config={"callbacks": [langfuse_handler]})
注意点:
- LLM呼び出しコストは予想以上に早く積み上がる可能性があります。Langfuseダッシュボードでトークン使用量を定期的に監視してください。
- 状態スキーマが複雑になるほどデバッグが難しくなります。各ノードの入出力をロギングする習慣をつけましょう。
- チェックポインタをメモリではなくPostgreSQLなどの永続ストレージに置き換えれば、サーバー再起動後も状態が維持されます。
この技術の限界はLLMの非決定性です。同じ入力でも異なる応答が返る可能性があるため、重要なビジネスロジック(価格、予約確定)は必ずコードで検証する防御ロジックが必要です。

結論:次のステップは?
ここまで、LangGraphとLangfuseを活用して状態ベースの予約エージェントを構築する方法を見てきました。このプロジェクトはv0レベルですが、モジュール化された設計のおかげで拡張が容易です。
実務適用のためのアドバイス:
- 日本のSI環境ではレガシーシステムとの連携が鍵となります。予約データを既存のERPやCRMに同期するアダプターレイヤーを必ず検討してください。
- フロントエンドはStreamlitで素早くプロトタイピングした後、実際のサービスではReactやVueに置き換えることを推奨します。
- LINE、Slackなどのメッセンジャー連携を追加すれば、顧客接点を大きく拡張できます。
次の学習方向:
- LangGraphの
interrupt機能を活用したhuman-in-the-loopワークフロー - Langfuseの評価(Evaluation)機能でエージェント応答品質を自動測定
- マルチエージェント構造への拡張(例:予約エージェント+通知エージェント)
AIエージェントは単なる流行ではなく、反復的なビジネスプロセスを自動化する実質的なツールです。小さなワークフローから始めてみてください。
合わせて読みたい記事:
根拠資料: I Replaced a 15-Minute Booking Process with a LangGraph AI Agent