长时运行的 Agent
构建可存活数天、数周甚至数月的 agent —— 它们能在重启后继续存在,按需唤醒,处理远超单次请求时长的工作。
为什么用 Cloudflare 来跑长时运行的 agent
Agent 大部分时间都在等待:等用户输入(数秒到数天)、等 LLM 响应(数秒到数分钟)、等工具结果(数秒到数小时)、等人工审批(数小时到数天),或是等定时唤醒(数分钟到数月)。在传统的 VM 或容器上,你为这些空闲时间全部付费。一个 99% 时间在休眠、1% 时间在工作的 agent,仍旧要按 100% 的服务器来计费。
Durable Objects 颠覆了这种模式。Agent 作为一个具备持久状态的可寻址实体存在,但休眠时消耗 0 计算资源。当某件事发生 —— HTTP 请求、WebSocket 消息、计划 alarm、入站邮件 —— 平台会唤醒 agent,从 SQLite 加载它的状态,把事件交给它。Agent 干完活,再回去睡。
这就是 actor 模型 ↗:每个 agent 都有身份、持久状态,并通过消息唤醒。你无需管理服务器、路由、健康检查或重启逻辑。平台负责放置、伸缩与恢复。
经济账自然就出来了:
| VM / 容器 | Durable Objects | |
|---|---|---|
| 空闲成本 | 始终按完整算力计费 | 0(休眠中) |
| 伸缩 | 需自行预置与管理容量 | 自动,按 agent 计 |
| 状态 | 需要外部数据库 | 内置 SQLite |
| 恢复 | 需自建(进程管理、健康检查) | 平台自动重启,状态保留 |
| 身份/路由 | 需自建(负载均衡、粘性会话) | 内置(按名映射到 agent) |
| 10000 个 agent,每个 1% 时间在工作 | 10000 个常驻实例 | 任意时刻约 100 个活跃 |
对于 agent 这种天然突发、有状态、长寿命的负载,这种模式非常契合。
长时运行 agent 的生命周期
长时运行的 agent 不是一个持续运行的进程,而是一个 持续存在 但 间歇性运行 的实体。理解其生命周期,是构建能在长时间维度上稳定运行的 agent 的关键。
Wake → onStart() → handle events → idle (~2 min) → hibernation
▲ │
└──────────────── alarm or request wakes agent ────────┘
Eviction (crash / redeploy) can happen at any point.
State persists in SQLite. Agent restarts on next event.
哪些会被保留
this.state—— 每次调用setState()时持久化到 SQLitethis.sql数据 —— 你创建的所有 SQLite 表- 计划任务 —— 存储在 SQLite 中,通过 alarm 唤醒 agent
- 连接状态 —— 每个 WebSocket 客户端的
connection.setState()数据 - Fiber 检查点 ——
runFiber()中通过stash()保存的数据
任何基于 SQLite 构建的高层抽象同样能保留下来,因为它们共享同一份持久存储。
哪些不会被保留
- 内存变量 —— 没有通过
setState()或this.sql存储的类字段 - 运行中的定时器 ——
setTimeout、setInterval在休眠/驱逐时丢失 - 进行中的 fetch 请求 —— 进行中的 HTTP 调用会被抛弃
- 本地闭包 —— 回调与 promise 链都会丢失
含义:任何重要的工作都必须被持久化或可恢复。SDK 为此提供了原语 —— schedule、fiber、queue —— 但理解“内存中“与“持久化“之间的边界至关重要。
贯穿示例:项目经理 agent
本文中我们将构建一个项目经理 agent,它具备如下能力:
- 在项目持续期间存活(数周或数月)
- 跟踪任务,把工作分派给子 agent,并汇报进度
- 按计划唤醒,检查截止日期并发送提醒
- 对外部事件做出反应(GitHub 的 webhook、团队成员的邮件)
- 处理长时间运行的操作(CI 流水线、代码审查、部署)
- 在过程中能扛过任意次数的重启与驱逐
TypeScript
import { Agent } from "agents";
type ProjectState = {
name: string;
status: "planning" | "active" | "review" | "complete";
tasks: Task[];
plan: Plan | null;
};
type Task = {
id: string;
title: string;
status: "pending" | "in_progress" | "blocked" | "complete";
assignee?: string;
dueDate?: string;
completedAt?: number;
externalJobId?: string;
};
export class ProjectManager extends Agent<ProjectState> {
initialState: ProjectState = {
name: "",
status: "planning",
tasks: [],
plan: null
};
}
Explain Code
Plan 类型会在 将 plan 作为持久化策略 一节引入。我们在每一节中逐步为该 agent 增加能力。
如何被唤醒
休眠的 agent 可以由以下任一方式唤醒:
| 唤醒来源 | 工作方式 | 示例 |
|---|---|---|
| HTTP 请求 | 任何对该 agent URL 的请求都会触发 onRequest() | 来自 GitHub 的 webhook |
| WebSocket 连接 | 客户端连接,触发 onConnect() | 团队成员打开 dashboard |
| RPC 调用 | 另一个 Worker 或 agent 通过 service binding 或 @callable 调用一个方法 | 协调者 agent 委派任务 |
| 计划 alarm | 已存储的 schedule 触发,调起你的回调 | 每天上午 9 点的站会提醒 |
| 邮件 | 入站邮件触发 onEmail() | 团队成员回复一封状态邮件 |
这种模式可以自然地推广到任何能够触达 Worker 的事件源 —— 从电话 webhook 到聊天平台机器人都可以。一个外部信号到达,平台唤醒 agent,agent 处理它。
agent 不需要为每种唤醒来源单独“启动“或“部署“ —— 它们都路由到同一个 Durable Object 实例。agent 的身份(名字)就是路由 key。
TypeScript
export class ProjectManager extends Agent<ProjectState> {
async onStart() {
// Daily deadline check at 9am UTC — idempotent, safe across restarts
await this.schedule(
"0 9 * * *",
"checkDeadlines",
{},
{
idempotent: true
}
);
// Progress sync every 30 minutes
await this.scheduleEvery(1800, "syncProgress");
}
async onRequest(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname.endsWith("/github-webhook")) {
const event = await request.json();
await this.handleGitHubEvent(event);
return new Response("OK");
}
return Response.json({
project: this.state.name,
status: this.state.status
});
}
async checkDeadlines() {
/* ... find overdue tasks, broadcast alerts ... */
}
async syncProgress() {
/* ... check on sub-agents, update task statuses ... */
}
}
Explain Code
在长任务期间保持存活
有时 agent 需要做一些超过空闲驱逐窗口(约 70 到 140 秒)的工作。例如流式 LLM 响应、编排多步工具链,或等待慢速 API,这些都可能让 agent 在任务中途被驱逐。
keepAlive() 通过创建一个心跳来重置不活跃计时器,从而避免被驱逐:
TypeScript
export class ProjectManager extends Agent<ProjectState> {
async generateProjectPlan(goal: string) {
const result = await this.keepAliveWhile(async () => {
const plan = await this.callLLM(`Create a project plan for: ${goal}`);
const tasks = await this.callLLM(
`Break this into tasks: ${JSON.stringify(plan)}`
);
return { plan, tasks };
});
this.setState({
...this.state,
status: "active",
plan: result.plan,
tasks: result.tasks
});
}
}
Explain Code
keepAliveWhile() 是推荐的方式 —— 它保证在工作完成(或抛出)后心跳一定会被清理。如果想手动控制,keepAlive() 会返回一个 disposer:
TypeScript
const dispose = await this.keepAlive();
try {
await longWork();
} finally {
dispose();
}
当 keepAlive 不够用时
keepAlive 适合分钟级而非小时级的工作。对于真正长时间的操作,使用其他策略:
| 时长 | 策略 |
|---|---|
| 秒级 | 普通的请求处理 |
| 分钟级 | keepAlive() / keepAliveWhile() |
| 分钟到小时 | Workflows |
| 小时到天 | 异步模式:启动任务、休眠、完成时被唤醒 |
扛过崩溃:fiber 与恢复
agent 可能在任意时刻被驱逐 —— 比如部署、平台重启或资源限制。如果 agent 当时处于任务中,且未被设置检查点,这部分工作就会丢失。
runFiber() 提供可在崩溃后恢复的执行能力。它在工作期间会向 SQLite 持久化一行,你可以通过 stash() 保存中间状态。如果 agent 被驱逐,这条 fiber 行会保留,下次激活时会调用 onFiberRecovered()。
TypeScript
export class ProjectManager extends Agent<ProjectState> {
async executeTask(task: Task) {
await this.runFiber(`task:${task.id}`, async (ctx) => {
const resources = await this.gatherResources(task);
ctx.stash({ phase: "prepared", resources, task });
const result = await this.runSubAgent(task, resources);
ctx.stash({ phase: "executed", result, task });
await this.updateTaskStatus(task.id, "complete", result);
});
}
async onFiberRecovered(ctx: FiberRecoveryContext) {
if (!ctx.name.startsWith("task:")) return;
const { phase, task } = ctx.snapshot as { phase: string; task: Task };
if (phase === "prepared") {
await this.executeTask(task);
} else if (phase === "executed") {
await this.updateTaskStatus(
task.id,
"complete",
(ctx.snapshot as { result: unknown }).result
);
}
}
}
Explain Code
模式是:在做昂贵工作之前打检查点,从最近的检查点恢复。 这不是自动重放 —— 你来定义“恢复“在你的领域里意味着什么。
本地测试恢复
在 wrangler dev 中,fiber 恢复行为与生产环境完全一致。kill 掉 wrangler 进程(Ctrl-C 或 SIGKILL),再重启,恢复会自动触发。SQLite 与 alarm 状态会在重启间持久化到磁盘。
完整 API 参考 —— FiberContext、FiberRecoveryContext、并发 fiber、内联与 fire-and-forget 模式 —— 请参阅 Durable Execution。
处理长时间的异步操作
项目经理常常会启动一些远超单次激活时长的工作 —— CI 流水线运行 20 分钟、设计评审耗时一天、视频素材生成需要数小时。agent 不应为此一直保持存活,而是启动工作、把任务 ID 持久化到 state、然后休眠。当结果到达时 —— 通过回调、轮询或 workflow 完成 —— agent 被唤醒、关联结果,然后继续。
模式:webhook 回调
项目经理为某个任务启动了 CI 流水线,流水线耗时 20 分钟。它不是去保持连接,而是把自己的 URL 注册为回调,然后去睡:
TypeScript
export class ProjectManager extends Agent<ProjectState> {
async startCIPipeline(task: Task) {
const response = await fetch("https://ci.example.com/api/pipelines", {
method: "POST",
body: JSON.stringify({
repo: "org/project",
branch: "main",
callback_url: `${this.url}/ci-callback?taskId=${task.id}`
})
});
const { pipelineId } = await response.json();
this.updateTask(task.id, {
status: "in_progress",
externalJobId: pipelineId
});
}
async onRequest(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname.endsWith("/ci-callback")) {
const taskId = url.searchParams.get("taskId");
const result = await request.json();
this.updateTask(taskId, {
status: result.status === "success" ? "complete" : "blocked"
});
return new Response("OK");
}
// ... other routes
}
}
Explain Code
模式:用 schedule 进行轮询
并不是每个外部服务都支持回调。当项目经理提交一个视频素材生成任务时,它需要周期性地检查直到任务完成:
TypeScript
export class ProjectManager extends Agent<ProjectState> {
async startVideoGeneration(task: Task) {
const response = await fetch("https://video-api.example.com/generate", {
method: "POST",
body: JSON.stringify({ prompt: task.title })
});
const { jobId } = await response.json();
this.updateTask(task.id, { status: "in_progress", externalJobId: jobId });
await this.schedule(60, "pollExternalJob", {
taskId: task.id,
jobId,
attempt: 1
});
}
async pollExternalJob(payload: {
taskId: string;
jobId: string;
attempt: number;
}) {
const response = await fetch(
`https://video-api.example.com/status/${payload.jobId}`
);
const status = await response.json();
if (status.state === "complete" || status.state === "failed") {
this.updateTask(payload.taskId, {
status: status.state === "complete" ? "complete" : "blocked"
});
return;
}
const nextDelay = Math.min(60 * payload.attempt, 600);
await this.schedule(nextDelay, "pollExternalJob", {
...payload,
attempt: payload.attempt + 1
});
}
}
Explain Code
模式:委派给 Workflow
一次生产部署涉及多个必须独立重试的步骤 —— 构建、测试、预发布、上线。项目经理不应该在内部管理这些步骤,而是委派给一个 Workflow,由它处理重试与步骤顺序:
TypeScript
export class ProjectManager extends Agent<ProjectState> {
async startDeployment(task: Task) {
const instanceId = await this.runWorkflow("DEPLOY_WORKFLOW", {
taskId: task.id,
environment: "production"
});
this.updateTask(task.id, {
status: "in_progress",
externalJobId: instanceId
});
}
async onWorkflowComplete(
workflowName: string,
instanceId: string,
result?: unknown
) {
const task = this.state.tasks.find((t) => t.externalJobId === instanceId);
if (task) this.updateTask(task.id, { status: "complete" });
}
}
Explain Code
长时间等待之后的上下文重建
CI 流水线 20 分钟后结束,webhook 唤醒了项目经理,任务状态被更新。然后呢?如果 agent 当时是用 LLM 来编排工作 —— 决定下一步做哪个任务、起草状态报告、推理阻塞点 —— 它需要把这条推理线接回去。原始的提示词、进行中的工具调用、思考链 —— 都已从内存中消失。
这是长时运行 AI agent 的根本挑战。大多数框架都假设工具调用在 LLM 的超时时间内完成,因此并未直接处理这个问题。
目前可行的方法有三种:
重放完整对话历史。 AIChatAgent 把所有消息持久化到 SQLite。结果到来时,把它追加到历史中并重新调用 LLM。这是最简单的方法,但会重新处理整个上下文窗口。
Stash 一个延续摘要。 在休眠前,持久化一个紧凑的描述,说明 agent 当时在做什么、结果到来时该如何处理:
TypeScript
ctx.stash({
task: "Waiting for CI results",
onSuccess: "Mark task complete, move to next step in plan",
onFailure: "Notify team, schedule retry in 1 hour",
relevantContext: { taskId, planStep: 3 }
});
恢复时,用 stash 构造一个聚焦的提示词,而不是重放所有内容。
用 plan 作为上下文。 如果 agent 有一个结构化的 plan,plan 本身就提供了足够的上下文:“我在 7 步中的第 3 步,这一步是’跑 CI 流水线’,结果刚刚到达”。这是长时运行 agent 最稳健的方式 —— plan 既是恢复机制也是上下文重建策略。详见下一节。
将 plan 作为持久化策略
结构化的 plan 不仅有助于向用户展示进度 —— 它也是一种持久化机制。带 plan 的 agent 可以从任何中断中恢复,只需查看上次停在哪里。
TypeScript
type Plan = {
goal: string;
steps: PlanStep[];
currentStep: number;
createdAt: string;
updatedAt: string;
};
type PlanStep = {
id: string;
description: string;
status: "pending" | "in_progress" | "complete" | "failed" | "skipped";
result?: unknown;
};
export class ProjectManager extends Agent<ProjectState> {
async createPlan(goal: string) {
const steps = await this.keepAliveWhile(async () => {
return this.callLLM(`
Break down this project goal into concrete steps.
Return a JSON array of { id, description } objects.
Goal: ${goal}
`);
});
this.setState({
...this.state,
plan: {
goal,
steps: steps.map((s: { id: string; description: string }) => ({
...s,
status: "pending" as const
})),
currentStep: 0,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
}
});
await this.schedule(0, "executeNextStep");
}
async executeNextStep() {
const { plan } = this.state;
if (!plan || plan.currentStep >= plan.steps.length) {
this.setState({ ...this.state, status: "complete" });
return;
}
const step = plan.steps[plan.currentStep];
try {
const result = await this.keepAliveWhile(() => this.executeStep(step));
const updatedSteps = plan.steps.map((s) =>
s.id === step.id ? { ...s, status: "complete" as const, result } : s
);
this.setState({
...this.state,
plan: {
...plan,
steps: updatedSteps,
currentStep: plan.currentStep + 1,
updatedAt: new Date().toISOString()
}
});
await this.schedule(0, "executeNextStep");
} catch (error) {
const updatedSteps = plan.steps.map((s) =>
s.id === step.id ? { ...s, status: "failed" as const } : s
);
this.setState({
...this.state,
plan: {
...plan,
steps: updatedSteps,
updatedAt: new Date().toISOString()
}
});
}
}
}
Explain Code
这种模式对长时运行 agent 有多个好处:
- 恢复极其简单 —— 重启时检查
plan.currentStep然后续作即可 - 进度可见 —— 客户端可以看到完成了哪些步骤、下一步是什么
- 可重新规划 —— 如果某步失败或需求变了,agent 可以修订剩余步骤而不丢失已完成的工作
- 人工监督 —— plan 是天然的审批检查点(“这是我打算做的 —— 是否继续?”)
- 上下文重建 —— plan 告诉 LLM 当前在哪、发生了什么、下一步是什么,不必重放完整对话
委派给子 agent
项目经理不会包揽一切。它把专门的工作委派给子 agent —— 每个子 agent 都有自己的身份、状态和生命周期。
TypeScript
export class ProjectManager extends Agent<ProjectState> {
async delegateTask(task: Task) {
const researcher = await this.subAgent(
ResearchAgent,
`research-${task.id}`
);
const findings = await researcher.research(task.title);
this.updateTask(task.id, { status: "complete" });
return findings;
}
}
Explain Code
子 agent 是独立的 Durable Object,有自己的 state、自己的 schedule、自己的生命周期。父 agent 不必在子 agent 工作期间一直保持存活 —— 它可以启动工作、休眠,等到回调或定时检查时再被唤醒。
完整的 subAgent() API —— 类型化 RPC stub、abort、delete、存储隔离与限制 —— 请参阅 Sub-agents。AI 专用的子 agent 流式传输(通过子 agent 跑完整的 LLM 回合)请参阅 Think: Sub-agent RPC。
恢复被中断的 LLM 流
上面的模式覆盖了项目经理的协调工作 —— 调度、委派、轮询。但项目经理也会直接使用 LLM:生成 plan、汇总进度、起草状态邮件。这些 LLM 调用会通过一个连接以流式方式输出 token,而当 agent 在响应中途被驱逐时,该连接是无法恢复的。
对于基于 AIChatAgent 的聊天型 agent,这个问题更加突出 —— 用户正在实时观看响应流,看到它在句子中途停下。chatRecovery 把每个聊天回合包装在 runFiber 中,在流式传输期间提供自动 keepAlive,并在 agent 重启时提供一个恢复钩子:
TypeScript
import { AIChatAgent } from "@cloudflare/ai-chat";
import type {
ChatRecoveryContext,
ChatRecoveryOptions
} from "@cloudflare/ai-chat";
class ProjectChat extends AIChatAgent<Env> {
override chatRecovery = true;
override async onChatRecovery(
ctx: ChatRecoveryContext
): Promise<ChatRecoveryOptions> {
// ctx.partialText — text generated before eviction
// ctx.recoveryData — whatever you stashed via this.stash()
// ctx.messages — full conversation history
return {};
}
}
Explain Code
正确的恢复策略取决于 LLM 提供方:
| 提供方 | 策略 | 工作方式 | Token 成本 |
|---|---|---|---|
| Workers AI | 从部分内容继续 | continueLastTurn() —— 模型通过 assistant 预填充进行延续 | 低 |
| OpenAI(Responses API) | 检索已完成的响应 | 在流式期间 stash responseId,恢复时检索 | 0 |
| Anthropic | 合成式延续 | 持久化部分内容,发送一个合成的用户消息让模型继续 | 中 |
| 其他 | 先尝试预填充,回退到合成 | 如果提供方支持 continueLastTurn() 就用它,否则使用合成消息 | 视情况 |
长期管理状态
一个跑数月的 agent 会积累数据:对话历史、时间线事件、已完成任务、schedule 记录。如果不管理,这些数据会无限增长。
日常清理
安排定期清理来修剪旧数据并归档已完成的工作:
TypeScript
export class ProjectManager extends Agent<ProjectState> {
async onStart() {
await this.schedule("0 0 * * *", "housekeeping", {}, { idempotent: true });
}
async housekeeping() {
const cutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;
const toArchive = this.state.tasks.filter(
(t) => t.status === "complete" && (t.completedAt ?? 0) < cutoff
);
for (const task of toArchive) {
this
.sql`INSERT INTO archived_tasks (id, data) VALUES (${task.id}, ${JSON.stringify(task)})`;
}
this.setState({
...this.state,
tasks: this.state.tasks.filter(
(t) => !toArchive.some((a) => a.id === t.id)
)
});
this.deleteWorkflows({
status: ["complete", "errored"],
createdBefore: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
});
}
}
Explain Code
对话历史管理
对于使用 AIChatAgent 的 agent,对话历史会随时间增长得很大。如果不管理,3 个月的对话早在项目结束之前就会撑爆 LLM 的上下文窗口。
管理对话规模的策略:
- 滑动窗口 —— 在活跃上下文中只保留最近 N 条消息,简单可预测。
- 摘要化 —— 周期性地把较旧的消息汇总,用紧凑的摘要替换。原始消息可以保留在 SQLite 中以便审计。
- 选择性保留 —— 保留含决策、审批与关键上下文的消息,修剪日常对话。
生命周期的终点
长时运行 agent 终究会完成它的使命。项目交付、调查结束、监控窗口关闭。要显式做清理:
TypeScript
export class ProjectManager extends Agent<ProjectState> {
async completeProject() {
const schedules = this.getSchedules();
for (const schedule of schedules) {
await this.cancelSchedule(schedule.id);
}
this.setState({ ...this.state, status: "complete" });
// All SQLite data, schedules, and state are permanently deleted
await this.destroy();
}
}
Explain Code
this.destroy() 是永久性的。如果你以后还可能需要这个 agent 的数据,在销毁之前先把它归档到外部存储(R2、D1 或 API 调用)。对于以后可能被重新激活的 agent,只需把它标记为完成、让它休眠 —— 空闲时它不消耗任何成本。
Workflow vs agent 内部模式:何时用什么
Workflow 与 agent 内部原语(schedule、fiber、queue)都支持长时运行的工作。选择哪种取决于工作的性质:
| Agent 内部 | Workflows | |
|---|---|---|
| 最适合 | 以 agent 为中心的工作:调度、轮询、状态更新 | 独立的多步流水线 |
| 持久化 | SQLite(可扛驱逐) | Workflow 引擎(扛得住一切) |
| 重试 | this.retry()、schedule 级别的重试 | 每步级别的重试,带退避 |
| 最长时长 | 每次激活分钟级(配合 keepAlive) | 每步 30 分钟,步骤数无上限 |
| 人工审批 | 自己实现(state + WebSocket) | 内置 waitForApproval() |
| 复杂度 | 较低 —— 一切都在 agent 内 | 较高 —— 独立的类、wrangler 配置 |
一个务实的经验法则:如果工作是关于 agent 自身的生命周期管理(检查截止、同步状态、发送提醒),用 schedule 与 fiber。如果工作是一条可独立失败与重试的离散流水线(部署、数据处理、报告生成),用 Workflow。
项目经理 agent 同时使用两者:用 schedule 实现自身节律(每日站会、进度同步),用 Workflow 处理重型操作(部署、CI 流水线)。
小结
Cloudflare 上的长时运行 agent 不是长时运行的进程,而是会唤醒、工作、入睡的持久实体 —— 跨度可能是数周或数月。关键原语:
| 原语 | 用途 |
|---|---|
| setState() / this.sql | 跨激活持久化状态 |
| schedule() / scheduleEvery() | 在未来时间唤醒 agent |
| keepAlive() / keepAliveWhile() | 在活跃工作期间防止被驱逐 |
| runFiber() / stash() | 给长任务打检查点并恢复 |
| chatRecovery | 恢复被中断的 LLM 流 |
| onRequest() / onEmail() / RPC | 在外部事件下被唤醒 |
| runWorkflow() | 把重型多步工作委派出去 |
| subAgent() | 把专门工作委派给子 agent |
| state 中的结构化 plan | 让恢复、可见性与重新规划成为可能 |
对于项目经理 agent,这些组合在一起,构成一个能够:
- 规划 —— 把目标拆成步骤,把 plan 持久化到 state
- 执行 —— 一次跑一个步骤,中间休眠
- 响应 —— 在 webhook、邮件与 schedule 上被唤醒
- 恢复 —— 任何中断后从最近的检查点续作
- 委派 —— 把工作交给子 agent 与 Workflow
- 维护 —— 修剪旧数据、归档已完成工作、管理自身生命周期
- 结束 —— 项目完成时清理并销毁自己
agent 不需要持续运行就能完成上述所有事情。它只需要“存在“。
相关
- Durable Execution ——
runFiber()、stash()与崩溃恢复 - Schedule tasks —— 延迟、cron 与间隔任务
- Retries —— 重试选项与模式
- Workflows —— 持久化的多步处理
- Store and sync state ——
setState()与持久化 - WebSockets —— 生命周期钩子与休眠
- Callable methods —— 通过
@callable与 service binding 的 RPC - Email routing —— 接收入站邮件
- Webhooks —— 接收外部事件
- Human in the loop —— 审批流