iT邦幫忙

2026 iThome 鐵人賽

DAY 22
0
AI Engineering

30天拆Agent:從Repo看設計系列 第 22 篇

Day 22|Rakazo:Agent 工作到一半,電腦、登入狀態與權限怎麼留下來?

  • 分享至 

  • xImage
  •  

前面幾篇從 ai-memory 看到 TeamAI,討論的是 Agent 怎麼保存經驗,以及團隊怎麼共享知識。但即使 Agent 記得「改票前要查票規」,重新開始工作時,昨天下載的報價、瀏覽器的登入狀態與工作檔案,還在嗎?

Rakazo 提供可以反覆交辦任務的 AI 助理,使用者透過網頁、桌面或手機介面請它做事,助理再操作瀏覽器、終端機與檔案。這篇以航空客服「小航」為例,先看一項任務如何執行,再說明為什麼 Rakazo 要把助理、工作電腦與保存資料的地方分開。

1. 先認識 Rakazo:Bot、執行流程與Computer各做什麼?

假設 Alice 建立航空客服「小航」,交辦:「登入航空後台,查詢這張機票的改票條件,把報價整理成檔案。」這件事需要幾個部分配合,不能只靠模型回答文字。

組成 在這個例子中負責什麼
使用介面 Alice 建立小航、交辦任務、查看結果,必要時接手瀏覽器
Bot與對話(Thread) Bot 記錄小航的設定與指示,Thread 保存這次討論的內容
後端的 Agent 執行流程 呼叫模型、處理模型提出的工具操作,再把結果交回模型
Computer 提供實際操作的瀏覽器、桌面、終端機與檔案環境
資料保存 保存 Bot、對話與任務等資料,並另外保存電腦的工作目錄

Bot 是 Alice 建立、可以反覆使用的助理;Agent 執行流程則是這個助理收到任務後,實際呼叫模型與工具的過程。Computer 可以分配給單一 Bot,也可以讓多個 Bot 共用,所以建立兩個 Bot,不代表一定要準備兩台電腦。

一次查詢如何走過這些部分?

Alice 送出要求後,Rakazo 後端啟動這次任務,把指示與對話交給模型。模型決定先開啟航空網站,後端便執行瀏覽器工具,在工作電腦上開啟網頁;工具回傳頁面內容或截圖,模型再根據結果決定下一步。

如果網站要求驗證碼,Alice 可以接手輸入。登入後,小航繼續查詢、下載 quote.csv,最後將結果回覆到對話。Alice 看見的聊天內容與電腦裡的報價檔,是兩種分開保存的資料。

下面是本文聚焦的架構關係,省略了認證、排程與審核等細節:

https://ithelp.ithome.com.tw/upload/images/20261005/20178568bBCmXZhXx9.png

圖中的工作目錄保存由 Rakazo 的程式協調,不是電腦自行備份;使用 Docker 時,也可能直接掛載這個目錄。

為什麼讓 Agent 與電腦分開?

模型呼叫與電腦操作有不同需求:呼叫模型需要對話、工具定義與模型連線;操作網站則需要瀏覽器、登入狀態與檔案。分開之後,Rakazo 可以保留同一個 Bot 與對話,另外啟動或替換它使用的工作電腦。選擇模型服務時,也不必連帶更換保存檔案的環境。

Rakazo 使用 Pi 執行 Agent 流程,Pi 在 Rakazo 後端運作,再透過工具操作 Computer。Computer 可以使用本機 Docker,也可以使用遠端電腦服務;其中 E2B 是遠端服務的例子。

這個分工可以從 packages/adapters/src/pi-runtime.ts 看出:Agent 的 Session ID 由對話與 Bot 組成,並未使用電腦 ID。

sessionId: conversationSessionId(request.threadId, request.botId),

因此,電腦被停止,不代表 Bot 與對話也要刪除。不過,「助理還在」並不保證「電腦裡的工作成果還在」,這正是下一部分要處理的問題。

2. 為什麼需要匯出、匯入工作目錄?因為下次可能不是同一台電腦

小航已下載報價,也完成瀏覽器登入,任務結束後電腦被暫停。下次 Alice 再請它查詢時,原本的電腦可能還能使用,也可能已被回收,必須建立一台新的。

