研究

打造雲端代理時,我們學到的事

Josh Ma閱讀時間 3 分鐘

一年前,當我們首次推出雲端代理時,它們看起來只是本機代理的自然延伸。從那之後,雲端代理的能力已大幅提升。

雲端代理現在可在各自專屬的虛擬機器上執行,擁有自己的環境、相依套件和網路存取。它們可以並行工作、在無人值守的情況下執行,並承擔比你筆電上的本機代理更長時間的任務。

這些能力也帶來了環境設定、可靠性和協調方面的挑戰;而當代理是在你的筆電上執行時,這些問題通常不會那麼明顯。

在這篇文章中,我們想分享打造雲端代理過程中最重要的幾個經驗,以及為什麼這項工作如今愈來愈不像是把本機代理移植到伺服器上,反而更像是在它周圍打造一層運作層。

開發環境就是產品本身

在過去一年裡,我們了解到,影響雲端代理輸出品質的最大因素,就是確保它擁有完整的開發環境,就像開發者一樣。

在本機端,這通常不太需要你特別操心,因為本機代理會直接沿用你筆電上現有的開發環境。在雲端,你必須從零開始重建這一切,而且令人意外的是,只要有一點沒做好,往往也很難察覺。

你通常不會看到當機或錯誤訊息;很多時候,唯一的跡象只是輸出品質些微下滑。你一開始可能不會注意到,就算注意到了,也可能會把原因歸咎於模型。

但我們一再追查後,最後總是得到同樣的結論:雲端代理缺少了執行或驗證其工作成果所需的環境。一年前,這件事還沒那麼重要,因為當時模型本來就不太會利用它們的環境。但隨著它們變得越來越聰明,環境設定已經成為決定它們能否發揮全部潛力的關鍵因素。

Cloud agents architectureCloud agents architecture

如今,要達到「完整環境」,需要重建多得令人意外的基礎架構:

  • 更好的使用者工具,用來打造代理環境
  • 能在訊息之間高效休眠及恢復代理 VM 的方法
  • 能快速且可靠地為 VM 影像建立檢查點、還原與分叉的流程
  • 緊密的 工具鏈 與用戶端整合,讓代理和人類都能理解這個環境,並與之互動

而隨著雲端代理承擔越來越多工作,它們也需要受控的網路存取,才能建立 PR (拉取請求) 、拉取相依套件,以及進行研究。隨著時間推移,我們最終打造出的,本質上就是給代理使用的企業 IT,具備敏感資訊遮蔽、網路政策和憑證管理等完整能力。

長時間運行代理需要持久執行

雲端代理面臨的可靠性挑戰,與本機代理不同。雲端代理不是在你的筆電上與其他程式爭奪本機資源,而是在各自獨立隔離的 VM 中運行。這讓開發者更容易並行執行大量代理,並委派那些經常需要數小時、而非幾分鐘就能完成的長時間任務。

但是,在 VM 中運行也更容易受到各種中斷影響,例如推論供應商停擺、pod 需要替換,以及 EC2 節點故障。

我們最初打造雲端代理時,採用了 work-stealing 架構,讓 worker 節點可以接手代理,並透過 loop 持續執行直到完成。這是把本機環境有效的做法移植到伺服器上,但這套設定相當脆弱——我們早期的雲端代理 beta 版,可靠性往往只有一個 9。

原始雲端代理架構原始雲端代理架構

隨著雲端代理逐漸成熟,我們發現自己幾乎要重新打造許多 Temporal 已經解決好的持久執行基礎機制 (例如重試機制、跨機器排程工作,以及在節點故障下維持持久性) ,因此我們改為移轉到那裡。

目前基於 Temporal 的雲端代理架構目前基於 Temporal 的雲端代理架構

我們目前在 Temporal 上的代理迴圈,能夠撐過推論可靠性的短暫波動、pod 的休眠與恢復,以及橫跨數天甚至數週的執行。光是這次移轉,就讓我們的可靠性突破了兩個 9;而如今,Temporal 每天會在超過 700 萬個獨特工作流程中處理超過 5,000 萬次動作。在內部,超過 40% 的 PR (拉取請求) 來自雲端代理,而且這個比例還在持續成長。

隨時間推移,來自雲端代理並合併到 Cursor monorepo 的 PR 百分比隨時間推移,來自雲端代理並合併到 Cursor monorepo 的 PR 百分比

