前面幾篇從 ai-memory 看到 TeamAI,討論的是 Agent 怎麼保存經驗,以及團隊怎麼共享知識。但即使 Agent 記得「改票前要查票規」,重新開始工作時,昨天下載的報價、瀏覽器的登入狀態與工作檔案,還在嗎?
Rakazo 提供可以反覆交辦任務的 AI 助理,使用者透過網頁、桌面或手機介面請它做事,助理再操作瀏覽器、終端機與檔案。這篇以航空客服「小航」為例,先看一項任務如何執行,再說明為什麼 Rakazo 要把助理、工作電腦與保存資料的地方分開。
假設 Alice 建立航空客服「小航」,交辦:「登入航空後台,查詢這張機票的改票條件,把報價整理成檔案。」這件事需要幾個部分配合,不能只靠模型回答文字。
| 組成 | 在這個例子中負責什麼 |
|---|---|
| 使用介面 | Alice 建立小航、交辦任務、查看結果,必要時接手瀏覽器 |
| Bot與對話(Thread) | Bot 記錄小航的設定與指示,Thread 保存這次討論的內容 |
| 後端的 Agent 執行流程 | 呼叫模型、處理模型提出的工具操作,再把結果交回模型 |
| Computer | 提供實際操作的瀏覽器、桌面、終端機與檔案環境 |
| 資料保存 | 保存 Bot、對話與任務等資料,並另外保存電腦的工作目錄 |
Bot 是 Alice 建立、可以反覆使用的助理;Agent 執行流程則是這個助理收到任務後,實際呼叫模型與工具的過程。Computer 可以分配給單一 Bot,也可以讓多個 Bot 共用,所以建立兩個 Bot,不代表一定要準備兩台電腦。
Alice 送出要求後,Rakazo 後端啟動這次任務,把指示與對話交給模型。模型決定先開啟航空網站,後端便執行瀏覽器工具,在工作電腦上開啟網頁;工具回傳頁面內容或截圖,模型再根據結果決定下一步。
如果網站要求驗證碼,Alice 可以接手輸入。登入後,小航繼續查詢、下載 quote.csv,最後將結果回覆到對話。Alice 看見的聊天內容與電腦裡的報價檔,是兩種分開保存的資料。
下面是本文聚焦的架構關係,省略了認證、排程與審核等細節:

圖中的工作目錄保存由 Rakazo 的程式協調,不是電腦自行備份;使用 Docker 時,也可能直接掛載這個目錄。
模型呼叫與電腦操作有不同需求:呼叫模型需要對話、工具定義與模型連線;操作網站則需要瀏覽器、登入狀態與檔案。分開之後,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 與對話也要刪除。不過,「助理還在」並不保證「電腦裡的工作成果還在」,這正是下一部分要處理的問題。
小航已下載報價,也完成瀏覽器登入,任務結束後電腦被暫停。下次 Alice 再請它查詢時,原本的電腦可能還能使用,也可能已被回收,必須建立一台新的。
如果只保存對話,小航可能知道「上次下載了報價」,卻找不到報價檔。若瀏覽器資料也消失,Alice 還得重新登入。Rakazo 因此另外保存工作目錄,把需要留下的檔案與瀏覽器設定檔,和目前使用的電腦分開管理。
這份可保存的工作目錄稱為 Home。它與 Memory 的用途不同:Memory 保存供 Agent 讀取的知識;Home 保存電腦工作的資料,例如 quote.csv 與瀏覽器 Cookie。
對遠端電腦而言,這件事分成兩步:
所以匯入、匯出不是每次聊天都要做的前置動作,而是讓工作資料能跨電腦保留的機制。只要不同電腦服務遵循共同的檔案格式,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 與瀏覽器設定檔。但這個設計有三個限制:
預設 Home Store 也只保留最新工作目錄,能力宣告為 revisions: false。homeRevision 是保存版本的標記,不代表能任選歷史版本還原;若要保存多個歷史版本或改用物件儲存,需要擴充 Home Store。
小航的工作資料可以留下來後,下一個問題是:誰能使用它?假設 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 繼續點擊,操作也會互相干擾。
Rakazo 因此記錄哪個任務取得操作權,以及控制權何時到期。這份有期限的記錄稱為「租約」,資料表名稱是 ComputerExecutionLease,以電腦與 Bot 的組合區分。不同 Bot 可以同時工作,同一個 Bot 則透過租約協調,避免多個任務搶著操作。
使用者接手操作時,也要先取得畫面的控制權。小航透過 request_takeover 等待 Alice 輸入一分鐘有效的驗證碼時,Alice 可以取得該畫面的控制權;若 Bot 正在正常執行,Team 接手流程原則上會要求先停止 Bot,避免人和 Agent 同時控制同一個畫面。
這個例子中,驗證碼由 Alice 直接輸入瀏覽器,完成後釋放控制,小航再繼續查詢。需要登入的情境,並不要求把驗證碼先寫進聊天,也不需要重新建立 Bot;完成後能否繼續,仍取決於網站是否接受這次登入。
檔案共用解決的是「另一個 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 資料範圍的測試。這些測試呈現了程式預期的權限行為,本文未另外執行整套測試。
到這裡,小航已經能操作電腦、留下成果,也能與其他 Bot 協作。但「拿得到操作環境」與「允許執行改票」是兩回事。
例如查報價可能需要航空 API 的金鑰,正式改票則可能需要 Alice 核准。前者要避免金鑰直接暴露在模型輸入裡,後者要決定工具呼叫能否執行,Rakazo 因此分別處理憑證保管與動作核准。
如果直接把 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 操作瀏覽器,無法保證它點擊交易按鈕前一定會停下來詢問。
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 換電腦後仍能取回已保存的檔案。至於下一步做什麼,要看對話與任務紀錄;能否繼續登入,要看網站是否接受原本的登入狀態;是否允許改票,則要看工具的核准規則。