如果只保存對話,小航可能知道「上次下載了報價」,卻找不到報價檔。若瀏覽器資料也消失,Alice 還得重新登入。Rakazo 因此另外保存工作目錄,把需要留下的檔案與瀏覽器設定檔,和目前使用的電腦分開管理。

這份可保存的工作目錄稱為 Home。它與 Memory 的用途不同:Memory 保存供 Agent 讀取的知識;Home 保存電腦工作的資料,例如 quote.csv 與瀏覽器 Cookie。

先保存成果,再讓新電腦取回

對遠端電腦而言,這件事分成兩步:

  1. 匯出:從目前的電腦取出工作目錄裡的檔案,交給 Rakazo 保存。
  2. 匯入:需要換電腦時,把已保存的檔案載入新電腦。

所以匯入、匯出不是每次聊天都要做的前置動作,而是讓工作資料能跨電腦保留的機制。只要不同電腦服務遵循共同的檔案格式,Rakazo 就能用相同方式保存與還原,不必依賴某家服務專用的虛擬機快照。

負責串接電腦環境的介面叫做 SandboxProvider,定義在 packages/adapter-kit/src/interfaces.ts。前一節提到的啟動、停止與操作電腦,以及這裡的匯出、匯入,都是它要求實作的能力。以下節錄兩個方法:

exportWorkspace(
  computer: ComputerRef,
  context: AdapterContext,
): AsyncIterable<PortableFile>;
importWorkspace(
  computer: ComputerRef,
  files: AsyncIterable<PortableFile>,
  context: AdapterContext,
): Promise<void>;

exportWorkspace() 交出檔案,importWorkspace() 接收檔案;它們服務的目的,是讓工作成果不必跟著舊電腦一起消失。若開發者要串接新的電腦服務,就需要實作這些操作,而非只填入服務名稱。

怎麼知道該載入哪一份資料?

Rakazo 分別記錄目前電腦的識別資訊,以及保存工作目錄的識別資訊。這樣即使電腦換了,也能找到原本的資料。

packages/db/prisma/schema.prisma 的 Computer 包含以下欄位:

homeKey      String  @unique
homeRevision String  @default("empty")
kind         String
providerRef  String?
state        String  @default("stopped")

其中 providerRef 記錄目前電腦的識別資訊,homeKey 用來找到已保存的工作目錄。當電腦服務回報新機器、電腦 ID 改變,或換用另一種電腦環境,程式就會載入對應的工作目錄;這一步由固定條件判斷,不需要模型猜測。

程式位置是 packages/adapters/src/computer-lifecycle.ts,以下節錄判斷與還原流程:

const replacement =
  ref.fresh === true ||
  !existing.providerRef ||
  existing.providerRef !== ref.providerRef ||
  existing.kind !== ref.kind;
if (replacement) {
  await onProgress?.("restoring");
  await restoreComputerWorkspace(
    deps.home, deps.sandbox, existing.homeKey, ref, context,
  );
}

負責保存目錄的介面是 AgentHomeStore。預設本機實作位於 packages/adapters/src/home.ts,檔案放在 DATA_DIR/homes/<computer-home-key>,保存版本的標記放在 DATA_DIR/home-revisions。

為什麼要選保存時機,不能直接隨時複製?

瀏覽器可能正在更新 Cookie 或設定檔資料庫,其他 Bot 也可能正在寫入同一份共享資料。如果此時直接複製,可能得到尚未寫完或前後不一致的內容。

Rakazo 將一次工作目錄的保存稱為 Checkpoint。官方文件列出的時機包括任務完成或失敗、明確停止電腦,以及閒置暫停之前。遠端匯出前會先讓瀏覽器停止活動;共用電腦若還有其他 Bot 或使用者正在操作,也會延後保存,等最後一個任務完成或電腦閒置時再處理。

相關流程在 packages/adapters/src/computer-workspace.ts。其中 checkpointComputerWorkspace() 把匯出的檔案寫入暫存目錄,再交給 Home Store 保存;checkpointRunComputerWorkspace() 則檢查共用電腦是否仍有人使用。

Docker 搭配本機 Home Store 時,做法更直接:容器已掛載 Rakazo 管理的目錄,檔案就在這裡,不必重新複製全部內容,保存時只更新版本標記。

