我們如何大規模運行 Agent 沙盒環境

@LegitSeanSmith
英語2 週前 · 2026年7月03日
319K
79
11
4
73

TL;DR

Adapt 技術長 Sean Smith 詳細介紹了其基礎架構從 gVisor 遷移至 Firecracker microVM 的過程,成功為 AI Agent 程式碼執行實現了數千個隔離且具備亞秒級啟動速度的沙盒環境。

我們很早就下定決心,要賦予 LLM 執行任意程式碼的能力。這篇文章將探討我們為何做出這個決定,以及要同時運行數千個這樣的沙盒(sandbox),並隨著使用者與 Agent 的對話開始與結束而快速啟動與關閉,需要付出什麼樣的努力。

使用者與 Adapt Agent 進行的每一場對話,背後都有專屬的電腦在支撐。這不只是共享伺服器上受到限制的容器,而是模型可以隨意操作的隔離虛擬機(VM):安裝軟體、編寫並執行程式、瀏覽網頁、呼叫 API。我們稱這些為沙盒,它們是 Adapt 建構的核心基礎之一。

完全掌控

LLM 是程式編寫的天才,而我的工作很大程度上就是為它們打造完美的開發環境。

將 AI 連接到外部世界的傳統方式是手動建立整合,例如為 GitHub 建立一個專屬連接器,為 HubSpot 建立另一個,為 Stripe 再建立一個,或者等待每個服務推出 MCP 伺服器。這種方式無法擴展,而且我也不想每天都在寫整合程式碼。

因此,我們沒有自己動手做這些工作,而是讓模型來完成。任何提供 API 的服務都可以從 Adapt 存取,因為我們為 LLM 提供了編寫與該 API 溝通的腳本或程式所需的一切。這就是我們稱 Adapt 為「水平智慧」(horizontal intelligence)的主要原因:它不會被綁定在固定的工具清單上,而是能隨時隨地打造它所需的工具。

這一切的基礎是讓 LLM 完全存取沙盒。我們沒有給模型一套靜態的語言和 CLI 工具,並限制其對檔案系統的存取,而是給予它對所有資源的完全存取權。它以 root 權限執行。雖然我們的沙盒預裝了 Node 和 Python 等常見執行環境,但如果某個服務 API 的最佳 SDK 是用 Go 語言編寫的呢?模型可以直接安裝並執行它。

Sean Smith - inline image

LLM 需要編寫 Go 程式嗎?儘管安裝 Go 並執行它吧。

那麼,如果我們允許模型安裝任何它想要的軟體,並執行未經人工驗證的程式碼,我們該如何確保安全呢?幸運的是,我們並非第一批需要執行不受信任程式碼的人。目前有兩個非常熱門的安全執行環境正是為此而生:gVisorFirecracker。我們目前的旅程讓我們對兩者都非常熟悉。

從 gVisor 到 Firecracker

我們首次嘗試為 LLM 建立安全沙盒時採取了「簡單」的方法:在 GKE(Google Kubernetes Engine)上使用 GKE Sandbox 運行每個 gVisor 沙盒。由於我們所有的其他服務都已經在 GKE 上運行,這對我們來說是自然而然的一步。

gVisor 位於容器與主機核心之間。它不會讓程式直接對真實的 Linux 核心發出系統呼叫(這是你最不希望不受信任的程式碼觸碰的地方),而是會在自己的使用者空間核心中攔截這些呼叫並自行處理。你既能獲得普通容器的便利性,又能擁有小得多的攻擊面。GKE Sandbox 將這一切封裝起來。你部署 Pod(容器),它們就會透明地在 gVisor 下運行,而我們幾乎不需要進行任何基礎設施配置。

起初,這種方式運作得非常好。我們將「基礎」沙盒定義為 Docker 映像檔,並讓 GKE 根據我們在任何時間點所需的沙盒數量進行擴展。更新沙盒所搭載的軟體,只需簡單地更新 Dockerfile 並在清單中增加版本號即可。

Sean Smith - inline image

數百個在 GKE Sandbox 下運行的沙盒 Pod。

但讓 gVisor 變得簡單的抽象化過程,正是我們不斷抗爭的地方。由於 gVisor 在使用者空間重新實作了 Linux 系統呼叫介面,並非所有東西的行為都與真實核心完全一致,而且我們的模型所構想的工作負載是極其不可預測的。這種為了安全而進行的攔截,在系統呼叫頻繁和 I/O 密集型任務中會付出效能代價。此外,依賴 GKE 來處理整個生命週期,意味著我們最想控制的部分——開機時間、打包密度、網路以及我們回收機器的積極程度——反而是我們控制力最弱的部分。上面那個孤零零的 OutOfcpu Pod,就是當你過度壓榨別人的排程器時會出現的情況。

