超光CodeAct

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

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

為什麼選擇 Hyperlight CodeAct

現代代理通常受限於調用工具時的開銷,而非模型本身。 一個讀取資料、執行輕度計算並組合結果的任務,很容易演變成一連串模型-> 工具-> 模型-> 工具的互動鏈,即使每個步驟都很簡單。

超光速支持的CodeAct打破了這個循環。 模型會寫一個簡短的 Python 程式,沙盒執行一次,然後從沙盒 call_tool(...)內部存取提供者擁有的工具。 在具代表性的工具密集型工作負載中,這種轉移可將延遲約減半,代幣使用量減少超過 60%,同時保持執行隔離與可稽核。

安裝套件

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

Microsoft.Agents.AI.Hyperlight 是獨立於核心抽象之外發佈的,所以你只有在需要時才會接手沙盒執行時。

Important

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

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

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

代理框架工具攜帶審核的元資料,控制是否能自動調用或必須暫停以供使用者核准。 在.NET中,核准是透過將 AIFunction 包裹在 ApprovalRequiredAIFunction 中來選擇加入。

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

  • 註冊在模型上的 HyperlightCodeActProviderOptions.Tools 工具會被隱藏為直接工具。 模型透過撰寫在 call_tool("name", ...) 程式碼中呼叫 execute_code 的方式來達到這些。
  • 直接在代理上註冊的工具(例如透過 AsAIAgent(tools: [...]))會以第一級工具的身分提供給模型,而每次直接呼叫都會遵循該工具本身的核准中繼資料。

call_tool(...) 是連接到主機回呼的橋梁;這不是工具的沙盒內重新實作。 這表示提供者擁有的工具仍可在主機程序中執行,使用主機程序能存取的任何檔案系統、網路和憑證。

CodeActApprovalMode Enum 控制工具本身的核准方式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 工具,同時將提供者自有的工具排除在直接代理工具操作界面之外。

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 式管理。

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

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

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

  • 註冊在模型上的 HyperlightCodeActProvider(tools=...) 工具會被隱藏為直接工具。 模型透過撰寫在 call_tool("name", ...) 程式碼中呼叫 execute_code 的方式來達到這些。
  • 註冊於 Agent(tools=...) 模型上的工具會被呈現為卓越工具,每次直接調用都會尊重該工具本身的 approval_mode

call_tool(...) 是連接到主機回呼的橋梁;這不是工具的沙盒內重新實作。 這表示提供者擁有的工具仍可在主機程序中執行,使用主機程序能存取的任何檔案系統、網路和憑證。

一般來說:

  • 在提供者身上放置便宜、確定性且可以安全地串聯的工具,讓模型能在一次 execute_code 運行中組合多個呼叫。
  • 將副作用或核准門檻操作作為直接代理工具,通常搭配 approval_mode="always_require",讓每個召喚都能獨立可見且可核准。

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

備註

透過 call_tool(...) 呼叫的工具會直接回傳其原生的 Python 值,包括 dictlist、原始物件或自訂物件,給客戶端。 任何 result_parser 設定在FunctionTool 上的都是針對面向 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元組。 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,以在你自己的環境中比較耗時和 token 使用量。

目前的限制

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

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

下一步