跳转到内容
搜索文档

Think

最后更新 查看 MarkdownAgent 设置

@cloudflare/think 让你通过扩展单个基类构建有状态的 AI 聊天 Agent——可流式回复、记住对话并调用工具。你通过 getModel() 提供模型,Think 为你接入其余聊天生命周期:智能体循环(模型调用工具、读取结果并持续直到有答案)、消息持久化、流式传输、客户端工具、流恢复与扩展——均由 Durable Object SQLite 支撑。

Think 既可作为顶层 Agent(通过 useAgentChat 向浏览器客户端 WebSocket 聊天),也可作为子 Agent(由另一 Agent 通过 chat() RPC 驱动)。

快速入门

安装

npm i @cloudflare/think @cloudflare/ai-chat agents ai @cloudflare/shell zod workers-ai-provider

Think 支持 AI SDK v6 与 v7。使用 ai@^6 配合 @ai-sdk/react@^3,或 ai@^7 配合 @ai-sdk/react@^4。整个项目保持 AI SDK 包主版本一致。

服务端

import { Think } from "@cloudflare/think";
import { createWorkersAI } from "workers-ai-provider";
import { routeAgentRequest } from "agents";

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

export default {
	async fetch(request, env) {
		return (
			(await routeAgentRequest(request, env)) ||
			new Response("Not found", { status: 404 })
		);
	},
};
import { Think } from "@cloudflare/think";
import { createWorkersAI } from "workers-ai-provider";
import { routeAgentRequest } from "agents";

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

export default {
	async fetch(request: Request, env: Env) {
		return (
			(await routeAgentRequest(request, env)) ||
			new Response("Not found", { status: 404 })
		);
	},
} satisfies ExportedHandler<Env>;

仅此而已。Think 处理 WebSocket 聊天协议、消息持久化、智能体循环、消息清理、流恢复、客户端工具支持与工作区文件工具。

客户端

import { useAgent } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";

function Chat() {
	const agent = useAgent({ agent: "MyAgent" });
	const { messages, sendMessage, status } = useAgentChat({ agent });

	return (
		<div>
			{messages.map((msg) => (
				<div key={msg.id}>
					<strong>{msg.role}:</strong>
					{msg.parts.map((part, i) =>
						part.type === "text" ? <span key={i}>{part.text}</span> : null,
					)}
				</div>
			))}

			<form
				onSubmit={(e) => {
					e.preventDefault();
					const input = e.currentTarget.elements.namedItem("input");
					sendMessage({ text: input.value });
					input.value = "";
				}}
			>
				<input name="input" placeholder="Send a message..." />
				<button type="submit">Send</button>
			</form>
		</div>
	);
}
import { useAgent } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";

function Chat() {
	const agent = useAgent({ agent: "MyAgent" });
	const { messages, sendMessage, status } = useAgentChat({ agent });

	return (
		<div>
			{messages.map((msg) => (
				<div key={msg.id}>
					<strong>{msg.role}:</strong>
					{msg.parts.map((part, i) =>
						part.type === "text" ? <span key={i}>{part.text}</span> : null,
					)}
				</div>
			))}

			<form
				onSubmit={(e) => {
					e.preventDefault();
					const input = e.currentTarget.elements.namedItem(
						"input",
					) as HTMLInputElement;
					sendMessage({ text: input.value });
					input.value = "";
				}}
			>
				<input name="input" placeholder="Send a message..." />
				<button type="submit">Send</button>
			</form>
		</div>
	);
}

配置

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  // Set this to today's date
  "compatibility_date": "2026-08-17",
  "compatibility_flags": [
    "nodejs_compat"
  ],
  "ai": {
    "binding": "AI"
  },
  "durable_objects": {
    "bindings": [
      {
        "class_name": "MyAgent",
        "name": "MyAgent"
      }
    ]
  },
  "migrations": [
    {
      "new_sqlite_classes": [
        "MyAgent"
      ],
      "tag": "v1"
    }
  ]
}
# Set this to today's date
compatibility_date = "2026-08-17"
compatibility_flags = ["nodejs_compat"]

[ai]
binding = "AI"

[[durable_objects.bindings]]
class_name = "MyAgent"
name = "MyAgent"

[[migrations]]
new_sqlite_classes = ["MyAgent"]
tag = "v1"

Think 与 AIChatAgent

Think 与 AIChatAgent 均扩展 Agent 并使用相同 cf_agent_chat_* WebSocket 协议,但目标不同。

AIChatAgent 是协议适配器。你重写 onChatMessage 并负责调用 streamText、接入工具、转换消息并返回 Response。AIChatAgent 处理管道——消息持久化、流式、中止、恢复——但 LLM 调用完全由你负责。

