@cloudflare/ai-chat (英语)
AI聊天代理,具有自动消息持续,可重复流出,以及工具支持等功能. 以 Cloudflare 持久物体和 AI SDK 软件。 。 。 .
安装
npm install @cloudflare/ai-chat agents ai workers-ai-provider
React 客户端也需要可选 React 的同位素 :
npm install @ai-sdk/react react
快速启动
服务器
import { AIChatAgent } from "@cloudflare/ai-chat";
import { createWorkersAI } from "workers-ai-provider";
import { streamText, convertToModelMessages } from "ai";
export class ChatAgent extends AIChatAgent {
async onChatMessage() {
const workersai = createWorkersAI({ binding: this.env.AI });
const result = streamText({
model: workersai("@cf/moonshotai/kimi-k2.7-code"),
messages: await convertToModelMessages(this.messages)
});
return result.toUIMessageStreamResponse();
}
}
这给了你:在SQLite中自动消息持续,在断开/再连接上可重复流线,以及实时WebSocket向所有连接客户端发送.
客户端
import { useAgent } from "agents/react";
import { useAgentChat } from "@cloudflare/ai-chat/react";
function Chat() {
const agent = useAgent({ agent: "ChatAgent" });
const { messages, sendMessage, clearHistory, 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({
role: "user",
parts: [{ type: "text", text: input.value }]
});
input.value = "";
}}
>
<input name="input" placeholder="Type a message..." />
</form>
</div>
);
}
朗格勒配置
// wrangler.jsonc
{
"ai": { "binding": "AI" },
"durable_objects": {
"bindings": [{ "name": "ChatAgent", "class_name": "ChatAgent" }]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["ChatAgent"]
}
]
}
工具
服务器侧工具
带有工具 execute 在服务器上自动运行的函数 :
import { createWorkersAI } from "workers-ai-provider";
import { streamText, convertToModelMessages, isStepCount, tool } from "ai";
import { z } from "zod";
export class ChatAgent extends AIChatAgent {
async onChatMessage() {
const workersai = createWorkersAI({ binding: this.env.AI });
const result = streamText({
model: workersai("@cf/moonshotai/kimi-k2.7-code"),
messages: await convertToModelMessages(this.messages),
tools: {
getWeather: tool({
description: "Get weather for a city",
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => {
const data = await fetchWeather(city);
return { temperature: data.temp, condition: data.condition };
}
})
},
stopWhen: isStepCount(5)
});
return result.toUIMessageStreamResponse();
}
}
客户端工具
没有工具 execute 客户端通过 onToolCall。用于需要浏览器 API(地理、剪贴板、相机)的工具:
// Server: define tool without execute
getLocation: tool({
description: "Get the user's location from their browser",
inputSchema: z.object({})
// No execute -- client handles it
});
// Client: handle via onToolCall
const { messages, sendMessage } = useAgentChat({
agent,
onToolCall: async ({ toolCall, addToolOutput }) => {
if (toolCall.toolName === "getLocation") {
const pos = await new Promise((resolve, reject) =>
navigator.geolocation.getCurrentPosition(resolve, reject)
);
addToolOutput({
toolCallId: toolCall.toolCallId,
output: { lat: pos.coords.latitude, lng: pos.coords.longitude }
});
}
}
});
工具审批(人-入-出)
使用 needsApproval 用于执行前需要用户确认的工具:
// Server
processPayment: tool({
description: "Process a payment",
inputSchema: z.object({ amount: z.number(), recipient: z.string() }),
needsApproval: async ({ amount }) => amount > 100, // Only require approval for large amounts
execute: async ({ amount, recipient }) => charge(amount, recipient)
});
// Client
const { messages, addToolApprovalResponse } = useAgentChat({ agent });
// When rendering tool parts with state === "approval-requested":
<button onClick={() => addToolApprovalResponse({ id: approvalId, approved: true })}>
Approve
</button>
<button onClick={() => addToolApprovalResponse({ id: approvalId, approved: false })}>
Reject
</button>
代理工具
AIChatAgent 子类可以用作保留、流出代理工具
父代理通过 runAgentTool() 或者说 agentTool()数字 :
import { AIChatAgent } from "@cloudflare/ai-chat";
import { agentTool } from "agents/agent-tools";
import { convertToModelMessages, streamText } from "ai";
import { z } from "zod";
export class Summarizer extends AIChatAgent<Env> {
protected override formatAgentToolInput(input: { text: string }, request) {
return {
id: `agent-tool-${request.runId}-input`,
role: "user",
parts: [{ type: "text", text: `Summarize:\n\n${input.text}` }]
};
}
async onChatMessage() {
const result = streamText({
model: this.env.MODEL,
messages: await convertToModelMessages(this.messages)
});
return result.toUIMessageStreamResponse();
}
}
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage() {
const result = streamText({
model: this.env.MODEL,
messages: await convertToModelMessages(this.messages),
tools: {
summarize: agentTool(Summarizer, {
description: "Summarize long text in a separate retained agent.",
inputSchema: z.object({ text: z.string() })
})
}
});
return result.toUIMessageStreamResponse();
}
}
特工工具转身无头. 服务器侧工具正常工作,但
浏览器提供的客户端工具不可用,除非您单独设计
服务器侧或由父机代理的交接。 覆盖 formatAgentToolInput(), (中文(简体) ),
getAgentToolOutput(),以及 getAgentToolSummary() 当您需要结构化
投入或产出.
可还原流
断开/重新连接时自动恢复流 。 不需要配置 .
当客户端断开中流时,块会被缓冲到 SQLite. 在重新连接时,客户端接收所有缓冲块并持续接收活流.
这样可以处理浏览器断开、导航和反应清理,而持久对象则继续运行。 持久聊天恢复单独处理模式调用时被拆迁的持久对象本身.
持久聊天恢复
每个 AIChatAgent 转而使用可持久恢复的纤维,因此转而可以在工人部署、可持久物体驱逐或再生过程中幸存。 指定 a chatRecovery 对象仅在需要调和预算或终端行为时:
import type {
ChatRecoveryContext,
ChatRecoveryOptions
} from "@cloudflare/ai-chat";
export class ChatAgent extends AIChatAgent<Env> {
override chatRecovery = {
maxAttempts: 6,
terminalMessage: "The assistant was interrupted. Please try again."
};
override async onChatRecovery(
ctx: ChatRecoveryContext
): Promise<ChatRecoveryOptions> {
console.log("Recovering", ctx.incidentId, ctx.recoveryKind);
return {}; // persist partial output and continue/retry when possible
}
}
chatRecovery = false 不再支持。 先前编译的仍然供应的 JavaScript false 接收默认持久配置。 如果自动续作不安全, 请返回 { continue: false } 从 onChatRecovery(); 使用持久状态进行取消或副作用警卫,并为成本控制配置回收预算.
见 docs/agents/chat-agents.md 用于移徙指导、针对提供者的恢复战略和可观察活动.
通用客户端流中止/清理默认只属于本地:服务器转会继续并可在稍后恢复. 明确 stop() 仍然取消服务器回合 :
const { messages, stop } = useAgentChat({ agent });
如果您的应用程序有意希望客户端生命周期拥有服务器生命周期, 请选择在客户端中止时取消 :
const { messages } = useAgentChat({
agent,
cancelOnClientAbort: true
});
用于请求寿命或节能符的流量 。 明确 stop() 总是
服务器端取消, 不论 cancelOnClientAbort。 。 。 .
禁用恢复为 resume: false数字 :
const { messages } = useAgentChat({ agent, resume: false });
重叠信件
当用户提交新消息,而另一个回合仍在运行时, AIChatAgent
可以队列、倒塌或丢弃重叠服务器侧:
export class ChatAgent extends AIChatAgent {
messageConcurrency = "latest";
async onChatMessage() {
// ...
}
}
现有战略:
"queue"(默认)——按顺序处理每次提交"latest"——只保留最新的重叠提交并跳过任何更旧的队列重叠回合"merge"– 队列重叠提交, 然后将队列中的用户信件崩溃为一个合并的后继用户回合"drop"- 忽略重叠提交{ strategy: "debounce", debounceMs: 750 }等待一个安静的窗口, 然后运行只运行最新的提交
选择一项战略: 使用 "latest" 用于用户的焦点助理
能够修正自己在中游。 使用 "queue" 或者说 "merge" 用于通讯
每个消息都很重要的应用程序 。 使用 "drop" 防止双发. 使用
"debounce" 当用户发送短信息时.
用户看到的: 与 "queue",每个消息都有自己的反应.
与 "latest"中,所有信件都出现,但只有最后一个重叠的
反应。 与 "merge",重叠的信息会崩溃成一个。 与
"drop"中,重叠的信息会短暂出现,然后消失(倒转).
此设置只影响重叠 sendMessage() 提交。 重新创造,
工具的延续、核准和方案 saveMessages() 打电话保持
现有序列化行为。 何时 debounceMs 缺少或无效,
AIChatAgent 返回到默认值 750 毫丝窗.
传递函数到 saveMessages() 以获取最新记录
转弯实际开始 —— 用于计时回调和 webhook 处理器
如果自电话发出以来消息可能有所改变:
await this.saveMessages((messages) => [
...messages,
{
id: crypto.randomUUID(),
role: "user",
parts: [{ type: "text", text: "Scheduled follow-up" }]
}
]);
saveMessages() 返回时 { requestId, status }编辑 status 字段为
"completed" 当转弯时, "skipped" 中空飞行无效时
(例如,a) chat-clear),或 "aborted" 当外部 AbortSignal 已取消
这个 过 options.signal 取消外部程序转接, 不包含
了解内部生成的请求 id:
const controller = new AbortController();
const result = await this.saveMessages([userMsg], {
signal: controller.signal
});
if (result.status === "aborted") {
// ...
}
这是相同的形状 Think.saveMessages 使用——见
cloudflare/agents#1406
用于推动API的代理工具管弦模式。 运出
代理工具 API 在
docs/agents/agent-tools.md。 。 。 .
储存管理
限制已存储信件
控制保存在 SQLite 的信件数量 :
export class ChatAgent extends AIChatAgent {
maxPersistedMessages = 200; // Keep last 200 messages
async onChatMessage() {
// ...
}
}
当计数超过限制时,删除最旧的消息 。 这只控制存储——不影响发送给LLM的内容.
控制 LLM 上下文
使用 AI SDK 软件 pruneMessages() 以控制发送到模型中的内容,而不受存储内容的影响:
import { createWorkersAI } from "workers-ai-provider";
import { streamText, convertToModelMessages, pruneMessages } from "ai";
export class ChatAgent extends AIChatAgent {
maxPersistedMessages = 200;
async onChatMessage() {
const workersai = createWorkersAI({ binding: this.env.AI });
const result = streamText({
model: workersai("@cf/moonshotai/kimi-k2.7-code"),
messages: pruneMessages({
messages: await convertToModelMessages(this.messages),
reasoning: "before-last-message",
toolCalls: "before-last-2-messages"
})
});
return result.toUIMessageStreamResponse();
}
}
行大小保护
信件接近 SQLite 的 2MB 行限制会自动压缩 。 大型工具产出取而代之的是方便LLM的摘要,该摘要指示模型建议重新运行工具。 压缩信息包括 metadata.compactedToolOutputs 这样客户可以检测和显示这个优雅.
自定义请求数据
包含自定义数据,每个聊天请求使用 body 选项 :
const { messages, sendMessage } = useAgentChat({
agent,
body: {
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
userId: "abc"
}
});
// Or use a function for dynamic values:
body: () => ({ token: getAuthToken(), timestamp: Date.now() });
通过 options.body数字 :
async onChatMessage(onFinish, options) {
const { timezone, userId } = options?.body ?? {};
}
API 参考
AIChatAgent<Env, State, Props>
扩展 Agent 从 agents 软件包.
| 财产/方法 | 类型 | 说明 |
|---|---|---|
messages | ChatMessage[] | 当前对话消息( 从 SQLite 上载) |
chatRecovery | ChatRecoveryConfig | 总是在持久恢复配置。 指定一个对象来调和预算和终端行为 |
maxPersistedMessages | number | undefined | 要保存在 SQLite 中的最大消息 。 默认:无限 |
messageConcurrency | MessageConcurrency | 货币战略 sendMessage() 提交。 默认 : "queue" |
onChatMessage(onFinish?, options?) | 覆盖 | 处理收到的聊天信息 。 还原 a Response。 。 。 . onFinish 是可选的. |
onChatRecovery(ctx) | 覆盖 | 聊天回合中断后自定义恢复 |
onChatResponse(result) | 覆盖 | 聊天回合完成后调用. result 已经 message, (中文(简体) ), requestId, (中文(简体) ), status, (中文(简体) ), continuation |
persistMessages(messages) | Promise<void> | 手动粘接信件( 通常是自动) |
saveMessages(messages, options?) | Promise<SaveMessagesResult> | 持久性信息和触发 onChatMessage。接受数组或函数. options.signal 取消外部转弯. |
waitUntilStable() | Promise<boolean> | 受保护的助手等待谈话完全稳定 |
resetTurnState() | void | 保护帮助中止活动回合并取消队列的续作 |
hasPendingInteraction() | boolean | 保护助手以检测待决工具输入或核准助理信件 |
useAgentChat(options)
聊天互动的反应钩. 包装 AI SDK 的 useChat 与WebSocket运输.
选项 :
| 选项 | 类型 | 说明 |
|---|---|---|
agent | ReturnType<typeof useAgent> | 代理连接( 需要) |
onToolCall | ({ toolCall, addToolOutput }) => void | 处理客户端工具执行 |
autoContinueAfterToolResult | boolean | 在客户端工具结果后自动继续. 默认 : true |
resume | boolean | 启用流恢复 。 默认 : true |
cancelOnClientAbort | boolean | 当发生通用客户端流中止/清理时取消服务器回合 。 明确 stop() 总是取消。 默认 : false |
body | object | () => object | 按每次请求发送的自定义数据(见下文) |
prepareSendMessagesRequest | (options) => { body?, headers? } | 按要求预先定制 |
getInitialMessages | (options) => Promise<ChatMessage[]> | 自定义初始信件加载器 |
回返情况:
| 财产 | 类型 | 说明 |
|---|---|---|
messages | ChatMessage[] | 聊天消息 |
sendMessage | (message) => void | 发送消息 |
clearHistory | () => void | 清除对话 |
addToolOutput | ({ toolCallId, output }) => void | 提供工具输出 |
addToolApprovalResponse | ({ id, approved }) => void | 批准/拒绝一个工具 |
setMessages | (messages | updater) => void | 设置信件( 同步到服务器) |
status | string | "idle" | "submitted" | "streaming" | "error" |
出口
| 导入路径 | 它提供的东西 |
|---|---|
@cloudflare/ai-chat | AIChatAgent, (中文(简体) ), ChatMessage, (中文(简体) ), createToolsFromClientSchemas, (中文(简体) ), ChatRecoveryContext, (中文(简体) ), ChatRecoveryConfig |
@cloudflare/ai-chat/react | useAgentChat |
@cloudflare/ai-chat/types | MessageType, (中文(简体) ), OutgoingMessage, (中文(简体) ), IncomingMessage |
实例
许可证
麻省理工学院