超光

Hyperlight 是 Agent Framework 中目前有文件記錄的 CodeAct 後端。 它暴露了一個由獨立沙盒執行環境支援的 execute_code 工具,並可透過 call_tool(...) 呼叫提供者擁有的主機工具。

此整合採用 CodeAct 模式:提供者貢獻程式碼執行工具,並管理每次執行的執行環境。

關於模式層級的概述,請參見 CodeAct

為什麼選擇 Hyperlight CodeAct

現代 Agent 受到的限制通常更多來自於工具呼叫的額外負荷,而不是模型本身。 一個讀取資料、執行輕度計算並組合結果的任務,很容易演變成一連串模型-> 工具-> 模型-> 工具的互動鏈,即使每個步驟都很簡單。

Hyperlight 支援的 CodeAct 會消除該迴圈。 模型會寫入一個簡短的 Python 程式,沙箱會執行它一次,並從沙箱內部透過call_tool(...)觸達提供者擁有的工具。 在具代表性的工具密集型工作負載中,這種轉移可將延遲約減半,代幣使用量減少超過 60%,同時保持執行隔離與可稽核。

安裝套件

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

Microsoft.Agents.AI.Hyperlight是獨立於核心抽象之外發佈的,因此您只需在需要時才引入沙箱執行階段。

這很重要

.NET 套件目前還在預覽階段。 它相依於來自 Hyperlight.HyperlightSandbox.Apihyperlight-dev/hyperlight-sandbox 的 NuGet 套件;在該相依套件發佈到 nuget.org 之前,專案將無法還原。 追蹤上游沙盒儲存庫的可用狀態。

備註

Hyperlight 需要主機上的硬體虛擬化:Linux 上的 KVM 或 Windows 的 Windows 虛擬機平台(WHP)。 Wasm 後端還需要一個 Hyperlight Python guest 模組——在執行前將 HYPERLIGHT_PYTHON_GUEST_PATH 設定為其絕對路徑。

使用 HyperlightCodeActProvider

HyperlightCodeActProvider是當您想為每次執行自動新增 CodeAct 時的建議進入點。 它是一個會注入執行範圍內 CodeAct 指令以及execute_code工具的AIContextProvider,同時將提供者擁有的工具排除在直接 Agent 工具介面外。 提供者會在每次執行時套用快照/還原,讓訪客每次呼叫都從已知的乾淨狀態開始。

使用HyperlightCodeActProviderOptions.CreateForWasm(modulePath)工廠來針對樣本所使用的 Wasm 型 Python 客體;對於 JavaScript 後端也提供CreateForJavaScript()

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。 提供者使用固定狀態金鑰,因此 ChatClientAgent的狀態金鑰唯一性驗證會拒絕重複註冊。 HyperlightCodeActProvider 實作 IDisposable;使用 using 宣告,當代理不再需要時,底層沙箱會被釋放。

工具、檔案掛載及出站允許清單項目可透過 HyperlightCodeActProviderOptionsToolsFileMountsAllowedDomainsHostInputDirectory)預先提供,或透過提供者的 AddTools(...)RemoveTools(...)ClearTools()AddFileMounts(...)AddAllowedDomains(...) 以及對應的 Get* 存取子在執行階段管理。

審核與主機工具的運作方式

代理框架工具攜帶審核的元資料,控制是否能自動調用或必須暫停以供使用者核准。 在 .NET 中,若要選擇使用核准機制,可透過將AIFunction裝合在ApprovalRequiredAIFunction中來達成。

在代理上註冊工具 HyperlightCodeActProvider 與直接在代理上註冊的主要差別在於工具 的呼叫方式,而非函式最終執行的位置:

  • 註冊在HyperlightCodeActProviderOptions.Tools上的工具不會作為直接工具向模型顯示。 模型透過在execute_code內部寫入呼叫call_tool("name", ...)的程式碼來觸達它們。
  • 直接註冊在 Agent 上的工具 (例如透過AsAIAgent(tools: [...])) 會作為第一類工具呈現給模型,且每一次直接呼叫都會遵循該工具本身的核准中繼資料。

call_tool(...)是通往主機的橋樑;並非工具在沙箱內的重新實作。 這表示提供者擁有的工具仍可在主機程序中執行,使用主機程序能存取的任何檔案系統、網路和憑證。

CodeActApprovalMode列舉會控制execute_code工具本身的核准方式:

  • CodeActApprovalMode.NeverRequire (預設:核准會從註冊工具中傳遞。 如果登錄檔中的任何工具被包裹在 ApprovalRequiredAIFunctionexecute_code 也需核准;否則則無需核准。
  • CodeActApprovalMode.AlwaysRequireexecute_code 在呼叫前,總是需要使用者的批准。

一般來說:

  • 將便宜、具決定性且可安全串連的工具放在提供者端,讓模型能夠在一個execute_code回合中組合許多呼叫。
  • 將具有副作用或敏感的操作封裝在 ApprovalRequiredAIFunction 中(並考慮改為保留為直接的代理程式工具),以便讓每次叫用都能個別保持可見且可核准。

下一個範例會註冊兩個安全工具(fetch_docsquery_data),以及一個封裝在 send_email 中的敏感 ApprovalRequiredAIFunction 工具。 由於至少有一個註冊工具需要核准,預設 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],
    });

