ARCHITECTURE SAAS DEEP DIVE

FastClaw:为 SaaS 多租户而生的 Agent 运行时

深度架构分析 — 存算分离、水平扩展、多租户隔离

分析日期:2026-06-02 | 仓库:github.com/fastclaw-ai/fastclaw | 语言:Go + TypeScript

1 一句话总结

FastClaw 是一个 单二进制、全状态外置 的 Go 语言 AI Agent 运行时。 它天然支持存算分离:Postgres 存元数据,S3 存文件,Gateway 无状态, 可以通过 K8s HPA 从 2 副本弹到 10 副本,且各副本共享同一份状态——这正是 SaaS 多租户 Agent 平台所需的核心能力。

2 存算分离全景图

FastClaw 没有 fastclaw.json 配置文件,也没有本地状态文件。所有持久化被清晰地拆入三个层级:

🗄️
结构化元数据
Postgres
用户 / API Key
Agent / SOUL / 会话
配置 / 渠道 / 用量
📦
非结构化文件
S3 / OSS / R2
Agent 生成的文件
PDF / 图片 / 音频
会话工作区产物
计算沙箱
E2B / Docker
工具执行环境
代码运行 / 文件操作
完成任务后自动回收
Tier 1 元数据层 — 所有 Pod 共享同一个 Postgres,配置/会话/Agent 定义即时一致 Tier 2 文件层 — S3 Signed URL 直接下载,绕开 Gateway Tier 3 执行层 — 用完即弃(Idle TTL eviction),文件在执行后自动回写持久层

3 为什么天然适合做 SaaS Agent 底座

3.1 Gateway 进程是彻底无状态的

启动依赖仅 2 个环境变量——剩下的全部从 DB 和对象存储读取。任何一个 Pod 启动后看到的世界完全相同。

# 一个 Pod 需要的全部启动参数
FASTCLAW_STORAGE_TYPE=postgres
FASTCLAW_STORAGE_DSN=postgres://u:pass@host:5432/db?sslmode=require
# 文件层(可选,单副本时可用 local)
FASTCLAW_OBJECT_STORE_TYPE=aws-s3
FASTCLAW_OBJECT_STORE_BUCKET=my-bucket
FASTCLAW_OBJECT_STORE_ACCESSKEY=AKIA...
FASTCLAW_OBJECT_STORE_SECRETKEY=xxx
无配置文件 无启动顺序依赖 Pod 随意替换

3.2 官方多副本验证——存算分离不是口号

项目自带的 deploy/multi-pod/docker-compose.yaml 是存算分离的活体证明:

services:
  db:        # Postgres 16 — 唯一的状态中心
  minio:     # MinIO — 文件对象存储
  pod-a:     # Gateway 实例 A(端口 18953)
  pod-b:     # Gateway 实例 B(端口 18954)— 完全相同配置,共享 DB + MinIO

核心验证场景:Pod A 创建 Agent → Pod B 立即可见;Pod A 写 SOUL.md → Pod B 读到相同内容;Kill Pod A → Pod B 继续服务。

3.3 多租户是原生设计,不是后加的

用户模型

super_admin / admin / user 三级角色,agent_quota 控制每个用户可创建的 Agent 数量

API Key 体系

admin / user / agent 三级 API Key,agent 级 Key 可绑定特定 Agent 白名单

公开 Agent

toggle Public access,开放后任何用户可用自己的 session/memory 与 Agent 对话,无需共享身份

配置继承链

System → User → Agent 三级 scope,Per-agent 覆盖 provider/model/channel,非 admin 可叠加私有 overlay

3.4 内置用量计量——SaaS 计费的前提

FastClaw 在 LLM Provider 调用点和 Workspace 写入点分别做了用量埋点,存入 Postgres 的 token_usage_daily 表:

-- 每次 API 调用的粒度
INSERT INTO token_usage_daily
  (day, user_id, agent_id, session_key, provider, model,
   input_tokens, output_tokens, cache_read_tokens, cache_create_tokens, request_count)
VALUES (...)
ON CONFLICT (day, user_id, agent_id, session_key, provider, model)
  DO UPDATE SET ...;
按天聚合 按 (用户, Agent, Session, 模型) 六维切片 Admin Dashboard Leaderboard Workspace 写入字节计量

