Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

长时运行的 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() 时持久化到 SQLite
  • this.sql 数据 —— 你创建的所有 SQLite 表
  • 计划任务 —— 存储在 SQLite 中,通过 alarm 唤醒 agent
  • 连接状态 —— 每个 WebSocket 客户端的 connection.setState() 数据
  • Fiber 检查点 —— runFiber() 中通过 stash() 保存的数据

任何基于 SQLite 构建的高层抽象同样能保留下来,因为它们共享同一份持久存储。

哪些不会被保留

  • 内存变量 —— 没有通过 setState()this.sql 存储的类字段
  • 运行中的定时器 —— setTimeoutsetInterval 在休眠/驱逐时丢失
  • 进行中的 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 参考 —— FiberContextFiberRecoveryContext、并发 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,这些组合在一起,构成一个能够:

  1. 规划 —— 把目标拆成步骤,把 plan 持久化到 state
  2. 执行 —— 一次跑一个步骤,中间休眠
  3. 响应 —— 在 webhook、邮件与 schedule 上被唤醒
  4. 恢复 —— 任何中断后从最近的检查点续作
  5. 委派 —— 把工作交给子 agent 与 Workflow
  6. 维护 —— 修剪旧数据、归档已完成工作、管理自身生命周期
  7. 结束 —— 项目完成时清理并销毁自己

agent 不需要持续运行就能完成上述所有事情。它只需要“存在“。

相关