因為主機工具運行在沙盒之外,FileMountsAllowedDomains 限制的是沙盒程式碼本身,而不是 call_tool(...) 背後的主機回調。 當你需要對敏感資源的受控存取時,建議使用狹窄的主機工具,而不是擴大沙盒權限。

使用HyperlightExecuteCodeFunction進行直接接線

當你需要在同一個代理程式上同時混用 execute_code 與僅支援 direct 的工具,或沙盒設定在代理程式的整個生命週期內固定不變時,請改用 HyperlightExecuteCodeFunction,不要使用 provider。 它是獨立的 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);

相同的 FileMountsAllowedDomains 集合以及工具,也可以在執行階段透過 AddFileMounts(...) 上的 RemoveFileMounts(...)AddAllowedDomains(...)RemoveAllowedDomains(...)HyperlightCodeActProvider 進行修改。

輸出導引

若要從 execute_code 輸出文字,請以 print(...) 結束來賓程式碼;Hyperlight 不會自動回傳最後一個運算式的值。

啟用檔案系統存取時,請改將較大的成品改為寫入/output/<filename>。 回傳的檔案會附加在工具結果中,而下方 /input 的檔案則可在沙盒內閱讀。

目前的限制

此套件仍屬預覽階段,有幾項限制值得規劃:

  1. 該套件相依於 Hyperlight.HyperlightSandbox.Api,但該套件尚未發佈到 nuget.org。在它發佈之前,專案還原將會失敗。
  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工具,同時將提供者擁有的工具排除在直接 Agent 工具介面外。

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(...)在沙箱內部使用,但它們不會作為直接的 Agent 工具公開。 提供者也透過add_tools(...)remove_tool(...)add_file_mounts(...)add_allowed_domains(...)等方法,提供工具、檔案掛載及外站允許清單條目之 CRUD 式管理。

審核與主機工具的運作方式

代理框架工具具有approval_mode來控制是否可以自動調用或需要暫停以供使用者批准。

註冊工具於 HyperlightCodeActProvider 和直接註冊於 Agent(tools=...) 之間的主要差別在於工具的呼叫方式,而非 Python 函式最終的執行地點:

  • HyperlightCodeActProvider(tools=...)上註冊的工具不會作為直接工具向模型顯示。 模型透過在execute_code內部寫入呼叫call_tool("name", ...)的程式碼來觸達它們。
  • 註冊在Agent(tools=...)上的工具會作為第一類工具呈現給模型,且每一次直接呼叫都會遵循該工具本身的approval_mode

call_tool(...)是通往主機的橋樑;並非工具在沙箱內的重新實作。 這表示提供者擁有的工具仍可在主機程序中執行,使用主機程序能存取的任何檔案系統、網路和憑證。

一般來說:

  • 將便宜、具決定性且可安全串連的工具放在提供者端,讓模型能夠在一個execute_code回合中組合許多呼叫。
  • 將會產生副作用或受核准控制的作業保留為直接的 Agent 工具,通常搭配approval_mode="always_require",以確保每一次叫用都是個別可見且可進行核准。

因為主機工具運行在沙盒之外,file_mountsallowed_domains 限制的是沙盒程式碼本身,而不是 call_tool(...) 背後的主機回調。 當你需要對敏感資源的受控存取時,建議使用狹窄的主機工具,而不是擴大沙盒權限。

備註

透過 call_tool(...) 呼叫的工具會直接回傳其原生的 Python 值,包括 dictlist、原始物件或自訂物件,給客戶端。 FunctionTool上設定的任何result_parser都是針對面向 LLM 的取用者所設計,且不會在沙箱路徑中執行 — 若您需要供沙箱內的取用者使用,請直接在工具函式本身內部套用格式設定。

使用HyperlightExecuteCodeTool進行直接接線

當您需要在同一個 Agent 上混合使用execute_code和僅限直接呼叫的工具時,請改用HyperlightExecuteCodeTool而非提供者。 對於固定配置,你可以先建立一次 CodeAct 指令,然後直接接線工具:

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具名 Tuple。 allowed_domains接受字串目標、明確的(target, method-or-methods)配對,或AllowedDomain具名 Tuple。

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 連接。 唯一的差別在於工具介面 — 直接工具與由HyperlightCodeActProvider支援的單一execute_code工具:

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,以便在您自己的環境中比較經過的時間與權杖使用量。

目前的限制

這個套件仍處於 alpha 階段,有幾個限制值得規劃:

  1. 平台支援遵循已發佈的 Hyperlight 後端套件。 如今,這代表支援的 Linux 和 Windows 環境;未支援的平台在建立沙盒時會失敗。
  2. 目前的系統整合執行 Python 客戶端程式碼。
  3. 記憶體直譯器的狀態不會在不同 execute_code 呼叫間持續存在。 當資料需要在跨呼叫期間存留時,請使用掛載的檔案和/output成品。
  4. 批准適用於整個execute_code調用,而不是同一程式碼區塊內的每個call_tool(...)
  5. 工具描述、參數註解和回傳形狀在這裡更重要,因為模型是根據該合約寫程式碼,而非選擇孤立的直接工具呼叫。

備註

Go 對此功能的支援即將推出。 最新狀態請參閱 Agent Framework Go 倉庫

下一步