3.5 面向第三方 App 的 End-User 供给

第三方应用(你自己的 SaaS)通过 API Key 调用 FastClaw 时,不需要预先创建用户——FastClaw 支持 lazy mint

# 方式 1:显式创建
POST /v1/users  { "api_key": "...", "external_id": "user-42" }
# → 幂等返回 stable fastclaw user_id

# 方式 2:首次调用时自动创建
POST /v1/chat/completions
{ "user": "user-42", ... }
# 或通过 Header: X-Fastclaw-End-User: user-42

每个 external_id 自动对应 FastClaw 内部的一个 user,session/memory/apiKey 自动隔离。

4 生产级 K8s 部署——不只是能跑,是能规模化

HPA 水平自动伸缩

2-10 副本,CPU 利用率 > 60% 触发扩容

滚动更新

maxUnavailable=0, maxSurge=1,零中断部署

PodDisruptionBudget

minAvailable=1,驱逐保证

优雅关停

preStop 15s sleep + Go graceful shutdown,SSE/WS 连接 drain

Session Affinity

Ingress Cookie affinity + Service ClientIP,SSE 长连接不中断

Helm Chart + 单文件 YAML

两种部署方式,适配不同运维偏好

5 对象存储适配层——S3 不是唯一选择

FastClaw 的 Workspace 层通过统一的 Store interface 抽象,后端可选:

Type 值 提供商 Endpoint 推导 场景
local 本地磁盘 单机开发 / 单副本部署
aws-s3 AWS S3 s3.{region}.amazonaws.com AWS 环境
aliyun-oss 阿里云 OSS oss-{region}.aliyuncs.com 国内 ACK 集群,支持 internal endpoint 免流量费
cloudflare-r2 Cloudflare R2 {accountId}.r2.cloudflarestorage.com 零出站流量费
backblaze-b2 Backblaze B2 s3.{region}.backblazeb2.com 低成本存储
minio 自建 MinIO 需提供 Endpoint 私有化部署
s3 S3 兼容 需提供 Endpoint DO Spaces / Wasabi 等
亮点:FastClaw 使用 MinIO Go SDK 的 CopyObject 实现跨 scope 的 Move 操作 (如 chat 拖入/拖出 project),数据不经过 Gateway——纯 S3 server-side copy,零带宽消耗。 下载也通过 PresignedGetObject 直接返回 S3 签名 URL 给浏览器,Gateway 不当中转站。

6 计算沙箱:用完即弃的"算"层

Docker 模式(单机)

本地 Docker daemon 启动容器,适合开发环境和单副本部署。启动时自动 hydrate skills + workspace 到容器。

E2B 模式(云端)

远程云端沙箱,K8s 环境的标准选择(Pod 内无 Docker daemon)。按需创建,API Key 管理。

关键设计:每次 tool call 执行完成后,沙箱内产生的文件自动 sync 回 Workspace Store (Postgres 或 S3)。沙箱本身有 Idle TTL,超时自动 eviction——"算"可以随时丢弃,"存"永远在持久层。 这也是存算分离在 Agent 框架中的关键体现:工具执行的环境是临时的,产出物是持久的。

7 任务队列:保证 Chat 级别的有序,全局并发可控

Per-Chat

每个 Chat 拥有独立的 FIFO 队列和 goroutine,同一会话内的消息严格串行——用户不会看到乱序回复。

Global

全局 counting semaphore 控制并发上限(默认 10),防止同时处理的 Chat 数打爆 LLM API 速率限制。

Timeout

每个 Task 有 5 分钟超时(可配),超时自动取消。

Idle Cleanup

5 分钟内无新消息的空闲队列自动回收 goroutine,内存友好。

8 API 设计:OpenAI 兼容 + SaaS 原语

/v1/chat/completions

OpenAI 兼容格式,支持 streaming。第三方应用无需改 Client 代码即可接入。

/api/chat/stream (SSE)

Web 端 SSE 推送,实时 token 流。另有 /api/chat/subscribe 用于 cron 触发的异步回复推送。

/api/agents CRUD

Agent 全生命周期管理,支持 forkFrom 克隆 Agent 给其他用户——"用户下单买 bot"的核心 API。

/v1/users (lazy mint)

第三方 App 按需创建用户,幂等 (api_key, external_id)。

