超光

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

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

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

為什麼選擇 Hyperlight CodeAct

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

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 時的建議進入點。 它是一個 AIContextProvider,它會注入執行範圍內的 CodeAct 指令以及 execute_code 工具,同時將提供者擁有的工具排除在直接代理程式工具介面之外。 提供者會在每次執行時套用快照/還原,讓訪客每次呼叫都從已知的乾淨狀態開始。

使用 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 宣告,當代理不再需要時,底層沙箱會被釋放。

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

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

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

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

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

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

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

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

一般來說:

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

下一個範例會註冊兩個安全工具(fetch_docs、query_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],
    });

因為主機工具運行在沙盒之外,FileMounts 和 AllowedDomains 限制的是沙盒程式碼本身,而不是 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);

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

AllowedDomains控制來自訪客的輸出要求。 它不會安裝套件,也不會讓主機程序的相依關係在訪客內部可用。 CreateForWasm(modulePath) 選擇現有的訪客模組。 Agent Framework 整合不提供自訂的訪客建置或套件安裝工作流程。

對於需要主機安裝函式庫或外部 API 的操作,請註冊一個窄主機工具。 請將憑證、授權和目的地政策保留在該工具中,因為主機端回呼是在來賓環境之外執行,不受沙箱的 AllowedDomains 設定所限制。

輸出導引

若要從 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-hyperlight 與 agent-framework-core 獨立發佈,因此您只需在需要時才引入沙箱執行階段。

備註

Hyperlight 沙盒後端支援 x86-64 Linux 及 AMD 64 Windows for Python 3.10 至 3.14 版本。 這需要相應的主機虛擬化支援。 Python 3.15 及其他不支援環境可以安裝 connector 套件,但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(...) 在沙箱內部使用,但它們不會做為直接的代理程式工具公開。 提供者也透過add_tools(...)、remove_tool(...)、add_file_mounts(...)和add_allowed_domains(...)等方法,提供工具、檔案掛載及外站允許清單條目之 CRUD 式管理。

控制主機工具參數描述

HyperlightCodeActProvider 和 HyperlightExecuteCodeTool 接受 tool_description_format。 預設 "compact"參數 包含標量參數類型、必要或可選狀態、描述、列舉值及預設值。 使用 "json" 以取得完整的 JSON Schema,或依完全相符且區分大小寫的工具名稱選取格式:

codeact = HyperlightCodeActProvider(
    tools=[compute, fetch_data],
    tool_description_format={
        "compute": "json",
        "fetch_data": "compact",
    },
)

地圖中省略的工具則使用精簡格式。 當 Compact 渲染無法在不失去限制條件(如巢狀物件、陣列、參考或聯集)的情況下表示結構時,會自動退回到完整的 JSON Schema。 參數結構對模型可見,因此不要在描述、列舉值、預設值或自訂結構欄位中包含憑證或其他秘密。

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

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

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

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

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

一般來說:

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

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

備註

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

使用HyperlightExecuteCodeTool進行直接接線

當您需要在同一個代理程式上將 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"),
    ],
)

allowed_domains控制來自訪客的輸出要求。 它不會安裝 Python 套件,也不會讓來自主機環境的套件可在沙盒化程式碼中匯入。 module_path 選擇現有的訪客模組。 Agent Framework 整合不提供自訂的訪客建置或套件安裝工作流程。

對於需要主機安裝函式庫或外部 API 的操作,請註冊一個窄主機工具。 將憑證、授權和目的地允許清單檢查保留在該函式中,因為主機回呼是在來賓之外執行,且不受 allowed_domains 限制。

輸出導引

要從 execute_code 中呈現文字,則以 print(...) 分號結尾。Hyperlight 不會自動回傳最後一個表達式的值。

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

/output 目錄的作用範圍僅限於一次 execute_code 叫用。 框架會將收集到的檔案附加到該次呼叫的結果中,然後清除或隔離輸出內容的產生。 請使用從目前結果傳回的附件;請勿依賴在/output底下繼續保留的檔案以供稍後的execute_code呼叫使用。

對於 Python,輸出附件收集預設為 20 個檔案,每個檔案 5 MiB,以及每個調用累積 20 MiB 的原始檔案資料。 過大或包含過多目錄的輸出會傳回結構化的執行錯誤,不含任何部分附件,同時保留沙盒的標準輸出。

受信任的應用程式可在 HyperlightExecuteCodeTool 或 max_output_files 上,透過 max_output_file_bytes、max_output_total_bytes 和 HyperlightCodeActProvider 以正整數提高這些始終有限的限制。 較高的限制會增加主機記憶體使用量,因為檔案是以內嵌 base64 編碼。 為了實現可攜式行為,請將附件檔案直接寫入 /output 下;在不支援安全目錄相對檔案開啟的平台上,巢狀附件會以封閉方式失敗。

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

目前的限制

這個套件目前還在測試階段。 請圍繞以下限制條件進行規劃:

  1. 平台支援遵循已公布的 Hyperlight 後端輪組:x86-64 Linux 搭配 KVM,以及 AMD64 Windows 搭配 WHP,使用 Python 3.10 至 3.14。
  2. 目前的系統整合執行 Python 客戶端程式碼。
  3. 記憶體內的直譯器狀態和 /output 檔案不會在不同 execute_code 呼叫間持續存在。
  4. 批准適用於整個execute_code調用,而不是同一程式碼區塊內的每個call_tool(...)。
  5. 工具描述、參數註解和回傳形狀在這裡更重要,因為模型是根據該合約寫程式碼,而非選擇孤立的直接工具呼叫。

備註

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

下一步