1 一句话总结
FastClaw 是一个 单二进制、全状态外置 的 Go 语言 AI Agent 运行时。 它天然支持存算分离:Postgres 存元数据,S3 存文件,Gateway 无状态, 可以通过 K8s HPA 从 2 副本弹到 10 副本,且各副本共享同一份状态——这正是 SaaS 多租户 Agent 平台所需的核心能力。
2 存算分离全景图
FastClaw 没有 fastclaw.json 配置文件,也没有本地状态文件。所有持久化被清晰地拆入三个层级:
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
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 数量
admin / user / agent 三级 API Key,agent 级 Key 可绑定特定 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 ...;
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 部署——不只是能跑,是能规模化
2-10 副本,CPU 利用率 > 60% 触发扩容
maxUnavailable=0, maxSurge=1,零中断部署
minAvailable=1,驱逐保证
preStop 15s sleep + Go graceful shutdown,SSE/WS 连接 drain
Ingress Cookie affinity + Service ClientIP,SSE 长连接不中断
两种部署方式,适配不同运维偏好
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 等 |
6 计算沙箱:用完即弃的"算"层
Docker 模式(单机)
本地 Docker daemon 启动容器,适合开发环境和单副本部署。启动时自动 hydrate skills + workspace 到容器。
E2B 模式(云端)
远程云端沙箱,K8s 环境的标准选择(Pod 内无 Docker daemon)。按需创建,API Key 管理。
7 任务队列:保证 Chat 级别的有序,全局并发可控
每个 Chat 拥有独立的 FIFO 队列和 goroutine,同一会话内的消息严格串行——用户不会看到乱序回复。
全局 counting semaphore 控制并发上限(默认 10),防止同时处理的 Chat 数打爆 LLM API 速率限制。
每个 Task 有 5 分钟超时(可配),超时自动取消。
5 分钟内无新消息的空闲队列自动回收 goroutine,内存友好。
8 API 设计:OpenAI 兼容 + SaaS 原语
OpenAI 兼容格式,支持 streaming。第三方应用无需改 Client 代码即可接入。
Web 端 SSE 推送,实时 token 流。另有 /api/chat/subscribe 用于 cron 触发的异步回复推送。
Agent 全生命周期管理,支持 forkFrom 克隆 Agent 给其他用户——"用户下单买 bot"的核心 API。
第三方 App 按需创建用户,幂等 (api_key, external_id)。
9 存算分离深度验证:沙箱回收后,定时任务还在吗?
问题:如果智能体配置了定时任务,沙箱回收以后这个定时任务还在吗?
答案:完全不受影响。因为定时任务的定义和调度跟沙箱根本不在同一层。
Agent 调用 create_cron_job 工具时,job 记录直接写入 Postgres 的 cron_jobs 表。这是"存"层——持久化的元数据。
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 对"后台任务"的理解分两层,分别对应"存"和"算"两个不同的生命周期:
第一层:Cron Job
第二层:Background Shell
Background Shell 详解(Claude Code 风格)
exec({
command: "npm run dev",
run_in_background: true
})
bash_output({
bash_id: "bash_3"
})
kill_shell({
bash_id: "bash_3"
})
• 用 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_task 和 spawn_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 就绪性清单
对 Blade Agent / Hermes 的启示
如果你在考虑类似"把 CLI Agent 改造成 SaaS 服务"的路径,FastClaw 提供了一个清晰的参考架构:
(1) 把会话状态从本地文件系统迁到 Postgres;
(2) 把文件产物从本地目录迁到 S3;
(3) 把代码执行放进远程沙箱(E2B 或容器);
(4) Gateway 进程变成纯路由 + LLM 编排层;
(5) 加上用户/租户/用量模型;
(6) 区分"持久后台"(cron,存 DB)和"会话后台"(background shell,存内存),不能混为一谈。