mcpField
I
integrate-arcjet-guard-openai-agents-py

integrate-arcjet-guard-openai-agents-py

github.com/arcjetセキュリティ4107 回インストール3 週間前に更新
リポジトリ

integrate-arcjet-guard-openai-agents-py について

公式 OpenAI Agents SDK の独自 FunctionTool に Arcjet Guard を適用する Python スキルです。ツールのコピーに入力ガードレールを加え、呼び出し側が管理する相関 ID を読み取ります。ホスト型ツールや MCP などは対象外です。

主な機能

  1. 01独自の FunctionTool を保護
  2. 02ツール入力ガードレールで拒否を処理
  3. 03呼び出し側管理の相関 ID を読み取り
  4. 04Guard ルールとツールのレート制限に対応

活用シーン

  1. 01リスクのある独自 FunctionTool の呼び出しを遮断
  2. 02Guard の判定をセッション ID に関連付け
  3. 03ツール呼び出しに制限を適用

MCP 対応

MCP ツールはこの統合の対象外です。MCP サーバーや MCP クライアントの機能も説明していません。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/arcjet/skills --skill integrate-arcjet-guard-openai-agents-py

インストール後、Claude Code で/integrate-arcjet-guard-openai-agents-pyを入力して読み込まれたか確認します。

詳細

Python OpenAI Agents に Arcjet Guard を統合する

arcjet.guard.openai_agents は、エージェントが既存の Arcjet クライアントをラップします。Arcjet API と直接通信することはありません。Guard の共通の基礎(クライアント、ルール、ラベル、判定、キャプチャ、登録)については、 ../arcjet/references/guards_python.md を参照してください。OpenAI Agents 固有ではない内容については、このリファレンスを読み込んでください。