Think 是约定式框架。它替你决策:getModel() 返回模型,getSystemPrompt()configureSession() 设置提示词,getTools() 返回工具。默认 onChatMessage 运行完整智能体循环。你重写各个部分,而非整条管道。

关注点 AIChatAgent Think
最小子类 ~15 行(接入 streamText + 工具 + 系统提示词 + 响应) 3 行(仅 getModel()
存储 扁平 SQL 表 Session:树形消息、上下文块、压缩、FTS5
重新生成 破坏性(旧响应删除) 非破坏性分支(保留旧响应)
上下文管理 手动 带 LLM 可写持久化记忆的上下文块
子 Agent RPC 未内置 StreamCallbackchat()
程序化轮次 saveMessages() saveMessages()submitMessages()continueLastTurn()
压缩 maxPersistedMessages(删除最旧) 通过覆盖层的非破坏性摘要
搜索 不可用 每会话与跨会话的 FTS5 全文搜索

何时使用 AIChatAgent

  • 需要完全控制 LLM 调用(RAG、多模型、自定义流式)
  • 需要 Response 返回类型用于 HTTP 中间件或测试
  • 构建无记忆需求的简单聊天机器人

何时使用 Think

  • 想快速交付(3 行子类全部接好)
  • 需要持久化记忆(模型可读写的上下文块)
  • 需要长对话(非破坏性压缩)
  • 需要对话搜索(FTS5)
  • 构建子 Agent 系统(带流式的父子 RPC)
  • 需要主动式 Agent(来自调度任务或 webhook 的程序化轮次)
  • 需要 webhook 或 RPC 调用方的持久异步提交

选择轮次 API

Think 有多种启动或继续轮次的方式。它们都汇入一个公共入口——runTurn(options)——旧方法仍作为便捷快捷方式保留。

runTurn()

runTurn() 是统一的轮次准入 API。一个方法、三种模式,由 options.mode 选择:

模式 适用场景 返回 快捷方式
"wait"(默认) 调用方可阻塞至模型响应完成 Promise<TurnResult> saveMessages()
"submit" 调用方需要快速持久接受与后续状态 Promise<SubmitMessagesResult> submitMessages()
"stream" 调用方希望响应流式到回调(RPC) Promise<void> chat()

input 接受字符串、UIMessage、消息数组,或在 waitstream 模式下接受在准入时求值的函数 (current) => UIMessage[]。(submit 不接受函数形式的输入。)

export class Assistant extends Think {
	async examples(inboundEventId) {
		// wait — block for the result
		const result = await this.runTurn({ input: "Summarize the latest thread" });
		if (result.status === "completed") {
			// result.message is the assistant message; result.continuation is false
		}

		// submit — durable acceptance, check status later
		const submission = await this.runTurn({
			mode: "submit",
			input: "Process this webhook",
			idempotencyKey: inboundEventId, // dedupe; safe to retry
		});
		// submission.accepted is true on first accept; submission.status is "pending"

		// stream — drive a callback (the same surface as chat())
		await this.runTurn({
			mode: "stream",
			input: "Stream me",
			callback: {
				onStart({ requestId }) {},
				onEvent(json) {}, // UIMessageChunk JSON
				onDone() {},
				onError(error) {},
			},
		});

		// continuation — continue the last assistant turn instead of sending input
		await this.runTurn({ continuation: true });
	}
}
export class Assistant extends Think<Env> {
	async examples(inboundEventId: string) {
		// wait — block for the result
		const result = await this.runTurn({ input: "Summarize the latest thread" });
		if (result.status === "completed") {
			// result.message is the assistant message; result.continuation is false
		}

		// submit — durable acceptance, check status later
		const submission = await this.runTurn({
			mode: "submit",
			input: "Process this webhook",
			idempotencyKey: inboundEventId, // dedupe; safe to retry
		});
		// submission.accepted is true on first accept; submission.status is "pending"

		// stream — drive a callback (the same surface as chat())
		await this.runTurn({
			mode: "stream",
			input: "Stream me",
			callback: {
				onStart({ requestId }) {},
				onEvent(json) {}, // UIMessageChunk JSON
				onDone() {},
				onError(error) {},
			},
		});

		// continuation — continue the last assistant turn instead of sending input
		await this.runTurn({ continuation: true });
	}
}

关键行为:

  • 阻塞模式不能嵌套。 在活跃轮次内调用 wait/stream/continuation(或等效快捷方式)——例如从工具的 execute 内——会抛出异常,因会死锁轮次队列。轮次内使用 runTurn({ mode: "submit" })(持久,当前轮次释放队列后运行)或 addMessages()(仅写入对话记录,无推理)。
  • submit 幂等。 传入 submissionId 和/或 idempotencyKey;用已知键重提交返回 accepted: false 的现有记录而非启动第二个轮次。见程序化提交
  • 恢复安全。 启用 chatRecovery 时,waitstream 与已排空的 submit 路径均在恢复 fiber 内运行推理,被中断的轮次可在驱逐后继续。

runTurn 与其选项、结果类型一并导出:RunTurnOptionsRunTurnWaitRunTurnSubmitRunTurnStreamTurnInputMessagesTurnResult

选择快捷方式

下表将各场景映射到最直接调用。各快捷方式签名不变;需要更窄接口时使用它们,或需要单一心智模型时用 runTurn()

用例 API
浏览器用户发送聊天消息 通过 WebSocket 聊天协议的 useAgentChat
服务端代码可等待模型响应 saveMessages()
服务端代码需要快速持久接受与后续状态 submitMessages()
代码应创建周期性提示词驱动的轮次或处理函数 getScheduledTasks()
父代码需要对特定子 Agent 的直接流式 RPC subAgent(...).chat()
父 Agent 将工作委托给保留的子 Agent agentTool()runAgentTool()
围绕轮次的幂等应用自有副作用 startFiber()
协调多步持久编排 Workflows
添加上下文或消息而不启动模型轮次 addMessages()
高级子类或恢复代码继续助手轮次 continueLastTurn()

调用方拥有触发条件且可等待轮次完成时用 saveMessages()。超时歧义会使重试不安全时用 submitMessages()

无轮次添加消息

addMessages() 写入对话记录 而不启动模型轮次——用于导入先前历史或注入下一轮次应看到的背景上下文:

export class Assistant extends Think {
	async importContext() {
		await this.addMessages([
			{
				id: crypto.randomUUID(),
				role: "user",
				parts: [{ type: "text", text: "Imported context" }],
			},
		]);
	}
}
export class Assistant extends Think<Env> {
	async importContext() {
		await this.addMessages([
			{
				id: crypto.randomUUID(),
				role: "user",
				parts: [{ type: "text", text: "Imported context" }],
			},
		]);
	}
}

addMessages() 追加(或 upsert)到 Session 树:

  • 运行推理,进入轮次队列,因此可在工具的 execute 内安全调用而不死锁。
  • 数组条目线性追加(每条挂接到前一条),导入历史保持单一路径。默认首条消息挂接到最新已提交叶子;传 parentId 挂接到其他位置,或 null 为根消息。
  • 追加按消息 id 幂等。传 { mode: "upsert" } 原地更新现有消息。

支持的模式是「添加上下文,再运行轮次」:调用 addMessages(),然后 runTurn()

代码拥有转发、取消与重放策略时用 chat() 做底层父子流式。父模型或 workflow 委托子 Agent 且需要保留的子运行、事件重放、中止桥接与 UI 下钻时用 Agent 作为工具

Think 外的持久单元是轮次周围的应用任务时用 startFiber():一次接受 webhook、恢复序列化渠道或线程目标、发布可见回复或记录应用级恢复策略。Think 提交拥有对话准入与轮次序列化;托管 fiber 拥有外部任务接受、幂等副作用与应用恢复。

本节内容

配置

配置重写、动态配置与会话集成。

工具

工作区工具、代码执行、浏览器工具与扩展。

操作

带幂等性、审批、授权与回复附件的服务端操作。

频道

按频道策略、频道选择与带外通知。

信使

接收并回复 Chat SDK messenger 的 webhook。

Workflows

Cloudflare Workflows 内的持久模型驱动推理步骤。

子 Agent RPC

`chat()` 流式、`saveMessages`、`continueLastTurn` 与中止。

持久恢复

聊天恢复、流停滞看门狗与稳定性检测。

Agent Skills

通过 `getSkills()` 按需加载说明、资源与脚本。

致谢

Think 的设计受 Pi 启发。

示例

Assistant 示例

探索带子 Agent 路由、共享工作区、MCP、聊天恢复与 GitHub OAuth 的多会话 Think 助手。

相关

  • 会话 — 上下文块、压缩、搜索、多会话(Think 所构建的存储层)
  • 子 AgentsubAgent()abortSubAgent()deleteSubAgent()(派生子 Agent 的基类方法)
  • 聊天 Agent — 需要完全控制 LLM 调用时的 AIChatAgent
  • 长期运行 Agent — 多周 Agent 生命周期的子 Agent 委托模式
  • 持久执行runFiber() 与崩溃恢复(chatRecovery 使用)
  • 浏览网页 — 完整 CDP 辅助 API 参考

这篇文档对您有帮助吗?