9 存算分离深度验证:沙箱回收后,定时任务还在吗?

问题:如果智能体配置了定时任务,沙箱回收以后这个定时任务还在吗?

答案:完全不受影响。因为定时任务的定义和调度跟沙箱根本不在同一层。

🗄️
任务定义 → Postgres

Agent 调用 create_cron_job 工具时,job 记录直接写入 Postgres 的 cron_jobs 表。这是"存"层——持久化的元数据。

调度器 → Gateway 进程

Scheduler 运行在 Gateway 进程内,pollStore() 每分钟轮询 DB 查到期任务。这是"算"层的编排——独立于沙箱。

🏗️
触发时 → 按需创建沙箱

Cron 触发时将消息投递到 MessageBus,Agent handler 处理时才 lazily 创建新沙箱执行工具。沙箱只是一个临时的"手套"。

完整代码链路

创建 agent 调用 create_cron_job
  → makeCreateCronJob()  // internal/agent/tools/cron.go:152
  → st.SaveCronJob(ctx, job)   ← 写入 Postgres / SQLite
  → cron.NotifyJobCreated()    ← 唤醒 Gateway 内的调度器
调度 Gateway 启动
  → NewSchedulerFromStore(st, mb)  // internal/cron/scheduler.go:135
  → pollStore()  每分钟轮询 cron_jobs 表
    → GetDueCronJobs(now)   查到期任务
    → LockCronJob(id, instanceID)  ← 分布式锁,防多 Pod 重复触发
    → bus.Inbound ← 投递消息
执行 bus.Inbound 消息到达
  → TaskQueue 分配 goroutine
  → Agent handler 处理
    → 如果沙箱已被回收,lazily 创建新沙箱
    → 工具执行完成 → 文件 sync 回持久层
    → 沙箱空闲超时后再回收

🤔 一个关键设计约束:Agent 必须用平台工具,不能用 OS cron

如果 Agent 自作聪明用 exec 去调 crontab -e 写 Linux cron,那任务在沙箱回收后就跟着没了。 这不是 bug,是存算分离架构下的一个契约约束:SOUL.md 和系统提示必须明确引导 Agent 用 create_cron_job 而非 OS 级 cron。 本质上,这是在 disposable 的计算层之上,对 LLM Agent 施加的一种 capability discipline——把持久化需求从临时执行环境剥离,引导 Agent 走正确的路径。

🌐 多 Pod 环境下的 Cron 安全

LockCronJob(jobID, instanceID) 实现了分布式锁:同一时刻只有一个 Pod 能拿到锁并触发该任务。 这避免了多副本场景下同一定时任务被重复执行。锁通过 Postgres 行级操作实现,天然跨 Pod 有效——又一个"用存来协调算"的例证。

10 后台任务的两层架构:Cron Job vs Background Shell

FastClaw 对"后台任务"的理解分两层,分别对应"存"和"算"两个不同的生命周期

C

第一层:Cron Job

存储Postgres
生命周期跨会话 / 跨沙箱
触发方式Scheduler 轮询 DB
工具接口create_cron_job
适用场景定时提醒 / 周期检查
归属"存" 层
B

第二层:Background Shell

存储Gateway 进程内存
生命周期跟随 Agent 会话
触发方式Agent 主动 exec(background)
工具接口exec(run_in_background=true)
适用场景dev server / 长脚本 / 构建
归属"算" 层

Background Shell 详解(Claude Code 风格)

启动
exec({
command: "npm run dev",
run_in_background: true
})
→ 返回 bash_id(如 bash_3)
观察
bash_output({
bash_id: "bash_3"
})
→ 增量返回新输出 + 运行状态
终止
kill_shell({
bash_id: "bash_3"
})
→ 进程组级 SIGKILL

• 用 context.Background() 而非请求 context——进程存活期不受单轮 tool call 超时限制

• 4 MiB 环形缓冲区,超出时 FIFO 丢弃旧字节,bash_output 返回时标注 [truncated]

• 进程组 kill(setProcessGroup + killProcessGroup),确保 fork 的子进程一并终止

• 环境变量显式构建,不继承 daemon 密钥(如 FASTCLAW_STORAGE_DSN)

仅 host 模式可用——sandbox 模式下被拒绝,提示改用 tmux 替代