還原工作目錄,能接回哪些東西?

小航完成報價並成功保存後,即使舊電腦被回收,新電腦仍可以取回 quote.csv 與瀏覽器設定檔。但這個設計有三個限制:

  • 登入可能已過期。 Cookie 能保存,網站是否仍接受它則由網站決定;失效時,Alice 仍須重新登入。
  • 執行中的程式不會原地續跑。 保存範圍是工作目錄,未包含記憶體、執行中的程序或整套作業系統。目錄外的系統套件要另外準備。
  • 保存之後的新變更仍可能丟失。 Checkpoint 並非每次操作都同步備份,遠端電腦若在下次保存前永久消失,最近的資料仍可能遺失。

預設 Home Store 也只保留最新工作目錄,能力宣告為 revisions: false。homeRevision 是保存版本的標記,不代表能任選歷史版本還原;若要保存多個歷史版本或改用物件儲存,需要擴充 Home Store。

3. 對話分開了,檔案與瀏覽器也分開了嗎?

小航的工作資料可以留下來後,下一個問題是:誰能使用它?假設 Alice 和 Bob 在同一個工作空間(Space)建立不同的 Bot,他們可能想共用票規摘要,卻不想共用旅客名單與登入帳號。

Rakazo 提供共用與獨立電腦兩種安排。共用電腦讓多個 Bot 直接使用同一份工作資料;需要分開檔案與登入資源時,則應使用獨立電腦。這項選擇與「是否分開聊天」不同,因此必須分別檢查對話、記憶與電腦的存取範圍。

資源 原始碼中的處理方式 實際用途
Space SpaceMember 綁定 Space、組織與使用者 記錄誰是這個工作空間的成員
Bot/Thread Bot 有 spaceId、userId,並關聯 Thread 記錄 Bot 與對話屬於誰
BotSection 綁定 spaceId、userId,用於整理 Bot 整理介面上的 Bot,不限制電腦存取
Memory 查詢帶入 Space、使用者、scope 與選用 Bot 記憶的讀取範圍
Computer scope 區分共用或獨立電腦 檔案與作業系統的共享方式
憑證/Approval 另有使用者與 Space 等綁定欄位 分別管理憑證與核准規則

這張表的依據在 packages/db/prisma/schema.prisma。Schema 告訴我們資料怎麼關聯,但真正的存取限制還要看查詢與 API,不能只看到 userId 欄位就宣稱所有東西都互相隔離。

共用電腦裡,檔案可共享,瀏覽器設定檔各自保存

例如,小航查完票規後,票規助理也要使用這份摘要。如果兩個 Bot 共用電腦,便能直接讀取同一個檔案,省去把檔案內容貼回聊天、再交給另一個 Bot 的步驟。

官方 Computer 文件定義,工作空間預設使用共用電腦(Team Computer),各 Bot 的工作檔案放在 bots/<bot-id>/,刻意共享的檔案放在 shared/。程式也會建立這兩類目錄,方便整理工作。

路徑解析在 packages/adapters/src/computer-support.ts。相對路徑通常會落到 Bot 目錄,但明確指定共享根目錄時,可以操作 Team 的其他位置。這是一套工作整理規則,Team Bot 可以存取整個 Team workspace,把檔案放在 bots/alice/,並不會阻止其他 Bot 讀取。

例如,小航把公開票規摘要放在 shared/fare-rules.md,同一台 Computer 的另一個 Bot 可以讀取它,不必透過模型轉述檔案內容。反過來,如果 Alice 的旅客名單不能讓其他 Bot 接觸,只把檔案放進小航的資料夾仍不夠,需要改用獨立 Computer。

共享檔案有利於協作,但瀏覽器若也使用同一份設定檔,一個 Bot 登入或登出,就可能改變另一個 Bot 的登入狀態。因此瀏覽器採用不同的安排:每個 Team Bot 有自己的操作畫面、Chrome 程序與可保存的瀏覽器設定檔,設定檔綁定各自的 Bot,即使重新分配畫面位置,也會使用原本的 Cookie。停止使用桌面時會關閉程序,但保留設定檔,下次打開仍使用原本那份。

