Butterbase Durable Objects 深度解析:用有状态 Actor 构建聊天室与长时运行 Agent

📅 发布时间:2026/9/25 20:09:54
Butterbase Durable Objects 深度解析:用有状态 Actor 构建聊天室与长时运行 Agent
Butterbase Durable Objects 深度解析用有状态 Actor 构建聊天室与长时运行 Agent【免费下载链接】butterbase-ossOpen-source backend-as-a-service. Postgres, auth, storage, functions, AI gateway, MCP.项目地址: https://gitcode.com/gh_mirrors/bu/butterbase-ossButterbase是一款开源的 Backend-as-a-ServiceBaaS平台提供 Postgres 数据库、认证、存储、Functions 与 AI 网关。其中的Durable ObjectsDO是有状态的计算原语每个实例像一个常驻内存的 Actor天然适合构建聊天室、多人游戏、实时协作和长时运行的 AI Agent。本文带你从零理解 DO 的工作机制并看一个真实模板如何用它跑起客服 Agent。什么是 Durable Objects有状态 Actor 模型 传统的 Serverless 函数是无状态的——请求来了算完就走下一个请求谁接都不知道。而 Durable Objects 反其道而行按实例隔离每个 DO 由「类名 实例 ID」唯一确定。/lobby、/general、/team-1是完全隔离的独立 Actor各自拥有独立状态和连接状态常驻内存Actor 在多次请求之间一直活在内存里跨请求持有变量、缓存、WebSocket 连接内置事务存储state.storage提供事务型 KV 持久化即使 Actor 被换到别的机器也能无损恢复原生 WebSocketacceptWebSocket()让 DO 能长驻连接这正是聊天室、实时游戏的刚需一句话判断准则只要状态是按房间 / 按用户 / 按 Agent划分的就用 DO如果是无状态的 API请用 Functions。完整概念说明见官方文档durable-objects.md3 步部署你的第一个 Durable Objects第 1 步写一个单文件 TS 类DO 的源码要求极简单文件、单类、无 npm 依赖只允许cloudflare:workers导入export class ChatRoom { constructor(public state: DurableObjectState, public env: any) {} async fetch(req: Request) { // 处理 HTTP 或 WebSocket 升级 } }第 2 步一条 CLI 命令部署butterbase do deploy chat-room.ts --name chat-roomCLI 的实现位于 do.ts部署成功后会直接打印出访问 URL。第 3 步拿到你的专属 URL部署后每个实例都有固定地址同时支持 HTTP 和 WebSockethttps://你的子域名.butterbase.dev/_do/chat-room/lobby⚠️ 注意DO只在应用子域名下可访问挂在控制 APIapi.butterbase.ai/v1/.../_do/...下会返回 404。用 DO 构建实时聊天室核心模式解析聊天室是 DO 最经典的应用。核心代码逻辑只有四件事WebSocket 升级收到Upgrade: websocket请求时创建WebSocketPair调用state.acceptWebSocket()接受连接新加入者补发历史从state.storage.get(messages)读出最近 100 条消息发给新客户端避免迟到的人看不到之前的聊天持久化 广播每条新消息写入存储并slice(-100)控制长度然后广播给所有连接防御性处理运行时可能投递字符串或 ArrayBuffer解析前必须做类型守卫否则会直接崩溃一个细节值得记住Cloudflare 会休眠空闲 DO——把它从内存中驱逐但保留 WebSocket 连接。所以关键 ID如ticket_id要存进state.storage让被唤醒的 DO能重新找回自己是谁。长时运行 Agent 实战Butter Support 模板 理论讲完看看生产级用法。仓库自带的 Butter Support 模板 是一个完整的 AI 客服台嵌入式小部件接住用户提问RAG 从你的文档中找答案Agent 起草回复后交由人工审批或按自治度配置自动处理。它背后跑着两个 Durable Objects① 工单大脑support-ticket-do.ts每个工单是一个独立的 DO 实例整个 Agent 生命周期都在这个房间里完成内置 RAG 检索search_docs、诊断、草稿回复、升级转人工等 7 个工具硬性护栏单轮最多 25 次 LLM 调用、15 万输入 Token 上限能感知客户情绪识别愤怒用词、全大写爆发、找真人话术自动提升处理优先级② 推送通道widget-ticket-do.ts面向客户的 WebSocket 扇出 Actor服务端函数一旦产生新回复就通过内部路由推给这个 DO它把消息帧广播给该工单下所有在线的小部件。访客身份通过visitor_token校验且只放行客户可见的消息角色——草稿、内部工具帧永远不会泄露给终端用户。访问模式与环境变量配置每个 DO 部署时声明一种访问模式模式说明适用场景public任何人可调面向浏览器的小部件authenticated默认需要终端用户 JWT内部应用调用service_key需要 Butterbase 服务密钥服务端到服务端⚠️WebSocket 认证陷阱浏览器 WebSocket 无法自定义请求头所以面向浏览器的 WS 通道要设public然后在fetch()里自己从?token或子协议头中校验 token。DO 还可以读取应用级环境变量butterbase do env set KEY VALUE变更会自动触发重新部署立即生效值只写不读list只返回键名。环境变量的管理实现见 durable-objects-client.ts。服务端互调ctx.invokeDO 让组件打电话Functions 和 DO 之间不需要拼公网 URL、不需要手动传 Bearer Token// 在 Function 中直接调用 DO const res await ctx.invokeDO(support-ticket-do, ticket-42, { cmd: handleFollowup, note: customer replied, });在 DO 内部则通过butterbase.ctx(req, env, state)拿到ctx可以invokeDO调兄弟 DO、invoke调同应用的 Function还能通过ctx.request.caller知道是谁在调我调用链最深 4 跳。什么时候不该用 DO❌场景推荐方案无状态 API 端点Function跨键的数据库式查询Postgres Auto-API数据库变更驱动的实时推送Postgres Realtime静态前端 / 服务端渲染Frontend Deployment / Edge SSR硬性限制与故障排查清单单应用最多 5 个 DO 类全部 DO 压缩后总和不超过 10 MB单个 KV 值上限 128 KB更大的文件请走 Storage删除 DO 类会立即抹掉所有实例和存储不可恢复暂不支持改类名——新名注册、迁移数据、删旧名常见报错速查报错原因Source must export exactly one class文件必须只导出一个类Import X is not allowed只允许cloudflare:*导入无 npm 打包Too many DO classes超过 v1 的 5 类上限WS 连接秒断检查访问模式authenticated会拒绝无 Bearer 的升级请求用量方面平台每 15 分钟拉取 Cloudflare 指标到do_requests请求数和do_cpu_msCPU 毫秒两个计量器可用butterbase do usage name查看。写在最后Durable Objects 把聊天室、游戏房间、长时 Agent这类最难写有状态后端的场景变成了一份单文件 TS 类加一条部署命令。配合 Butter Support 模板你甚至不用从零写起——克隆一个现成的 AI 客服台配置好 7 个 DO 环境变量RAG 文档导入后你的 Agent 就开始工作了。想动手试试仓库可以这样克隆git clone https://gitcode.com/gh_mirrors/bu/butterbase-oss更多资料控制面 DO 数据模型、服务端部署逻辑、REST 路由。【免费下载链接】butterbase-ossOpen-source backend-as-a-service. Postgres, auth, storage, functions, AI gateway, MCP.项目地址: https://gitcode.com/gh_mirrors/bu/butterbase-oss创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考