Agent 的第三次浪潮:Cloudflare Project Think 是什么,要解决什么问题

原文:Project Think: building the next generation of AI agents on Cloudflare


一个改变了认知的观察

Cloudflare 团队每天在用 Claude Code、Codex 这类编码 Agent。他们发现了一件事:人们用这些工具做的,远不只是写代码。

管理日历、分析数据集、谈判采购、填税表、自动化整条业务流程------这些用法背后的模式是一致的:Agent 读取上下文,推理,写代码来采取行动,观察结果,然后迭代。代码成了行动的通用媒介。

这个洞察很有力量,但当前的 Agent 碰到了三堵结构性的墙:

  • 只跑在本地或高价 VPS 上:无法共享、无法协作、无法在设备之间交接
  • 闲置也在烧钱:无论 Agent 在不在工作,每月的固定成本都在跑。拓展到一个团队、一家公司,成本会快速叠加
  • 需要手动管理和配置:安装依赖、管理更新、配置身份和密钥

这三个问题加在一起,意味着"每个用户配一个 Agent"在现有的基础设施范式下,根本跑不通。


规模化的根本矛盾:Agent 天然是一对一的

传统应用的扩容逻辑是:一个实例服务多个用户,用户越多,单个用户的基础设施成本越低。

Agent 不是这样的。每个 Agent 是一个唯一的实例,服务一个用户,运行一项任务。餐厅有一张菜单、一个厨房,可以批量出餐;Agent 更像私人厨师,每次都是不同的食材、不同的技法、不同的工具。

这从根本上改变了扩容的数学。如果 1 亿知识工作者各自拥有一个 Agent,哪怕并发使用率不高,你也需要同时支撑数千万个活跃会话。按照当前的容器成本,这是不可持续的。

这就是 Project Think 要解决的问题:Agent 需要一个不同的计算基础。


基础:为什么 Durable Objects 改变了经济账

Project Think 建立在 Cloudflare 的 Durable Objects(DO)之上。理解 DO 的特性,是理解后续所有设计决策的前提。

DO 实现的是 Actor 模型 :每个 Agent 是一个可寻址的实体,有自己独立的 SQLite 数据库。关键在于它的休眠机制------Agent 不工作时,消耗的计算资源是零。当某件事发生(一条 HTTP 请求、一条 WebSocket 消息、一封入站邮件、一个定时闹钟),平台才唤醒 Agent,加载它的状态,把事件交给它处理。处理完,Agent 重新进入休眠。

这和容器的差异,用一张表来对比会更直观:

容器 / VM Durable Objects
闲置成本 全额计算费用,始终在跑 零(休眠态)
扩容方式 需要预置和管理容量 自动,按 Agent 粒度
状态存储 需要外部数据库 内置 SQLite
崩溃恢复 自己实现(进程管理、健康检查) 平台重启,状态保留
路由寻址 自己实现(负载均衡、会话粘性) 内置(名称直接路由到 Agent)
1 万个 Agent,各自 1% 时间活跃 1 万个常驻实例 约 100 个活跃实例

这张表的最后一行说明了问题。DO 把"同时跑 1 万个 Agent"的成本,实际上压缩成了"同时跑约 100 个"的成本。

这改变了产品设计的可能性边界。"每个客户一个 Agent"、"每个任务一个 Agent"、"每条邮件线程一个 Agent",这些原来成本不可接受的设计,在 DO 上都变得可行。创建一个新 Agent 实例的边际成本,几乎是零。


Project Think 的六项新原语

一、持久执行:Agent 崩溃了也能续跑

一次 LLM 调用可以持续 30 秒,一个多轮 Agent 循环可以跑更长时间。在这个过程中,执行环境随时可能消失:一次部署、一次平台重启、撞到资源上限。连接断开,内存状态丢失,客户端看到的是流突然停了,没有任何说明。

