← Vytvářejte agenty na Cloudflare / agents / harnesses / think
Workflows
ThinkWorkflow propojuje Think s Cloudflare Workflows, když trvalá úloha potřebuje jeden krok uvažování řízený modelem.
Použijte ho, když proces vlastní Workflow:
- trvalá vícekroková orchestrace
- schvalovací brány nebo dlouhá čekání
- opakovatelné deterministické vedlejší efekty
- kolo Think, které by mělo vytvořit typovaný strukturovaný výstup
Opakující se prompty uchovávejte jako naplánované úlohy, a jednoduchá jednorázová kola na pozadí ponechte na submitMessages(). Workflows jsou určené pro úlohy, u kterých záleží na jednotlivých krocích.
API
Importujte z @cloudflare/think/workflows:
import { ThinkWorkflow } from "@cloudflare/think/workflows";Rozšiřte ThinkWorkflow a volejte step.prompt() uvnitř run():
import { z } from "zod";
import { ThinkWorkflow } from "@cloudflare/think/workflows";
const draftSchema = z.object({
title: z.string(),
summary: z.string(),
labels: z.array(z.string()),
});
export class TriageWorkflow extends ThinkWorkflow {
async run(event, step) {
const draft = await step.prompt("triage-issue", {
prompt: `Triage issue #${event.payload.issueNumber}`,
output: draftSchema,
timeout: "3 days",
});
await step.do("apply-labels", async () => {
await this.agent.applyLabels(draft.labels);
});
}
}import { z } from "zod";
import { ThinkWorkflow } from "@cloudflare/think/workflows";
import type { ThinkWorkflowStep } from "@cloudflare/think/workflows";
import type { AgentWorkflowEvent } from "agents/workflows";
const draftSchema = z.object({
title: z.string(),
summary: z.string(),
labels: z.array(z.string()),
});
export class TriageWorkflow extends ThinkWorkflow<TriageAgent, Params> {
async run(event: AgentWorkflowEvent<Params>, step: ThinkWorkflowStep) {
const draft = await step.prompt("triage-issue", {
prompt: `Triage issue #${event.payload.issueNumber}`,
output: draftSchema,
timeout: "3 days",
});
await step.do("apply-labels", async () => {
await this.agent.applyLabels(draft.labels);
});
}
}Spusťte Workflow uvnitř svého Think Agent pomocí runWorkflow():
export class TriageAgent extends Think {
async triageIssue(issueNumber) {
return this.runWorkflow(
"TRIAGE_WORKFLOW",
{ issueNumber },
{ metadata: { issueNumber } },
);
}
}export class TriageAgent extends Think<Env> {
async triageIssue(issueNumber: number): Promise<string> {
return this.runWorkflow(
"TRIAGE_WORKFLOW",
{ issueNumber },
{ metadata: { issueNumber } },
);
}
}runWorkflow() vytvoří instanci Workflow a vloží identitu Agenta, kterou ThinkWorkflow se potřebuje znovu připojit k this.agent uvnitř run(). Upřednostněte ji před přímým voláním vazby Workflows:
// Avoid this for Agent workflows. It does not include Agent context.
await this.env.TRIAGE_WORKFLOW.create({ params: { issueNumber } });Použijte sendWorkflowEvent() z Agenta, když čekající Workflow potřebuje externí signál, například schválení člověkem:
await this.sendWorkflowEvent("TRIAGE_WORKFLOW", workflowId, {
type: "approval",
payload: { approved: true },
});step.prompt() přijímá řetězec s promptem a objektové schéma Zod. Toto schéma se před voláním Agentu z Workflow převede na JSON Schema. Think poté spustí celý agentní tah: Agent může v rámci více kroků použít své nástroje a strukturovaný výsledek vrátí voláním interní final_answer nástroj, jehož argumenty odpovídají schématu. Používá se běžné volání nástrojů místo streamovacího response_format, takže to funguje u všech poskytovatelů, které Think podporuje, včetně Workers AI, který u streamovaných požadavků odmítá odpovědi ve formátu JSON Schema. Když se Workflow obnoví, payload se znovu ověří podle původního schématu Zod, než se vrátí typovaná hodnota.
Nepodporované funkce Zod, které nelze vyjádřit jako JSON Schema, způsobí selhání při vytváření kroku promptu. Think tiše neopravuje neplatný výstup modelu. Pokud model nevytvoří platný final_answer volání se odeslání dostane do konečného chybového stavu a step.prompt() vyvolá výjimku.
Poznámky k chování
- Agent může nejprve použít své nástroje.
step.prompt()tah je plnohodnotný agentní tah: Agent může v několika krocích volat své vlastní nástroje a poté zavolat nástroj pro závěrečnou odpověď. Povolte alespoňmaxSteps: 2pokud očekáváte, že agent před odpovědí použije nástroj, smaxSteps: 1se vynutí odpověď hned v prvním kroku a nelze zavolat žádný jiný nástroj. - Během strukturovaného kola je použití nástroje vynucené. Aby bylo zaručeno, že Agent skončí strukturovanou odpovědí (a ne obyčejným textem), Think nastaví
toolChoicepro dané kolo. NepřepisujtetoolChoicezbeforeTurnnastep.prompt()tah: to může Agentovi zabránit ve volání nástroje pro závěrečnou odpověď, což způsobí selhání promptu. think_final_answerje vyhrazen. Think vloží interníthink_final_answernástroj pro přenos strukturovaného výsledku. Tento název (a jakýkolithink_final_answer_*varianta) je rezervovaná; její volání a výsledek se z uložené konverzace odstraní, takže přepis ani pozdější kola interní zákulisí Think nevidí.- Model musí podporovat streamovaná volání nástrojů. Think streamuje každý tah, takže
step.prompt()funguje pouze s modely, které při streamování spolehlivě vydávají vynucené volání nástroje. Modely dobře zvládající volání nástrojů (například OpenAIgpt-4o-mini, Anthropicclaude-haiku-4-5, a Workers AI@cf/moonshotai/kimi-k2.6) jsou ověřeně funkční. Některé modely respektují vynucenétoolChoicepouze u požadavků bez streamování a odpoví prostým textem a zastaví se při streamování, například Workers AI@cf/meta/llama-3.3-70b-instruct-fp8-fast. U těchto modelů kolo skončí bezthink_final_answervolání astep.prompt()selže (Model ended the turn without calling the think_final_answer tool); použijte místo toho model s funkčním streamováním volání nástrojů.
Jak to běží
Volání vypadá jako blokující krok, ale ve skutečnosti nedrží dlouhodobě otevřené RPC k Durable Object.
step.do("<name>:submit", ...)vytvoří nebo najde idempotentní odeslání Think.- Think spouští odeslané kolo přes běžnou frontu odeslání.
- Když podání dosáhne
completed,error,aborted, neboskipped, Think zaznamená čekající oznámení o workflow. - Think vyprazdňuje frontu odchozích oznámení pomocí
sendWorkflowEvent()a alarmy Durable Object, dokud se doručení neprovede úspěšně. step.waitForEvent("<name>:wait", ...)obnoví Workflow.step.prompt()ověří strukturovaný výstup, nebo vyvolá typovanou výjimku.
Strojově čitelný výstup se přenáší v payloadu čekajícího oznámení a v payloadu události Workflow. Think neukládá samostatný output_json sloupec v evidenci odeslání a po doručení vymaže payload notifikace. Po doručení vlastní trvalý výsledek Workflow.
Idempotence
Standardně step.prompt() odvodí klíč idempotence z identity Workflow a názvu kroku:
think-workflow:<workflowName>:<workflowId>:<stepName>Pro smyčky předejte řetězec key k rozlišení opakovaného použití stejného názvu kroku:
await step.prompt("summarize-file", {
key: file.path,
prompt: `Summarize ${file.path}`,
output: summarySchema,
});Text promptu není součástí odvozeného klíče, Think ale pro diagnostiku ukládá metadata workflow a otisk promptu/konfigurace.
Časové limity
Předejte timeout pro řízení toho, jak dlouho Workflow čeká na konečnou událost. Pokud čekání vyprší, step.prompt() ve výchozím nastavení zruší odeslání Think a vyvolá ThinkPromptTimeoutError.
Nastavte cancelOnTimeout: false když záměrně chcete, aby odeslání Think pokračovalo i poté, co Workflow přestane čekat.
Hranice vůči ostatním primitivům
Použijte getScheduledTasks() pro opakovaná odeslání promptů nebo deterministické naplánované obslužné rutiny:
getScheduledTasks() {
return {
dailySummary: {
schedule: "every day at 09:00",
timezone: "UTC",
prompt: "Generate the daily report."
},
dailyWorkflow: {
schedule: "every day at 09:00",
timezone: "UTC",
retry: { maxAttempts: 3 },
handler: async ({ idempotencyKey, scheduledFor, timezone }) => {
await this.env.REPORT_WORKFLOW.create({
id: idempotencyKey,
params: { scheduledFor, timezone }
});
}
}
};
}Použijte submitMessages() pro trvalá jednorázová kola, u nichž volající může stav odeslání zkontrolovat později.
Použijte startFiber() pro Agentem vlastněné idempotentní úlohy, které vyžadují zotavení uvnitř Agenta. Doručování oznámení workflow ve službě Think nepoužívá fibery, ale privátní outbox, protože potřebuje uchovat událost, dokud se úspěšně nedoručí.
Použijte Workflows, pokud proces zahrnuje více deterministických kroků, dlouhá čekání nebo schválení člověkem.