這可以讓小航與票規助理各自操作瀏覽器,不互相覆蓋正常瀏覽操作產生的登入狀態。然而,Team Bot 仍共用 OS 使用者,也能透過 Shell 接觸同一台 Computer 的資源。官方文件因此明確指出:真正限制資源存取的是容器;分開瀏覽器設定檔、分配畫面控制權,主要是避免操作互相干擾。

用有期限的控制權,避免人與 Bot 同時操作

即使瀏覽器分開,同一個 Bot 若同時收到兩項任務,也可能出現一邊切換頁面、另一邊還在填表的衝突。使用者接手時,若 Bot 繼續點擊,操作也會互相干擾。

Rakazo 因此記錄哪個任務取得操作權,以及控制權何時到期。這份有期限的記錄稱為「租約」,資料表名稱是 ComputerExecutionLease,以電腦與 Bot 的組合區分。不同 Bot 可以同時工作,同一個 Bot 則透過租約協調,避免多個任務搶著操作。

使用者接手操作時,也要先取得畫面的控制權。小航透過 request_takeover 等待 Alice 輸入一分鐘有效的驗證碼時,Alice 可以取得該畫面的控制權;若 Bot 正在正常執行,Team 接手流程原則上會要求先停止 Bot,避免人和 Agent 同時控制同一個畫面。

這個例子中,驗證碼由 Alice 直接輸入瀏覽器,完成後釋放控制,小航再繼續查詢。需要登入的情境,並不要求把驗證碼先寫進聊天,也不需要重新建立 Bot;完成後能否繼續,仍取決於網站是否接受這次登入。

同一個 Space,也不等於所有人的 Memory 自動共用

檔案共用解決的是「另一個 Bot 能不能讀到這份檔案」,記憶管理處理的則是「這次任務可以讀取誰的知識」。例如 Bob 想查共用票規,不代表他也應該取得 Alice 的個人偏好。

Rakazo 的預設記憶讀取會檢查工作空間、使用者與記憶範圍,必要時再限定 Bot 或文件路徑。這些條件出現在 packages/memory/src/index.ts 的 MarkdownMemoryStore.read():

where: {
  spaceId: context.spaceId,
  userId: context.userId,
  scope: request.scope,
  ...(request.botId ? { botId: request.botId } : {}),
  ...(request.path ? { path: request.path } : {}),
},

讀取時仍限制 context.userId,因此不能因為 Alice、Bob 在同一個 Space,就推導成 Bob 會讀到 Alice 全部的個人記憶。若要讓兩三人共用航空客服知識,需要另外決定知識存在哪裡,以及誰可以讀取。

記憶搜尋的做法是:它先取得範圍內文件,將查詢轉成小寫,再用 includes() 比對內容或路徑,找到的結果一律回傳 score: 1。這是字串搜尋,沒有使用向量來判斷語意相似度或排序。保存時則用資料庫交易更新文件、增加版本號,再建立 MemoryRevision 修訂紀錄。expectedRevision 可用來檢查文件是否已被其他操作改過,避免覆蓋別人的更新。

與其說 Rakazo 有「多人記憶」,更精確的說法是:哪些記憶能被讀取、哪些電腦檔案可以共享,是兩套不同的設定,需要分別確認。

Repo 的 packages/testkit/src/authorization.test.ts 也包含跨使用者資源存取、同一 Space 中的個人 Approval 規則,以及切換 Space 後 Computer 資料範圍的測試。這些測試呈現了程式預期的權限行為,本文未另外執行整套測試。

4. 金鑰由後端保管,哪些操作要核准則另外設定

到這裡,小航已經能操作電腦、留下成果,也能與其他 Bot 協作。但「拿得到操作環境」與「允許執行改票」是兩回事。

例如查報價可能需要航空 API 的金鑰,正式改票則可能需要 Alice 核准。前者要避免金鑰直接暴露在模型輸入裡,後者要決定工具呼叫能否執行,Rakazo 因此分別處理憑證保管與動作核准。

Bot 提供金鑰名稱,後端取出金鑰並送出請求

