Hyperlight CodeAct

Hyperlight は、エージェント フレームワークの CodeAct の現在文書化されているバックエンドです。 分離サンドボックス ランタイムによってサポートされる execute_code ツールが公開され、 call_tool(...)を介してプロバイダー所有のホスト ツールを呼び出すことができます。

パターン レベルの概要については、「 CodeAct」を参照してください。

Hyperlight CodeAct の理由

最新のエージェントは、多くの場合、モデル自体よりもツール呼び出しのオーバーヘッドによって制限されます。 データを読み取り、軽い計算を実行し、結果をアセンブルするタスクは、個々のステップが単純な場合でも、モデル -> ツール -> model -> ツールの相互作用のチェーンに簡単に変換できます。

ハイパーライトを搭載したCodeActがそのループを短縮します。 モデルは短い Python プログラムを 1 つ書き込み、サンドボックスはそれを 1 回実行し、 call_tool(...)を使用してサンドボックス内からプロバイダー所有のツールにアクセスします。 代表的なツール負荷の高いワークロードでは、そのシフトによって待機時間をほぼ半分に短縮し、トークンの使用量を 60%以上削減しながら、実行を分離して監査可能に保つことができます。

パッケージをインストールする

dotnet add package Microsoft.Agents.AI.Hyperlight --prerelease

Microsoft.Agents.AI.Hyperlightはコア抽象化とは別に提供されるため、サンドボックス ランタイムは必要なときにのみ実行されます。

Important

.NET パッケージはプレビュー段階です。 これはHyperlight.HyperlightSandbox.Api からの NuGet パッケージに依存します。その依存関係が nuget.org に発行されるまで、プロジェクトは復元に失敗します。 アップストリームサンドボックスリポジトリを追跡して可用性を確保します。

Hyperlight には、ホスト上のハードウェア仮想化 (Linux 上の KVM)、または Windows 上の Windows Hypervisor Platform (WHP) が必要です。 Wasm バックエンドには、Hyperlight Python ゲスト モジュールが必要です。実行前に、HYPERLIGHT_PYTHON_GUEST_PATH を絶対パスに設定します。

HyperlightCodeActProvider を使用する

HyperlightCodeActProvider は、実行ごとに CodeAct を自動的に追加する場合に推奨されるエントリ ポイントです。 これは、実行スコープの CodeAct 命令とAIContextProvider ツールを挿入するexecute_codeで、プロバイダー所有のツールを直接エージェント ツールサーフェスから離します。 プロバイダーは、呼び出しごとに既知のクリーン状態からゲストが開始されるように、実行ごとにスナップショット/復元を適用します。

HyperlightCodeActProviderOptions.CreateForWasm(modulePath) ファクトリを使用して、サンプルで使用される Wasm ベースのPython ゲストを対象とします。CreateForJavaScript() は JavaScript バックエンドでも使用できます。

using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Hyperlight;
using OpenAI.Chat;

var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
    ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-5.4-mini";
var guestPath = Environment.GetEnvironmentVariable("HYPERLIGHT_PYTHON_GUEST_PATH")
    ?? throw new InvalidOperationException("HYPERLIGHT_PYTHON_GUEST_PATH is not set.");

using var codeAct = new HyperlightCodeActProvider(
    HyperlightCodeActProviderOptions.CreateForWasm(guestPath));

AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetChatClient(deploymentName)
    .AsAIAgent(new ChatClientAgentOptions()
    {
        ChatOptions = new()
        {
            Instructions = "You are a helpful assistant. When the user asks something quantitative, "
                + "write Python and call `execute_code` instead of guessing.",
        },
        AIContextProviders = [codeAct],
    });

Console.WriteLine(await agent.RunAsync("What is the 20th Fibonacci number?"));

特定のエージェントにアタッチできる HyperlightCodeActProvider は 1 つだけです。 プロバイダーは固定状態キーを使用するため、 ChatClientAgentの状態キーの一意性検証では重複する登録が拒否されます。 HyperlightCodeActProviderIDisposable実装します。 using 宣言を使用して、エージェントが不要になったときに基になるサンドボックスが解放されるようにします。

ツール、ファイル マウント、および送信許可リスト エントリは、 HyperlightCodeActProviderOptions (ToolsFileMountsAllowedDomainsHostInputDirectory) を介して事前に提供することも、プロバイダーの AddTools(...)RemoveTools(...)ClearTools()AddFileMounts(...)AddAllowedDomains(...)、照合 Get* アクセサーを使用して実行時に管理することもできます。

承認とホスト ツールのしくみ