runFiber() 解决这个问题。Fiber 是一种持久化的函数调用:在执行开始前就注册到 SQLite,可以通过 stash() 在任意节点设置检查点,在 Agent 重启后通过 onFiberRecovered 从最近的检查点恢复:

typescript 复制代码
export class ResearchAgent extends Agent {
  async startResearch(topic: string) {
    void this.runFiber("research", async (ctx) => {
      const findings = [];

      for (let i = 0; i < 10; i++) {
        const result = await this.callLLM(`Research step ${i}: ${topic}`);
        findings.push(result);

        // 检查点:如果 Agent 被驱逐,从这里恢复
        ctx.stash({ findings, step: i, topic });
        this.broadcast({ type: "progress", step: i });
      }

      return { findings };
    });
  }

  async onFiberRecovered(ctx) {
    if (ctx.name === "research" && ctx.snapshot) {
      const { topic } = ctx.snapshot;
      await this.startResearch(topic);
    }
  }
}

SDK 会在 Fiber 执行期间自动维持 Agent 存活,不需要额外配置。对于以分钟计的任务,keepAlive() 防止在活跃工作期间被驱逐;对于更长的操作(CI 流水线、视频生成),Agent 启动任务、持久化任务 ID、进入休眠,等待回调唤醒。

二、子 Agent:把工作分发出去

一个 Agent 不应该什么都自己做。子 Agent 是与父 Agent 并置的子 Durable Objects,各有独立的 SQLite 和执行上下文:

typescript 复制代码
export class Orchestrator extends Agent {
  async handleTask(task: string) {
    const researcher = await this.subAgent(ResearchAgent, "research");
    const reviewer = await this.subAgent(ReviewAgent, "review");

    const [research, review] = await Promise.all([
      researcher.search(task),
      reviewer.analyze(task)
    ]);

    return this.synthesize(research, review);
  }
}

子 Agent 之间的数据完全隔离------没有隐式的共享状态,各自的 SQLite 互不可见。Sub-agent 之间的 RPC 调用延迟等同于一次函数调用,而 TypeScript 在编译阶段就能捕获接口误用。

三、持久会话:支撑长达数周的对话

跑几天甚至几周的 Agent,光靠一个扁平的消息列表是不够的。Session API 把对话建模为树形结构 ,每条消息都有 parent_id

这带来了几个实际能力:分叉 (在不丢失原始路径的情况下探索另一个方向)、非破坏性压缩 (总结老消息而不是删除它们,完整历史仍保存在 SQLite 里)、以及通过 FTS5 全文索引在对话历史里搜索。

四、从工具调用到代码执行

传统的工具调用有一个固有的尴尬:模型调用一个工具,结果拉回上下文窗口,再调用下一个,再拉回,如此循环。100 个文件意味着 100 次往返。工具数量越多,这个过程越笨重也越昂贵。

@cloudflare/codemode 背后的洞察是:让模型写一个程序来处理整个任务,比让它逐个玩工具调用要好得多。

javascript 复制代码
// LLM 写出这段代码,在沙箱 Dynamic Worker 里运行
const files = await tools.find({ pattern: "**/*.ts" });
const results = [];
for (const file of files) {
  const content = await tools.read({ path: file });
  if (content.includes("TODO")) {
    results.push({ file, todos: content.match(/\/\/ TODO:.*/g) });
  }
}
return results;

100 次模型往返变成 1 次。Cloudflare 在自己的 API MCP Server 上验证了这个效果:只暴露 search()execute() 两个工具(约 1,000 个 Token),对比为每个 API 端点各暴露一个工具的等效方案(约 117 万个 Token),Token 消耗减少了 99.9%

五、执行阶梯:五个层级,按需升级

一旦接受"让模型写代码来行动"这个前提,下一个问题就是:这些代码在哪里安全地跑?

Project Think 定义了一个执行阶梯,Agent 根据任务需要逐级提升执行环境的能力:

Tier 0 --- 工作空间 :基于 SQLite 和 R2 的持久化虚拟文件系统。读、写、编辑、搜索、grep、diff,由 @cloudflare/shell 提供支撑。

