Vibe Coding 一键部署——火山引擎推出 Supabase, 驱动Agent 应用快速上线
Agent 开发者几乎都会遇到这样的场景:脑海中智能交互的蓝图清晰无比,动手时却被繁杂的后端基建卡住——搭建服务架构、设计数据库表结构、配置认证体系、编写海量 API……好不容易让应用上线,新的问题又接踵而至:用户量未起时,闲置服务器空耗成本;用量起来后,流量洪峰又易引发服务崩溃。
在构建 AI Agent 的浪潮中,是否有一种方案,能快速扫清后端障碍,让创意一键落地?
为此,火山引擎推出火山 Supabase ——一个让开发者能专注业务逻辑的“云上开发工具箱”,旨在让开发者摆脱后端基建的束缚,实现高效的 Vibe Coding,并聚焦于 Agent 交互逻辑与体验创新。
Supabase,作为一款广受欢迎的开源 BaaS(Backend as a Service,后端即服务),将数据库、用户认证、文件存储、实时通信等所有通用后端能力,打包成即取即用的标准化服务。
Vercel 创始人,Next.js 之父 Guillermo Rauch 称 Supabase 是 PostgreSQL 的最佳 BaaS 实现,为 Vibe Coding 提供了坚实的“道路”和数据基础,是开发者构建应用时不可或缺的后端平台。
火山 Supabase 100% 兼容开源 Supabase 生态,保障开源开发者能向云上无缝迁移,更在成本控制、数据安全、开发效率三大核心维度实现突破性升级,让开发者摆脱基建内耗,聚焦核心业务创新与价值落地。目前火山 Supabase 已服务于字节内外客户,如豆包、扣子、TRAE 等典型的 AI Agent 平台。
助力Agent 开发提效 80%,资源利用率大幅提升
开源 Supabase 凭借其灵活性和与 PostgreSQL 生态的深度兼容,在 GitHub 上斩获了近 10 万 Star,深受全球开发者青睐。
而火山 Supabase 在保留开源优势的基础上,注入了字节跳动大规模业务场景锤炼出的企业级服务能力,为开发者带来了更极致的性价比与稳定性。
全链路 Serverless 架构,实现弹性与成本双赢。传统 Serverless 架构通常仅覆盖计算层,数据库仍需固定配置,成本控制依然是核心挑战。火山 Supabase 创新性地将 Serverless 理念贯穿至数据库层,实现了 BaaS 服务层到数据库层的全链路弹性。业务低谷时,资源可自动休眠,费用趋近于零;流量波峰时,系统则能秒级自动扩容,无需人工干预。经实际生产业务验证,与自建开源 Supabase 相比,火山 Supabase 最高可节省 23 倍的成本。
企业级数据安全体系,筑牢业务资产防线。依托字节跳动海量业务验证的“数据保险箱”方案,火山 Supabase 提供了核心的 Data as Git 能力,让数据管理如代码版本控制般便捷。企业可创建独立的数据分支,用于新功能测试、AI 模型训练,全程不影响生产环境。当遇到误操作导致的数据损坏时,通过时间点回溯功能,可瞬间恢复到任意时间点的数据状态。结合金融级高可用底座与存算分离架构,即便面对电商大促、金融交易等业务规模的激增,也能确保数据不丢失、服务不中断。
AI 原生极简交互,开发效率提升 80%+。火山 Supabase 重构了开发者的交互流程。首先,开发者可以通过自然语言下达指令,例如“创建一个用于测试环境的 Supabase 实例”,系统便会自动完成所有配置,传统开发模式下需要十余个步骤的繁琐操作,如今仅需 2-3 步即可完成。其次,基于 火山Supabase 的 RLS 和 标准化 REST API,开发者无需再开发后端服务,仅需开发前端代码即可完成 AI Agent 等应用的制作,大幅降低了开发、调试、部署的成本。
以扣子编程为例,在每个 Vibe Coding 生成物(网页应用、移动应用、小程序、智能体、技能等)背后,都会同步创建和使用一个Supabase 实例运行这些产物,并且使用火山 Supabase 的多分支能力(Branching)进行环境隔离。
在使用火山 Supabase 后,扣子编程整体的交付效率、质量、成本,都得到极大的改善。以交付效率为例,基于火山 Supabase,扣子编程在 Vibe Coding 场景,提供了以下功能:
开箱即用的云端环境:打开网页即可开始,每个项目自动分配云端运行环境和对应资源,无需安装任何工具。遇到问题也能一键重启、自动恢复。
一键部署和项目构建服务:一键完成云端打包、构建与服务部署,支持自定义域名。版本可回退,部署记录完善、可追踪。
这极大降低了 Agent 开发的门槛,让开发者一站式完成从构建到落地的完整生产级闭环,让整个开发过程更聚焦于创意和价值创造。
站在 PostgreSQL 肩膀上的 Agent 全栈开发平台
火山 Supabase 的强大之处,在于它巧妙地将一系列成熟的开源组件,围绕 PostgreSQL 这颗强大的“心脏”进行整合与封装,为开发者提供了一套连贯、高效的工具集。下面,我们深入其核心组件,探究其技术原理。
核心架构:以 PostgreSQL 为中心的全栈协同
火山 Supabase 的架构并非重新发明轮子,而是“站在巨人的肩膀上”。它以功能强大且极度可靠的 PostgreSQL 数据库为中心,集成了一系列专注于特定领域的服务,每个服务都力求做到小而精,并通过良好定义的接口协同工作。
PostgreSQL:不止开源 PostgreSQL,火山团队为更好服务 Agent 场景,全新打造 Serverless PostgreSQL,提供了一系列前所未有的体验——秒级弹性、资源自动休眠、秒级 Branch 管理、Timetravel 灵活查询历史数据等。
PostgREST:一个神奇的工具,它能将你的 PostgreSQL 数据库瞬间转换成一个 RESTful API。你无需编写一行后端代码,数据库中的表、视图、函数,都会自动拥有对应的 API 端点。
GoTrue: 一个基于 JWT (JSON Web Tokens) 的身份验证服务,负责用户注册、登录和管理。它与 PostgreSQL 的行级安全(Row Level Security, RLS)机制深度集成,为数据访问提供了精细的权限控制。
Realtime:一个基于 Elixir 构建的高性能 WebSocket 服务。它通过监听 PostgreSQL 的预写日志(Write-Ahead Log, WAL),能够实时地将数据库的变更推送给客户端,是构建实时协作应用的关键。
Storage: 提供对象存储服务,用于管理图片、视频等大文件。其元数据存储在 Postgres 中,权限管理同样与 GoTrue 和 RLS 集成打通。
Edge Functions:分布式 Serverless 函数。开发者可以编写 TypeScript、Python 函数,按需执行,可用于处理 Webhooks、安全地调用第三方 API 或执行自定义的后端逻辑。
数据流视角下的协同工作
用户请求:一个前端应用通过 supabase-js 客户端库发起请求。
API 网关 (Kong):所有请求首先经过 API 网关,它负责路由、认证和负载均衡。
身份验证 (GoTrue):如果是需要认证的请求,网关会携带 JWT 令牌与 GoTrue 通信,验证用户身份。
API 服务 (PostgREST):验证通过后,请求被转发到 PostgREST。PostgREST 将 HTTP 请求(如 GET /tasks)解析成 SQL 查询。
数据库权限 (PostgreSQL RLS):PostgreSQL 在执行 SQL 前,会检查为当前用户角色(从 JWT 中解析)设定的 RLS 策略。例如,一个 RLS 策略可以规定“用户只能访问 tasks 表中 user_id 等于自己 ID 的行”。
数据响应: 数据库返回符合权限的数据,经由 PostgREST 和 API 网关,最终到达客户端。
实时更新 (Realtime):如果某个操作(如 INSERT 或 UPDATE)修改了数据库,Realtime 服务会监听到 WAL 的变化,并将变更通过 WebSocket 推送给所有订阅了该数据的客户端,实现界面自动更新。
服务端逻辑 (Edge Functions):如果需要执行复杂或敏感的操作(如调用外部支付接口),客户端会调用一个 Edge Function。该函数在沙箱环境中运行,可以使用 service_role_key 安全地与数据库或其他服务交互,并将结果返回给客户端。
火山 Supabase一站式AI基建能力供给
技术实操:将火山 Supabase 集成到 Agent 开发环境中,开启 Vibe Coding
将火山 Supabase 集成到开发者的 Agent 开发环境中,可以极大地加速 Agent 和全栈应用的后端构建。下面我们将通过两个具体的 Agent 开发场景——“任务管理与记忆”、“RAG功能”,展示如何实现集成。
基于火山的Supabase的Agent的数据链路示意图如下:
1. 环境配置:连接你的 Supabase 项目
在项目环境中,第一步是安全地配置 Supabase 的连接凭证。我们推荐使用环境变量来管理这些敏感信息。
在你的项目设置或 .env 文件中,添加以下两个变量:
SUPABASE_URL="YOUR_SUPABASE_PROJECT_URL"#例如br123123123.supabase.aidap-global.cn-beijing.volces.com:443SUPABASE_ANON_KEY="YOUR_SUPABASE_ANON_KEY"
SUPABASE_URL 和 SUPABASE_ANON_KEY 可以在火山 Supabase 控制台的“连接”页面中获取到。ANON_KEY 是公开的匿名密钥,它受到 RLS 策略的保护,可以安全地在前端环境使用它。
2. 初始化 supabase-js 客户端
在项目中(无论是 Node.js 后端还是前端代码),首先需要安装 supabase-js 客户端库:
npm install @supabase/supabase-js然后,创建一个客户端实例。通常,我们会将这个实例放在一个单独的文件中(例如 lib/supabaseClient.js),以便在整个项目中复用。
// lib/supabaseClient.jsimport { createClient } from'@supabase/supabase-js'const supabaseUrl = process.env.SUPABASE_URLconst supabaseAnonKey = process.env.SUPABASE_ANON_KEYexportconst supabase = createClient(supabaseUrl, supabaseAnonKey)
3. 示例1:为 Agent 实现用户任务管理与记忆
假设我们正在构建一个 Agent,它需要记录用户的任务,并能根据历史任务提供建议。
(1) 创建相关表结构 及 RLS 策略
首先,在火山 Supabase 的 Dashboard 中 SQL Editor 里创建 tasks 表,并为 Agent 的“记忆”创建一个 memories 表,后者将包含向量数据。
上下滑动查看完整内容
-- 启用 pgvector 扩展CREATE EXTENSION IF NOT EXISTS vector;-- 创建任务表CREATE TABLE public.tasks (id uuid primary key default gen_random_uuid(),user_id uuid references auth.users not null,title text not null,is_complete boolean defaultfalse,created_at timestamptz default now());-- 为任务表启用行级安全 (RLS)ALTER TABLE public.tasks ENABLE ROW LEVEL SECURITY;-- 策略:用户只能看到和操作自己的任务CREATE POLICY "Users can manage their own tasks."ON public.tasksFOR ALLUSING(auth.uid() = user_id)WITH CHECK(auth.uid() = user_id);-- 创建记忆表,用于存储向量化后的任务信息CREATE TABLE public.memories (id uuid primary key default gen_random_uuid(),task_id uuid references public.tasks on delete cascade,user_id uuid references auth.users not null,content text not null, -- 任务标题或描述embedding vector(384), -- 假设使用 384 维的 embedding 模型created_at timestamptz default now());-- 为记忆表启用 RLSALTER TABLE public.memories ENABLE ROW LEVEL SECURITY;-- 策略:用户只能访问自己的记忆CREATE POLICY "Users can access their own memories."ON public.memoriesFOR ALLUSING(auth.uid() = user_id)WITH CHECK(auth.uid() = user_id);
(2) 创建向量检索Function
创建一个 PG Function 来进行向量相似度检索。
-- 创建一个函数来匹配相似的记忆CREATE OR REPLACE FUNCTION match_memories(query_embedding vector(384),match_threshold float,match_count int)RETURNS TABLE (id uuid, content text, similarity float)LANGUAGE sql STABLE AS $$SELECTmemories.id,memories.content,1 - (memories.embedding <=> query_embedding) as similarityFROM memoriesWHERE auth.uid() = memories.user_id -- 确保只在当前用户记忆中搜索AND 1 - (memories.embedding <=> query_embedding) > match_thresholdORDER BY similarity DESCLIMIT match_count;$$;
(3) 实现基本的 CRUD 操作
现在,在代码中,我们可以使用 supabase-js 与这些表进行交互。
上下滑动查看完整内容
import { supabase } from './lib/supabaseClient.js';// 获取当前用户的任务列表async function getTasks(){const { data: tasks, error } = await supabase.from('tasks').select('*').order('created_at', { ascending: false });if (error) {console.error('Error fetching tasks:', error);return;}console.log('Tasks:', tasks);}// 创建一个新任务async function createTask(title){const { data: { user } } = await supabase.auth.getUser(); // 获取当前登录用户if (!user) {console.error('User not logged in');return;}const { data: newTask, error } = await supabase.from('tasks').insert({ title: title, user_id: user.id }).select().single();if (error) {console.error('Error creating task:', error);} else {console.log('New task created:', newTask);// 异步生成并存储记忆向量 (具体实现在 Edge Function 的 generate-memory 函数中,见下节)await supabase.functions.invoke('generate-memory', {body: { task_id: newTask.id, content: newTask.title },});}}
(4) 使用 Edge Function 实现记忆信息的Embedding并入库
使用 Edge Function 进行记忆信息的Embedding并入库,即上节提及的“generate-memory”的具体实现。
相比于直接在客户端执行Embedding并入库,在 Edge Function 中会更安全,能避免暴露实现细节。
上下滑动查看完整内容
// supabase/functions/generate-memory/index.tsimport { serve } from 'https://deno.land/[email protected]/http/server.ts';import { pipeline } from 'https://cdn.jsdelivr.net/npm/@xenova/[email protected]';import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';serve(async (req) => {const { task_id, content } = await req.json();// 使用 service_role key 安全地初始化 Admin 客户端const supabaseAdmin = createClient(Deno.env.get('SUPABASE_URL') ,Deno.env.get('SUPABASE_SERVICE_ROLE_KEY'));// 1. 生成 Embeddingconst generateEmbedding = await pipeline('feature-extraction', 'Supabase/gte-small');const output = await generateEmbedding(content, { pooling: 'mean', normalize: true });const embedding = Array.from(output.data);// 2. 获取任务信息,以拿到 user_idconst { data: task, error: taskError } = await supabaseAdmin.from('tasks').select('user_id').eq('id', task_id).single();if (taskError) {returnnew Response(JSON.stringify({ error: taskError.message }), { status: 500 });}// 3. 将向量存入 memories 表const { error: insertError } = await supabaseAdmin.from('memories').insert({task_id,user_id: task.user_id,content,embedding,});if (insertError) {returnnew Response(JSON.stringify({ error: insertError.message }), { status: 500 });}returnnew Response(JSON.stringify({ message: 'Memory created' }), { status: 200 });});
(5) 在 APP前端 或 Edge Function 中检索记忆信息
在 APP前端 或 Edge Function 中,调用以下函数来检索进行记忆信息。
asyncfunctionfindSimilarMemories(text) {// 1. 将当前文本生成 embedding (此处省略)const queryEmbedding = await generateEmbeddingFor(text);// 2. 调用 RPC 函数进行搜索const { data: memories, error } = await supabase.rpc('match_memories', {query_embedding: queryEmbedding,match_threshold: 0.7, // 相似度阈值match_count: 5, // 返回最多 5 个结果});if (error) {console.error('Error searching memories:', error);return [];}console.log('Found similar memories:', memories);return memories;}
(6) 使用 Edge Function 中访问 大模型 (或MCP、外部工具等)
Edge Functions 可以用于承载 AI Agent 的核心逻辑,如调用 LLM、MCP Tools、执行工具)的执行。
上下滑动查看完整内容
// supabase/functions/agent-core/index.tsimport { serve } from "https://deno.land/[email protected]/http/server.ts";import { createClient } from "https://esm.sh/@supabase/supabase-js@2";serve(async (req) => {const supabase = createClient(Deno.env.get("SUPABASE_URL")!,Deno.env.get("SUPABASE_ANON_KEY")!);// 1. 解析用户请求(用户输入、Agent ID)const { user_id, query, agent_id } = await req.json();// 2. 检索长期记忆(结构化+非结构化)const user_prefs = await supabase.from("user_profiles").select("*").eq("user_id", user_id).single();// 3. 调用 LLM(比如 OpenAI)生成 Agent 响应const llmResponse = await fetch("https://api.openai.com/v1/chat/completions", {method: "POST",headers: {"Content-Type": "application/json","Authorization": `Bearer ${Deno.env.get("OPENAI_API_KEY")}`},body: JSON.stringify({model: "gpt-3.5-turbo",messages: [{ role: "system", content: `你是一个基于 Supabase 的 AI Agent,用户偏好:${JSON.stringify(user_prefs.data)}` },{ role: "user", content: query }]})});const llmData = await llmResponse.json();const agent_answer = llmData.choices[0].message.content;// 4. 保存本次交互到长期记忆await supabase.table("agent_sessions").upsert({user_id,agent_id,query: query,response: agent_answer,updated_at: new Date()});// 5. 返回 Agent 响应returnnew Response(JSON.stringify({ answer: agent_answer }), {headers: { "Content-Type": "application/json" }});});
部署该函数后,客户端调用 supabase.functions.invoke('generate-memory', ...) 即可触发服务端的向量生成与存储,整个过程对前端透明且安全。
4. 示例2:为 Agent 实现RAG功能
(1) 创建相关表结构 及 RLS 策略
创建两个表:一个存储原始文档分块,一个存储向量(也可合并,分开更易管理):
上下滑动查看完整内容
-- 启用 pgvector 扩展CREATE EXTENSION IF NOT EXISTS vector;-- 文档元数据表:存储原始文档信息CREATE TABLE IF NOT EXISTS rag_documents(id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),document_name TEXT NOT NULL, -- 文档名称document_type TEXT, -- 文档类型(pdf/txt/md 等)user_id UUID, -- 所属用户(关联 auth.users)created_at TIMESTAMP DEFAULT NOW());-- 文档分块&向量表:存储分块文本和对应的 Embedding 向量CREATE TABLE IF NOT EXISTS rag_document_chunks(id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),document_id UUID REFERENCES rag_documents(id) ON DELETE CASCADE, -- 关联文档chunk_text TEXT NOT NULL, -- 文档分块文本chunk_index INT, -- 分块序号(保持上下文顺序)embedding vector(1536), -- OpenAI Embedding 向量(维度 1536,可根据模型调整)created_at TIMESTAMP DEFAULT NOW());-- 创建向量索引:加速相似度检索(核心!否则大数据量检索慢)CREATE INDEX IF NOT EXISTS idx_rag_embeddingsON rag_document_chunksUSING ivfflat(embedding vector_cosine_ops) -- 余弦相似度WITH(lists = 100); -- lists 数值:数据量小设 10-100,大数据量设 1000+-- (可选)启用 RLS 规则,确保用户只能访问自己的文档ALTER TABLE rag_documents ENABLE ROW LEVEL SECURITY;ALTER TABLE rag_document_chunks ENABLE ROW LEVEL SECURITY;CREATE POLICY "Users can only access their own documents"ON rag_documents FOR ALL USING(auth.uid() = user_id);CREATE POLICY "Users can only access their own chunks"ON rag_document_chunks FOR ALLUSING(EXISTS (SELECT 1 FROM rag_documentsWHERE rag_documents.id = rag_document_chunks.document_idAND rag_documents.user_id = auth.uid()));
(2) 预处理文档:Embedding并入库
上下滑动查看完整内容
import osimport uuidfrom dotenv import load_dotenvfrom supabase import create_client, Clientfrom openai import OpenAIfrom PyPDF2 import PdfReader# 加载环境变量load_dotenv()SUPABASE_URL = os.getenv("SUPABASE_URL")SUPABASE_KEY = os.getenv("SUPABASE_ANON_KEY")OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")# 初始化客户端supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)openai_client = OpenAI(api_key=OPENAI_API_KEY)# 1. 文档分块工具(通用:支持文本/PDF)def split_document(file_path, chunk_size=500, chunk_overlap=50):"""拆分文档为小分块,避免向量长度超限,同时保留上下文重叠"""chunks = []# 处理 PDFif file_path.endswith(".pdf"):reader = PdfReader(file_path)text = ""for page in reader.pages:text += page.extract_text() or""# 处理纯文本else:with open(file_path, "r", encoding="utf-8") as f:text = f.read()# 分块逻辑start = 0while start < len(text):end = start + chunk_sizechunk = text[start:end].strip()if chunk:chunks.append(chunk)start = end - chunk_overlap # 重叠部分,保持上下文连贯return chunks# 2. 生成 Embedding 向量def get_embedding(text):"""调用 OpenAI Embedding 模型生成向量"""response = openai_client.embeddings.create(input=text,model="text-embedding-3-small" # 轻量、低成本,维度 1536)return response.data[0].embedding# 3. 文档入库主函数def ingest_document(file_path, user_id):# 步骤 1:拆分文档chunks = split_document(file_path)ifnot chunks:raise ValueError("文档内容为空")# 步骤 2:创建文档元数据document_name = os.path.basename(file_path)document_type = file_path.split(".")[-1]doc_response = supabase.table("rag_documents").insert({"document_name": document_name,"document_type": document_type,"user_id": user_id}).execute()document_id = doc_response.data[0]["id"]# 步骤 3:生成向量并入库chunk_records = []for idx, chunk in enumerate(chunks):embedding = get_embedding(chunk)chunk_records.append({"document_id": document_id,"chunk_text": chunk,"chunk_index": idx,"embedding": embedding})# 批量插入(提升效率)supabase.table("rag_document_chunks").insert(chunk_records).execute()print(f"文档 {document_name} 入库完成,共拆分 {len(chunks)} 个分块")return document_id# 测试:上传一个 PDF 文档if __name__ == "__main__":# 替换为你的文件路径和用户 ID(Supabase Auth 的 user_id)ingest_document("test_document.pdf", "your-user-uuid-here")
(3) 使用 Edge Function 实现RAG功能
上下滑动查看完整内容
// supabase/functions/rag-retrieve/index.tsimport { serve } from "https://deno.land/[email protected]/http/server.ts";import { createClient } from "https://esm.sh/@supabase/supabase-js@2";import OpenAI from "https://esm.sh/openai@4";serve(async (req) => {// 解析请求参数const { query, user_id } = await req.json();if (!query || !user_id) {returnnew Response(JSON.stringify({ error: "缺少参数" }), { status: 400 });}// 初始化客户端const supabase = createClient(Deno.env.get("SUPABASE_URL")!,Deno.env.get("SUPABASE_ANON_KEY")!);const openai = new OpenAI({ apiKey: Deno.env.get("OPENAI_API_KEY")! });// 1. 生成问题向量const embeddingResponse = await openai.embeddings.create({input: query,model: "text-embedding-3-small",});const queryEmbedding = embeddingResponse.data[0].embedding;// 2. 向量检索const { data: chunks } = await supabase.raw(`SELECT rc.chunk_text, 1 - (rc.embedding <=> $1) as similarityFROM rag_document_chunks rcJOIN rag_documents rd ON rc.document_id = rd.idWHERE rd.user_id = $2ORDER BY similarity DESCLIMIT 5;`, [queryEmbedding, user_id]);// 3. 生成回答const context = chunks.map((c: any) => c.chunk_text).join("\n\n");const llmResponse = await openai.chat.completions.create({model: "gpt-3.5-turbo",messages: [{ role: "system", content: "基于上下文回答问题,不要编造内容" },{ role: "user", content: `上下文:${context}\n问题:${query}` }]});returnnew Response(JSON.stringify({answer: llmResponse.choices[0].message.content,context: context}), {headers: { "Content-Type": "application/json" }});});
5. 示例:利用 Realtime 实现实时状态同步
Agent 需要实时交互(比如多用户协作 Agent、实时任务进度更新),Realtime 可以实现实时主动地推送实时消息。
在APP前端代码(例如 React 组件)中,可以这样订阅 tasks 表的变更:
上下滑动查看完整内容
import { useEffect, useState } from 'react';import { supabase } from './lib/supabaseClient';function RealtimeTasks(){const [tasks, setTasks] = useState([]);useEffect(() => {// 初始加载任务const fetchInitialTasks = async () => {const { data } = await supabase.from('tasks').select('*');setTasks(data || []);};fetchInitialTasks();// 订阅变更const channel = supabase.channel('public:tasks').on('postgres_changes',{ event: '*', schema: 'public', table: 'tasks' },(payload) => {console.log('Change received!', payload);// 简单地重新拉取数据以更新 UI// 更优化的方式是根据 payload.eventType 来增量更新 statefetchInitialTasks();}).subscribe();// 清理订阅return () => {supabase.removeChannel(channel);};}, []);return (- {task.title});}
这样,任何用户创建、更新或删除任务,所有打开该页面的客户端都会几乎瞬间收到通知并更新 UI,无需手动刷新。
6. 高级用法示例:Branch多分支/多环境管理
在前文我们提到火山 Supabase 的 Data as Git 能力。站在工程视角,Branch 就是一条独立的数据时间线:你可以为每个环境(Dev / Staging / Prod),甚至为重要客户或一次数据库大改,创建各自的分支,在分支上做结构调整、压测与演练,不会污染生产主线。火山 Supabase 为整套 BaaS 服务,包括 Database、Auth、Storage、Edge Functions 都提供了分支能力,并且创建分支时可以选择 “最新数据”或者“空” 等不同策略。
在项目中,其开发和生产环境使用同一个 Supabase Workspace,但 Branch 完全独立。整套机制原理如下:
开发分支开发:在 Dev Branch 上调整 Schema、调试 RLS、验证 Agent 逻辑,并用 Realtime、pgvector 等能力跑通端到端链路。
预发分支验证:将 Dev 上稳定的 Schema 迁移到 Staging Branch,使用部分真实数据或脱敏数据进行灰度验证。
生产分支发布:仅将 Schema 变更从 Staging 合入 Prod Branch,不带任何测试数据,把风险锁在前两级环境。
开发环境PITR恢复:当某次尝试在开发环境“玩砸”时,可以利用火山 Supabase 的PITR恢复能力,将开发分支回滚到指定时间。
在 Branch 机制之上,前文提到的 全链路 Serverless 弹性、数据库即 API(PostgREST)、RLS 多租户隔离、Realtime 实时推送 与 pgvector 向量检索 会以“整套能力”挂载在每一个分支之上。
这意味着:你可以在 Dev / Staging 分支上放心压测 Realtime 推送、调参数、改 Schema,再把稳定的变更以“仅同步 Schema”的方式迁移到 Prod分支,为 Agent、全栈应用和多人协作场景提供一个安全可控的迭代闭环。
给 Agent 开发者的快速起步清单
通过这些步骤,我们为 Agent 构建了一个功能完备、安全且实时的后端,而这一切几乎没有编写传统的后端服务代码。那么,准备好在你的下一个 Agent 或全栈项目中使用火山 Supabase 了吗?
这里有一份快速上手清单:
访问火山引擎官网:搜索“火山 Supabase”并创建一个新项目。
获取 API 凭证:在控制台的“连接”页面中,找到你的 Project URL 和 anon_key。
安装 supabase-js:在你的前端或 Node.js 项目中运行 npm install @supabase/supabase-js。
初始化客户端:使用获取的凭证创建 Supabase 客户端实例。
设计数据表:使用仪表盘的 Table Editor 或 SQL Editor 创建你的表结构。
开启 RLS:为你需要保护的每一张表启用行级安全,并至少为授权用户添加一条 SELECT 策略,否则 API 将无法读取任何数据。
开始编码:利用 select, insert, rpc 等方法,尽情享受无需后端编码的全栈开发体验吧!
结语:火山 Supabase,释放 Vibe Coding 的高效创造力
技术的终极价值在于降低创新的门槛,火山引擎 Supabase 融合了开源的灵活性与字节跳动的企业级技术可靠性,将复杂的后端能力转化为普惠的工具,助力开发者在诸如扣子、豆包、TRAE 这样高效的 Vibe Coding 中,跳出基建内耗的循环。无论是初创团队快速验证 MVP,还是大型企业构建稳定业务,都能以更低的成本、更高的效率和更强的安全保障,让每一个好想法,一键变为现实。
目前,火山 Supabase 已正式上线火山引擎官网。欢迎试用产品或查阅技术文档,开启你的高效Vibe Coding之旅。