【調査レポ8】Google Antigravity SDKでAIの暴走を防ぐ!ライフサイクルフック(Hooks)によるセキュリティ監査とログ記録を解説

Antigravity SDK入門 AI

前回の調査レポ7では、skills_pathsSKILL.md を活用してAIエージェントに専門知識や指示書を動的ロードさせるモジュール化テクニックを検証しました。

今回は、Google Antigravity SDKの高度な運用機能である「ライフサイクルフック(Hooks)」について調べた内容をお届けします!

AIエージェントにWeb検索やファイル操作、コマンド実行などの「道具(ツール)」を持たせる際、プロンプト(指示文)だけで「危険な操作をしないでください」と伝えるのは限界があります。誤った指示や悪意ある入力によってAIが意図しない処理を実行してしまうリスクを防ぐためには、プログラムレベルでの検証・割り込み処理が必要です。Google Antigravity SDKのフック機能を活用することで、ツール実行の前後にカスタム処理を挿入し、安全なセキュリティ検疫やロギングを実現できます。

ライフサイクルフック(Hooks)の役割とセキュリティ効果

ライフサイクルフックとは、AIエージェントが思考・動作する特定のタイミング(起動時、ツール実行の直前・直後、エラー発生時など)に、開発者が定義したPython関数を自動的に割り込ませる仕組みです。主なフック機能として「Pre-hook(実行前フック)」と「Post-hook(実行後フック)」が用意されています。

  • ツール実行前フック(Pre-hook)による入力検疫
    AIがツールを呼び出そうとした直前に介入し、渡された引数をチェックします。不正なキーワードが検知された場合、types.HookResult(allow=False) を返却することでツールの実行を安全にブロック(中断)します。
  • ツール実行後フック(Post-hook)による監査ロギング
    ツール実行が完了した直後に自動的に呼び出され、実行日時や渡された引数、ツールの実行結果をログファイルへ記録します。万が一のトラブル時にもトレーサビリティを確実に確保できます。

検証用Pythonサンプルコード(hooks_demo.py)

ツール実行前の検疫を行う Pre-hook と、実行完了後の結果を自動ロギングする Post-hook の両方を組み込んだサンプルプログラムを作成しました。

import os
import sys
import asyncio
import datetime

# 1. 安全対策:python-dotenv ライブラリの検出と環境変数の読み込み
try:
    from dotenv import load_dotenv
    load_dotenv()
except ImportError:
    print("注意: python-dotenv がインストールされていません。環境変数から直接APIキーを読み込みます。")

# 2. Google Antigravity SDK のインポート
try:
    from google.antigravity import Agent, LocalAgentConfig, types
    from google.antigravity.hooks import pre_tool_call_decide, post_tool_call
except ImportError:
    print("エラー: google.antigravity パッケージが見つかりません。pip install google-antigravity で導入してください。", file=sys.stderr)
    sys.exit(1)

# 3. ツール(システム操作ツール)の定義
def execute_system_command(command: str) -> str:
    """指定されたシステムコマンドを実行して結果を返すツール。

    Args:
        command (str): 実行するコマンド文字列 (例: 'ls -l', 'date')

    Returns:
        str: 実行結果メッセージ
    """
    return f"【実行成功】コマンド '{command}' を正常に処理しました。"

# 4. ライフサイクルフック(Pre-hook / Post-hook)の定義

# 【Pre-hook】ツール実行前フック:セキュリティ検疫とブロック
@pre_tool_call_decide
async def pre_tool_execution_hook(data):
    """ツール実行前に割り込み、引数をチェックして危険なコマンドをブロックするフック。"""
    print(f"\n[Pre-hook] ツール '{data.name}' の実行前検疫を行っています... (引数: {data.args})")
    
    command = str(data.args.get("command", ""))
    # 不正なキーワードのチェック
    dangerous_keywords = ["danger_cmd", "forbidden_op"]
    for kw in dangerous_keywords:
        if kw in command.lower():
            print(f"[Pre-hook Alert] 不正なキーワード '{kw}' が検知されました!実行をブロックします。")
            return types.HookResult(allow=False, message="不正なコマンドのためブロックされました。")
            
    print(f"[Pre-hook] 検疫クリア: 安全なコマンドです。")
    return types.HookResult(allow=True)