Agent Framework ツールには、自動呼び出しが可能か、ユーザーの承認のために一時停止する必要があるかを制御する承認メタデータが含まれています。 .NETでは、承認は AIFunctionApprovalRequiredAIFunction でラップすることによってオプトインされます。

HyperlightCodeActProviderにツールを登録することとエージェントに直接登録する主な違いは、関数が最終的に実行される場所ではなく、ツールを呼び出す方法です。

  • HyperlightCodeActProviderOptions.Toolsに登録されたツールは、直接ツールとしてモデルに表示されません。 モデルは、call_tool("name", ...)内でexecute_codeを呼び出すコードを記述することによってそれらに到達します。
  • エージェントに直接登録されたツール ( AsAIAgent(tools: [...]) など) は、最上位クラスのツールとしてモデルに表示され、各直接呼び出しでは、そのツールの独自の承認メタデータが優先されます。

call_tool(...) は、ホスト コールバックへのブリッジ バックです。これは、ツールのサンドボックス内の再実装ではありません。 つまり、プロバイダー所有のツールは、ホスト プロセス自体がアクセスできるファイルシステム、ネットワーク、資格情報を使用して、ホスト プロセスで引き続き実行されます。

CodeActApprovalMode列挙型は、execute_code ツール自体の承認方法を制御します。

  • CodeActApprovalMode.NeverRequire (既定値): 登録されたツールから承認が反映されます。 レジストリ内のツールが ApprovalRequiredAIFunctionでラップされている場合、 execute_code には承認も必要です。それ以外の場合は必要ありません。
  • CodeActApprovalMode.AlwaysRequire: execute_code は、呼び出し前に常にユーザーの承認が必要です。

経験則として:

  • 安価で確定的で安全なチェーンツールをプロバイダーに配置して、モデルが 1 回のターン内で多くの呼び出しを作成できるように execute_code します。
  • 副作用や機密性の高い操作を ApprovalRequiredAIFunction でラップし (代わりに直接エージェント ツールとして保持することを検討してください)、各呼び出しが個別に表示され、承認できるようにします。

次のサンプルでは、2 つの安全なツール (fetch_docsquery_data) と、send_emailでラップされた機密性の高いApprovalRequiredAIFunction ツールを登録します。 少なくとも 1 つの登録済みツールには承認が必要であるため、既定の NeverRequire モードでは、 execute_code 自体が呼び出されるたびに承認が必要になります。

AIFunction fetchDocs = AIFunctionFactory.Create(
    (string topic) => $"Docs for {topic}: (...)",
    name: "fetch_docs",
    description: "Fetch documentation for a given topic.");

AIFunction queryData = AIFunctionFactory.Create(
    (string query) => $"Rows for `{query}`: []",
    name: "query_data",
    description: "Run a read-only SQL-like query against the sample store.");

AIFunction sendEmail = new ApprovalRequiredAIFunction(
    AIFunctionFactory.Create(
        (string to, string subject) => $"Sent '{subject}' to {to}.",
        name: "send_email",
        description: "Send an email on behalf of the user."));

var options = HyperlightCodeActProviderOptions.CreateForWasm(guestPath);
options.Tools = [fetchDocs, queryData, sendEmail];

using var codeAct = new HyperlightCodeActProvider(options);

AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetChatClient(deploymentName)
    .AsAIAgent(new ChatClientAgentOptions()
    {
        ChatOptions = new()
        {
            Instructions = "You are a helpful assistant. Prefer orchestrating your work in a single "
                + "`execute_code` block using `call_tool(...)` over issuing many direct tool calls.",
        },
        AIContextProviders = [codeAct],
    });

ホスト ツールはサンドボックスの外部で実行されるため、FileMountsAllowedDomainscall_tool(...)の背後にあるホスト コールバックではなく、サンドボックス コード自体を制約します。 機密性の高いリソースへのアクセスを制御する必要がある場合は、サンドボックスのアクセス許可を広げるよりも狭いホスト ツールを使用します。

直接配線に HyperlightExecuteCodeFunction を使用する

execute_codeを同じエージェント上の直接専用ツールと混在させる必要がある場合、またはサンドボックス構成がエージェントの有効期間中に固定されている場合は、プロバイダーではなくHyperlightExecuteCodeFunctionを使用します。 これは、構築時に指定されたオプションの単一のスナップショットをキャプチャし、呼び出しごとに再利用するスタンドアロン AIFunction です。

