
Sora Fujimoto
AI Solutions Architect

sessions: write権限がない場合の403エラーと、ツールの最初のパラメータにPydantic BaseModelの注釈が欠如している場合のValidationErrorです。このガイドでは、CapSolverをComposioとしてエージェントツールに統合し、reCAPTCHA v2ワークフローを完了する方法を紹介します。トークンのみを返すのではなく、ツールはフルなページシーケンスを実行し、ページの実際の応答を成功条件として扱います。OpenAI Agents SDKはツールを呼び出すタイミングを決定し、Playwrightブラウザ自動化は提出および検証に使用されるページコンテキストを保持します。
このパターンは、法的、合理的、責任ある、ユーザーに許可されたワークフローにのみ使用してください。技術的な能力は、プライベート、制限、機密、または許可されていないデータへのアクセスを許可しません。展開前に関連するAI自動化ガイドを確認してください。
ワークフロー:
スクリプトを実行
-> OpenAI Agents SDKがどのツールを呼び出すかを決定
-> Composioカスタムツール: complete_recaptcha_v2
-> Playwrightでページを開く
-> capsolver.solve(...)がgRecaptchaResponseを返す
-> トークンをg-recaptcha-responseに適用
-> Playwrightで送信し、ページを待機
-> ページを読み込み、承認されたかを判断
-> ツールが{"accepted": ..., "message": ...}を返す
-> エージェントがacceptedからの結果を報告
コンポーネントの責任:
| コンポーネント | 責任 |
|---|---|
| OpenAI Agents SDK | 自然言語の指示を理解し、ツールを呼び出すタイミングを決定し、実行し、応答を整理する |
| Composio | 通常のPython関数をエージェント呼び出し可能なツールとして登録する |
| Playwright | ページを開き、結果を適用し、フォームを送信し、結果のページ状態を読み取る |
| CapSolver SDK | 1回のsolve()呼び出しでCAPTCHA結果を返す |
pip install composio composio-openai-agents openai-agents capsolver pydantic playwright
playwright install chromium
各依存関係には特定の役割があります:
| パッケージ | 目的 |
|---|---|
| composio | セッションを作成し、カスタムツールを登録またはロードする |
| composio-openai-agents | ComposioツールをOpenAI Agentsが呼び出せるオブジェクトに変換する |
| openai-agents | Agent、Runner、SQLiteマルチターンメモリを提供する |
| capsolver | お手伝いSDKを提供し、solve()で結果を返す |
| pydantic | ツール入力スキーマを定義する |
| playwright | ページを開き、結果を適用し、フォームを送信し、応答を読み取る |
# APIキー。
COMPOSIO_API_KEY = "ak_..."
OPENAI_API_KEY = "sk-..." # あなたの公式OpenAI APIキー。
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY # OpenAI SDKはキーを環境から読み込みます。
# CapSolverとComposioを設定。
capsolver.api_key = "CAP-..."
composio = Composio(
api_key=COMPOSIO_API_KEY,
provider=OpenAIAgentsProvider(),
)
設定の注意点:
OPENAI_API_KEYは環境に書き込まれる必要があります。SDKはここでキーを読み込みます。OpenAIAgentsProviderはsession.tools()が返すツールをAgentと互換性を持たせます。Composioキーにはsessions: write権限が必要で、それがないとセッション作成は403エラーになります。
現在のComposio OpenAIプロバイダーとOpenAI Agents SDKのリファレンスは、この設定で使用されるプロバイダーとエージェントの境界を説明しています。
CapSolverボーナスコードを取得する
自動化予算を即座に増やす!
CapSolverアカウントにチャージする際にボーナスコードCAP26を使用すると、毎回5%のボーナスが追加されます—制限なし。
CapSolverダッシュボードで今すぐ利用してください
終了条件: ページに期待される成功テキストが含まれている場合にのみツールは成功と報告されます。
finallyブロックは成功および失敗の両方のパスでブラウザを閉じます。
import os
from typing import List, cast
import capsolver
from agents import Agent, Runner, SQLiteSession
from composio import Composio
from composio.core.models.custom_tool import CustomTool
from composio.core.models.tool_router import ToolRouterExperimentalConfig
from composio_openai_agents import OpenAIAgentsProvider
from playwright.sync_api import sync_playwright
from pydantic import BaseModel, Field
# APIキー。
COMPOSIO_API_KEY = "ak_..."
OPENAI_API_KEY = "sk-..." # あなたの公式OpenAI APIキー。
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
# CapSolverとComposioを設定。
capsolver.api_key = "CAP-..."
composio = Composio(
api_key=COMPOSIO_API_KEY,
provider=OpenAIAgentsProvider(),
)
# カスタムツールの入力スキーマ; ComposioはここにPydantic BaseModelが必要です。
class CompleteRecaptchaInput(BaseModel):
target_url: str = Field(
default="https://www.google.com/recaptcha/api2/demo",
description="reCAPTCHA v2デモを含むページのURL",
)
website_key: str = Field(
default="6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
description="現在のページからのreCAPTCHA v2ウェブサイトキー",
)
# すべてのフローを1つのComposioツールとして登録し、エージェントが呼び出せます。
# 最初のパラメータの型注釈は、Composioがスキーマを推測するために必要です。
@composio.experimental.tool(preload=True)
def complete_recaptcha_v2(input: CompleteRecaptchaInput, _ctx):
"""Playwrightでページを開き、reCAPTCHA v2を解決し、送信し、検証します。"""
with sync_playwright() as p:
browser = p.chromium.launch(headless=False) # ウィンドウを非表示にするにはheadless=Trueに設定してください。
page = browser.new_page()
try:
page.goto(input.target_url)
# CapSolverにreCAPTCHA v2チャレンジを解決させます。
solution = capsolver.solve(
{
"type": "ReCaptchaV2TaskProxyLess",
"websiteURL": input.target_url,
"websiteKey": input.website_key,
}
)
token = solution.get("gRecaptchaResponse")
page.evaluate(
"""
(token) => {
const textarea = document.getElementById('g-recaptcha-response');
if (textarea) {
textarea.value = token;
}
}
""",
token,
)
page.click("#recaptcha-demo-submit")
page.wait_for_load_state("networkidle")
result_page = page.content()
# ページが実際に成功テキストを表示している場合のみ成功
accepted = "Verification Success" in result_page
return {
"accepted": accepted,
"message": (
"Verification Success"
if accepted
else "ページはVerification Successを報告していません"
),
}
finally:
browser.close()
def main():
experimental: ToolRouterExperimentalConfig = {
"custom_tools": cast(List[CustomTool], [complete_recaptcha_v2]),
}
session = composio.sessions.create(
user_id="playwright-recaptcha-demo-user",
experimental=experimental,
sandbox={"enable": False}, # サンドボックスではなくこのプロセスでツールを実行します。
)
agent = Agent(
name="Playwright reCAPTCHAアシスタント",
instructions=(
"ユーザーがデモを実行するよう要求した場合、complete_recaptcha_v2をデフォルト値で呼び出してください。acceptedがtrueのときのみ成功と報告してください。"
),
model="gpt-5.2",
tools=session.tools(),
)
# マルチターン会話用メモリ
memory = SQLiteSession("conversation")
print("Composio + Playwright reCAPTCHA v2デモを実行中...")
user_input = (
"現在、complete_recaptcha_v2をデフォルトのtarget_urlとwebsite_keyで呼び出してください。確認は不要です。"
)
result = Runner.run_sync(
starting_agent=agent,
input=user_input,
session=memory,
)
print(f"アシスタント: {result.final_output}\n")
if __name__ == "__main__":
main()
同じパターンは標準的な画像テキストCAPTCHAを処理できます。2つ目のComposioツールとして登録します。この例では、BotDetect CAPTCHAデモを使用します。画像要素は#demoCaptcha_CaptchaImage、入力は#captchaCode、検証ボタンは#validateCaptchaButtonです。

