Source Code

Supabase 怎麼讓 agent 看得懂、又可控制:一個為人設計的 Postgres 平台

2026-10-10 ·約 21 分鐘 · — views
本文目錄

「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 isolationMCP 不放進核心,它跟 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 層就是外掛上去的那一塊。

Supabase 的 agent 層
Coding agent
↓
看得懂
MCP · Skills · Plugin · Prompts · llms.txt
可控制
project scope · feature groups · read-only role · 執行前確認 · 非 production 環境
↓
Control plane
Management API · hosted MCP · 開發者權限
↓
PostgREST
Auth
Storage
Realtime
↓
Postgres
資料 · RLS 權限規則 · extensions

這樣一來,平台不必為 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 能做什麼怎麼設定
devagent 可以自由建表、改 schema、灌測試資料。一個專門給 agent 的開發專案,MCP 用 project_ref 鎖在這裡,開寫入。
stagingagent 只能查,用來驗證改動。另一個專案,MCP 加上 read_only。
productionagent 完全不連。不設定任何 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 放在花錢和破壞之前最划算;但不留紀錄就只能擋,不能拿來稽核。