用 OpenClaw + Vercel + Supabase 搭建 AI 公司——两周后它们自己运营了
6 个 AI 智能体,1 台 VPS,1 个 Supabase 数据库——从"智能体能对话"到"智能体自主运营网站",我花了两周时间。这篇文章讲的就是中间缺失的部分、如何修复,以及一套你可以直接拿去用的架构。
起点:你有了 OpenClaw,然后呢?
如果你最近在玩 AI 智能体,大概率已经装好了 OpenClaw。
它解决了一个大问题:让 Claude 能用工具、浏览网页、操作文件、运行定时任务。你可以给智能体分配 cron 任务——每日发推、每小时情报扫描、定期研究报告。
我也是从这里开始的。
我的项目叫 VoxYZ Agent World——6 个 AI 智能体在一个像素风办公室里自主运营一个网站。技术栈很简单:
- OpenClaw(VPS 上):智能体的"大脑"——负责圆桌讨论、cron 任务、深度研究
- Next.js + Vercel:网站前端 + API 层
- Supabase:所有状态的唯一数据源(提案、任务、事件、记忆)
六个角色各司其职:Minion 做决策,Sage 分析策略,Scout 收集情报,Quill 写内容,Xalt 管社交媒体,Observer 做质量检查。
OpenClaw 的 cron 任务让它们每天"来上班"。圆桌功能让它们讨论、投票、达成共识。
但这只是"能对话",还不是"能运营"。
智能体产出的所有内容——推文草稿、分析报告、内容文章——都停留在 OpenClaw 的输出层。没有东西把它变成实际执行,也没有东西在执行完后告诉系统"搞定了"。
从"智能体能产出内容"到"智能体能端到端运行",中间缺了一个完整的 执行 → 反馈 → 重新触发 的闭环。这就是这篇文章要讲的。
闭环长什么样
先定义"闭环",免得搞错方向。
一个真正无人值守的智能体系统需要这个循环不断运行:
智能体提出想法(提案)
↓
自动审批检查
↓
创建任务 + 步骤
↓
Worker 认领并执行
↓
发出事件
↓
触发新的反应
↓
回到第一步
听起来简单?实际操作中我踩了三个坑——每一个都让系统"看起来在跑,实际在空转"。
坑 1:两个地方争抢工作
我的 VPS 上 OpenClaw worker 在认领并执行任务。同时 Vercel 上有一个心跳 cron 在跑 mission-worker,也在试图认领同样的任务。
两边查同一张表,抢同一个步骤,各自独立执行。没有协调,纯粹的竞态条件。偶尔一个步骤会被两边打上冲突的状态。
修复:砍掉一边。VPS 是唯一的执行者。Vercel 只跑轻量的控制平面(评估触发器、处理反应队列、清理卡住的任务)。
改动很小——从心跳路由中移除 runMissionWorker 调用:
// 心跳现在只做 4 件事
const triggerResult = await evaluateTriggers(sb, 4_000);
const reactionResult = await processReactionQueue(sb, 3_000);
const learningResult = await promoteInsights(sb);
const staleResult = await recoverStaleSteps(sb);
额外好处:省了 Vercel Pro 的费用。心跳不再需要 Vercel 的 cron——VPS 上一行 crontab 搞定:
*/5 * * * * curl -s -H "Authorization: Bearer $KEY" https://yoursite.com/api/ops/heartbeat
坑 2:触发了但没人接
我写了 4 个触发器:推文爆了自动分析、任务失败自动诊断、内容发布后自动审查、洞察获得多个点赞后自动提升。
测试时发现:触发器正确检测到了条件并创建了提案。但提案永远停在 pending——从没变成任务,也从没生成可执行的步骤。
原因:触发器直接插入 ops_mission_proposals 表,但正常的审批流程是:插入提案 → 评估自动审批 → 如果通过,创建任务 + 步骤。触发器跳过了后面两步。
修复:提取一个共享函数 createProposalAndMaybeAutoApprove。所有创建提案的路径——API、触发器、反应——都必须调用这一个函数。
// proposal-service.ts — 所有提案创建的唯一入口
export async function createProposalAndMaybeAutoApprove(
sb: SupabaseClient,
input: ProposalServiceInput,
): Promise<ProposalServiceResult> {
// 1. 检查每日限额
// 2. 检查 Cap Gates
// 3. 插入提案
// 4. 发出事件
// 5. 评估自动审批
// 6. 如果通过 → 创建任务 + 步骤
// 7. 返回结果
}
改完后触发器只返回提案模板,由评估器调用服务:
// trigger-evaluator.ts
if (outcome.fired && outcome.proposal) {
await createProposalAndMaybeAutoApprove(sb, {
...outcome.proposal,
source: 'trigger',
});
}
一个函数统治一切。未来任何检查逻辑(限流、黑名单、新的上限)——改一个文件就行。
坑 3:配额满了但队列还在增长
最隐蔽的 bug——表面上一切正常,日志没报错,但数据库里排队的步骤越来越多。
原因:推文配额满了,但提案仍在被批准,生成任务,生成排队步骤。VPS worker 看到配额满了就直接跳过——没认领,也没标记失败。第二天又来一批。
修复:Cap Gates——在提案入口就拒绝。根本不让它生成排队步骤。
const STEP_KIND_GATES: Record<string, StepKindGate> = {
write_content: checkWriteContentGate, // 检查每日内容上限
post_tweet: checkPostTweetGate, // 检查推文配额
deploy: checkDeployGate, // 检查部署策略
};
每种步骤有自己的门禁。推文配额满了?提案直接被拒,原因清楚写明,警告事件发出。没有排队步骤 = 没有堆积。
示例——推文门禁:
async function checkPostTweetGate(sb: SupabaseClient) {
const autopost = await getOpsPolicyJson(sb, 'x_autopost', {});
if (autopost.enabled === false) return { ok: false, reason: 'x_autopost disabled' };
const quota = await getOpsPolicyJson(sb, 'x_daily_quota', {});
const limit = Number(quota.limit ?? 10);
const { count } = await sb
.from('ops_tweet_drafts')
.select('id', { count: 'exact', head: true })
.eq('status', 'posted')
.gte('posted_at', startOfTodayUtcIso());
if ((count ?? 0) >= limit) return { ok: false, reason: `Daily tweet quota reached (${count}/${limit})` };
return { ok: true };
}
核心原则:在门口拒绝,不要在队列里堆积。 被拒的提案会被记录(用于审计),而不是默默丢弃。
让它活起来:触发器 + 反应矩阵
三个坑修完,闭环能跑了。但系统只是一条"无错误的流水线",还不是一个"有响应能力的团队"。
触发器
4 条内置规则——每条检测一个条件并返回提案模板:
| 条件 | 动作 | 冷却时间 |
|---|---|---|
| 推文互动率 > 5% | Growth 分析为什么爆了 | 2 小时 |
| 任务失败 | Sage 诊断根因 | 1 小时 |
| 新内容发布 | Observer 审查质量 | 2 小时 |
| 洞察获得多个点赞 | 自动提升为永久记忆 | 4 小时 |
触发器只负责检测——不直接操作数据库,而是把提案模板交给提案服务。所有 Cap Gates 和自动审批逻辑自动生效。
冷却时间很重要。没有它,一条爆了的推文会在每个心跳周期(每 5 分钟)都触发一次分析。
反应矩阵
最有意思的部分——自发的智能体间交互。
存储在 ops_policy 表中的 reaction_matrix:
{
"patterns": [
{ "source": "twitter-alt", "tags": ["tweet","posted"], "target": "growth",
"type": "analyze", "probability": 0.3, "cooldown": 120 },
{ "source": "*", "tags": ["mission:failed"], "target": "brain",
"type": "diagnose", "probability": 1.0, "cooldown": 60 }
]
}
Xalt 发了一条推 → 30% 概率 Growth 会分析其表现。任何任务失败 → 100% 概率 Sage 会诊断。
probability 不是 bug,是特性。100% 确定性 = 机器人。加入随机性 = 更像一个真实团队——“有时候有人回应,有时候没有”。
自愈:系统必然会卡住
VPS 重启、网络抖动、API 超时——步骤会卡在 running 状态,但实际上没人在处理。
心跳中包含 recoverStaleSteps:
// 30 分钟没进展 → 标记失败 → 检查任务是否应该结束
const STALE_THRESHOLD_MS = 30 * 60 * 1000;
const { data: stale } = await sb
.from('ops_mission_steps')
.select('id, mission_id')
.eq('status', 'running')
.lt('reserved_at', staleThreshold);
for (const step of stale) {
await sb.from('ops_mission_steps').update({
status: 'failed',
last_error: 'Stale: no progress for 30 minutes',
}).eq('id', step.id);
await maybeFinalizeMissionIfDone(sb, step.mission_id);
}
maybeFinalizeMissionIfDone 检查任务中的所有步骤——有任何失败意味着整个任务失败,全部完成才算成功。不再出现"一个步骤成功了整个任务就被标记为成功"的情况。
完整架构
三层架构,职责清晰:
- OpenClaw(VPS):思考 + 执行(大脑 + 双手)
- Vercel:审批 + 监控(控制平面)
- Supabase:所有状态(共享皮层)
你可以带走的东西
如果你有 OpenClaw + Vercel + Supabase,这是最小可行闭环清单:
1. 数据库表(Supabase)
至少需要:
| 表 | 用途 |
|---|---|
| ops_mission_proposals | 存储提案(pending/accepted/rejected) |
| ops_missions | 存储任务(approved/running/succeeded/failed) |
| ops_mission_steps | 存储执行步骤(queued/running/succeeded/failed) |
| ops_agent_events | 存储事件流(所有智能体动作) |
| ops_policy | 存储策略(auto_approve、x_daily_quota 等,JSON 格式) |
| ops_trigger_rules | 存储触发规则 |
| ops_agent_reactions | 存储反应队列 |
| ops_action_runs | 存储执行日志 |
2. 提案服务(一个文件)
把提案创建 + Cap Gates + 自动审批 + 任务创建放在 一个函数 里。所有来源(API、触发器、反应)都调用它。这是整个闭环的枢纽。
3. 策略驱动的配置(ops_policy 表)
不要硬编码限制。所有行为开关都在 ops_policy 表中:
// auto_approve: 哪些步骤类型允许自动通过
{ "enabled": true, "allowed_step_kinds": ["draft_tweet","crawl","analyze","write_content"] }
// x_daily_quota: 每日推文上限
{ "limit": 8 }
// worker_policy: Vercel 是否执行步骤(设为 false = 仅 VPS)
{ "enabled": false }
随时调整策略,无需重新部署代码。
4. 心跳(一个 API 路由 + 一行 crontab)
Vercel 上的 /api/ops/heartbeat 路由。VPS 上一行 crontab 每 5 分钟调用它。内部运行:触发器评估、反应队列处理、洞察提升、过期任务清理。
5. VPS Worker 契约
每种步骤对应一个 worker。完成步骤后调用 maybeFinalizeMissionIfDone。永远不要因为一个步骤完成就把整个任务标记为成功。
两周时间线
| 阶段 | 时间 | 完成内容 |
|---|---|---|
| 基础设施 | 已有 | OpenClaw VPS + Vercel + Supabase |
| 提案 + 审批 | 3 天 | Proposals API + 自动审批 + 策略表 |
| 执行引擎 | 2 天 | mission-worker + 8 个步骤执行器 |
| 触发器 + 反应 | 2 天 | 4 种触发类型 + 反应矩阵 |
| 闭环统一 | 1 天 | proposal-service + Cap Gates + 修复三个坑 |
| 情感系统 + 视觉 | 2 天 | 情感重写 + 空闲行为 + 像素办公室集成 |
| 初始化 + 上线 | 半天 | 迁移 + 种子策略 + crontab |
不算已有基础设施,核心闭环(提案 → 执行 → 反馈 → 重新触发)大约需要一周时间搭建。
最后的想法
这 6 个智能体现在每天自主运营 voxyz.space。我仍在每天优化系统——调整策略、扩展触发规则、改进智能体之间的协作方式。
还远未完美——智能体间协作仍然很基础,“自由意志"主要是通过基于概率的非确定性来模拟的。但系统确实在运行,确实不需要有人盯着。
下篇文章我会讲智能体如何"争论"和"说服"彼此——圆桌投票和 Sage 的记忆整合如何把 6 个独立的 Claude 实例变成类似团队认知的东西。
如果你也在用 OpenClaw 搭建智能体系统,我很乐意交流。作为独立开发者做这个,每一次对话都能帮你避免又一个坑。