Tier 1 --- Dynamic Worker(沙箱隔离) :LLM 生成的 JavaScript 跑在一个独立的 V8 隔离环境里,默认无网络访问globalOutbound: null)。这和"先给一台通用机器再想办法限制它"的思路相反------Dynamic Worker 从零权限开始,开发者通过 bindings 显式授予每一项能力。

在规模上:一个新 Dynamic Worker 的启动时间是毫秒级,内存占用在几 MB 量级,约是容器的 100 倍速度、100 倍内存效率。

Tier 2 --- npm@cloudflare/worker-bundler 从 npm 注册表拉取包,用 esbuild 打包,加载进 Dynamic Worker。Agent 写 import { z } from "zod",直接可用,不需要预装任何东西。

Tier 3 --- 无头浏览器:通过 Browser Run 实现网页导航、点击、内容提取、截图。在目标服务还没有支持 MCP 或 API 的时候,这是让 Agent 仍然能行动的方案。

Tier 4 --- 完整沙箱 :配置好工具链、代码仓库和依赖的 Cloudflare Sandbox,支持 git clonenpm testcargo build,和工作空间双向同步。

设计原则:Agent 在 Tier 0 单独就能工作,每一层都是增量能力的叠加,而不是必须整体引入。

六、自编写扩展:Agent 为自己写工具

Think 把代码执行推进了一步。Agent 可以在运行时为自己编写新的扩展------TypeScript 程序,运行在 Dynamic Worker 里,声明对网络和工作空间的权限:

json 复制代码
{
  "name": "github",
  "description": "GitHub integration: PRs, issues, repos",
  "tools": ["create_pr", "list_issues", "review_pr"],
  "permissions": {
    "network": ["api.github.com"],
    "workspace": "read-write"
  }
}

ExtensionManager 打包扩展(可以带 npm 依赖),加载进 Dynamic Worker,注册新工具。扩展持久化在 DO 存储里,休眠后仍然存在。

30 秒前还没有 github_create_pr 工具,现在有了。这不是通过微调或 RLHF 实现的自我改进,而是通过代码------沙箱隔离、可审计、可撤销的 TypeScript。


Think 基类:10 行代码得到一个完整 Agent

Project Think 同时提供了一个叫做 Think 的基类,把上述所有原语接在一起,处理完整的 chat 生命周期:会话循环、消息持久化、流式输出、工具执行、流恢复。

最简单的用法只有 10 行:

typescript 复制代码
import { Think } from "@cloudflare/think";
import { createWorkersAI } from "workers-ai-provider";

export class MyAgent extends Think<Env> {
  getModel() {
    return createWorkersAI({ binding: this.env.AI })(
      "@cf/moonshotai/kimi-k2.5"
    );
  }
}

这已经是一个拥有流式输出、消息持久化、中止/取消、错误处理、流恢复、以及内置工作空间文件系统的完整 Agent。npx wrangler deploy 即可部署。

需要更多控制时的覆盖接口

Think 做了很多默认决策,当你需要干预时,覆盖对应方法即可:

方法 用途
getModel() 返回使用的语言模型
getSystemPrompt() 系统提示
getTools() 工具集(兼容 AI SDK 格式)
maxSteps 每轮最大工具调用轮数
configureSession() 上下文块、压缩策略、搜索、技能文件

生命周期钩子覆盖了每个阶段,不需要接管整条流水线:

复制代码
beforeTurn()
  → streamText()
    → beforeToolCall()
    → afterToolCall()
  → onStepFinish()
→ onChatResponse()

在后续轮次切换更便宜的模型、限制工具集、注入客户端上下文、记录所有工具调用到分析系统------这些都可以通过钩子完成,而不是替换整个 onChatMessage

跨休眠的持久记忆

Think 在 Session API 的树形消息存储之上,增加了上下文块(Context Blocks):结构化的系统提示片段,模型可以读取并主动更新,跨休眠持久化。

