powered by TechFeed
表示モード
主要ニュース

OpenAI CodexのAIループに自分のコードを割り込ませる「フック」機能 — プロンプトだけでは無理だった品質チェックや条件分岐が実現可能に

8月25日、Towards Data Scienceが「Put Your Own Logic Inside the Codex Agentic Loop」と題した記事を公開した。AIエージェントの非決定的な動作に、確定的なロジックを「外側から差し込む」——そんな発想から生まれたのが、OpenAI Codexの「フック(hooks)」機能だ。プロンプトをいくら工夫しても制御しきれなかった「品質チェック」「ツール呼び出し前の検査」「条件付き再試行」が、自作スクリプトをAgentic Loopに組み込むことで実現できる。

8月25日、Towards Data Scienceが「Put Your Own Logic Inside the Codex Agentic Loop」と題した記事を公開した。AIエージェントの非決定的な動作に、確定的なロジックを「外側から差し込む」——そんな発想から生まれたのが、OpenAI Codexの「フック(hooks)」機能だ。プロンプトをいくら工夫しても制御しきれなかった「品質チェック」「ツール呼び出し前の検査」「条件付き再試行」が、自作スクリプトをAgentic Loopに組み込むことで実現できる。


プロンプトだけでは制御できない問題

OpenAI Codexはプロンプトを通じて動作を制御できるが、それだけでは不十分な場面がある。例えば「エージェントが結果を返す前に品質チェックを挟みたい」「ツール呼び出しの前に内容を検査したい」といった要件は、プロンプトエンジニアリングだけでは実現しにくい。プロンプトは「お願い」にすぎず、エージェントが必ずその通りに振る舞う保証はないからだ。

これを解決するのが Codexフック(hooks) だ。フックはCodexのAgentic Loopが発行するライフサイクルイベントに自作スクリプトを紐づける仕組みで、OpenAI公式のCodexドキュメントでも拡張ポイントとして位置づけられている。


フックの仕組み:ライフサイクルのどこに割り込むか

Codexがタスクを処理する際、内部では「Agenticループ」が回る。このループは以下のライフサイクルイベントを順に発行する。

イベント タイミング
SessionStart セッション開始時
PreToolUse ツール呼び出し直前
PostToolUse ツール呼び出し完了後
Stop Codexが応答を終了しようとする直前
SessionEnd セッション終了時

フックはこれらのイベントに自作スクリプトを紐づける仕組みだ。フック設定に必要な要素は3つだけ。

  1. event — どのライフサイクルポイントで実行するか
  2. matcher — そのポイントでどの条件のときに実行するか
  3. handler — 実際に何を実行するか

この3点を決めるだけで、AIの動作フローに自分のロジックを組み込める。プロンプトへの追記とは異なり、フックはCodexの応答そのものを「ブロック」したり「通過させる」判定を下せる点が本質的に異なる。


実践:ディープリサーチワークフローに品質ゲートを追加する

記事では、この仕組みをDeep Research(深掘り調査)ワークフローで実演している。Codexに「指定トピックの直近90日間のトレンドを3つ調査し、構造化されたリサーチブリーフを返す」タスクを与え、そこにStopフックで品質チェックを挟む構成だ。

品質チェックの条件

  • 各トレンドにソースが2件以上含まれること
  • ブリーフ全体でユニークなソースが10件以上あること
  • それらのソースが5ドメイン以上にまたがること

条件を満たさない場合、フックはCodexの終了をブロックし、問題点をフィードバックとして返す。Codexはそのまま同一セッション内で調査を継続する。重要なのは、このチェックロジックが完全にPythonで記述された決定論的なコードであり、LLMの「判断」に依存しないという点だ。

バリデーションスクリプト

.codex/hooks/validate_research.pyとして配置するスクリプトの核心部分:

import json
import sys
from urllib.parse import urlparse

MIN_PER_TREND = 2
MIN_SOURCES = 10
MIN_DOMAINS = 5

event = json.load(sys.stdin)
brief = json.loads(event["last_assistant_message"])

