中心化 Agent + 动态 Sandbox 架构
从 per-tenant VM 到 ephemeral compute · 让 onboarding 从分钟级降到秒级
01当前架构的问题
现在每接入一个新用户,都要在 Fly.io 上配一台 VM,里面装着 agent loop、tenant 前端、所有持久化状态。 这套结构把前端、agent、工具执行、持久化四种关注点强行打包在一个进程里, 任何一层的故障会击穿整层。更要命的是它把 onboarding 流程拉长到了无法接受的程度—— 用户注册到第一次看到 Crewlet 的价值之间,隔着一次基建配置。
- Onboarding 阻塞在 VM 配置上。用户注册之后要等 Fly machine 拉起、镜像 pull、初始化跑完,时间从几十秒到几分钟。免费用户大概率已经走了。
- 免费用户也烧钱。哪怕用户只来用 5 分钟,VM 仍在那耗资源。
- 故障爆炸半径大。VM 崩溃 = 用户的会话、记忆、产物全丢。
- OAuth token 在不可信环境里。今天得用 console-api 的 credential proxy 来绕开,代码复杂、踩过多次坑。
- 无法独立伸缩。前端流量大 ≠ agent 负载大,但今天它们绑死在同一台机器上。
02Anthropic 的范式 · Brain · Hands · Session
Anthropic 在他们自己的 Claude managed agents 平台上踩过完全一样的坑:单容器把一切打包在一起, 故障即灾难、调试不可能、每个 session 都吃完整的初始化成本。他们的总结值得直接抄。
他们的解法是把 agent 基建解耦成三个独立抽象——
Brain(agent + harness,stateless,可随时唤醒)、
Hands(sandbox/工具,作为通用 execute(name, input) 接口)、
Session(durable 事件日志,活在 Claude context window 之外)。
三层之间不互相假设对方的存在位置。
关键收益:移除强制 container 初始化之后, time-to-first-token 提升 ~60% (p50)、90%+ (p95)。这跟我们 onboarding 的痛点直接对应。
03新架构 · 三层解耦
各层职责
- Frontend 中心化。所有用户访问同一个
app.crewlet.dev,前端走 Vercel/CF。 - Agent 中心化。一组 stateless 服务实例跑所有用户的 agent loop。OAuth token 在中心可信环境里直接调外部 API,credential proxy 整体删除。
- Sandbox 按需。用户发起一次 agent run,中心服务才
sandbox.create()一个 ephemeral 实例作为这次跑的执行环境。结束即销毁。 - 持久化分两条路。结构化业务数据(proposals、对话、用户画像)通过显式 tool 直写 Postgres;agent 自己的 fs 状态(memory markdown、SKILL.md、session JSONL)放进共享存储,靠 subpath 做多租户隔离。
原语设计 · 借鉴 Claude Managed Agents
上面是高层职责划分,每一层内部应该长什么样则参考 Anthropic 自家的 Claude Managed Agents 平台。 他们把 agent 系统拆成四个独立可寻址的概念,每个都是干净边界。 我们不直接用他们的服务(绑死 Claude + Beta + plugin 要全改 MCP),但抄这种切法。
| Claude Managed Agents 原语 | 我们的实现对应 | 带来的好处 |
|---|---|---|
| Agent model + system prompt + tools + MCP + skills |
Postgres agents 表 + 中心 service 的 tool registry |
同一 agent 定义跑在不同 environment 上 · 一次配置 N 次复用 |
| Environment 容器模板 · packages · network · mounts |
Sandbox image + 启动参数(Postgres environments 表) |
Tier 1 / Tier 2 用不同 env · 重度任务换大 env · 不需要为不同任务维护不同 agent |
| Session 运行中的 agent 实例 + 持久化 state |
Postgres sessions + 共享存储 subpath |
跨 sandbox 实例 resume · 中心服务崩了不丢 · 可中断 / steer |
| Events SSE 双向流(user turn · tool result · status) |
WebSocket 流 + Postgres 事件日志(append-only) | 客户端断线重连不丢 token · 历史完全可回放 · agent 步骤可观测 |
这种拆法的本质:每个原语都是数据,独立寻址、版本化、复用。 今天 crewlet 把 agent 配置、environment、session state 全部塞在同一个进程里, 改一个要重启整套。四原语模型彻底解开这个绑死。
额外值得借鉴的实现细节
- MCP 作为外部 plugin 扩展点。我们的 plugin 系统未来可以改造成 MCP server 形态,接入更大工具生态而不破坏内部 agent 设计;同时第三方也能给 Crewlet 写 plugin。
- Session 可中断 / steer。用户中途发新消息打断 agent 改方向,不用等它跑完——明显的 UX 提升。
- 内置工具 + 外接工具分层。bash / fs / web 这类基础工具内置(每个 environment 都有),业务工具走 plugin/MCP(按 agent 配置注入)。今天我们没有这个区分。
- Outcomes / 结构化产物。Anthropic 的 outcomes feature 把 agent 最终产出抽象成结构化对象,跟 events 流分开存。我们对应的是"Proposal"这种业务产物——也应该独立建模而不是埋在 conversation 里。
04对比 · Onboarding 时序与成本
架构差异最直接的体现在用户 onboarding 上。下图把"新用户从填表到看到第一个 Proposal"这条路径放在同一条时间轴上对比。
关键不是"总时长缩短了多少秒",而是把基建等待从用户感知的关键路径上移出去了。 新架构里用户始终在"做事"——填表、看 streaming,sandbox 拉起在后台跑。
每用户成本对比
免费用户那一栏是决胜负的地方。今天的模型一台 VM ≈ $5 长期占用 + 维护成本, 而漏斗转化率通常是 5–10%。新模型让免费用户的基建成本压到接近 0(按需 ephemeral + 共享存储免费/极低成本), 让我们可以放心地把试用入口做宽。付费用户成本基本持平,本来就该花的钱。
05Tier 1 / Tier 2 · 同一套基建,两种产品形态
这套架构同时支持两种产品形态,共用同一个 agent loop 代码,区别只在 sandbox 生命周期和工具集。
| Tier 1 · 免费试用 | Tier 2 · 付费私有环境 | |
|---|---|---|
| 入口 | /content · Content Generation |
完整 Crewlet workspace |
| 用户操作 | 填表单 → 看 Proposed Actions | 持续接入 integrations · 执行 actions |
| Sandbox 模式 | Ephemeral · 跑完即删 | Long-lived · 15min auto-stop |
| 共享存储 subpath | tier1/{workspace_id} |
tier2/{workspace_id} |
| Compute 成本 | ~$0.01 / session | $3 ~ $10 / 用户 / 月 |
| 容忍延迟 | 1–2 min agent 调研 | 异步执行无强约束 |
转化的瞬间
Workspace ID 从用户首次注册就发。Tier 1 阶段所有数据都以这个 workspace_id 落 Postgres + 共享存储 subpath。
付费时只是给同一个 workspace 把 sandbox 模式从 ephemeral 切到 long-lived、subpath 从 tier1/ 迁到 tier2/,
不存在"数据迁移"。
06对 Sandbox Service 的需求清单
先不绑定具体供应商。这套架构对 sandbox service 层有以下硬需求和软需求,据此对市面方案打分。
硬需求
- Ephemeral sandbox API。能在几秒内通过 SDK 拉起一个隔离的 Linux 环境,跑完销毁。
- 共享持久存储。某种形式的 volume / 网络存储,可以挂到任意 sandbox 上、独立于 sandbox 生命周期。
- 多租户隔离机制。同一共享存储下用 subpath 或类似机制做 workspace 级隔离。
- 自定义镜像。能跑我们的 Node + Python + 工具链。
- 合理的计费颗粒。按秒/分钟计费、idle 不计费 compute。
软需求
- 稳定的 stopped → started 延迟(p95 < 3s 较理想)。
- Open source 自托管选项(降低长期锁定风险)。
- SDK 覆盖 TypeScript(首选)+ Python。
- 公网入口 / preview URL 能力(未来 Tier 2 可能需要暴露 sandbox 内的服务)。
- 组织级 quota 容得下试用流量(1 万+ workspace)。
候选供应商
| 方案 | 核心机制 | 启动量级 | 风险 |
|---|---|---|---|
| Daytona | 容器 + FUSE volume | ~90ms warm pool | FUSE 不适合 block storage (SQLite 风险) |
| E2B | Firecracker microVM | ~150ms 创建 | 持久化模型较弱 |
| Fly Sprites | Firecracker + NVMe | checkpoint/restore ~300ms | 较新 · 跟现有 Fly 账号关系待评估 |
| Blaxel | microVM + 内存 snapshot | resume ~25ms | 较新 · 价格不透明 |
| Modal | Function as compute | sub-second cold start | 更偏向 task runner,sandbox 抽象较弱 |
| 自建 Firecracker | — | 可控 | 工程量巨大,违背项目初衷 |
07迁移路径
分阶段,最小可发布优先,每阶段独立可验证。
| 阶段 | 交付 | 范围 |
|---|---|---|
| P0 | Sandbox provider PoC。30 行脚本验 ephemeral + 持久存储 + 多租户隔离 + 启动延迟分布。在 2–3 个候选供应商上跑同一组测试,得出 p50/p95 数据再选型。 | ~1 周 |
| P1 | Tier 1 · Content Generation MVP。新 /content 入口、中心 agent service、ephemeral sandbox 集成、复用现有 crewlet agent loop。Postgres schema(workspaces / proposals / biz_profiles)。 |
~3-4 周 |
| P2 | 转化漏斗。Tier 1 → Tier 2 升级流程、付费、long-lived sandbox 模式、workspace_id 不变。 | ~2 周 |
| P3 | Plugin 系统接回。Slack / GitHub / PostHog / Vercel 等 integrations 在中心服务直调(删除 credential proxy)。 | ~2-3 周 |
| P4 | 老 Fly VM 用户迁移或下线。视存量决定平行运行或一次性迁移。 | 视情况 |
P0 是必经的卡口。Sandbox provider 选型 / 性能假设 / 持久化机制三件事在 P0 里同时验证, 不通过则 P1 的部分子系统(特别是 memory)走 fallback 方案。
08待决策 · 开放问题
- Tier 1 agent 工具集边界。研究 agent 只用 read_file / write_file / web_search / save_proposal,还是也要 memory tools?决定 PoC 是否要测某种形式的向量库 over 网络存储。
- Tier 1 用户回访的 fs 保留策略。无限保留?30 天后清理 subpath?这是产品决策。
- Frontend 部署目标。Vercel vs Cloudflare Pages?决定 build pipeline。
- Postgres 托管选型。Supabase 继续?还是换 Neon / RDS?
- 老 Fly VM 用户的迁移承诺。是否做兼容层让现有付费用户透明切换。
- Sandbox provider 最终选型。基于 P0 实测结果决定(见 §06 候选清单)。
- 是否将 plugin 改造为 MCP server 形态。短期不动,但长期方向需要早表态——影响 Tier 2 plugin 接入设计。