typescript 复制代码
configureSession(session: Session) {
  return session
    .withContext("memory", {
      description: "Important facts learned during conversation.",
      maxTokens: 2000
    })
    .withCachedPrompt();
}

模型在上下文里看到 "MEMORY [42%, 462/1100 tokens]" 这样的信息,可以用 set_context 工具主动记下重要事实。这些记忆和 Agent 一起持久化,不依赖任何外部存储。

会话长度增长时,Think 用非破坏性压缩处理上下文限制:老消息被总结而不是删除,完整历史依然存在于 SQLite,随时可以全文检索。


三次浪潮

Cloudflare 用"三次浪潮"描述 AI Agent 的演进路径,这个框架本身值得单独看一下。

第一波:聊天机器人。无状态、被动、脆弱。每次对话从零开始,没有记忆,没有工具,无法主动行动。适合回答问题,但被限制在只能回答问题。

第二波:编码 Agent。Claude Code、Codex 这类工具证明了有状态、有工具的 Agent 是怎样的。LLM 加上读文件、写代码、执行代码的能力,就成了一台通用机器。但它跑在你的笔记本上,服务一个用户,没有持久化保证,关机就断。

第三波:Agent 作为基础设施。持久、分布式、架构上安全、Serverless。这是跑在互联网上的 Agent,能从失败中恢复,闲置时成本为零,安全性通过架构来保证而不是通过行为约束。任何开发者都可以为任意数量的用户部署和运行。

这是一个选择问题,也是一个赌注。Cloudflare 明确说这是他们押注的方向。


小结

Project Think 的核心贡献是给出了一个完整的垂直切片:从计算经济学(Durable Objects 把闲置成本降到零),到执行安全(Dynamic Worker 从零权限起步),到长期记忆(树形会话 + 上下文块),到自我扩展能力(运行时写工具)。

这些原语单独拿出来,都在解决具体的工程问题。但把它们接在一起,形状就变了:一个 Agent 不再是一个运行在本地、崩溃就没了的进程,而是一个可以持续数周、跨越网络中断、在无人值守时自主行动的实体。

对于正在构建 Agent 应用的团队来说,有几个具体判断值得关注:codemode 的 99.9% Token 减少 不是小优化,它改变了工具集设计的方式;执行阶梯的分层设计 让你不需要一开始就接入完整沙箱,按需升级;自编写扩展意味着 Agent 的能力边界不是在部署时就固定的。

目前 Project Think 处于预览阶段,API 仍在演进,但核心的使用方式已经稳定。


参考链接

相关推荐
草莓熊Lotso3 小时前
【Linux网络】UDP Socket 编程全解析:从回显服务到通用字典服务,从零实现工业级代码
linux·运维·服务器·数据库·c++·单片机·udp
woxihuan12345610 小时前
SQL删除数据时存在依赖关系_设置外键级联删除ON DELETE
jvm·数据库·python
东风破13710 小时前
DM8达梦共享存储集群DSC搭建步骤
数据库·学习·dm达梦数据库
雪碧聊技术10 小时前
当数据库字段数大于Java实体类属性数时,MyBatis还能映射成功吗?一文详解
数据库·自动映射·mybatis映射机制·java实体类·宽容映射机制
Jetev10 小时前
如何确定SQL字段是否为空_使用IS NULL与IS NOT NULL
jvm·数据库·python
m0_7020365311 小时前
mysql如何处理不走索引的OR查询_使用UNION ALL优化重写
jvm·数据库·python
代钦塔拉11 小时前
Qt4 vs Qt5 带参数信号槽的连接方式详解
开发语言·数据库·qt
2401_8463395611 小时前
MySQL在云环境如何选择存储类型_SSD与高性能云盘配置建议
jvm·数据库·python
zhaoyong22212 小时前
SQL如何统计每个用户的首次行为时间_MIN聚合与分组
jvm·数据库·python