errors = []
all_urls = set()

for number, trend in enumerate(brief["trends"], 1):
    urls = set(trend["sources"])
    all_urls.update(urls)
    if len(urls) < MIN_PER_TREND:
        errors.append(f"Trend {number} needs at least {MIN_PER_TREND} sources.")

domains = {urlparse(url).netloc for url in all_urls}

if len(all_urls) < MIN_SOURCES:
    errors.append(f"Add at least {MIN_SOURCES} unique sources.")
if len(domains) < MIN_DOMAINS:
    errors.append(f"Use at least {MIN_DOMAINS} source domains.")

if errors:
    message = "Research brief check failed:\n- " + "\n- ".join(errors)
    result = {"decision": "block", "reason": message}
else:
    result = {}

print(json.dumps(result))

Stopイベントでは、Codexがlast_assistant_messageをスクリプトの標準入力に渡す。スクリプトが{"decision": "block", "reason": "..."}を返すと、Codexは終了せずにフィードバックを受け取って調査を続ける。**blockはセッションを終了させるのではなく、あくまで「今の応答を完了させない」指示**である点が重要だ。条件を満たせば空のオブジェクト{}を返すだけで通過となる。このシンプルな入出力設計により、Pythonに限らず任意のスクリプト言語でハンドラを実装できる。

フック設定ファイル

.codex/hooks.jsonでイベントとハンドラを紐づける:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 .codex/hooks/validate_research.py",
            "commandWindows": "python .codex\\hooks\\validate_research.py"
          }
        ]
      }
    ]
  }
}

なお、現時点ではStopイベントにはmatcherが適用されない仕様のため、matcher設定は省略している。設定ファイル自体は最小限の記述で済むが、commandWindowsキーでWindows環境向けのパスを別途指定できる点は実運用上の配慮として押さえておきたい。

ヘッドレス実行

実際のタスク実行はCLIのexecサブコマンドで行う:

codex --search exec \
  --model gpt-5.6-sol \
  --json \
  --output-schema schemas/research_brief.schema.json \
  -o outputs/research_brief.json \
  - \
  < outputs/research_prompt.md \
  > outputs/run.jsonl

--model gpt-5.6-solは記事執筆時点でのモデル名であり、利用可能なモデルは今後変更される可能性がある。

  • --search でウェブ検索ツールを有効化
  • --output-schema でJSONスキーマを渡し、出力構造を強制
  • --json で実行イベントをJSONL形式で記録(デバッグ用トレースとして活用可能)

--output-schemaによるJSON Schema指定は、フックのバリデーションスクリプトが前提とする出力構造(brief["trends"]など)を保証するうえで欠かせない設定だ。スキーマによる出力の型固定と、フックによる内容検証を組み合わせることで、「構造的に正しく、かつ内容的に十分な」出力を担保する二重の品質管理が成立する。

実行結果

記事著者がデータセンターインフラのトレンドを題材にテストしたところ、初回のCodex出力は7件のソースしか含まれておらず品質チェックで弾かれた。Codexはフィードバックを受けて調査を継続し、最終的に10ドメインから12件のユニークなソースを含むブリーフを生成してチェックを通過した。


どのイベントをどう使うか

記事では最後に、各イベントの使い所を整理している。

  • SessionStart — セッション開始時に追加コンテキストをロード
  • PreToolUse — シェルコマンドなど危険な操作を実行前に検査・ブロック
  • PostToolUse — ツール実行結果を後処理・ログ保存
  • Stop — 今回のように、最終出力の品質を検証して再試行を促す

フックの設計思想はシンプルで、「ライフサイクルのどこで・どんな条件で・何をするか」の3点を決めるだけだ。AIエージェントの非決定的な動作に対して、確定的なロジック(deterministic logic)を外側から差し込むための公式な拡張ポイントとして機能する。プロンプトで「念押し」するアプローチの限界を感じている開発者にとって、実用的な選択肢となり得る機能だ。


詳細はPut Your Own Logic Inside the Codex Agentic Loopを参照していただきたい。