隨著時間推移,我們也逐漸學會如何更妥善地設計 Temporal 工作流程。我們已從「永久」代理工作流程,轉向多個在完成單一任務後就會結束的較短工作流程,這讓版本升級變得更容易。隨著 async tool calls、子代理,以及推論供應商停擺改變了我們原本的底層假設,我們也將 activities 拆分出來,以便更妥善地處理逾時與重試。

雲端代理工作流程中每天的 Temporal 動作數雲端代理工作流程中每天的 Temporal 動作數

將代理與機器從對話狀態中解耦

雲端代理不再只是單一機器上執行的一個迴圈。相反地,代理可能在某一台機器上執行、在多台機器上啟動非同步子代理,或先在本機啟動,再把工作委派到雲端。子代理甚至可能比上層代理存活更久,或在完全不同類型的 pod 上執行。

代理、機器與對話狀態解耦的雲端代理迴圈代理、機器與對話狀態解耦的雲端代理迴圈

為了讓這種架構可行,我們發現,將代理迴圈、機器狀態和對話狀態維持為彼此解耦的元件非常重要。由於代理迴圈運行於 Temporal,而不是直接在 VM 上,我們就能獨立管理 pod 的生命週期,並讓代理在不同類型的 pod 之間執行——包括唯讀 VM、預熱 VM 等最佳化配置。

在對話層面上,我們將儲存和串流層從核心代理工作流程中拆分出來。我們打造了一套高效率的僅追加式儲存機制,可將對話更新串流到 Web 與桌面用戶端。這一層也納入了重試機制,因此如果代理迴圈中的某個步驟在串流部分輸出後失敗,之後又重新重試,用戶端就能偵測到這種情況、將串流倒回,並顯示新資料而非舊資料。

知道何時該讓開

雲端代理對話流程雲端代理對話流程

打造雲端代理工具鏈,意味著必須持續重新評估:哪些行為應該保持為確定性的,哪些該交由代理處理。

一開始,我們其實不太信任代理,所以工具鏈會在每項任務後再次檢查它的成果、強制建立提交,然後推送。隨著模型越來越聰明,我們開始把邏輯從工具鏈中移出,改放進由代理控制的工具裡。一年前,multi-repo 設定還需要寫死在工具鏈中的行為。現在,我們可以把儲存庫版面配置提供給代理,開放分支和 PR 的工具,讓它自行決定如何完成工作。

CI Autofix 也經歷了同樣的演變。先前版本的雲端代理工具鏈中,包含了抓取工作失敗日誌並寫入 VM 的邏輯。現在,我們只需要讓代理存取 GitHub CLI,並自動把大型輸出寫入它可以搜尋的檔案即可。給代理的通知簡化了許多,而且我們預期這個趨勢會持續下去。

工具鏈並不是要消失,而是它承載的內容正在改變。電腦操作就是目前一個很好的例子。我們的雲端代理工具鏈有一種專門用於電腦操作的 子代理 類型,具備自己的模型路由、自訂提示詞和螢幕錄製。VNC 和 Chrome 屬於環境的一部分,由父代理與 子代理 共用。這讓父代理也能直接使用它們,例如執行 Playwright 指令碼。我們使用這套鷹架,是因為模型還沒準備好完全獨立處理電腦操作,但是否要呼叫它,仍由代理決定。

雲端代理在工具鏈中也需要不同於本機代理的提示詞。我們會鼓勵它們更自主,因為卡住的代價高得多。在本機上,你知道代理何時停止並等待許可;但在雲端,它可能會就這樣停上好幾個小時,直到你回頭查看。

具自我修復能力的代理環境

展望未來,我們專注於跳脫「手把手帶著代理」與「完全放手不管」這種非此即彼的做法。更好的模式,是提供代理工具,讓它能理解周遭的系統。

我們希望雲端代理能在缺少機密資訊、網路存取遭到封鎖,或環境以其他方式阻礙進展時主動回報,接著還能以自我修復的方式採取行動。在一篇近期的研究部落格中,我們談到了一條實現這件事的路徑,我們稱之為「autoinstall」。

雲端代理在過去短短幾個月內已有大幅改進,而我們預期這種變化的速度只會持續加快。Cursor 雲端代理讓團隊無需打造或維護底層基礎架構,也能充分利用這片廣泛的能力空間。

分類於: 研究

作者: Josh Ma