# 【Post-hook】ツール実行後フック:監査ロギングと実行結果のトレース
@post_tool_call
async def post_tool_execution_hook(data):
    """ツール実行完了直後に割り込み、実行結果やタイムスタンプをログ記録するフック。"""
    now_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(f"\n[Post-hook Log] タイムスタンプ: {now_str} | ツール '{data.name}' の実行完了を記録しました。")

# 5. メイン処理
async def main():
    api_key = os.environ.get("GEMINI_API_KEY")
    if not api_key:
        print("エラー: GEMINI_API_KEY が設定されていません。.env ファイルを確認してください。", file=sys.stderr)
        return

    print("--- ライフサイクルフック(Pre-hook & Post-hook)の動作検証デモを開始します ---\n")

    # LocalAgentConfig の hooks パラメータに Pre-hook と Post-hook をリスト形式で登録
    config = LocalAgentConfig(
        system_instructions=(
            "あなたはシステム管理AIアシスタントです。"
            "ユーザーからの指示に応じて execute_system_command ツールを呼び出してコマンドを実行してください。"
        ),
        tools=[execute_system_command],
        model="gemini-3.1-flash-lite",
        hooks=[pre_tool_execution_hook, post_tool_execution_hook]
    )

    user_query = "システムの現在の状態を確認したいので、'date' コマンドを実行してください。"
    print(f"ユーザーの質問: {user_query}\n")

    async with Agent(config) as agent:
        response = await agent.chat(user_query)
        result_text = await response.text()
        print(f"\n--- [AIエージェントの最終回答] ---\n{result_text}\n")

if __name__ == "__main__":
    asyncio.run(main())

プログラムコードの詳細解説

今回作成したフック検証プログラムの仕組みについて解説します。

  • 1. インポートと安全対策(dotenv)
    from google.antigravity import Agent, LocalAgentConfig, types およびフック用デコレータ from google.antigravity.hooks import pre_tool_call_decide, post_tool_call をインポートします。dotenvload_dotenv() を `try-except` で囲むことで、ライブラリ未検出時でも安全に環境変数を参照できるよう配慮しています。
  • 2. 【重要】デコレータ(@記号)の仕組みとSDKで事前定義されている主なフック一覧
    関数の直前に記述している @pre_tool_call_decide@post_tool_call は、Pythonの「デコレータ」と呼ばれる特殊な記法です。関数のコードを直接書き換えることなく、前後に共通処理を付け足す仕組みであり、これらは google.antigravity.hooks モジュール内で事前定義されています。
    インポートして関数に付けるだけで、SDKがイベントのタイミングを自動判定して割り込み処理を実行します。SDKで事前定義されている主なフックデコレータは以下の通りです。
    • @pre_tool_call_decide:ツール実行直前に割り込み、実行の許可(allow=True)または拒否(allow=False)を判定するデコレータ
    • @post_tool_call:ツール実行完了直後に割り込み、実行結果やタイムスタンプをログ保存するデコレータ
    • @on_tool_error:ツール実行中にエラーが発生した際に自動的に割り込み処理を行うデコレータ
    • @pre_turn / @post_turn:AIとの対話(1ターン)の開始直前や終了直後に処理を挿入するデコレータ
    • @on_session_start / @on_session_end:会話セッションの開始時や終了時に自動動作するデコレータ
  • 3. ツール定義とDocstring・型ヒントの仕様
    AIがツールを正しく選択・引数生成できるように、関数宣言時に型ヒント(command: str)と詳細なドキュメント文字列(Docstring)を記述しています。関数の説明文(Docstring)がAIへの取扱説明書として読み取られ、型ヒントが入力ルールとして送信されるというSDK独自の重要な仕様を意識することが大切です。
  • 4. Pre-hook(実行前フック)のデコレータと判定型(types.HookResult)
    @pre_tool_call_decide デコレータを非同期関数(async def)に付与して定義します。引数 data.args から command = str(data.args.get("command", "")) という記述で安全にコマンド文字列を取り出します。キーが存在しない場合の KeyError を防ぐデフォルト値指定("")と、型エラーを防ぐ str() による型変換を行うことで、プログラムを停止させずに検疫チェックを行う配慮です。ブラックリストが含まれていないか走査し、実行を許可する場合は types.HookResult(allow=True) を返し、不正検知時は types.HookResult(allow=False, message=...) を返却することで、SDKはツールの呼び出しを自動キャンセルして安全にブロック処理を行います。
  • 5. Post-hook(実行後フック)のデコレータとロギング処理
    @post_tool_call デコレータを非同期関数に付与して定義します。ツール実行が正常に終了した直後にSDKから自動呼び出しされ、引数 data からツール名や実行結果の情報を受け取ります。ここでタイムスタンプとともにログを出力することで、AIがどのようなツールをどう実行したかを後からトレースできます。
  • 6. LocalAgentConfig の hooks パラメータへの登録
    LocalAgentConfighooks=[pre_tool_execution_hook, post_tool_execution_hook] というリスト形式で作成したフック関数を指定します。これにより、ツール呼び出しの「直前」と「直後」の両方に割り込み処理が組み込まれます。