公式の openai-agents>=0.19.0,<1 のみが対象です。JS の @openai/agents アダプター(@arcjet/guard/openai-agents/v0、ドキュメント https://docs.arcjet.com/guards/openai-agents/)や、コミュニティ製フォークは対象外です。 arcjet.guard.openai_agents をインポートしても LangChain は読み込まれません。

エクスポート:guard_tool、openai_agents_context。作成者が定義した FunctionTool / @function_tool のみが対象です。ホスト型ツール、MCP、Computer / Shell / ApplyPatch、ハンドオフ、Agent.as_tool() は対象外です。

2 つのインターフェースで、判定ルールは 1 つです。

  • 作成者が定義した FunctionTool → guard_tool。ゲートには FunctionTool.tool_input_guardrails + reject_content(ArcjetDenialResult の JSON)を使います。例外を発生させないでください。
  • 相関付け → openai_agents_context は呼び出し側が所有するセッション / 会話 ID を読み取ります。ID を新たに生成することはありません。trace_id は読み取りません。

ドキュメント:https://docs.arcjet.com/guards/openai-agents/。

ゲートには tool_input_guardrails + reject_content を使います

guard_tool はコピーを返し、入力ガードレールの先頭に Arcjet を配置します。そのため、DENY(またはデフォルトの on_guard_error="deny" による未評価の Guard)の場合、on_invoke_tool は実行されません。拒否は ToolGuardrailFunctionOutput.reject_content に ArcjetDenialResult の JSON({ arcjetDenied: true, … })を設定して表します。例外を発生させないでください。 raise_exception() はトリップワイヤーによる停止であり、on_invoke_tool で発生した例外は default_tool_error_function によって握りつぶされます。#196 と同じフェイルクローズのデフォルトです。 "allow" の場合に限りフェイルオープンし、DENY は常にブロックします。コアの guard() は引き続きフェイルオープンします(has_failed_open())。

needs_approval はポリシーゲートではありません

needs_approval はヒューマン・イン・ザ・ループの仕組みです(state.approve / state.reject)。 JS OpenAI Agents の needsApproval、LangGraph の interrupt()、Genkit の interrupt() と同じ落とし穴があります。インバウンド用ヘルパーも承認用ヘルパーもありません。 RunConfig.tool_execution.pre_approval_tool_input_guardrails=True はアプリケーション側で明示的に有効にするものです。このヘルパーでは設定しません。

Runner.run の前にインバウンドをスクリーニングする

インバウンド用のヘルパーはありません。SDK の input_guardrails / output_guardrails / ツール出力ガードレールは SDK 独自のトリップワイヤーであり、Arcjet のものではありません。アプリケーションで aj.guard(...) を呼び出し、判定に応じて処理してください。コアの guard() はフェイルオープンします。ALLOW はルールが実行された証明にはなりません。この呼び出し箇所でフェイルクローズが必要な場合は、decision.has_failed_open() を条件にしてください。 guard_tool はすでにデフォルトでそのように動作します。

まず人に確認する質問

コードから推測できないことだけを質問し、デフォルトも提案してください。

  1. どのツールがリスクを伴いますか(外部への副作用、取り消し不能、費用の発生、メッセージの送信など)?対象のツールには guard_tool を使います。ホスト型 / MCP / ハンドオフ / as_tool は対象外です。
  2. どのような制限が必要ですか?(例:「ユーザーごとに 1 分あたり 10 回の検索」→ TokenBucket。)
  3. メタデータに使うユーザーは誰ですか。不透明なユーザー / テナント ID(PII は使用しません)ですか? デフォルト:なし。すでに持っている会話 / セッション ID を、Runner.run に渡すアプリケーションコンテキストに設定してください。その ID は相関 ID であり、ユーザーではありません。
  4. Arcjet の障害は許容できませんか?すべてのヘルパーはデフォルトで on_guard_error="deny" です。Runner.run 前のインバウンドスクリーニングについては、明示的に確認してください。そこでフェイルクローズにするとエージェントが実行されなくなるため、その呼び出し箇所に限って "allow" を選ぶことは一般的で、妥当な選択です。

読者が誤解しやすい点

  1. これは JS アダプターではありません。 @arcjet/guard/openai-agents/v0 をインポートしないでください。
  2. 受信リクエスト用のヘルパーはありません。 SDK のガードレールは Arcjet ではありません。Runner.run の前にコアの guard() でスクリーニングしてください。
  3. needs_approval は HITL であり、ポリシーではありません。
  4. 拒否されるのは reject_content のみです。 例外を発生させるとトリップワイヤーによる停止になるか、default_tool_error_function によって握りつぶされます。
  5. 相関 ID は読み取るだけで、生成しません。 trace_id は使わないでください。OpenAIConversationsSession() を構築しないでください。
  6. レート制限はモデルが指定した注文 ID ではなく、認証済みの呼び出し元をキーにしてください。 guard_tool が返すコピーをエージェントに渡してください。元のツールはガードされないままです。
  7. すべてのツールを生の guard() で個別にラップしないでください。
  8. inputs= は受け付けられます。 判定がないことは拒否を意味しません。Console/CLI で確認してください。

ステップ 1:ガードクライアントをインストールして取得する

このモジュールは PyPI の arcjet 1.0.0 に含まれています。

pip install "arcjet[openai-agents]"

エージェントにガードクライアントがまだない場合は、モジュールスコープで 一度だけ 起動してください。

import os
from arcjet.guard import launch_arcjet

aj = launch_arcjet(key=os.environ["ARCJET_KEY"])

ステップ 2:作成したツールをゲートする — guard_tool

from agents import Agent, Runner, function_tool
from arcjet.guard import DetectPromptInjection, TokenBucket, launch_arcjet
from arcjet.guard.openai_agents import guard_tool, openai_agents_context

aj = launch_arcjet(key=os.environ["ARCJET_KEY"])
lookup_limit = TokenBucket(
    label="order.looked-up",
    bucket="lookups",
    refill_rate=10,
    interval_seconds=60,
    max_tokens=10,
)
user_id = authenticated_user_id

@function_tool  # needs_approval=... is HITL — not this policy gate
def lookup_order(order_number: str) -> dict:
    """Look up an order by number."""
    return {"order_number": order_number, "status": "shipped"}

lookup_order = guard_tool(
    guard=aj,
    tool=lookup_order,
    action="order.looked-up",
    rules=[lookup_limit(key=user_id, requested=1)],
    on_guard_error="deny",
)

agent = Agent(
    name="support-agent",
    instructions="Help the user.",
    tools=[lookup_order],
)

guard_tool では action と rules を使用してください。

ステップ 3:Runner.run の前に受信リクエストをスクリーニングする

inbound = DetectPromptInjection()
app_context = {"session_id": conversation_id}
derived = openai_agents_context(app_context)
decision = await aj.guard(
    label="message.received",
    rules=[inbound(user_text)],
    correlation_id=derived.correlation_id,
)
if decision.conclusion == "DENY":
    raise Exception("message blocked")
if decision.has_failed_open():
    raise Exception("inbound guard unavailable")

await Runner.run(agent, user_text, context=app_context)

受信リクエスト用のヘルパーはありません。

ステップ 4:相関

openai_agents_context は、呼び出し元が所有する ID を読み取ります。優先順位は、runContext.context/アプリオブジェクトそのものにあるフィールド(correlation_id、次に session_id、次に conversation_id、次に group_id。スネークケースまたはキャメルケース)、次にエンベロープ上の同じ名前、次に correlation_id=/session_id= キーワード引数、最後に外側の arcjet_sequence です。OpenAIAgentsContext を返すため、.correlation_id を guard() に渡してください。ID を生成することはありません。trace_id を読み取ることもありません。OpenAIConversationsSession() を構築することもありません。ターンごとに相関 ID を新たに作らないでください。

統合を検証する

  1. python -m py_compile(またはプロジェクトの型チェック)が成功することを確認します。
  2. 受信 PI(Runner.run の前)、ツールの拒否(例外ではなく reject_content)、レート制限、フェイルクローズ(到達不能なガード)をテストします。needs_approval がゲートとして扱われないことを確認します。
  3. Arcjet Console/CLI で、判定が trace_id ではなく、呼び出し元が所有するセッション ID/会話 ID を共有していることを確認します。
  4. 実際の ARCJET_KEY を使用した手動 E2E は、実行するまで未検証です。

例の fastapi-openai-agents-guard は Runtime に置いたままにしてください。新しい例の名前を考案しないでください。この skills リポジトリに例を追加しないでください。

コメント