HyperlightCodeActProviderとは異なり、スタンドアロン関数はプロンプト ガイダンスを自動的に挿入しないため、BuildInstructions(...)出力をエージェントの指示に自分で追加する必要があります。 登録されたツールがtoolsVisibleToModel: false経由でのみ到達できる場合はcall_tool(...)を渡し、同じツールもモデルに直接公開されている場合はtrueします。

AIFunction calculate = AIFunctionFactory.Create(
    (double a, double b) => a * b,
    name: "multiply",
    description: "Multiply two numbers.");

var options = HyperlightCodeActProviderOptions.CreateForWasm(guestPath);
options.Tools = [calculate];

using var executeCode = new HyperlightExecuteCodeFunction(options);

var instructions =
    "You are a helpful assistant. When math is involved, solve it by writing Python "
    + "and calling `execute_code` instead of computing values yourself.\n\n"
    + executeCode.BuildInstructions(toolsVisibleToModel: false);

AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetChatClient(deploymentName)
    .AsAIAgent(instructions: instructions, tools: [executeCode]);

HyperlightExecuteCodeFunction はまた、IDisposable を実装します。 構成に承認が必要な場合 (ApprovalModeごと、または構成済みのツール自体が ApprovalRequiredAIFunction でラップされているため)、インスタンスはApprovalRequiredAIFunction経由でAITool.GetService(...) プロキシを表示します。これは、フレームワークの残りの部分で承認要件を検出する方法です。

ファイルと送信アクセスを構成する

Hyperlight では、読み取り専用の /input ツリーと、生成された成果物の書き込み可能な /output 領域を公開できます。

  • HostInputDirectoryを使用して、ホスト ディレクトリを /input/ で使用できるようにします。
  • FileMountsを使用して、new FileMount(hostPath, mountPath)を使用して特定のホスト パスをサンドボックスにマップします。
  • AllowedDomainsを使用して、new AllowedDomain(target, methods)経由で特定のターゲットまたはメソッドに対してのみ送信アクセスを有効にします。
var options = HyperlightCodeActProviderOptions.CreateForWasm(guestPath);
options.Tools = [compute];
options.FileMounts =
[
    new FileMount("/host/data", "/input/data"),
    new FileMount("/host/models", "/sandbox/models"),
];
options.AllowedDomains =
[
    new AllowedDomain("https://api.github.com"),
    new AllowedDomain("https://internal.api.example.com", ["GET"]),
];

using var codeAct = new HyperlightCodeActProvider(options);

FileMountsAllowedDomainsAddFileMounts(...)RemoveFileMounts(...)、およびAddAllowedDomains(...)を通じて、同じRemoveAllowedDomains(...)コレクションとHyperlightCodeActProviderコレクションに加えて、ツールも実行時に変更できます。

出力ガイダンス

execute_codeからテキストを表示するには、ゲスト コードを print(...) で終了します。Hyperlight は、最後の式の値を自動的に返しません。

ファイルシステムアクセスが有効になっている場合は、代わりに /output/<filename> に大きなアーティファクトを書き込みます。 返されたファイルはツールの結果に添付されますが、 /input の下のファイルはサンドボックス内で読み取るために使用できます。

現在の制限

このパッケージはまだプレビュー段階であり、いくつかの制約を考慮する必要があります。

  1. パッケージは、nuget.org でまだ公開されていない Hyperlight.HyperlightSandbox.Apiに依存します。それが出荷されるまで、プロジェクトの復元は失敗します。
  2. プラットフォームのサポートは、公開されている Hyperlight バックエンド パッケージ (サポートされている Linux (KVM) 環境と Windows (WHP) 環境) に従います。 サンドボックスを作成すると、サポートされていないプラットフォームまたは不足している仮想化バックエンドが失敗します。
  3. 現在の Wasm バックエンドは、HYPERLIGHT_PYTHON_GUEST_PATH で指定されたPythonゲスト モジュールを実行します。 JavaScript バックエンド (CreateForJavaScript()) は、JavaScript のゲスト コードで使用できます。
  4. インメモリ インタープリターの状態は、個別の execute_code 呼び出し間で保持されません。 データが呼び出し間で存続する必要がある場合は、マウントされたファイルと /output 成果物を使用します。
  5. 承認は、同じコード ブロック内の個々のexecute_codeではなく、call_tool(...)呼び出し全体に適用されます。
  6. ツールの説明、パラメーター注釈、および戻り値の図形は、分離された直接ツール呼び出しを選択するのではなく、モデルがそのコントラクトに対してコードを記述しているため、ここで重要です。
  7. Python ベンチマーク サンプルと同等の.NETはまだありません。公開されている比較ハーネスについては、「Python」タブを参照してください。