プログラムの実行手順と動作確認

実際に手元の環境でプログラムを動かす手順と、検疫および監査ログの確認ステップです。
仮想環境等の詳細については過去の環境構築編をご参照ください。

手順1. パッケージ準備とAPIキー設定

# 仮想環境の有効化
source .venv/bin/activate

# パッケージのインストール
pip install google-antigravity python-dotenv

# APIキーの設定 (.env ファイルを作成)
echo 'GEMINI_API_KEY="YOUR_GEMINI_API_KEY_HERE"' > .env

手順2. 正常コマンド実行の検証

python3 hooks_demo.py

実行時の出力ログ例:

--- ライフサイクルフック(Pre-hook & Post-hook)の動作検証デモを開始します ---

ユーザーの質問: システムの現在の状態を確認したいので、'date' コマンドを実行してください。


[Pre-hook] ツール 'execute_system_command' の実行前検疫を行っています... (引数: {'command': 'date'})
[Pre-hook] 検疫クリア: 安全なコマンドです。

[Post-hook Log] タイムスタンプ: 2026-08-21 07:42:00 | ツール 'execute_system_command' の実行完了を記録しました。

--- [AIエージェントの最終回答] ---
【実行成功】コマンド 'date' を正常に処理しました。

Pre-hook による事前検疫をクリアした後にツールが実行され、さらに実行完了直後に Post-hook によってタイムスタンプと実行結果ログが記録されていることが確認できます!

開発上の注意点と落とし穴

フック機能を本番運用する際、気をつけるべき「2つの注意点」をまとめました。

① フック関数内での同期ブロッキングによる遅延の注意点

フック関数内で重い外部ネットワーク通信や時間のかかるファイル処理を同期的に実行してしまうと、AIエージェント全体のレスポンス速度が著しく低下します。Post-hook でログをファイルやDBに外部保存する際は、できる限り処理を軽量に保ち、非同期処理や高速なバッファリングを活用することを推奨します。

② 例外処理(try-except)の記述漏れリスク

フック関数内部で未捕捉の例外(KeyError や AttributeError など)が発生した場合、フック処理が中断されるだけでなくエージェント全体のプログラムが停止してしまう落とし穴があります。特に Post-hook 内のログ整形時などでエラーが発生してもエージェントの動作を止めないよう、必ず `try-except` ブロックを配置する設計を推奨します。

まとめ

今回は、Google Antigravity SDKの「ライフサイクルフック(Pre-hook / Post-hook)」機能を使い、ツール実行前のセキュリティ検疫と実行後の監査ロギングを行う実践プログラムを検証しました。

プロンプトでの指示だけに頼るのではなく、Pre-hook と Post-hook を組み合わせたコードレベルのガードレールを設けることで、より安全で信頼性の高いAIエージェントシステムを構築できます。次回は、バックグラウンドでの定期自動化の検証を進めていきますので、ぜひご期待ください!

コメント

タイトルとURLをコピーしました