ログイン無料トライアルを開始
Meta Tech Provider

OpenAI Agents SDK のエージェントを WhatsApp で動かす

電話番号の Webhook の送信先を、Python アプリ内のルートに設定します。メッセージを受信するたびに、Runner.run と送信者の番号をキーにしたセッションでエージェントを実行し、result.final_output を、その番号のトークンと phone number id を使って Cloud API から返信します。同じ番号で WhatsApp Business アプリも引き続き使えます。

SQLiteSession

SDK 組み込みのセッション(ファイル保存またはインメモリ)が、セッション ID ごとに過去のやり取りを記憶します。

params["auth"]

MCPServerStreamableHttp では、サーバー認証に httpx.Auth か Authorization ヘッダーを渡せます。

v25.0

Meta の最新のメッセージ送信例で使われている Graph API のバージョンです。

WhatsApp のメッセージはどのようにエージェントの実行になりますか?

Meta が呼び出す、自社アプリ内のルートを経由します。電話番号の Webhook の送信先にそのルートを設定し、パスには長くランダムなシークレットを含めてください。ルートは、Meta の検証用 GET に対して hub.challenge をプレーンテキストで返し、各 POST を受け付けてすぐに 200 を返したうえで、処理をキューに入れます。Meta は応答が遅いとリトライするため、先にエージェントを実行するとエージェントが二重に動いてしまうからです。

その後、ワーカーがペイロードから送信者とテキストを読み取り、Runner.run を呼び出します。このとき、送信者の番号をセッション ID としたセッションを渡します。SDK がその ID で会話を保存するため、同じ顧客の次のメッセージは前回の続きから始まり、別の顧客と履歴が混ざることはありません。最初は SQLiteSession で十分です。複数のワーカーで動かす場合は、SDK に含まれる Redis や SQLAlchemy のセッションを使えます。

ここでは URL 内のシークレットが認証の役割を果たします。Meta は Tech Provider のアプリシークレットで配信に署名するため、顧客側では署名ヘッダーを検証できないからです。

Worker: run the agent for one message and send the answer
import os, httpx
from agents import Agent, Runner, SQLiteSession

agent = Agent(name="Front desk", instructions="Answer briefly and politely.")
URL = f"https://graph.facebook.com/v25.0/{os.environ['PHONE_NUMBER_ID']}/messages"

async def handle(sender: str, text: str) -> None:
    session = SQLiteSession(sender, "whatsapp.db")
    result = await Runner.run(agent, text, session=session)
    async with httpx.AsyncClient() as http:
        await http.post(
            URL,
            headers={"Authorization": f"Bearer {os.environ['WA_TOKEN']}"},
            json={"messaging_product": "whatsapp", "to": sender,
                  "type": "text", "text": {"body": result.final_output}},
        )

返信はエージェントではなく、なぜ自社のコードが送るべきですか?

絶対に破ってはいけない唯一のルールは時間に関するルールであり、プロンプトよりもコードのほうが確実に守れるからです。顧客がメッセージを送ると、Meta は 24 時間のカスタマーサービスウィンドウを開きます。この間はフリーテキストを送れますが、ウィンドウ外では承認済みのメッセージテンプレートしか送れず、フリーテキストはエラー 131047 で返されます。

届いたばかりのメッセージに答えるワーカーは常にウィンドウ内にいるため、result.final_output をテキストとして送る方法は構造上安全です。翌朝のフォローアップやリマインダーなど、後から行う処理は別の経路に分け、フリーテキストではなく必ずメッセージテンプレートを送ってください。

エージェントにツールを持たせることもできます。注文や予約の照会などにはファンクションツールを渡し、WhatsApp への送信はワーカー側に残してください。そうすれば、モデルが任意の引数で呼び出せるものの中に、アクセストークンが入りません。

エージェントから EasyCoexistence の MCP サーバーを使えますか?

使えます。MCPServerStreamableHttp を通じて接続できますが、ヘッダーを足すだけより設定は多くなります。SDK は params["auth"] に Authorization ヘッダーまたは httpx.Auth を受け付けます。EasyCoexistence の MCP サーバーは、ブラウザーでのサインイン後に動的クライアント登録と PKCE を使って独自の OAuth トークンを発行するため、固定のキーはありません。MCP Python SDK には、PKCE とトークン更新を含むそのフローを実行する HTTP 認証ハンドラーの OAuthClientProvider があり、これを params["auth"] に渡します。

この方法が向くのは、エージェント自身に判断させたい場合です。たとえば、番号の接続状態を確認する、メッセージテンプレートの状態を読む、ツールの説明にあるルールに従って send_message と send_template を選ぶ、といった用途です。応答するだけの窓口であれば、前述のワーカーのほうが短く済み、問題も起きにくくなります。

どちらの方法でも Webhook は必要です。MCP はリクエストとレスポンスの仕組みであり、顧客のメッセージがエージェントに届く経路は、Meta が呼び出すルートだけだからです。

よくある間違い

  • Meta に 200 を返す前にエージェントを実行する。遅い応答はリトライされ、顧客に回答が 2 回届きます。
  • 全顧客で 1 つのセッションを使う。送信者の番号をキーにしないと、履歴が混ざります。
  • 遅れて送るフォローアップでフリーテキストを使う。24 時間を過ぎると 131047 で失敗するため、メッセージテンプレートを送ってください。
EasyCoexistence で実現する

easycoexistence.com で番号を接続し、Webhook の送信先を自社のルートに設定したら、ダッシュボードでトークンと phone number id を確認します。料金は番号 1 件あたり月額 US$ 9 から、台数が増えると US$ 1 まで下がり、最初の 3 日間は無料です。

よくある質問

OpenAI Responses API のホスト型 MCP ツールは必要ですか?

いいえ。ワーカーが Runner.run でエージェントをローカル実行し、WhatsApp 側は自社のコードが行う通常の HTTPS 呼び出しです。

どの Graph API バージョンを使えばよいですか?

Meta の最新の例では v25.0 が使われています。バージョンはコード内の 1 か所で固定しておくと、アップグレードが 1 行の変更で済みます。

電話から人が対応を引き継げますか?

はい。Coexistence により WhatsApp Business アプリが引き続き使え、電話からの返信は echo イベントとしてルートに届くため、ワーカーはそれを使ってエージェントを一時停止できます。

EasyCoexistence は会話を保存しますか?

いいえ。Meta がルートへ直接配信します。セッションが保存する内容は、すべて自社のデータベースにあります。

続きを読む

始める準備はできましたか?

WhatsApp Coexistence の設定は数分で完了し、数か月もかかりません。スマートフォン上のアプリも引き続き使えます。

無料トライアルを始める

確認日

OpenAI Agents SDK を WhatsApp で動かす | Cloud API