パッケージをインストールする

pip install agent-framework-hyperlight --pre

agent-framework-hyperlightagent-framework-coreとは別に提供されるため、サンドボックス ランタイムは必要なときにのみ実行されます。

パッケージは Hyperlight サンドボックス コンポーネントに依存します。 バックエンドが現在のプラットフォーム用にまだ発行されていない場合、サンドボックスを作成しようとしたときに execute_code は失敗します。

HyperlightCodeActProvider を使用する

HyperlightCodeActProvider は、実行ごとに CodeAct を自動的に追加する場合に推奨されるエントリ ポイントです。 実行範囲に限定された CodeAct 命令と execute_code ツールを挿入し、プロバイダー所有のツールがエージェント ツールサーフェスから除外されます。

import os

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework.hyperlight import HyperlightCodeActProvider
from azure.identity import AzureCliCredential

# 1. Create the Hyperlight-backed provider and register sandbox tools on it.
codeact = HyperlightCodeActProvider(
    tools=[compute, fetch_data],
    approval_mode="never_require",
)

# 2. Create the client and the agent.
agent = Agent(
    client=FoundryChatClient(
        project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
        model=os.environ["FOUNDRY_MODEL"],
        credential=AzureCliCredential(),
    ),
    name="HyperlightCodeActProviderAgent",
    instructions="You are a helpful assistant.",
    context_providers=[codeact],
)

# 3. Run a request that should use execute_code plus provider-owned tools.
query = (
    "Fetch all users, find admins, multiply 7*(3*2), and print the users, "
    "admins, and multiplication result. Use execute_code and call_tool(...) "
    "inside the sandbox."
)
result = await agent.run(query)
print(result.text)

プロバイダーに登録されているツールは、 call_tool(...)を介してサンドボックス内で使用できますが、直接エージェント ツールとして公開されません。 また、プロバイダーは、ツール、ファイル マウント、および送信許可リスト エントリの CRUD スタイルの管理を、 add_tools(...)remove_tool(...)add_file_mounts(...)add_allowed_domains(...)などのメソッドを使用して公開します。

承認とホスト ツールのしくみ

Agent Framework ツールには、自動呼び出しが可能か、ユーザーの承認のために一時停止する必要があるかを制御する approval_mode が含まれています。

HyperlightCodeActProviderにツールを登録し、Agent(tools=...)に直接登録する主な違いは、Python 関数が最終的に実行される場所ではなく、ツールがどのように呼び出されるかです。

  • HyperlightCodeActProvider(tools=...)に登録されたツールは、直接ツールとしてモデルに表示されません。 モデルは、call_tool("name", ...)内でexecute_codeを呼び出すコードを記述することによってそれらに到達します。
  • Agent(tools=...)に登録されたツールは、最上位クラスのツールとしてモデルに表示され、各直接呼び出しでは、そのツール独自のapproval_modeが受け入れられます。

call_tool(...) は、ホスト コールバックへのブリッジ バックです。これは、ツールのサンドボックス内の再実装ではありません。 つまり、プロバイダー所有のツールは、ホスト プロセス自体がアクセスできるファイルシステム、ネットワーク、資格情報を使用して、ホスト プロセスで引き続き実行されます。

経験則として:

  • 安価で確定的で安全なチェーンツールをプロバイダーに配置して、モデルが 1 回のターン内で多くの呼び出しを作成できるように execute_code します。
  • 副作用や承認が必要な操作は、approval_mode="always_require" を使用してエージェント内の直接ツールとして利用し、各呼び出しを個別に表示して承認できるようにします。

ホスト ツールはサンドボックスの外部で実行されるため、file_mountsallowed_domainscall_tool(...)の背後にあるホスト コールバックではなく、サンドボックス コード自体を制約します。 機密性の高いリソースへのアクセスを制御する必要がある場合は、サンドボックスのアクセス許可を広げるよりも狭いホスト ツールを使用します。

call_tool(...) によって呼び出されたツールは、ネイティブ Python値 (dictlist、プリミティブ、またはカスタム オブジェクト) をゲストに直接返します。 result_parserで構成されたFunctionToolは、LLM を対象とするコンシューマー向けであり、サンドボックス経路では実行されません—サンドボックス内で使用するコンシューマーに対して必要な場合は、ツール関数自体で書式を適用してください。

直接配線に HyperlightExecuteCodeTool を使用する

execute_codeを同じエージェント上の直接専用ツールと混在させる必要がある場合は、プロバイダーではなくHyperlightExecuteCodeToolを使用します。 固定構成の場合は、CodeAct 命令を 1 回ビルドし、ツールを直接接続できます。

