多数のtool callを一つのcode blockにまとめ、安全な環境で実行したい場合、Microsoft Agent FrameworkのCodeActとHyperlightは有力な選択肢です。モデルには多数の個別ツールではなくexecute_codeを見せ、生成されたコードからcall_tool(...)で必要なツールを連続実行します。これにより、モデルとツールの往復回数を減らし、token消費とlatencyを抑えられます。
一方で、Hyperlightが隔離するのは主にモデルが生成したコードです。call_tool(...)から呼び出されるツール本体はホストプロセスで動くため、ツールの権限設計を誤ると、micro-VMを使っていても安全とはいえません。読み取り専用の小さなツールだけをCodeAct側に置き、メール送信やデータ更新などの副作用を伴う処理は、個別承認できる直接ツールとして残すのが基本です。
2026年7月時点では、Azure Update ID 563566としてCodeActとHyperlightの提供が案内され、Microsoft LearnではPythonと.NET向けのHyperlight CodeActがプレビューとして説明されています。公開プレビュー段階のため、まず非本番環境で従来方式と比較測定してから採用範囲を広げるべきです。(Microsoft Azure)
Agent Framework CodeActとHyperlightで何が変わるのか
従来のtool callingでは、エージェントが一つのツールを呼び、結果をモデルへ返し、次のツールを選ばせる処理を繰り返します。
たとえば、次のタスクを考えてみましょう。
- ユーザー一覧を取得する
- ユーザーごとの注文を取得する
- 各明細の金額を計算する
- ユーザー単位で集計する
- 全体の合計を返す
直接tool callingでは、処理の途中で何度も「モデル→ツール→モデル」の往復が発生します。CodeActでは、モデルが処理全体を次のような一つのコードとして生成します。
users = call_tool("list_users")
results = []
grand_total = 0
for user in users:
orders = call_tool("get_orders_for_user", user_id=user["id"])
user_total = 0
for order in orders:
line_total = call_tool(
"compute_line_total",
unit_price=order["unit_price"],
quantity=order["quantity"],
)
user_total += line_total
results.append({
"user": user["name"],
"total": user_total,
})
grand_total += user_total
print({
"users": results,
"grand_total": grand_total,
})
このコード全体がexecute_codeの一回の呼び出しとしてHyperlightへ渡されます。ツールの実行回数そのものが必ず減るわけではありませんが、途中経過ごとにモデルを再呼び出す必要がなくなります。
| 比較項目 | 直接tool calling | CodeActとHyperlight |
|---|---|---|
| モデルに見せるツール | 複数の業務ツール | 主にexecute_code |
| 処理の組み立て | モデルがターンごとに決定 | モデルが一つのプログラムを生成 |
| ループ・分岐・集計 | 複数ターンになりやすい | code block内で処理できる |
| 中間結果 | モデルへ何度も返る | sandbox内で加工してから返せる |
| 生成コードの実行場所 | 実装次第 | Hyperlight micro-VM |
| 個別ツールの承認 | 呼び出し単位で設定可能 | 原則としてexecute_code全体に適用 |
| 向いている処理 | 少数の独立した操作 | 多数の検索、集計、変換、軽量計算 |
Microsoftの説明では、Hyperlight CodeActはexecute_codeツールを追加し、sandbox内のコードからcall_tool(...)を通じてホスト側ツールを利用する構成です。Hyperlightはハイパーバイザーで隔離された軽量なmicro-VMを短時間で起動するランタイムとして提供されています。(Microsoft Learn)
tokenとlatencyを削減できる理由
CodeActの効果は、計算処理自体が突然高速になることではありません。主な削減対象は、LLMによるオーケストレーションの往復です。
直接tool callingでは、各ターンで次の情報が再びモデルへ送られる可能性があります。
- システムプロンプト
- 会話履歴
- ツール定義
- 直前までのツール結果
- 次の操作を選ぶための追加トークン
CodeActでは、モデルが最初に処理手順をコードとしてまとめます。その後の検索、ループ、フィルター、集計はsandbox内で進むため、中間データを毎回モデルへ返す必要がありません。
特に効果が大きいのは、大きな取得結果から最終回答に必要な数件だけを抽出する処理です。取得結果をそのままモデルへ返さず、sandbox内で絞り込んでから最小限の結果だけをprint(...)すれば、入力tokenを大きく削減できます。
Microsoftが公開した代表的な測定例
MicrosoftのPythonベンチマークでは、同じモデル、同じ5個のツール、同じプロンプト、同じ出力スキーマを使い、ツールの配線方法だけを変更しています。8人分の注文を検索し、割引率や税率を取得しながら明細を集計する、数十回のツール呼び出しを含むworkloadです。
| 実行方式 | 実行時間 | token数 |
|---|---|---|
| 従来のtool calling | 27.81秒 | 6,890 |
| CodeAct | 13.23秒 | 2,489 |
| 改善率 | 52.4% | 63.9% |
これは代表的な一回の測定結果であり、すべてのエージェントで同じ改善率になるわけではありません。API応答時間が支配的な処理、ツールが一つしかない処理、生成コードの再試行が多い処理では、改善幅が小さくなる可能性があります。.NETについては、Microsoft Learn上でもPythonと同等の公開ベンチマークサンプルはまだないと説明されています。(Microsoft for Developers)
CodeActを使うべき処理と使わない方がよい処理
CodeActは、すべてのtool callingを置き換える機能ではありません。削減できるモデル往復のコストが、sandbox起動やコード生成の追加コストを上回る処理に向いています。
| 処理の特徴 | 推奨方式 | 理由 |
|---|---|---|
| 多数の読み取りAPIを連続実行する | CodeAct | モデルの中間ターンを削減しやすい |
| データの検索、結合、フィルター、集計を行う | CodeAct | Pythonコードで処理をまとめられる |
| 大量データから小さな結果を抽出する | CodeAct | 中間データをモデルへ返さずに済む |
| 一つか二つのツールだけを呼ぶ | 直接tool calling | 削減できる往復が少ない |
| メール送信、購入、削除、更新を行う | 直接tool calling | 操作ごとの承認と監査が必要 |
| ツールごとに人の承認を求めたい | 直接tool calling | CodeActではcode block全体の承認になる |
| ツール仕様や戻り値が不安定 | まずツールを改善 | 生成コードが契約を誤解しやすい |
| 長時間実行する重いバッチ処理 | 別のジョブ基盤も検討 | エージェント内の短時間sandboxだけでは管理しにくい |
実務上は、一回の要求で3~5個以上の安全な小規模ツールを連鎖させているかを最初の判断材料にするとよいでしょう。一つか二つのツール呼び出ししかない場合は、Microsoftも従来の直接tool callingを継続するよう案内しています。(Microsoft Learn)
試す前に確認する実行要件
Hyperlight CodeActは通常のPythonライブラリだけで完結する機能ではありません。ホスト側でHyperlightのバックエンドを動かせる必要があります。
| 確認項目 | 内容 |
|---|---|
| 提供状態 | Python、.NETともプレビュー |
| Pythonパッケージ | agent-framework-hyperlightを--pre付きで導入 |
| .NETパッケージ | Microsoft.Agents.AI.Hyperlightをprereleaseで導入 |
| Linux | KVMを利用できること |
| Windows | Windows Hypervisor Platformを利用できること |
| macOS | 現行バックエンドの対応状況を実行前に確認 |
| 認証 | FoundryまたはAzure OpenAIへ接続できる認証情報 |
| Python guest | 使用するバックエンドに応じたguestモジュール |
| 本番利用 | まず非本番環境で評価する |
HyperlightはLinuxではKVM、WindowsではWindows Hypervisor Platformを必要とします。仮想マシンやCI環境で試す場合、nested virtualizationが利用できるかも確認してください。バックエンドが対象プラットフォーム向けに公開されていなければ、パッケージのインストールに成功しても、sandbox作成時にexecute_codeが失敗します。(Microsoft Learn)
.NETはNuGet依存関係も確認する
Microsoft Learnでは、.NETパッケージがHyperlight.HyperlightSandbox.Apiに依存し、その依存パッケージがnuget.orgで利用できない間はrestoreに失敗する可能性があると説明されています。
Azure Update上でpublic previewが発表されていても、利用するOS、NuGetフィード、パッケージ公開状況によっては、すぐに実行できるとは限りません。最初に空のプロジェクトで次のコマンドを実行し、復元が完了することを確認してください。(Microsoft Learn)
dotnet new console -n CodeActSample
cd CodeActSample
dotnet add package Microsoft.Agents.AI.Hyperlight --prerelease
dotnet restore
PythonでCodeActとHyperlightを試す手順
パッケージをインストールする
Foundryを利用する例では、Hyperlight連携、Foundryクライアント、Azure認証を導入します。
python -m pip install --upgrade pip
python -m pip install --pre agent-framework-hyperlight agent-framework-foundry azure-identity
az login
agent-framework-hyperlightは、sandbox機能を必要なプロジェクトだけに追加できるよう、Agent Frameworkのcoreとは分離して配布されています。現行のPyPIパッケージはpre-releaseとして提供されているため、再現性を確保するには、動作確認後にlock fileやrequirementsファイルへ解決済みバージョンを固定してください。(PyPI)
続いて、次の環境変数を設定します。
FOUNDRY_PROJECT_ENDPOINT=https://<プロジェクトのエンドポイント>
FOUNDRY_MODEL=<デプロイ済みモデル名>
安全な読み取りツールを登録する
以下は、ユーザー一覧と注文一覧を取得し、各明細を計算するサンプルです。複数の小さなtool callを一つのexecute_codeへまとめる動作を確認できます。
from __future__ import annotations
import asyncio
import os
from typing import Annotated
from agent_framework import Agent, tool
from agent_framework.foundry import FoundryChatClient
from agent_framework_hyperlight import HyperlightCodeActProvider
from azure.identity import AzureCliCredential
@tool(approval_mode="never_require")
def list_users() -> list[dict[str, object]]:
"""Return users whose orders should be summarized."""
return [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"},
{"id": 3, "name": "Charlie"},
]
@tool(approval_mode="never_require")
def get_orders_for_user(
user_id: Annotated[int, "ID returned by list_users."],
) -> list[dict[str, object]]:
"""Return order lines for one user."""
orders = {
1: [
{"unit_price": 1200.0, "quantity": 2},
{"unit_price": 500.0, "quantity": 3},
],
2: [
{"unit_price": 800.0, "quantity": 1},
],
3: [
{"unit_price": 1500.0, "quantity": 2},
{"unit_price": 300.0, "quantity": 4},
],
}
return orders.get(user_id, [])
@tool(approval_mode="never_require")
def compute_line_total(
unit_price: Annotated[float, "Unit price before tax."],
quantity: Annotated[int, "Number of units."],
) -> float:
"""Calculate one order line total."""
if unit_price < 0:
raise ValueError("unit_price must not be negative")
if quantity < 0:
raise ValueError("quantity must not be negative")
return unit_price * quantity
async def main() -> None:
codeact = HyperlightCodeActProvider(
tools=[
list_users,
get_orders_for_user,
compute_line_total,
],
approval_mode="never_require",
)
agent = Agent(
client=FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=AzureCliCredential(),
),
name="OrderSummaryCodeActAgent",
instructions=(
"複数の安全な読み取りツールが必要な場合は、"
"個別のtool callを繰り返さず、可能な限り一つのexecute_codeで処理してください。"
"providerのツールはcall_tool(...)で呼び出し、"
"中間データをsandbox内で集計してください。"
"最後は必要最小限のJSONだけをprintしてください。"
),
context_providers=[codeact],
)
result = await agent.run(
"全ユーザーの注文を取得し、ユーザー別合計と全体合計を計算してください。"
)
print(result.text)
if __name__ == "__main__":
asyncio.run(main())
PyPIのクイックスタートでは、独立したパッケージ名前空間であるagent_framework_hyperlightからimportする例が掲載されています。一方、Agent Frameworkのmeta packageなどを導入した環境では、agent_framework.hyperlightというlazy-loading名前空間も利用できます。import errorが発生した場合は、インストール済みパッケージと参照しているサンプルのバージョンを揃えてください。(PyPI)
実行結果で確認するポイント
回答が正しいだけでは、CodeActが使われたか判断できません。トレースまたはmiddlewareで、次の点を確認します。
- モデルが
execute_codeを一回呼んでいる - 生成されたcode block内に複数の
call_tool(...)がある - ユーザー一覧や注文一覧の全データを
print(...)していない - 最終的な集計結果だけがモデルへ返されている
- 失敗時に直接tool callingへ無制限に切り替わっていない
Microsoftの公式サンプルでも、middlewareからexecute_codeのcode引数を取得し、生成されたコードと実行時間を記録する構成が使われています。(GitHub)
.NETでHyperlightCodeActProviderを構成する手順
.NETでは、HyperlightCodeActProviderをAIContextProviderとしてエージェントへ登録します。Python guestをWasmバックエンドで実行する例では、HYPERLIGHT_PYTHON_GUEST_PATHにguestモジュールの絶対パスを設定します。
AZURE_OPENAI_ENDPOINT=https://<Azure OpenAIエンドポイント>
AZURE_OPENAI_DEPLOYMENT_NAME=<モデルのデプロイ名>
HYPERLIGHT_PYTHON_GUEST_PATH=<guestモジュールの絶対パス>
以下は、値の一覧を取得し、それぞれを乗算して合計する構成例です。現在のMicrosoft Learnで説明されているCreateForWasm(...)とHyperlightCodeActProviderの配線方法に沿っています。(Microsoft Learn)
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Hyperlight;
using Microsoft.Extensions.AI;
using OpenAI.Chat;
string endpoint =
Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
?? throw new InvalidOperationException(
"AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName =
Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME")
?? throw new InvalidOperationException(
"AZURE_OPENAI_DEPLOYMENT_NAME is not set.");
string guestPath =
Environment.GetEnvironmentVariable("HYPERLIGHT_PYTHON_GUEST_PATH")
?? throw new InvalidOperationException(
"HYPERLIGHT_PYTHON_GUEST_PATH is not set.");
AIFunction getValues = AIFunctionFactory.Create(
static () => new[] { 2d, 3d, 5d, 7d },
name: "get_values",
description: "Return numeric values to process.");
AIFunction multiply = AIFunctionFactory.Create(
static (double value, double multiplier) => value * multiplier,
name: "multiply",
description: "Multiply one value by a multiplier.");
var options =
HyperlightCodeActProviderOptions.CreateForWasm(guestPath);
options.Tools = [getValues, multiply];
options.ApprovalMode = CodeActApprovalMode.NeverRequire;
using var codeAct = new HyperlightCodeActProvider(options);
AIAgent agent =
new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName)
.AsAIAgent(
new ChatClientAgentOptions
{
ChatOptions = new()
{
Instructions =
"Use one execute_code block for safe multi-step calculations. " +
"Call provider-owned tools through call_tool(...), " +
"aggregate inside the sandbox, and print only the final result.",
},
AIContextProviders = [codeAct],
});
Console.WriteLine(
await agent.RunAsync(
"Get all values, multiply each value by 10, and return their sum."));
一つのエージェントに登録できるHyperlightCodeActProviderは一つです。また、providerはIDisposableを実装しているため、usingで確実にsandboxリソースを解放します。(Microsoft Learn)
ProviderとStandalone Toolの選び方
Hyperlight CodeActには、主に二つの配線方法があります。
| 構成 | 向いているケース |
|---|---|
HyperlightCodeActProvider | 実行ごとにCodeActの説明とexecute_codeを自動追加したい |
HyperlightExecuteCodeTool / HyperlightExecuteCodeFunction | 直接ツールとCodeActを明示的に混在させたい |
| 直接agent tool | 個別承認が必要な副作用操作 |
| Provider所有tool | 安価、決定的、読み取り中心で連鎖可能な操作 |
Providerは、CodeActに必要なプロンプトとexecute_codeを自動的に注入します。Standalone方式では、CodeAct用のinstructionを自分で組み込みます。
実務では、次のように役割を分ける構成が扱いやすくなります。
Provider所有tool
├─ 顧客情報の検索
├─ 注文一覧の取得
├─ マスタ参照
├─ 税率計算
└─ 読み取り専用の社内API
直接agent tool
├─ メール送信
├─ データ更新
├─ 注文確定
├─ ファイル削除
└─ 課金を伴う処理
Hyperlightのsandbox境界を正しく理解する
最も重要なのは、call_tool(...)がツールをmicro-VM内で実行する仕組みではないことです。
モデルが生成したPythonコードはHyperlight内で動きますが、Providerに登録した関数はホストプロセスへブリッジされ、ホスト側で実行されます。そのため、ホストツールはアプリケーションが持つファイル、ネットワーク、資格情報へアクセスできます。(Microsoft Learn)
LLM
│
│ execute_code
▼
Hyperlight micro-VM
│
│ call_tool("search_customer", ...)
▼
ホストプロセス上のsearch_customer関数
│
├─ データベース
├─ 社内API
└─ Managed IdentityやAPI資格情報
つまり、Hyperlightを導入しても、次のようなツールは危険なままです。
@tool
def run_sql(sql: str) -> list[dict]:
"""Run any SQL supplied by the caller."""
このツールをProviderへ渡すと、生成コードは任意のSQL文字列を指定できます。micro-VMはデータベースを隔離してくれません。
代わりに、入力と操作範囲を限定します。
@tool(approval_mode="never_require")
def get_customer_orders(
customer_id: int,
max_rows: int = 100,
) -> list[dict]:
"""Return up to 100 readable orders for one authorized customer."""
ホストツール側では、モデルから渡された引数を信用せず、次の制御を行います。
- 呼び出しユーザーの認可
- テナント境界の検証
- IDや検索条件の形式検証
- 取得件数の上限
- タイムアウト
- レート制限
- 機密項目の除去
- 監査ログへの記録
file mountとネットワーク許可は最小限にする
Hyperlightでは、ホスト側ファイルをsandboxへmountしたり、送信先ドメインをallow listで許可したりできます。
Pythonでは、次のような構成が可能です。
codeact = HyperlightCodeActProvider(
tools=[list_users],
file_mounts=[
("/srv/codeact/input", "/input/data"),
],
allowed_domains=[
("api.example.com", "GET"),
],
)
.NETでは、FileMountsとAllowedDomainsをoptionsへ設定します。
var options =
HyperlightCodeActProviderOptions.CreateForWasm(guestPath);
options.FileMounts =
[
new FileMount(
"/srv/codeact/input",
"/input/data"),
];
options.AllowedDomains =
[
new AllowedDomain(
"https://api.example.com",
["GET"]),
];
入力ファイルは/input配下で読み取り、生成した大きな成果物は/output/<filename>へ保存する設計が基本です。テキスト結果を返す場合は、生成コードの最後でprint(...)する必要があります。Hyperlightは最後の式の値を自動返却しません。(Microsoft Learn)
file mountと外向き通信を同時に広げない
読み取り可能なmountと自由な外向き通信を同時に許可すると、生成コードがファイル内容を外部へ送信できる構成になります。
特に避けるべき設定は次のとおりです。
- ホームディレクトリ全体のmount
- ソースリポジトリ全体のmount
.env、SSH鍵、クラウド資格情報のmount- 任意ドメインへのHTTP許可
GETだけでよいAPIへの全HTTPメソッド許可- 本番データと検証用sandboxの共有
「ファイルを読める」「外部へ送れる」という二つの権限は、個別ではなく組み合わせで評価してください。
AllowedDomainsはホストツールを制限しない
allowed_domainsやAllowedDomainsが制約するのは、sandbox内のコードが直接行う通信です。call_tool(...)で呼び出されたホストツールの通信先は制限しません。
したがって、機密APIへアクセスさせたい場合は、sandboxへ広いネットワーク権限を与えるより、次のような用途限定ツールをホスト側に実装する方が安全です。
@tool(approval_mode="never_require")
def get_exchange_rate(
base_currency: str,
quote_currency: str,
) -> dict[str, object]:
"""Return one approved currency pair from the internal rate service."""
この境界はMicrosoft Learnでも明確に説明されています。(Microsoft Learn)
承認はcode block全体に適用される
CodeActでは、同じexecute_code内に複数のcall_tool(...)が含まれていても、承認は個々のツール呼び出しではなく、原則としてexecute_code全体に適用されます。
たとえば、次のコードが一つのblockとして生成された場合を考えます。
customer = call_tool("get_customer", customer_id=100)
invoice = call_tool("create_invoice", customer_id=100)
call_tool("send_invoice_email", invoice_id=invoice["id"])
print(invoice)
ユーザーが承認画面で把握すべき操作は、顧客検索だけではありません。請求書作成とメール送信も含まれます。しかし、個別のcall_tool(...)ごとに承認を分けることはできません。
そのため、create_invoiceやsend_invoice_emailはProviderに入れず、直接agent toolとして登録し、操作単位で承認させる方が安全です。Microsoftも、副作用や個別承認が必要な操作を直接ツールとして残すよう案内しています。(Microsoft Learn)
ツールの説明と戻り値をCodeAct向けに整える
直接tool callingでは、モデルがツール名とJSON Schemaを見て一つの呼び出しを選びます。CodeActでは、モデルがその契約を使ってプログラムを書きます。
そのため、次の情報が曖昧だと、生成コードの失敗率が高まります。
- ツール名
- docstring
- 引数名
- 引数の型
- 許容値
- 戻り値のフィールド
- エラー条件
- 空データ時の戻り値
悪い例は、名前から用途が判断できず、戻り値も不定なツールです。
@tool
def execute(data: dict) -> object:
"""Execute data."""
CodeAct向けには、次のように契約を狭くします。
@tool(approval_mode="never_require")
def search_products(
query: Annotated[str, "Product name keyword. Maximum 100 characters."],
limit: Annotated[int, "Maximum number of results from 1 to 50."],
) -> list[dict[str, object]]:
"""
Return products matching the keyword.
Each item contains:
- product_id: integer
- name: string
- unit_price: float
- stock: integer
Returns an empty list when no product matches.
"""
Pythonでは、Provider経由のツール結果がdictやlistなどのnative valueとしてguestへ返されます。LLM向けに設定したresult_parserはsandbox経路では適用されないため、sandbox内で特定の形式が必要ならツール関数自体で整形します。(Microsoft Learn)
token削減を失敗させる出力設計に注意する
CodeActを使っても、最後に全中間データをprint(...)すればtoken削減効果は失われます。
悪い例は、取得した全レコードをそのまま出力するコードです。
records = call_tool("search_logs", hours=24)
print(records)
より適切なのは、sandbox内で絞り込みと集計を完了させる方法です。
records = call_tool("search_logs", hours=24)
errors = [
record
for record in records
if record["level"] == "ERROR"
]
summary = {
"total": len(records),
"error_count": len(errors),
"top_error_codes": {},
}
for record in errors:
code = record.get("error_code", "unknown")
summary["top_error_codes"][code] = (
summary["top_error_codes"].get(code, 0) + 1
)
print(summary)
大きなCSVやJSONを成果物として返したい場合は、会話テキストへ展開せず、/outputへファイルとして保存します。
execute_code間でメモリ状態は保持されない
個別のexecute_code呼び出しをまたいで、Python変数やインメモリ状態が残ることを前提にしてはいけません。
次のような会話は失敗する可能性があります。
1回目: 大量データを取得して変数dataへ保存
2回目: 先ほどのdataを使って別の集計を実行
呼び出し間でデータを残す必要がある場合は、明示的に/outputへ保存するか、ホスト側の状態管理やストレージを利用します。Hyperlight CodeActの現在の制約として、インメモリのinterpreter stateは別のexecute_codeへ引き継がれないと説明されています。(Microsoft Learn)
自環境でtokenとlatencyを比較する方法
公開された改善率をそのまま採用判断に使わず、直接tool calling版とCodeAct版を同じ条件で比較します。
比較条件を固定する
少なくとも、次の条件を揃えます。
| 項目 | 固定する内容 |
|---|---|
| モデル | 同じモデルとデプロイ |
| temperature | 同じ設定 |
| ツール | 同じ処理内容 |
| データ | 同じテストデータ |
| プロンプト | 同じ要求 |
| 出力 | 同じJSON Schema |
| 認証・接続先 | 同じ環境 |
| タイムアウト | 同じ上限 |
| 再試行 | 同じポリシー |
違いは、ツールをAgent(tools=...)へ直接渡すか、HyperlightCodeActProviderの背後へ渡すかだけにします。Microsoft Learnの比較方法も、この条件を前提としています。(Microsoft Learn)
記録すべき指標
latencyとtokenだけでなく、成功率も測定します。
- end-to-end latency
- p50、p95 latency
- input token
- output token
- total token
- モデル呼び出し回数
execute_code回数call_tool(...)回数- 正しい結果を返した割合
- 構文エラー率
- ツール引数エラー率
- 再試行回数
- sandbox作成エラー率
- 一件当たりの推定モデル費用
CodeActでlatencyが下がっても、計算結果の誤りや再試行が増えれば、本番品質は改善していません。
Pythonでの簡易計測例
from dataclasses import dataclass
from time import perf_counter
from typing import Any
@dataclass
class Measurement:
elapsed_seconds: float
usage: Any
text: str
async def measure(agent, prompt: str) -> Measurement:
started = perf_counter()
result = await agent.run(prompt)
elapsed = perf_counter() - started
usage = getattr(result, "usage", None)
return Measurement(
elapsed_seconds=elapsed,
usage=usage,
text=result.text,
)
最初の一回には初期化や認証、接続確立の影響が含まれることがあります。cold startとwarm runを分け、同一プロンプトを20~30回程度実行して分布を比較すると判断しやすくなります。
また、モデルのキャッシュやAPI側の混雑による偏りを避けるため、直接方式をすべて実行してからCodeAct方式を実行するのではなく、実行順を交互にする方法も有効です。
よくあるエラーと対処方法
| 症状 | 主な原因 | 対処 |
|---|---|---|
execute_code作成時に失敗する | Hyperlightバックエンド非対応 | OS、CPU仮想化、KVMまたはWHPを確認する |
| Pythonのimportに失敗する | 名前空間と導入パッケージの不一致 | agent_framework_hyperlightとagent_framework.hyperlightを公式サンプルに合わせる |
| .NETのrestoreに失敗する | prerelease依存パッケージが取得できない | NuGetソースと公開状況を確認する |
| 結果が空になる | 生成コードにprint(...)がない | instructionに最終結果をprintするよう明記する |
| HTTPアクセスが拒否される | allowed_domains未登録 | 必要なドメインとHTTPメソッドだけを追加する |
| ファイルが見つからない | sandbox内のパスが異なる | host pathとmount pathを分けて確認する |
| 前回の変数が消える | 呼び出し間で状態が保持されない | /outputまたは外部ストレージへ保存する |
| tokenが減らない | 中間データを全件printしている | sandbox内で絞り込み、要約結果だけを返す |
| 依然として直接tool callが多い | instructionまたはProvider登録が不十分 | ツールをProvider側へ移し、execute_code優先を明記する |
| 危険な処理が一括承認される | 副作用ツールをProviderへ登録している | 直接agent toolへ戻して個別承認させる |
公開プレビュー段階での安全な導入順序
Azure Updatesでは、previewを非本番での利用とテストを想定した状態として区別しています。APIやパッケージ構成が変わる可能性もあるため、最初から本番の更新処理へ組み込むべきではありません。(Microsoft Azure)
読み取り専用の検証タスクを選ぶ
最初の対象には、次のような処理が適しています。
- 複数APIから情報を検索する
- ログを集計する
- 在庫や注文を読み取ってレポート化する
- 複数のマスタを結合する
- 数値を計算してJSONを返す
削除、更新、送信、課金は含めません。
直接方式とCodeAct方式を並行実装する
同じツールを使って、次の二つのエージェントを用意します。
Agent A
└─ tools=[list_users, get_orders, compute_total]
Agent B
└─ context_providers=[
HyperlightCodeActProvider(
tools=[list_users, get_orders, compute_total]
)
]
両方へ同じ評価データを入力し、latency、token、成功率、出力差分を記録します。
sandboxの権限をゼロから追加する
最初は次の状態から始めます。
file mount: なし
outbound network: なし
provider tools: 読み取り専用のみ
direct tools: なし
必要性が確認できた権限だけを、一つずつ追加します。最初から広いファイルアクセスやネットワークアクセスを許可すると、どの権限が本当に必要なのか判断できません。
バージョンを固定して段階展開する
動作確認後はpre-releaseパッケージのバージョンを固定し、更新時には同じ評価セットを再実行します。
本番相当環境へ進める場合も、対象ユーザーや処理件数を限定し、従来方式へ戻せる切り替えを残してください。
CodeAct導入で最初に実施すべきこと
Agent Framework CodeActとHyperlightは、多数の小さなtool callを一つの実行可能code blockへまとめ、モデル往復に伴うtokenとlatencyを削減する仕組みです。特に、検索、ループ、フィルター、集計、軽量計算を組み合わせるタスクで効果を期待できます。
ただし、micro-VMが隔離するのはモデル生成コードであり、call_tool(...)先の関数はホストプロセスで動きます。安全性を確保するには、読み取り専用で入力範囲の狭いツールだけをProviderへ登録し、副作用のある処理は個別承認可能な直接ツールとして残す必要があります。
まずはPythonで読み取り専用の実データに近いworkloadを用意し、従来方式とCodeAct方式を同じ条件で測定してください。latencyとtokenだけでなく、成功率、再試行、生成コード、権限境界も確認します。.NETはNuGet依存関係とHyperlightバックエンドの利用可否を先に検証し、復元とsandbox作成に成功してから同じ比較へ進むのが確実です。

コメント