⚠ 关键差异:会话关闭时

Agent 会话关闭时,Registry.Close()shellManager.Close() 会杀掉所有 background shell。 这和 cron job 根本不同——cron 存在 DB 里永不过期,background shell 存在内存里随会话消亡。 这就是存算分离在后台任务上的直接体现:持久需求走"存",临时需求走"算"。

补充:delegate_taskspawn_subagent 虽然能委派子任务,但它们都是同步阻塞的——主 Agent 等待子 Agent 完成才继续。 这不是"后台"任务,而是"子任务委派"。三个概念各自独立:Cron(持久后台)、Background Shell(会话内长进程)、Delegate(同步子任务)。

11 对比:FastClaw vs 典型的 Agent 框架

维度 FastClaw 典型 CLI Agent
(Hermes / Claude Code / Codex)
部署方式 Server + 多副本 CLI 单进程
状态管理 全外置:Postgres + S3 文件系统:~/.hermes/、~/.claude/ 等
多租户 原生支持 单用户(同一个 OS user)
用户管理 内置角色 + API Key + 配额
水平扩展 K8s HPA 2-10 副本 无法水平扩展
用量计量 内置 Token + Storage 计量 通常无或仅本地日志
接口协议 HTTP REST + SSE + WebSocket
OpenAI 兼容 /v1/chat/completions
本地 stdin/stdout 或 WebSocket
不提供 OpenAI 兼容 API
渠道接入 Telegram / Discord / Slack
内置 Bot 绑定
部分支持(如 Hermes 的 gateway)
但非独立多租户架构
目标场景 SaaS 平台底座 开发者个人工具

12 结论 & 启示:从 SaaS 角度的完整评估

FastClaw 的架构哲学可以用一句话概括:

"Gateway 是传话的,Postgres 是记事的,S3 是存文件的,沙箱是干活的——四个角色各司其职,没有一个承担双重身份。"

这份存算分离的架构带来的 SaaS 能力是结构性的,不是功能堆砌出来的:

  • 无状态 → 可水平扩展:因为 Gateway 不存状态,所以它可以像任何标准的 Web 服务一样做 HPA。Agent 逻辑不再是单体的瓶颈。
  • 外置存储 → 多租户隔离天然:Postgres 的行级数据天然按 user_id / agent_id 隔离,S3 的 key prefix 也按 agent 命名空间分层。不需要在代码里硬写租户路由逻辑。
  • 用量透明 → 计费可行:token_usage_daily 表让 SaaS 平台可以按用户/Agent/模型维度出账单,这是任何 SaaS 商业化的前提。
  • API-first → 易于集成:OpenAI 兼容的 /v1/chat/completions 意味着现有的 AI 应用生态可以零成本接入。
  • 单二进制 → 运维简单:整个系统打成一个 Go 二进制(内嵌 React 前端),Docker 镜像极小,启动极快。

SaaS 就绪性清单

多租户用户体系(角色 + 配额 + API Key 三级)
Token 用量计量(六维切片:日×用户×Agent×会话×模型)
存储用量计量(workspace metering)
水平伸缩(HPA 2-10 副本 + 滚动更新零中断)
定时任务持久化(Cron Job → DB,分布式锁防重复)
公开 Agent 共享(session/memory per-chatter 隔离)
App-user lazy provisioning(幂等 external_id)
7 种对象存储后端 + 7 种 LLM Provider
内置 Web Dashboard(Agent 管理 / 用量面板)
IM 渠道接入(Telegram / Discord / Slack)

对 Blade Agent / Hermes 的启示

如果你在考虑类似"把 CLI Agent 改造成 SaaS 服务"的路径,FastClaw 提供了一个清晰的参考架构:
(1) 把会话状态从本地文件系统迁到 Postgres;
(2) 把文件产物从本地目录迁到 S3;
(3) 把代码执行放进远程沙箱(E2B 或容器);
(4) Gateway 进程变成纯路由 + LLM 编排层;
(5) 加上用户/租户/用量模型;
(6) 区分"持久后台"(cron,存 DB)和"会话后台"(background shell,存内存),不能混为一谈。

注意:FastClaw 当前是 source-available 协议(FastClaw Community License),允许商用但禁止将其作为多租户 SaaS 转售给不相关组织。用于自己产品的后端是允许的。