from agent_framework.hyperlight import HyperlightExecuteCodeTool

execute_code = HyperlightExecuteCodeTool(
    tools=[compute],
    approval_mode="never_require",
)

codeact_instructions = execute_code.build_instructions(tools_visible_to_model=False)

このパターンは、CodeAct サーフェスが固定されていて、実行ごとにプロバイダーのライフサイクルが必要ない場合に便利です。 HyperlightCodeActProviderとは異なり、スタンドアロン ツールはプロンプト ガイダンスを自動的に挿入しないため、build_instructions(...)出力をエージェントの指示に自分で追加する必要があります。

ファイルと送信アクセスを構成する

Hyperlight では、読み取り専用の /input ツリーと、生成された成果物の書き込み可能な /output 領域を公開できます。

  • workspace_rootを使用して、/input/でワークスペースを使用できるようにします。
  • file_mountsを使用して、特定のホスト パスをサンドボックスにマップします。
  • 特定のターゲットまたはメソッドに対してのみ送信アクセスを有効にするには、 allowed_domains を使用します。

file_mounts は、短縮文字列、明示的な (host_path, mount_path) ペア、または FileMount 名前付きタプルを受け取ります。 allowed_domains は、文字列ターゲット、明示的な (target, method-or-methods) ペア、または AllowedDomain 名前付きタプルを受け取ります。

from agent_framework.hyperlight import HyperlightCodeActProvider

codeact = HyperlightCodeActProvider(
    tools=[compute],
    file_mounts=[
        "/host/data",
        ("/host/models", "/sandbox/models"),
    ],
    allowed_domains=[
        "api.github.com",
        ("internal.api.example.com", "GET"),
    ],
)

出力ガイダンス

execute_codeからテキストを表示するには、print(...)でコードを終了します。Hyperlight は、最後の式の値を自動的に返しません。

ファイルシステムアクセスが有効になっている場合は、代わりに /output/<filename> に大きなアーティファクトを書き込みます。 返されたファイルはツールの結果に添付されますが、 /input の下のファイルはサンドボックス内で読み取るために使用できます。

CodeAct と直接ツール呼び出しの比較

概念的な比較は、任意の CodeAct バックエンドの場合と同じです。同じクライアント、モデル、ツール、プロンプト、構造化された出力スキーマは、従来のツール呼び出しまたは Hyperlight に基づく CodeAct を使用してワイヤードできます。 唯一の違いはツールのインターフェイスです。つまり、直接ツールであるか、execute_codeを基盤とする単一の HyperlightCodeActProvider ツールであるかという点です。

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from agent_framework.hyperlight import HyperlightCodeActProvider

# Direct tool calling: the model picks one tool at a time per turn.
direct = Agent(
    client=FoundryChatClient(...),
    instructions="...",
    tools=[fetch_data, compute],
)

# Hyperlight-backed CodeAct: the model writes one program per turn that
# orchestrates the same tools through call_tool(...).
codeact = Agent(
    client=FoundryChatClient(...),
    instructions="...",
    context_providers=[
        HyperlightCodeActProvider(
            tools=[fetch_data, compute],
            approval_mode="never_require",
        ),
    ],
)

データセット全体の合計を計算するワークロードでは、データを繰り返し検索し、簡単な計算を実行します 。多くの小さなチェーン可能な手順では、CodeAct はオーケストレーションのオーバーヘッドを取り除くことができます。 両方の実行をストップウォッチでラップし、返された ChatResponse.usage を調べて、独自の環境での経過時間とトークンの使用状況を比較します。

現在の制限

このパッケージはまだアルファであり、いくつかの制約を考慮する必要があります。

  1. プラットフォームのサポートは、公開されている Hyperlight バックエンド パッケージに従います。 現在は、サポートされている Linux 環境と Windows 環境を意味します。サンドボックスを作成すると、サポートされていないプラットフォームが失敗します。
  2. 現在の統合では、Python ゲスト コードが実行されます。
  3. インメモリ インタープリターの状態は、個別の execute_code 呼び出し間で保持されません。 データが呼び出し間で存続する必要がある場合は、マウントされたファイルと /output 成果物を使用します。
  4. 承認は、同じコード ブロック内の個々のexecute_codeではなく、call_tool(...)呼び出し全体に適用されます。
  5. ツールの説明、パラメーター注釈、および戻り値の図形は、分離された直接ツール呼び出しを選択するのではなく、モデルがそのコントラクトに対してコードを記述しているため、ここで重要です。

次のステップ