如果直接把 API Key 貼進聊天,這個值就會成為對話內容。Rakazo 提供另一種流程:Bot 告訴使用者需要哪個服務的憑證,使用者在專用輸入卡片提交,後端加密保存;之後 Bot 只用名稱引用,真正的金鑰由後端取出、加入 API 請求。

官方 docs/bot-secrets.md 將索取憑證的工具稱為 request_secret。Bot 要指定憑證名稱、服務網址的來源(origin,也就是協定、主機名稱與連接埠)及認證方式。後端將憑證加密保存到 bot_secrets,並綁定使用者、Space 與 Bot,限制這份憑證的使用範圍。

下次呼叫 API,Bot 使用的參數可以是:

{
  "name": "flight_api",
  "url": "https://api.flight.example/v1/quotes",
  "method": "GET"
}

這是 secret_request 的情境示例,flight_api 代表已儲存的引用名稱,參數裡沒有真正的 Key。後端在 packages/adapters/src/bot-secrets.ts 檢查目的地:

const url = new URL(request.url);
if (url.origin !== destination.origin || url.username || url.password || url.hash) {
  return { error: "This credential cannot be sent to that destination." };
}
const plaintext = input.secretStore.load(row.ciphertext, row.id);

這段程式會檢查請求網址,拒絕把憑證送往不符合設定的目的地。符合限制後,後端解密、組合認證 Header,再送出請求;回傳內容也會過濾服務可能回傳的金鑰,包括原值與常見編碼形式。

HTTP API 金鑰也不會直接放進任意由 AI 控制的終端機(Shell)或環境變數,避免 Bot 透過指令讀出金鑰。若 API 需要請求簽章、更新 OAuth 憑證或特殊通訊方式,官方建議撰寫 Connector Adapter,由專門的串接程式處理。

網站登入的處理方式不同:browser_act 的 fill_secret 可以把已儲存的帳密填入相同網站來源的欄位;一次性驗證碼、圖形驗證(CAPTCHA)與通行金鑰(passkey)則由使用者接手完成。網站帳密填進真實瀏覽器後,仍可能被能存取該瀏覽器的程序讀取,不能把「模型輸入中沒有密碼」理解成對惡意 Bot 的完整防護。

要求人工核准,需要設定明確規則

假設 Alice 允許小航查報價,但要求正式交易前先詢問。只在 Bot 指示中寫「改票前問我」,仍是讓模型自行遵循提醒;若要由工具執行流程檢查,就需要保存一條核准規則。

設定規則的 API 定義在 packages/contracts/src/rpc.ts,approvalRules.set 接受 effect、matchKind 與 matchValue。例如要指定某個航空 Connector 的操作需核准,可以透過 API 客戶端傳入以下示意資料;名稱須換成實際安裝的 Connector:

{
  "effect": "require_approval",
  "matchKind": "connector",
  "matchValue": "flight"
}

規則儲存後,由 packages/core/src/action-approval.ts 的 resolveActionApprovalDetail() 比對。針對個別工具的規則優先,其次是服務串接(Connector)的規則,最後才是操作類別;同一層若同時有「允許執行」與「要求核准」,就採用「要求核准」。網頁的 ApprovalRulesSettings.tsx 也透過同一套 API 保存設定。

設定後仍要確認實際執行的工具是否命中這條規則:核准範圍取決於工具、Connector 與操作類別,不是模型從聊天中理解的「改票」兩個字。

會改動資料的工具,不一定會先要求核准

這裡需要區分兩件事:程式知道某個工具會改動資料,不代表執行時一定要求人工核准。Rakazo 還會看是否命中明確規則、是否啟用自動審核(Auto Review),以及有沒有設定審核器。

原始碼中,toolRequiresApproval() 負責辨識部分會改動資料或對外執行動作的工具,planActionGate() 則綜合設定,決定接著放行、審核或詢問。相關邏輯位於 packages/core/src/action-approval.ts 與 packages/adapters/src/executor.ts。

在本文版本中,沒有命中規則時,resolveActionApprovalDetail() 回傳的是 allow;工具會改動資料或執行對外動作,且已開啟 Auto Review、設定審核器時,才可能進入 judge,交給審核器判斷。Auto Review 結果可放行或轉為詢問,自動審核發生錯誤時,這類工具也會轉為詢問使用者。