ImageToTextTaskリクエストは、bodyを介してBase64画像を送信します。トークンベースのタスクとは異なり、このタスクは直接認識されたテキストを返し、別途ポーリングループは必要ありません。
image_src = page.locator("#demoCaptcha_CaptchaImage").get_attribute("src")
if not image_src or "," not in image_src:
raise RuntimeError("有効なCAPTCHA画像のData URLが見つかりませんでした")
base64_image = image_src.split(",", 1)[1] # "data:image/...;base64,"プレフィックスを削除します。
class CompleteImageCaptchaInput(BaseModel):
target_url: str = Field(
default="https://captcha.com/demos/features/captcha-demo.aspx",
description="画像CAPTCHAデモページのURL",
)
module: str = Field(
default="common",
description="CapSolver ImageToTextTask認識モジュール",
)
@composio.experimental.tool(preload=True)
def complete_image_captcha(input: CompleteImageCaptchaInput, _ctx):
"""Playwrightでページを開き、画像CAPTCHAを認識し、送信し、検証します。"""
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
try:
page.goto(input.target_url)
page.wait_for_selector("#demoCaptcha_CaptchaImage", state="visible")
# 画像のsrcはすでにデータURL; プレフィックスを削除してBase64を取得します。
image_src = page.locator("#demoCaptcha_CaptchaImage").get_attribute("src")
if not image_src or "," not in image_src:
raise RuntimeError("有効なCAPTCHA画像のData URLが見つかりませんでした")
base64_image = image_src.split(",", 1)[1]
solution = capsolver.solve(
{
"type": "ImageToTextTask",
"websiteURL": input.target_url,
"module": input.module,
"body": base64_image,
}
)
captcha_text = solution.get("text")
if not isinstance(captcha_text, str) or not captcha_text:
raise RuntimeError("CapSolverは認識されたテキストを返しませんでした")
page.fill("#captchaCode", captcha_text) # 認識されたテキストを入力します。
page.click("#validateCaptchaButton")
page.wait_for_load_state("networkidle")
result_page = page.content()
# デモページは成功時に"Correct!"、失敗時に"Incorrect!"を表示します。
accepted = "Correct!" in result_page
return {
"accepted": accepted,
"recognized_text": captcha_text,
"message": "Correct!" if accepted else "ページはCorrect!を報告していません",
}
finally:
browser.close()
フローの概要:
PlaywrightでCAPTCHAページを開く
-> #demoCaptcha_CaptchaImageが表示されるのを待つ
-> src(データURL)を読み込み、プレフィックスを削除してBase64を取得
-> capsolver.solve(ImageToTextTask)がテキストを返す
-> page.fillが結果を#captchaCodeに書き込む
-> page.clickが#validateCaptchaButtonをアクティブに
-> page.contentがCorrect!またはIncorrect!をチェック
-> finallyでブラウザを閉じる
moduleパラメータはオプションで、デフォルトはcommonです。CAPTCHAに数字のみが含まれる場合、numberを使用してください。特殊なスタイルの場合は、適切なときにドキュメント化された独立モデルを使用してください。