這就是推動我們轉向 Firecracker 的原因。

Firecracker 微型虛擬機(microVM)是真正的虛擬機,每個都有自己的客體核心,透過硬體虛擬化運行,但經過精簡,只需幾毫秒即可啟動,且僅佔用幾 MB 的開銷。這正是 AWS 用來將大量 Lambda 和 Fargate 工作負載打包到共享硬體上的相同技術。它為我們提供了比共享核心更強的隔離邊界,啟動速度快到感覺像是瞬間完成,而且體積小到可以在單一主機上打包許多個。

代價是 Firecracker 只給你一個虛擬機,除此之外什麼都沒有。沒有 GKE 風格的層來處理排程、網路和生命週期編排。所以我們自己建立了一個,我們稱之為 orc。

rootfs 只是個映像檔

在放棄容器的過程中,我們不想放棄的一件事就是將沙盒定義為普通的 Dockerfile。容器讓這件事變得輕而易舉;而傳統的虛擬機則不然,因為微型虛擬機啟動的是根檔案系統,而不是 OCI 映像檔。

因此,orc 橋接了兩者。當它被要求建立一個虛擬機時,它會獲取一個普通的 Docker/OCI 映像檔,並即時產生虛擬機的根檔案系統,同時快取結果,以便後續啟動相同的映像檔時能快速完成。我們的基礎沙盒仍然只是一個 Dockerfile,而 orc 會在請求時將其轉換為可啟動的 rootfs。

這讓我們的開發流程與 GKE 時期保持一致:編輯 Dockerfile,發布新的沙盒,同時在底層運行真實的虛擬機。這也開啟了一扇我們才剛開始探索的大門。因為任何 OCI 映像檔都可以變成微型虛擬機,我們可以從預設映像檔以外的映像檔啟動沙盒。想要一個已經內建 Postgres 和 pgvector 的虛擬機嗎?將 orc 指向該映像檔,你就能得到一個獨立的機器。沙盒不再是一個單一的固定環境,而變成了「工作所需的任何映像檔,以獨立虛擬機的形式啟動」。

大規模執行

這就是讓問題變得真正困難的地方:每一場對話都有自己的沙盒。一場對話對應一台機器。在任何給定時刻,我們都有數千個沙盒處於活動狀態,而且這個數字從未靜止。每當有人開啟對話,沙盒就必須出現;每當對話閒置,沙盒就必須消失,這樣我們才不用為其付費。我們不斷地啟動和關閉沙盒。

兩個數字決定了一切:我們準備一個沙盒的速度有多快,以及我們能在單一主機上容納多少個沙盒。

啟動延遲。 Firecracker 微型虛擬機在幾百毫秒內即可啟動。這速度快到我們根本不需要保留預熱池,這是此次轉換中較少被提及的優勢之一。在 GKE 下,我們必須保留閒置容量來掩蓋啟動時間。有了 orc,一個全新的沙盒在使用者察覺到之前就已準備就緒,所以我們只需在對話開始時按需建立,並在對話結束時將其銷毀。不再需要維護或支付閒置池的費用。

密度。 由於每個微型虛擬機都很小,我們可以在一台實體主機上打包許多個。我們根據沙盒實際需要的 CPU 和記憶體來調整大小,而不是過度配置,這讓我們能以經濟實惠的方式運行數千個沙盒。

orc 本身刻意保持精簡。它是一個控制平面,使用簡單的 API:從給定的映像檔建立一個具有 N 個 vCPU 和 M MB 記憶體的虛擬機、將指令串流傳輸到其中、在內部讀寫檔案、為其加上標籤以便日後尋找,並在完成後將其刪除。每個客體系統都運行一個微小的 init 進程作為 PID 1,並擁有自己獨立的網路。這就是大部分內容。魔法不在於任何聰明的技巧,而在於這些基礎元件足夠枯燥且快速,足以支撐整個機群的運行。

所有這些基礎設施的成果就是我們最初提到的:一個可以安裝任何東西、編寫程式、呼叫 API,並在真實電腦上為你提供答案的模型。

一鍵儲存

使用 YouMind AI 深度閱讀爆款文章

保存原文、追問細節、總結觀點,並在一個 AI 工作空間裡把爆款文章沉澱成可複用筆記。

了解 YouMind
寫給創作者

把你的 Markdown 變成乾淨的 𝕏 文章

圖片上傳、表格、程式碼區塊,往 𝕏 上手動重排太痛苦。YouMind 把整篇 Markdown 一鍵轉成乾淨、可直接發佈的 𝕏 文章草稿。

試試 Markdown 轉 𝕏

更多可拆解樣本

近期爆款文章

探索更多爆款文章