Skip to content
Greg's Space
Go back

什麼是 FilesystemMiddleware?

如果你有一個 AI 助理,你希望它不只會「講話」,還能真的幫你做事——讀檔案、寫檔案、甚至自己跑一段程式碼試試看結果對不對——FilesystemMiddleware 就是讓這件事發生的東西。

先想像一個情境

假設你交了一個超聰明的新朋友,他什麼都懂,問他什麼都答得出來。但有一個問題:他被關在你家門外,完全進不來。

他可以隔著門跟你說「你應該去翻一下抽屜裡的筆記本」,但他自己沒辦法伸手去翻——因為他沒有鑰匙。

這就是一個「沒有工具」的 AI 助理的狀態:它只能用講的,沒辦法真的動手做事。

FilesystemMiddleware 就是那把鑰匙

FilesystemMiddleware 做的事情很簡單:給這個朋友一把鑰匙,讓他可以真的走進你家做事,而不是只能隔著門講話。

拿到鑰匙之後,他可以做的事情大概有這幾種(想成家裡的各種行為):

能力代號白話翻譯
ls看看房間裡放了哪些東西(列出檔案清單)
read_file拿起一張紙條來讀(讀取檔案內容)
write_file寫一張新的紙條(建立新檔案)
edit_file修改已經寫好的紙條內容(編輯檔案)
delete把某張紙條丟進垃圾桶(刪除檔案)
glob在一堆東西裡找「名字長得像某個樣子」的(用檔名規則搜尋)
grep翻遍所有紙條,找裡面有寫到某個關鍵字的那幾張(全文搜尋)
execute自己動手做個小實驗,看看結果會怎樣(執行程式碼)

在程式碼裡面,這件事只需要一行就能設定好:

from deepagents.backends import LocalShellBackend
from deepagents.middleware import FilesystemMiddleware

execute_middleware = FilesystemMiddleware(backend=LocalShellBackend(), tools=["execute"])

這一行的意思是:「給這個 AI 朋友一把鑰匙,但只開放 execute 這一種能力——他可以自己動手做實驗(跑程式碼),但不能翻我的抽屜(讀寫檔案)、也不能亂丟東西(刪檔案)。」

為什麼不乾脆全部都給他?

想像一下:你剛認識一個新朋友,你會直接把整棟房子的鑰匙都給他,讓他想進哪個房間就進哪個房間嗎?大部分人應該不會,對吧?比較合理的做法是——他現在需要用到哪個房間,就先只給那個房間的鑰匙。

這就是為什麼上面那行程式碼裡,tools=["execute"] 只寫了一個。這個 AI 助理現在的任務只是「幫忙跑一下程式碼」,所以就只給它「執行」這一把鑰匙,其他像是刪檔案、改檔案的鑰匙都先收著,之後真的需要了再開放。

那 LocalShellBackend 又是什麼?

回頭看一下那行程式碼:

FilesystemMiddleware(backend=LocalShellBackend(), tools=["execute"])

FilesystemMiddleware 只負責回答「允許做哪些事」——決定要給幾把鑰匙、哪幾把。但光有鑰匙的種類還不夠,還要有人告訴你「這把鑰匙實際上開的是哪一間房子」,這件事就是 LocalShellBackend 在負責的。

換句話說:FilesystemMiddleware 是規則制定者,LocalShellBackend 才是真正動手做事的人。

為什麼特別強調「Local」?

因為這種「動手做事的人」其實不只一種,deepagents 提供好幾種不同的「房子」可以選,LocalShellBackend 只是其中一種——它開的門,通往的是你自己這台電腦的真實房子。

想像一下差別:

這就是為什麼用 LocalShellBackend 要特別小心——它名字裡的「Local」,就是在告訴你「這不是樣品屋,這是你家本人」。

LocalShellBackend() 括號是空的,代表沒設定嗎?

不是喔。LocalShellBackend() 雖然括號裡什麼都沒寫,但它其實有 6 個參數,每一個都幫你先填好了預設值——空括號的意思是「用預設值」,不是「什麼都沒有」。

用交朋友的比喻來說:你朋友拿到鑰匙走進你家,就算你沒特別交代任何規矩,他心裡其實也自動有一套「預設規矩」——例如「先站在玄關,不要亂跑」「借用廚房最多只能用 2 分鐘」。下面把這 6 條「預設規矩」跟怎麼修改,一條一條用生活例子講給你聽:

1. root_dir——他一進門,要先站在哪個房間?

預設值:None,意思是「你執行指令的當下,人站在哪個資料夾,他就從那個資料夾開始活動」。

生活例子:就像你朋友一進你家門,預設就站在玄關,而不是自動跑去你的書房。如果你希望他一進門就直接站在書房裡,你可以自己指定:

LocalShellBackend(root_dir="/home/xxx/我的書房")

2. virtual_mode——他能不能用逃生梯跑到別的樓層?

預設值:True,意思是「幫檔案讀寫類的動作(讀紙條、寫紙條)畫一條線,不准超出 root_dir 這個房間」。

生活例子:就像貼了一張告示「本樓層訪客禁止使用逃生梯(..)跑到別的樓層」。但這張告示只貼在「翻抽屜、拿紙條」的門上,沒有貼在「做實驗」(execute)的門上——這是最容易搞混的地方,後面會單獨講。

3. timeout——借他用一次东西,最多能用多久?

預設值:120 秒(2 分鐘),意思是「他做一件事,最多讓他忙 2 分鐘,時間到就強制喊停」。

生活例子:就像你說「廚房借你用,但瓦斯我最多開 2 分鐘,時間到我自動關掉」,避免他卡在裡面出不來、一直佔用你的廚房。想讓他忙久一點,可以自己改:

LocalShellBackend(timeout=300)  # 改成 5 分鐘

4. max_output_bytes——他做完實驗,最多能寫多長的報告給你?

預設值:100000 bytes(約 10 萬字元),意思是「他做完事情要跟你回報結果,結果太長的話,超過的部分會被直接剪掉」。

生活例子:就像你只給他一張紙讓他寫實驗報告,寫滿了紙,後面想寫的字就寫不下、被截斷了。

5. env——他做實驗需要的材料,你有先準備好嗎?

預設值:None,意思是「預設沒有先準備任何材料給他,是空的」。

生活例子:就像做化學實驗需要的藥水、器材,預設一樣都沒幫他準備。如果他需要用到某個特定材料(環境變數),你要自己列清單給他:

LocalShellBackend(env={"PATH": "/usr/bin:/bin"})

6. inherit_env——你家的秘密,會自動被他知道嗎?

預設值:False,意思是「你自己電腦裡原本設定好的那些秘密資訊(例如密碼、API key),預設不會自動被他繼承拿走」。

生活例子:就像你家客廳的保險箱密碼,不會因為朋友進了你家就自動知道——除非你明確說「好啦,你可以繼承我家全部的東西」:

LocalShellBackend(inherit_env=True)

⚠️ 最容易誤會的陷阱:virtual_mode 管不到 execute

前面第 2 點提到的「逃生梯告示」,只貼在「翻抽屜、拿紙條」這幾道門上(read_file/write_file/edit_file/delete/glob/grep),完全沒有貼在「做實驗」這道門上(execute)。

也就是說,就算你設了 virtual_mode=True(預設值),只要開放了 execute 這個能力,朋友一樣可以在你家任何角落做實驗——這條「不准跑出這個房間」的規矩,對「做實驗」這件事完全沒有約束力。如果你像我們的範例一樣只開了 tools=["execute"],virtual_mode 這個設定其實完全沒有發揮作用,因為根本沒開放任何一個會被它管到的能力。

不過要講精確一點:不是全部 6 個設定都被 execute 繞過,只有跟「路徑」有關的那兩個會被繞過,其他跟「這件事本身怎麼被執行」有關的設定,還是有效的:

設定管的是什麼對 execute 有效嗎?
root_dir他能去哪些地方❌ 會被繞過,execute 可以存取任何路徑
virtual_mode禁不禁止用逃生梯跑出房間❌ 會被繞過,對 execute 完全沒有約束力
timeout這件事最多讓他忙多久✅ 一樣有效,時間到照樣被強制中止
max_output_bytes報告最多能寫多長✅ 一樣有效,輸出太長照樣被截斷
env有沒有先準備材料給他✅ 一樣有效,沒給的材料他就是拿不到
inherit_env你家的秘密會不會自動被他知道✅ 一樣有效,不開 inherit_env=True 他就是不知道

用一句話記住這個區別:root_dir/virtual_mode 管的是「空間」(能去哪),execute 完全不受它們約束;但 timeout/max_output_bytes/env/inherit_env 管的是「這件事本身怎麼被執行」(多久、能講多少話、手上有什麼材料),這幾條規矩對 execute 一樣有效,不會被繞過。

一句話總結

FilesystemMiddleware 是一個「工具包」,負責把「讀寫檔案、執行程式碼」這些原本 AI 只能用嘴巴描述的動作,變成它真的可以動手做的能力,你可以自己決定要開放哪幾種能力給它;而 LocalShellBackend 則是決定「這些動作會真的發生在哪裡」——用它的話,答案就是:你自己的電腦。



Previous Post
文章標題
Next Post
什麼是 SummarizationMiddleware?