另外,shell、computer_act、browser_act 等工具,在一般工具分類中列為免除審核的項目,不能宣稱每個電腦操作都會自動跳出核准卡片。特定路徑另有強制限制,例如 create_space 要求明確核准;外部 webhook 觸發時,會改動資料或執行對外動作的操作,也有更嚴格的核准要求。

這對航空客服尤其重要:如果小航透過瀏覽器點擊「確認改票」,不能因為那是業務上的重大操作,就推論框架會辨識按鈕含義並阻擋。開發者應在送出改票前加入確實會阻擋執行的核准步驟,或把改票交易做成專用工具,再設定核准規則。單靠 Agent 操作瀏覽器,無法保證它點擊交易按鈕前一定會停下來詢問。

5. 哪些改設定就好,哪些需要寫程式?

Rakazo 提供現成產品介面與自架流程,但航空客服的業務工具、票規判斷與交易核准仍要自行整合。從前面的分工來看,部署設定負責選擇與保存環境,Bot 指示負責交代工作,核准規則負責限制操作;接上新的電腦服務,則需要寫串接程式。常見需求可以從以下位置調整:

想調整的事情 從哪裡開始 調整種類
選擇本機 Docker 或遠端電腦 .env 的 SANDBOX_PROVIDER 與對應憑證 部署設定
保留工作檔案與瀏覽器設定檔 DATA_DIR 與掛載可保留資料的目錄 部署設定,另須備份
限制 Docker 同時開啟的桌面 SANDBOX_TEAM_SCREEN_LIMIT,0 表示不設此上限 部署設定
指定 Bot 任務與口吻 Bot 的 instructions Prompt,不能取代權限檢查
共享檔案或使用獨立電腦 Team/Private Computer;程式中的模式為 team/dedicated 產品設定
指定工具需要核准 approvalRules.set 的三個欄位 執行規則
串接新的電腦服務,或改變工作目錄的儲存方式 SandboxProvider/AgentHomeStore 程式擴充

不同電腦環境支援的工具也可能不同。例如直接讀取網頁文字、操作按鈕與欄位的 pageBrowser 是選用功能,Docker 已實作,其他服務需要另外支援;若使用截圖與桌面操作,模型也要能理解圖片。

自行部署時,可以使用官方提供的容器映像與安裝腳本,不必先安裝 Node 或編譯 Repo:

mkdir -p rakazo
cd rakazo
curl -fsSLO https://raw.githubusercontent.com/elie222/rakazo/main/infra/compose/install-images.sh
bash install-images.sh

依官方 README,安裝前需要準備 Docker Engine、Compose plugin、curl 與 OpenSSL,安裝程式會下載 Compose 檔案、產生服務所需的隨機金鑰並啟動服務。接著開啟 http://127.0.0.1:5173、建立帳號、連接模型,本機 Docker Computer 預設啟用。這是官方提供的安裝入口,實際版本與環境需求應再對照 References 的自架文件。

若要讓 Alice、Bob 隨時使用這套服務,後端須持續運作,並保留 PostgreSQL 與 DATA_DIR。只備份聊天資料庫,無法涵蓋 Computer Home 的檔案與瀏覽器設定檔;只保留 Home,也不會得到完整的 Bot、Run 與權限資料。

至於兩三人共用的航空客服,應先確定共享的是票規、任務成果,還是可操作的登入帳號。Team Computer 適合刻意共享工作目錄;需要隔離旅客資料與登入資源時,應使用分開的 Computer,並檢查每一條 API、Memory 與工具的授權範圍。BotSection 只負責整理介面,不會替檔案、登入狀態或記憶設定存取權限。

Rakazo 分別管理對話、工作目錄、執行中的電腦與操作權限,讓 Bot 換電腦後仍能取回已保存的檔案。至於下一步做什麼,要看對話與任務紀錄;能否繼續登入,要看網站是否接受原本的登入狀態;是否允許改票,則要看工具的核准規則。

References


上一篇
Day 21|TeamAI CLI:不同 Agent,怎麼共用同一套 Skill、Memory 與工作方式?
下一篇
Day 23|OpenDots:讓 AI 助理整理文件,也能操作獨立的瀏覽器與執行環境
系列文
30天拆Agent:從Repo看設計 共 23 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言