Skip to main content

フックが存在する理由

システムプロンプトの指示は提案です。十分に頑固または混乱したLLMはそれらを無視できます。ほとんどの智能体の動作では、それはまさにあなたが望むことです — 指示はモデルに適応する余地を与えます。 しかし、いくつかの要件は提案ではありません。「すべての機密ツール呼び出しはログに記録される必要があります」「書き込み操作は、組織が読み取り専用モードの場合はブロックされます」「¥50k以上の支払いは実行前に人間の確認が必要です」。これらは不変条件 — モデルがどのターンで何を決定しようとも成立する必要があるシステムについての事実です。 フックは、智能体の実行ライフサイクルの明確に定義されたポイントでLLMループの外で実行されるコードです。LLMはフックを見ることができません。LLMはフックに異議を唱えることができません。LLMはフックにステップをスキップするよう説得することはできません。PreToolUseフックがallow=Falseを返した場合、ツール呼び出しは発生しません — 推理トレースがどれほど執拗であっても関係ありません。 これが重要なアーキテクチャ上の区別です: フックは、FIM Oneが「智能体は…することになっている」を「智能体は…をバイパスできない」に変える方法です。

フックが接続される場所

現在、3つのフックポイントが定義されています。各ポイントは、智能体が1つのループ反復中に越える境界をマークします: 同じポイントの複数のフックは優先度順に実行されます。前のPreToolUseフックで書き直された引数は後続のフックに引き継がれるため、ミドルウェアが構成されます。

フックと命令のどちらを使うか

要件をプロンプト命令またはフックで解決するかの判断は、「実行時アサーション対コードコメント」と同じ計算です: 経験則:間違った動作がインシデントの場合はフックを使用します。間違った動作が軽微な不便の場合は、命令で問題ありません。

フックコントラクト

フックは PreToolUseHookPostToolUseHook、または SessionStartHook のサブクラスで、1つの必須メソッドを持ちます:
渡される HookContexttool_nametool_argsagent_iduser_id、およびエンジンがリクエストごとの事実(org id、conversation id、コネクタアクションの requires_confirmation フラグなど)を入力する柔軟な metadata 辞書を含みます。 返される HookResult は結果を制御します:
  • allow: bool = True — ツール呼び出しが進行するかどうか(PostToolUse / SessionStart では無視されます)
  • error: str | None — 人間が読める理由で、ブロックされた場合は観測値として LLM に表示されます
  • modified_args: dict | None — 設定されている場合、実行前にツール引数を置き換えます
  • modified_result: Any | None — 設定されている場合(PostToolUse)、LLM に返される前に観測値を置き換えます
  • side_effects: list[str] — フックが実行した内容の監査証跡で、エージェントのトレースにマージされます

ケーススタディ: FeishuGateHook

このシステムの上に構築された最初のフックは FeishuGateHook です。これは PreToolUse フックで、requires_confirmation=True とフラグ付けされたツールを、組織の Feishu グループに投稿されるヒューマン・イン・ザ・ループ承認カードに変換します。 このフックは完全なライフサイクルを実行します: このデザインがもたらすもの:
  • ツール呼び出しは本当に一時停止します。 エージェントの SSE ストリームは「oa__purchase_pay を呼び出します」と観察の間で一時停止します。ユーザーはエージェントが待機しているのを見ます。これは内部で起きていることと一致します。
  • 承認はプロセス再起動後も保持されます。 保留中の行はデータベースにあり、メモリにはありません。カードが未処理の状態でバックエンドが再起動した場合、次のポーリングは中断したところから再開します。
  • 決定は監査されます。 ConfirmationRequestpayloadresponded_atresponded_by_open_id、および最終ステータスを保持します。誰が何をいつ承認したかの監査可能な記録です。
  • 決定ループに LLM はありません。 モデルはツール呼び出しを生成します。人間は判定を生成します。フックは決定論的なブリッジです。
FeishuGateHook は設定済みの Feishu Channel に依存します。フックはチャネルの send_interactive_card() メソッドを通じてカードを送信し、チャネルが解析したコールバックイベントをリッスンします。この分離は意図的です。フックは「承認ステートマシン」を所有し、チャネルは「IM プラットフォーム機構」を所有します。同じフックは、ロジックを変更することなく、明日 Slack または WeCom をターゲットにすることができます。チャネル実装のみを変更します。

計画中のフック (v0.9)

v0.9 ロードマップには 4 つのフックパターンがあり、すべて同じライフサイクルを再利用します: ユーザー定義フックレイヤーも計画中です: エージェントごとの YAML 設定 (hooks: [...]) で、マッチングツールイベントで実行するシェルコマンドまたは Python 呼び出し可能オブジェクトを宣言します。これは最新のエージェントフレームワーク (Claude Code、OpenDevin) が収束したパターンに従います — フックベースの強制により、「必ず実行される」ロジックをプロンプトから除外します。

Hooks vs. Channels

The two abstractions solve orthogonal problems: Hooks は Channels を消費します — 外部世界と通信する必要があるフック(カードを送信、アラートを投稿、グループにエスカレート)は、組織の Channel を呼び出します。フックが使用していない Channel でも有用です(例:智能体がツール経由で主動的に通知を送信できます)が、承認ゲートパターンは両方が揃っていることが必要です。 別の言い方をすると:Channels は「人間と通信する場所」のプラミング、Hooks は「人間と通信する必要がある時」のポリシーです。本番環境の人間参加型ワークフローには両方が必要です。

Current state (v0.8.4)

Snapshot of what shipped and what is still ahead:
  • HookRegistryHookContextHookResult プリミティブが ReAct と DAG の両方に統合
  • PreToolUseHook / PostToolUseHook / SessionStartHook 抽象基底クラス
  • FeishuGateHook — 完全実装。ConfirmationRequest テーブル、ポーリングループ、タイムアウト/有効期限、コールバック駆動の状態遷移を含む
  • ✅ Feishu チャネルコールバックエンドポイント。card.action.trigger をデコードして保留中の行を更新
  • ✅ エージェントレベルのフック宣言:agent.model_config_json.hooks.class_hooks が ReAct/DAG セッションごとにインスタンス化された HookRegistry に解決
  • すべての実行サーフェスでフックが発火:メインチャットパス(Portal、API、DAG)、委譲されたサブエージェント(CallAgentTool)、Workflow AGENT ノード。Eval Center は意図的にフックをバイパス(自動評価は人間の承認でブロックされてはいけない)。 委譲されたエージェントは呼び出し元のレジストリを継承しない——自身の model_config_json から独自のレジストリを構築する。確認ゲートはすべてのエージェントに自動的に付加されるため、再構築は継承のスーパーセット:委譲先はゲートプラス自身が宣言したもの を取得し、ゲートは呼び出し元の require_confirmation_for_all ではなく委譲先の require_confirmation_for_all を解決する。両方のサーフェスは安全側で失敗:フックを構築できないエージェントは実行されない。
  • AuditLogHookReadOnlyGuardResultTruncateHookConnectorRateLimitHook(v0.9)
  • ❌ ユーザー定義 YAML フック宣言(v0.9)
Hook System は v0.9 本番環境対応の基盤となるシステム。その最初のユーザー(FeishuGateHook)も本番機能そのもの。そのため、フック全体カタログを待つのではなく、2026-04-24 路演のために早期にスケルトンをリリースした。