Supabase 怎麼讓 agent 看得懂、又可控制:一個為人設計的 Postgres 平台
「The main thing that we offer is the database. It’s a full-on Postgres database. It’s not abstractions.」(Paul Copplestone,Supabase CEO,Changelog #476,2022-01)
Supabase 現在的定位句是「The Postgres development platform」,首頁沒有提到 agent。但這兩年,AI builder 幾乎都把它當成預設後端,Lovable、Bolt.new、v0 生成的 app,資料庫多半開在 Supabase 上。Fortune 在 2025-10 的報導指出,AI builder 大約佔它三成的註冊;Supabase 自己公布的數字是每天超過 4 萬個新資料庫。
一個為人設計的平台,成了 agent 最常用的後端之一,而它沒有為 agent 重寫核心。核心還是那個 Postgres,Supabase 做的是在核心外面加一層:一半讓 agent 看得懂這個平台,一半讓 agent 被控制在安全的範圍裡。
這篇沿著這兩半走,每個設計都看它換到什麼、付出什麼。
讀完這篇,你會理解:
- Supabase 為什麼不為 agent 改核心,以及這個決定怎麼一路決定 agent 層的形狀
- 不改核心的前提下,Supabase 怎麼讓 agent 看得懂:介面、能力、文件各放在哪,以及 agent 為什麼還是不讀
- agent 拿到開發者的權限之後,平台怎麼用環境分離和 human-in-the-loop 控制它,以及留下的缺口
核心是 Postgres,所以不為 agent 改
Supabase 不只有一個 Postgres。它整合了 PostgREST(依 schema 自動產生 REST API)、Auth、Storage、Realtime、Edge Functions 等一整組服務,但這些服務的資料和權限規則都收斂在同一個 Postgres:使用者存在 auth.users 這張表,檔案的 metadata 放在 storage schema,誰能讀哪一列、哪個檔案,用 RLS(Row Level Security,Postgres 的列級權限規則)寫在資料庫裡。
這個形狀就是 Supabase 的賣點。執行長在 2025-01 接受創投 Felicis 訪談時說,他們一路把同一句話放進行銷、網站,甚至迷因裡:「It’s just Postgres. Supabase is just Postgres.」官方 Architecture 頁的產品原則,也把核心綁在標準的 Postgres 上。Everything works in isolation 的檢驗標準是「Can a user run this product with nothing but a Postgres database?」;Play the long game 舉的例子是不跑自己的 Postgres fork,缺什麼功能就推回上游;Everything is portable 寫的是「To avoid lock-in, we make it easy to migrate in and out.」,要搬走時 pg_dump 就帶得走。
所以 agent 來了,Supabase 不改核心,這是原則推出來的結果。在核心裡為 agent 加專屬的機制,Supabase 就不再「just Postgres」,不 fork、可攜這些承諾都會跟著破。
同一組原則也決定了 agent 層長什麼樣。這篇後面的每一節,都能對回一條原則:
| 原則 | 推出的 agent 設計 | 在哪一節 |
|---|---|---|
| Everything works in isolation | MCP 不放進核心,它跟 Dashboard 一樣只是一個 client。 | agent 沒有專屬通道 |
| Everything is portable | 出現標準就跟,Supabase 不自己發明 agent 協定。 | agent 沒有專屬通道 |
| Everything is extensible | 能力做成 Postgres extension,agent 的介面就是 SQL。 | 排程、佇列、密鑰,都是一句 SQL |
| Support existing tools | 文件鋪成多種格式,最舊的工具也讀得到。 | 量了才知道,agent 很少讀 skill |
這個選擇換到的是核心穩定、可攜、不被綁住。代價是核心不動,agent 需要的任何東西,都只能加在核心外面,或寫成 SQL。平台想提醒 agent 的話只能寫在 tool 說明裡,能力的用法要靠 agent 自己懂 SQL。
先看第一半:Supabase 怎麼讓 agent 看得懂這個平台。
agent 沒有專屬通道
Supabase 給 agent 的主要介面是 MCP server。它沒有放進平台核心,是一個獨立的 repo,透過 Management API 操作平台,跟 Dashboard、CLI 這些既有的 client 走同一條路。agent 能做的事,就是 Management API 開放的事。
連 Supabase 自己的 agent 也一樣。Dashboard 裡內建的 AI 助手,是用一般 MCP client 的身分連上同一個 hosted MCP server,而且固定以唯讀模式連線。Supabase 很重視 agent,但不給它特權:投入很多,在架構裡的位置跟其他 client 是同一層。
這個 MCP server 有 39 個 tool,分成 9 個 feature group:文件、帳號、資料庫、除錯、開發、Edge Functions、branching、storage、notebooks。分組讓使用者可以只開需要的部分。
把 MCP 放在核心外面,延續了 isolation 原則:MCP 只是另一個工具,平台的服務不需要知道 agent 存在。它也呼應 portable 原則裡一句平常不太會注意的話:「If a new standard emerges which competes with a “Supabase” approach, we will deprecate the approach in favor of the standard.」出現標準時,寧可放棄自己的做法。Supabase 在 2025-04 推出 MCP server,之後跟上 agent skills,沒有自己發明一套 agent 協定。Build for developers 這條也寫了「As the profile of a developer changes over time, Supabase will continue to evolve the product to fit this evolving profile.」,開發者的樣貌在變,產品跟著變,agent 層就是外掛上去的那一塊。
這樣一來,平台不必為 agent 改動任何服務,agent 層可以自己發版、自己演進。問題也出在同一個位置:agent 能做的事被 Management API 的範圍限住;平台想對 agent 說的話,只能寫在邊界上,也就是 tool description。查 log 的 tool,說明裡直接寫了「Do not poll this tool in a loop」,這是一條行為規範,卻只能放在 tool 的說明文字裡,agent 讀不讀、聽不聽,平台管不到。能力的上限也被標準綁住,MCP 規格還沒有的機制,Supabase 得等規格和 client 都支援了才能用。
排程、佇列、密鑰,都是一句 SQL
extensible 原則落到能力上,就是能在資料庫裡做的,都做成 Postgres extension:排程用 pg_cron,佇列用 pgmq,密鑰用 vault,向量搜尋用 pgvector,GraphQL 用 pg_graphql。
對 agent 來說,大部分能力的介面都是 SQL。agent 不用為排程學一組 API、為佇列再學一組,一個執行 SQL 的 tool 就夠了。要每小時清一次過期資料,寫一句 cron.schedule();要送一筆工作進佇列,寫一句 pgmq.send()。
麻煩在於這些能力沒有專屬的 tool。cron.schedule() 的參數怎麼填、pgmq 的函式叫什麼,agent 得自己知道,平台沒有在 tool 層幫它包好。Supabase 用 skill 來補。2026-01 發布 Postgres best practices skill 時,官方這樣說明它的定位:「Think of it this way: the MCP server is the steering wheel, and the best practices are the driving lessons.」MCP 給 agent 方向盤,skill 教它怎麼開。同一篇也說 skills 是「documentation written for machines」,寫給機器讀的文件。
知識放進 skill,平台就不用為每個 extension 維護一組 tool;但 agent 能不能用對,變成取決於它有沒有讀到那份知識。而 agent 到底有沒有讀到,要量了才知道。
量了才知道,agent 很少讀 skill
Supabase 用自己的 evals 量出,agent 很少主動讀它準備的知識:skill 大約十個 session 只載入一次,就算載入了,Claude Code 查文件的情境也不到四成。文件本身其實鋪得很廣,照著 Support existing tools 原則,同一份文件被做成好幾種格式:給人看的 MDX、每頁一份的 Markdown、llms.txt、Management API 的 openapi.json,還有一份有測試保護的 agent 資源目錄 ard.json。文件之外再包成 MCP、Skills、一次裝好兩者的 Plugin,以及給什麼都不支援的工具用的 prompt 檔,連最陽春的工具都讀得到。
讀得到,agent 卻不一定會去讀。2026-07,Supabase 推出自己的 evals,讓 Claude Code、Codex、OpenCode 透過實際的 MCP 和 CLI 完成 Supabase 的任務。官方的理由是:「As more people ship Supabase projects through an agent instead of by hand, we wanted a way to measure that experience instead of guessing.」
量出來的結果有幾個發現:
| 發現 | 內容 |
|---|---|
| skill 很少被載入 | Postgres best practices skill 原本只在大約十分之一的 session 裡載入。改寫描述、把觸發條件寫在最前面之後,載入率升到 60%。 |
| 載入了也不查文件 | 「Claude Code checks our docs in under 40% of scenarios even with skills loaded.」 |
| 照舊習慣做事 | 專案已經在用 declarative schema(直接寫下 schema 最終的樣子,由工具算出差異),agent 還是去手寫 migration。 |
| 不知道新東西 | 寫 Edge Functions 時,agent 選了舊的 library,沒注意到較新的 @supabase/server。 |
這些發現有一個共同點:只看任務成功或失敗,一個都看不到。skill 有沒有載入、文件有沒有查、最後選了哪個 library,都藏在 agent 每一次執行的過程裡。Supabase 看的是每個 session 做了什麼,再跨大量 session 統計,才知道問題出在 skill 根本沒被載入,跟內容寫得好不好無關。
有了這組數字,優化方向就從猜變成算。沒有量測時,直覺的做法是把 skill 寫得更長、更完整;量測顯示瓶頸在描述,只改寫描述,載入率就從一成升到六成。Supabase 下一步規劃的是「a new CLI command and MCP tool that will allow agents to submit feedback when they struggle」,讓 agent 卡住時自己回報,等於再多一個資料來源。
這組結果還有一個時間差。這個 skill 在 2026-01 發布,evals 到 2026-07 才量出它只有一成的載入率,中間半年,skill 一直在那裡,多數時候沒被用到。我認為這說明了 agent 系統的 Day 2 為什麼重要:skill、文件、tool description 上線只是第一天,它們在實際 session 裡有沒有發揮作用,要上線之後持續量才知道。Supabase 的 evals 是固定題目的 benchmark,不是 production 的使用紀錄,但它被當成一件持續做的事,每次改動都能回頭驗證。
拿這組結果回頭看,可以拆成兩個問題。第一個是 context engineering:該給 agent 的知識有沒有準備好、寫得對不對。Supabase 在這一層做得很完整,文件、skill、tool description 都有。第二個是 harness engineering:這些知識有沒有在對的時機進到 agent 的 context。載入率從一成升到六成,skill 的內容沒動,動的是描述,描述決定了 agent 在什麼時候判斷「現在該載入這份 skill」。這是 harness 層的事,而 Supabase 碰不到 harness,要不要載入、要不要查文件,由 Claude Code 自己決定。平台能做的只有把描述寫得更好,再用量測確認有沒有效。
agent 為什麼不查?官方說 skill 的工作之一,是幫 agent「unlearn outdated pre-training knowledge」,忘掉訓練資料裡過時的知識。我的解讀是,「It’s just Postgres」在這裡變成兩面刃:模型的訓練資料裡有大量 Postgres,agent 不需要學新抽象就能上手,但也因為太熟,以為自己懂,就直接套用訓練資料裡的舊寫法。
讓 agent 看得懂,沒有一次做完的版本,要靠持續量測、找到瓶頸、改完再量。
看得懂是一半。另一半是 agent 看懂之後,平台怎麼控制它能做什麼。
agent 只碰得到 production 以外的環境
Supabase 控制 coding agent 最有效的方式,是讓它碰不到 production,改動只能經過 PR review 和 CI 上線。要理解為什麼,先看 agent 用的是誰的身分。hosted MCP 跑在 Supabase 的平台控制層,代表的是開發者本人,官方文件的說法是:「The MCP server operates under the context of your developer permissions, so you should not give it to your customers or end users.」開發者能動的,agent 原則上都能動。前面提到的 RLS 保護的是 app 的使用者,每個人帶著自己的 JWT 進來;開發者在自家產品裡架給使用者用的 MCP server,才走這條路,官方說「Anything the tools read or write goes through RLS」。同樣是 agent,代表開發者還是代表使用者,受的是不同的權限機制。
代表開發者的 agent,Supabase 能收的權限有兩層:
| 層 | 決定什麼 | 機制 |
|---|---|---|
| 平台層 | agent 看得到哪些 tool、能動哪個專案。 | OAuth 登入或 personal access token;project_ref 鎖定專案;features 只開指定的 group。 |
| 資料庫層 | SQL 最後以什麼權限執行。 | 唯讀模式改用唯讀的 Postgres role。 |
project_ref 的做法很細:設定之後,server 會把專案 id 從每個 tool 的參數裡拿掉,改由 server 自己帶入,agent 連其他專案的 id 都沒有地方填。唯讀也不靠 regex 擋寫入語句,官方的說法是「implemented at the Postgres role level」,由資料庫保證,SQL 怎麼寫都寫不進去。
這兩層有一個限制:粒度不夠細。personal access token 已經可以按 tool 細分權限,但 hosted MCP 走 OAuth 時,文件要你「Grant write access to all of the available scopes」,Remote MCP 的發布文也承認目前只能「either grant all permissions to your MCP client, or none」。一旦開了寫入,agent 拿到的就是整個專案的寫入權。
權限切不細,Supabase 給的答案是切環境。〈Defense in Depth for MCP Servers〉的原話是:「Never connect AI agents directly to production data.」2025-10 的 Remote MCP 發布文也說「Supabase MCP should be used for development」。這跟企業本來就有的 dev、staging、production 三層剛好對得上,每一層各給 agent 不同的權限:
| 環境 | agent 能做什麼 | 怎麼設定 |
|---|---|---|
| dev | agent 可以自由建表、改 schema、灌測試資料。 | 一個專門給 agent 的開發專案,MCP 用 project_ref 鎖在這裡,開寫入。 |
| staging | agent 只能查,用來驗證改動。 | 另一個專案,MCP 加上 read_only。 |
| production | agent 完全不連。 | 不設定任何 MCP 連線,改動只能從 CI 進來。 |
staging 的連線網址長這樣:
https://mcp.supabase.com/mcp
?project_ref=stg123 # 只碰 staging 專案,帳號類 tool 整組關掉
&read_only=true # SQL 以唯讀 role 執行,寫入類 tool 不出現
&features=database,docs # 只開資料庫與文件兩組 tool
production 那一格是整個設計的關鍵:agent 手上沒有 production 的連線,改動要上線,只有一條路。agent 在 dev 把 schema 變更寫成 migration 檔,進 git、開 PR。Supabase 的 branch 在這裡扮演一次性的 staging:開 PR 時從 production 複製 schema 開出一個雲端環境,預設不帶 production 的資料,把 migration 套上去驗證。官方 2023 年發布 branching 時就說要把這些環境當成「cattle, not pets」,壞了就丟,不必修。驗證通過、人 review 過 PR 之後 merge,GitHub 整合才把 migration 套到 production;官方也建議把 migration 檢查設成必過的 status check,「stops invalid migrations from being merged into your production branch」。
在這條路上,agent 負責寫,人負責放行,碰到 production 的只有 CI。我認為這是為人設計的平台控制 agent 最有效的方式:不必替 agent 發明新的權限模型,把它放進團隊本來就在用的發布流程,讓 PR review 當閘門。
這個做法換到的是 production 的安全,而且跟企業既有的流程相容,不用為 agent 另訂一套規則。代價是 agent 看不到真實資料,資料量大才出現的效能問題、只有某些髒資料才觸發的 bug,都不會在 dev 和 staging 出現。環境分得越乾淨,維護成本也越高:三個專案的 schema 要靠 migration 保持一致,每個 branch 的規格跟專案的運算規格相同,按小時計費。
人在花錢和刪資料前點頭
Supabase 在兩個時間點讓人介入:花錢之前和刪資料之前,agent 會停下來等人同意。環境切開之後,dev 裡的 agent 還是可能出錯,甚至被誘導。2025 年 6 月公開的一個攻擊就是例子:攻擊者在客服工單裡藏一段指令,開發者請 Cursor 透過 Supabase MCP 看工單時,agent 照著指令去查敏感資料表,再把結果寫回工單。Supabase 事後補強了 tool 說明,並把查詢結果標成不可信的資料,但也承認「These approaches reduced risk but did not eliminate it.」
最晚加上的一層是 human-in-the-loop。MCP 規格裡有一個機制叫 elicitation,讓 server 在執行途中停下來,透過 client 請人確認。Supabase 把它放在兩個時間點:建專案或 branch 要付費,執行前先把費用顯示給人看;SQL 裡有 DROP、DELETE、TRUNCATE,或沒有 WHERE 的 UPDATE,先把 SQL 顯示給人看。人按下同意才執行。這是人和 agent 的一個協作點:agent 負責做,人只在成本和破壞發生前介入,其他時候不打擾。client 沒有宣告支援 elicitation,需要確認的 tool 就不會出現;要跳過確認得逐一指名,沒有「全部跳過」的開關。
這個把關只發生在當下,不會留下紀錄。官方文件要你把它當成「a guardrail rather than proof that a person approved each action」,它能擋,卻不能拿來當稽核的證據。MCP 送出的 SQL 也沒有來源標記,從 Dashboard 送出的會帶一行 -- source: dashboard 的註解,MCP 的沒有。事後在資料庫裡看到一筆奇怪的變更,很難分辨是人做的還是 agent 做的,也查不到當時有沒有人點過頭。
設計啟示
- 核心先定好,agent 層掛在外面。 平台不為 agent 改動核心,agent 層就能獨立演進、跟著標準走。代價是平台想對 agent 說的話只能寫在邊界上,這個限制要一開始就接受。
- 讓 agent 用它本來就會的語言。 介面越接近模型熟悉的東西,agent 上手越快。熟悉也是盲點,越熟的東西 agent 越不會去查證,過時的知識要主動幫它忘掉。
- 上線只是第一天,要持續量測 agent 有沒有用上。 文件格式鋪得再廣,載不載入仍由 harness 決定。把 agent 每次執行的過程記下來分析,優化方向才會從猜變成算。
- 權限切不細,就用環境切。 代表開發者的 agent 拿到的權限很粗,最有效的控制是讓它碰不到 production,改動只能經過 PR review 和 CI 上線。
- 人只在關鍵時刻介入,而且要留下紀錄。 human-in-the-loop 放在花錢和破壞之前最划算;但不留紀錄就只能擋,不能拿來稽核。