たとえば、数値のみの認識に変更しないで元のソースコードを使用してください:
solution = capsolver.solve({
"type": "ImageToTextTask",
"module": "number",
"images": [base64_image],
})
answers = solution["answers"]
numberモデルは1回の提出で複数の画像をサポートし、imagesには最大9つのBase64文字列が含まれます。サポートされるモデル名と使用ケースは、上記のCapSolver ImageToTextTaskページに記載されています。
experimental.tool: "complete_recaptcha_v2"の最初のパラメータはPydantic BaseModelのサブクラスで注釈付けられている必要があります。取得: <class 'inspect._empty'>
Composioは最初のパラメータの型注釈から入力スキーマを推測するため、input: CompleteRecaptchaInputを省略することはできません。これは関数の注釈であり、オプションの型ヒントではありません。Pydantic BaseModelのリファレンスは、スキーマに使用されるモデルタイプを説明しています。
セッションの作成は、次のエラーを返すことがあります:
403 APIKey_InsufficientPermissions
このルートには「sessions」の書き込みアクセスが必要です
原因は、composio.sessions.create() がセッションのプロジェクトキーの書き込みアクセスを必要としているのに対し、現在のキーには読み取り専用アクセスのみが付与されているためです。キーは有効ですが、そのスコープが不十分なため、401 ではなく 403 が返されます。
解決手順:
sessions: write を持つ新しいキーを作成し、スクリプト上部の COMPOSIO_API_KEY を置き換えます。この統合のコアは、1つのComposioツールとしてパッケージされた完全なビジネスワークフローです:
Composioツール = Playwrightページ操作 + CapSolver結果 + ページ状態の検証
この例を実行する際は、所有しているページや自動化に許可が与えられたプロセスでのみ行ってください。資格情報には環境変数またはシークレットマネージャーを使用し、ページが期待されるビジネス状態に達しない場合は停止し、繰り返し失敗した場合は無限にリトライせず、確認してください。
認可されたComposioエージェントワークフローで、焦点を当てたCAPTCHAインフラストラクチャーレイヤーが必要な場合、独自の制御されたページでCapSolverをテストし、各解決後にアプリケーション結果を確認してください。
この統合でComposioはどの部分を処理していますか?
ComposioはPython関数をエージェント呼び出し可能なカスタムツールとして登録し、セッションを作成し、ツールのスキーマを公開し、OpenAIエージェントからの実行をルーティングします。
最初のツールパラメータがPydantic BaseModelでなければならないのはなぜですか?
Composioはこの注釈を使用してツールの入力スキーマを推論します。これを省略するとスキーマの構築が不可能となり、ブラウザワークフローが開始される前に検証エラーが発生します。
reCAPTCHA v2ツールはCapSolverからトークンが返された後で停止しますか?
いいえ。変更されていないコードはトークンを適用し、デモフォームを送信し、結果のHTMLを読み取り、ページに期待される「Verification Success」テキストが含まれている場合にのみ成功を報告します。
ImageToTextTaskには別途ポーリングループが必要ですか?
いいえ。このワークフローでは、公式SDKが直接認識されたテキストを返します。その後、ツールは入力を埋め込み、ページを送信し、「Correct!」を停止条件として確認します。
このワークフローはどのウェブサイトで使用できますか?
いいえ。法的に、合理的に、責任を持って、ユーザーの許可を得た自動化のみに使用してください。サイトの利用規約、適用可能な法律、レートリミット、データ最小化の要件を尊重してください。
AIエージェントreCAPTCHA v3ソルバーは、チャレンジを生成したアクション、ページ、ブラウザセッション、認証コンテキストを保持している場合にのみ信頼できます。CapSolverは、Core SDK、エージェントツール、MCPを通じてドキュメント化されたCAPTCHAインフラストラクチャーレイヤーを提供します。エージェントは依然としてポリシー、リトライ、および元のタスクの確認を保有しています。このガイドでは、Enterpriseを含むreCAPTCHA v3の運用統合について説明し、返されたトークンを最終的な成功とみなさずに説明します。

AIエージェントのCAPTCHAが動作しない報告が届いた場合、そのフレーズにはいくつかの異なる障害が隠れています。検出が間違っている可能性がある、エージェントが利用できないツールにルーティングしている可能性がある、ブラウザが結果が返ってくる前にナビゲートしている可能性がある、またはアプリケーションが技術的に生成された結果を拒否している可能性があります。CapSolverは文書化されたCAPTCHAインフラストラクチャを提供していますが、あなたのオーケストレーターは証拠を保持し、正しい復元ブランチを選択する必要があります。このガイドは曖昧なインシデントを階層化します。
