← Vytvářejte agenty na Cloudflare / agents / harnesses
Think
@cloudflare/think umožňuje vytvořit stavového chatovacího agenta AI, tedy takového, který streamuje odpovědi, pamatuje si konverzaci a volá nástroje, a to rozšířením jediné základní třídy. Modelu předáte getModel(), a o zbytek životního cyklu chatu se postará Think: agentní smyčku (model volá nástroje, čte výsledky a pokračuje, dokud nemá odpověď), perzistenci zpráv, streamování, klientské nástroje, obnovení streamu a rozšíření, to vše na bázi Durable Object SQLite.
Think funguje jak jako agent nejvyšší úrovně (WebSocket chat pro klientské prohlížeče prostřednictvím useAgentChat) a sub-agent (podřízený agent, který jiný agent řídí přes RPC prostřednictvím chat()).
Rychlý start
Instalovat
npm i @cloudflare/think @cloudflare/ai-chat agents ai @cloudflare/shell zod workers-ai-providerThink podporuje AI SDK v6 a v7. Použijte ai@^6 hodnotou @ai-sdk/react@^3, nebo použijte ai@^7 hodnotou @ai-sdk/react@^4. V celém projektu udržujte balíčky AI SDK na shodných hlavních verzích.
Server
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>;To je vše. Think se stará o protokol WebSocket chatu, perzistenci zpráv, agentickou smyčku, sanitizaci zpráv, obnovení streamu, podporu klientských nástrojů a nástroje pro práci se soubory pracovního prostoru.
Klient
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>
);
}Konfigurace
{
"$schema": "./node_modules/wrangler/config-schema.json",
// Set this to today's date
"compatibility_date": "2026-08-28",
"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-28"
compatibility_flags = ["nodejs_compat"]
[ai]
binding = "AI"
[[durable_objects.bindings]]
class_name = "MyAgent"
name = "MyAgent"
[[migrations]]
new_sqlite_classes = ["MyAgent"]
tag = "v1"Trasování
Think používá wrapAISDK() interně k instrumentaci kol modelu, volání nástrojů a segmentů životního cyklu schvalování. Není třeba obalovat AI SDK ani konfigurovat adaptér. Pro odeslání invoke_agent, chat, execute_tool, a tool_approval spany do Workers Observability, zapněte Workers traces:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"observability": {
"traces": {
"enabled": true
}
}
}[observability.traces]
enabled = trueTrasování se zobrazuje v zobrazení Agents na Cloudflare Dashboard. Můžete si prohlédnout konverzace a časové osy trasování. Chcete-li trasování vypnout, nastavte observability.traces.enabled na false. Třídu agenta Think není potřeba měnit.
Atributy spanů, ovládání payloadu, export trasování a přímé nastavení AI SDK v6 nebo v7 najdete v Trasování.
Think oproti AIChatAgent
Jak Think, tak AIChatAgent rozšiřte Agent a mluvit stejným cf_agent_chat_* protokol WebSocket. Slouží k odlišným účelům.
AIChatAgent je adaptér protokolu. Přepište onChatMessage a odpovídají za volání streamText, propojuje nástroje, převádí zprávy a vrací Response. AIChatAgent řeší podpůrnou logiku: perzistenci zpráv, streamování, přerušení a obnovení, ale volání LLM je zcela na vás.
Think je framework s pevně danými konvencemi. Rozhoduje za vás: getModel() vrátí model, getSystemPrompt() nebo configureSession() nastaví prompt, getTools() vrátí nástroje. Výchozí onChatMessage spouští kompletní agentní smyčku. Přepisujete jednotlivé části, ne celý pipeline.
| Aspekt | AIChatAgent | Think |
|---|---|---|
| Minimální podtřída | ~15 řádků (přenosový streamText + nástroje + systémový prompt + odpověď) |
3 řádky (getModel() pouze) |
| Úložiště | Plochá tabulka SQL | Session: stromově strukturované zprávy, kontextové bloky, komprimace, FTS5 |
| Regenerace | Destruktivní (stará odpověď se smaže) | Nedestruktivní větvení (staré odpovědi zůstávají zachovány) |
| Správa kontextu | Ruční | Kontextové bloky s trvalou pamětí zapisovatelnou LLM |
| RPC podřízeného agenta | Není vestavěné | chat() hodnotou StreamCallback |
| Programová kola | saveMessages() |
saveMessages(), submitMessages(), continueLastTurn() |
| Komprimace | maxPersistedMessages (odstraní nejstarší) |
Nedestruktivní souhrny pomocí překryvů |
| Hledat | Není k dispozici | Fulltextové vyhledávání FTS5 v rámci relace i napříč relacemi |
Kdy použít AIChatAgent
- Potřebujete plnou kontrolu nad voláním LLM (RAG, více modelů, vlastní streamování)
- Chcete
Responsenávratový typ pro middleware HTTP nebo testování - Vytváříte jednoduchého chatbota bez nároků na paměť
Kdy použít Think
- Chcete rychle nasadit (třířádková podtřída se vším propojeným)
- Potřebujete trvalou paměť (kontextové bloky, které model může číst a zapisovat)
- Potřebujete dlouhé konverzace (nedestruktivní komprimace)
- Potřebujete vyhledávání v konverzaci (FTS5)
- Vytváříte systém sub-agentů (RPC mezi nadřazeným a podřízeným se streamováním)
- Potřebujete proaktivní agenty (programová kola spouštěná naplánovanými úlohami nebo webhooky)
- Potřebujete trvalé asynchronní odesílání pro volající přes webhook nebo RPC
Zvolte API pro kola
Think nabízí několik způsobů, jak kolo zahájit nebo v něm pokračovat. Všechny vedou přes jediný veřejný vstupní bod: runTurn(options) : Starší metody zůstávají zachovány jako praktické zkratky.
runTurn()
runTurn() je jednotné API pro připuštění kola. Jedna metoda, tři režimy, které se volí podle options.mode:
| Režim | Kdy použít | Vrací | Zkratka pro |
|---|---|---|---|
"wait" (výchozí) |
Volající může počkat, dokud odpověď modelu nebude hotová | Promise<TurnResult> |
saveMessages() |
"submit" |
Volající potřebuje rychlé a trvalé přijetí požadavku a stav zjistit až později | Promise<SubmitMessagesResult> |
submitMessages() |
"stream" |
Volající chce, aby se odpověď streamovala do callbacku (RPC) | Promise<void> |
chat() |
input přijímá řetězec, UIMessage, pole zpráv nebo, v wait a stream režimech, funkce (current) => UIMessage[] se vyhodnotí při přijetí. (submit nepřijímá vstup funkce.)
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 });
}
}Klíčové chování:
- Blokovací režimy nelze vnořovat. Volání
wait/stream/continuation(nebo odpovídající zkratku) z uvnitř aktivní tah, například zexecute: vyvolá výjimku, protože by to způsobilo deadlock fronty kol. Uvnitř kola použijterunTurn({ mode: "submit" })(trvalé, spustí se poté, co aktuální kolo uvolní frontu) neboaddMessages()(pouze přepis, žádná inference). submitje idempotentní. PředejtesubmissionIda/neboidempotencyKey; opětovné odeslání známého klíče vrátí existující záznam saccepted: falsemísto zahájení druhého kola. Viz Programové odesílání.- Bezpečné pro obnovení.
wait,stream, a vyprázdněnésubmitcesty spouštějí inferenci uvnitř recovery fiberu, takže přerušené kolo pokračuje po vyřazení z paměti.
runTurn je exportován spolu s typy pro jeho možnosti a výsledek: RunTurnOptions, RunTurnWait, RunTurnSubmit, RunTurnStream, TurnInputMessages, a TurnResult.
Vyberte zkratku
Tabulka níže přiřazuje ke každému scénáři nejpřímější volání. Každá zkratka má nezměněnou signaturu, sáhněte po ní, když chcete užší rozhraní, nebo použijte runTurn() když chcete jeden mentální model.
| Případ použití | API |
|---|---|
| Uživatel v prohlížeči odesílá chatové zprávy | useAgentChat přes chatovací protokol WebSocket |
| Kód serveru může počkat na odpověď modelu | saveMessages() |
| Kód serveru potřebuje rychlé trvalé přijetí a pozdější stav | submitMessages() |
| Kód by měl vytvářet opakující se kola řízená promptem nebo handlery | getScheduledTasks() |
| Nadřazený kód potřebuje přímé streamované RPC ke konkrétnímu podřízenému agentovi | subAgent(...).chat() |
| Nadřazený agent deleguje práci na zachovaného podřízeného agenta | agentTool() nebo runAgentTool() |
| Obklopte kolo idempotentními vedlejšími efekty spravovanými aplikací | startFiber() |
| Koordinace vícekrokové trvalé orchestrace | Workflows |
| Přidání kontextu nebo zpráv bez zahájení kola modelu | addMessages() |
| Pokročilá podtřída nebo kód pro obnovení pokračuje v kole asistenta | continueLastTurn() |
Použijte saveMessages() když volající vlastní spouštěč a může počkat na dokončení kola. Použijte submitMessages() když by nejednoznačnost časového limitu činila opakované pokusy nebezpečnými.
Přidání zpráv bez kola
Použijte addMessages() k zápisu do přepisu bez před začátkem kola modelu: pro import předchozí historie nebo vložení kontextu na pozadí, který by měl být vidět v následujícím kole:
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() se přidá (nebo aktualizuje) do stromu Session:
- To dělá ne spouští inferenci a ne vstupují do fronty kol, takže je bezpečné je volat zevnitř
executebez uváznutí. - Položky pole se připojují lineárně (každá se připojí pod tu předchozí), takže importovaná historie zůstává jedinou větví. Ve výchozím nastavení se první zpráva připojí k poslednímu potvrzenému listu, předejte
parentIdpřipojit jinam, nebonullpro kořenovou zprávu. - Připojení jsou idempotentní podle ID zprávy. Předejte
{ mode: "upsert" }k aktualizaci existující zprávy přímo na místě.
Podporovaný vzor je „přidat kontext, poté spustit kolo“: zavolejte addMessages(), poté runTurn().
Použijte chat() pro nízkoúrovňové streamování mezi nadřazeným a podřízeným prvkem, pokud váš kód sám řídí přeposílání, rušení a zásady opakovaného přehrání. Použijte Agents jako nástroje když nadřazený model nebo workflow deleguje na podřízeného agenta a chcete zachované běhy podřízených agentů, přehrávání událostí, přemostění přerušení a možnost proklikat se v UI k detailu.
Použijte startFiber() mimo Think, když je trvalou jednotkou úloha aplikace kolem jednoho kola: jednorázové přijetí webhooku, obnovení serializovaného kanálu nebo cíle vlákna, odeslání viditelné odpovědi nebo zaznamenání zásady zotavení na úrovni aplikace. Odesílání do Think řídí přijímání konverzace a serializaci kol; spravovaná vlákna řídí externí přijímání úloh, idempotentní vedlejší efekty a zotavení aplikace.
V této části
Konfigurace
Nástroje
Akce
Kanály
Hooky životního cyklu
Klientské nástroje
Messengery
Naplánované úlohy
Workflows
RPC podřízeného agenta
Programové odesílání
Trvalé obnovení
Agent Skills
Poděkování
Design Think je inspirován Pi ↗.
Příklad
Příklad asistenta
Související
- Relace : Kontextové bloky, komprimace, vyhledávání, více relací (úložná vrstva, na které je Think postaven)
- Podřízení agenti,
subAgent(),abortSubAgent(),deleteSubAgent()(základní metody Agent pro vytváření podřízených agentů) - Chat agenti,
AIChatAgentpro případy, kdy potřebujete mít plnou kontrolu nad voláním LLM - Dlouhodobě běžící agenti : vzory delegování na podřízené agenty pro vícetýdenní životní cykly agenta
- Trvalé provádění,
runFiber()a zotavení po pádu (používanéchatRecovery) - Procházet web : úplná referenční dokumentace pomocného API CDP