news 2026/10/15 13:44:17

eve Tasks 升级指南:从 `execution: “background“`、`agentId` 与 `subagent.*` 事件完整迁移到 Tasks

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
eve Tasks 升级指南:从 `execution: “background“`、`agentId` 与 `subagent.*` 事件完整迁移到 Tasks
  • 人工智能
  • AI Agent
  • Agent 框架
  • 后端
  • 工具调用

【免费下载链接】eve

The Open Framework for Building Agents

项目地址:https://gitcode.com/gh_mirrors/eve28/eve
点击查看免费下载

本文是 eve 开源框架(The Open Framework for Building Agents)在 "Upgrade to Tasks" 版本中关于后台任务(background tasks)升级为 Tasks 体系的完整迁移实战指南。它面向已经使用过 eve 0.66 之前 API(execution: "background"、dismissible、ctx.agent(name, { message, agentId })、subagent.*事件等)的开发者,逐节给出破坏性变更的替换代码、错误语义变化、客户端与服务端的事件协议差异,以及远端 Agent(remote agent)协议的升级顺序。读完本文,你将能一次性识别并改写工作流工具、Agent 调用、客户端流处理、Hooks 与 evals 中所有受影响的代码路径,平稳升级到新的 Tasks API。

本版本的迁移核心一句话概括:后台任务被task(及serve)取代,agentId延续被taskId取代,subagent.*事件被task.*/agent.started事件取代,turn.completed/session.waiting的语义被turn.waiting收紧。下面对照 eve 官方文档 docs/tools/tasks-upgrade.md 的八个小节逐一展开,并结合仓库源码与测试验证每一条迁移规则。

一、迁移总览:哪些代码会变,哪些保持不变

先建立一个全局判断标准:不是每个工作流工具都需要改。如果一个工作流工具没有使用execution: "background"、dismissible或ctx.agent这三者中的任何一个,它的代码可以原样保留:

  • execute(input, ctx)的函数签名不变;
  • ctx.abortSignal与ctx.callId仍在原来的位置。

但所有execute工具都有一项行为变化:一条转向消息(steering message)现在会中止该调用的ctx.abortSignal(详见下文"去掉dismissible"一节)。也就是说,旧版里"问题可以跨消息保持开放"的行为被统一收口为"会话向前推进时,execute调用随之终止"。

好消息是,绝大多数代码变更都可以被 TypeScript 类型检查直接标记出来——被移除的execution、dismissible选项以及旧的ctx.agent调用签名都会产生类型错误。从 eve 的兼容性说明(packages/eve/src/compiler/extension-compatibility.ts)可以看到对应的版本行为描述:"Workflow tools no longer accept execution or return background task receipts, and every call blocks until it settles. ctx.ask() no longer accepts dismissible… ctx.agent(name) returns a session handle whose send() delivers a message and whose result() resolves the turn."

本文覆盖的迁移面如下:

  1. execution: "background"→task(input, ctx)
  2. dismissible选项移除 → 转向消息中止execute
  3. ctx.agent(name, { message, agentId })→ctx.agent(name)会话句柄
  4. 模型侧 Agent 工具参数agentId→taskId
  5. 后台投递选项(taskDeliveryPolicy等)整体移除
  6. subagent.*流事件 →task.*/agent.started事件
  7. 客户端对"开放回合(open turn)"的新处理(turn.waiting)
  8. 远端 Agent 先于调用方升级(remote agent 协议 v2)

二、把execution: "background"替换为task(input, ctx)

2.1 机械替换:改名 + 删选项

后台任务的核心写法是把execute与execution: "background"组合使用;新 API 中直接定义task(input, ctx),函数体完全不用动:

export default defineWorkflowTool({ description: "Deploy a service.", inputSchema: z.object({ service: z.string() }), - execution: "background", - async execute({ service }, ctx) { + async task({ service }, ctx) { "use workflow"; return await deploy(service, ctx.abortSignal); }, });

如果遗漏了删除execution选项,defineWorkflowTool会在工具定义时直接抛错。仓库中的校验逻辑位于 packages/eve/src/tools/workflow-definition.ts:

if ("execution" in definition) { throw new Error( '"execution" was replaced by task(). Define task(input, ctx) to run each call as a task.', ); }

对应的测试用例 packages/eve/src/tools/workflow-definition.test.ts 也验证了这一错误信息。同理,一个工作流工具必须恰好定义一个入口点——execute、task、serve三选一,定义零个或多个都会在定义时抛出Define exactly one of execute(input, ctx), task(input, ctx), or serve(receive, ctx); this tool defines ${found}.(见 workflow-definition.ts)。

2.2task与execute的运行时差异

维度execute(input, ctx)task(input, ctx)
运行方式普通工具调用,回合等待其结果任务:立刻返回收据,结果稍后到达
结果到达工具结果收据 + 后续task.result消息
转向消息打断会中止其abortSignal不会打断(task 无感)
ContextWorkflowToolContext同样的WorkflowToolContext

task函数体拿到的WorkflowToolContext与execute完全相同,且转向消息永远不会中止 task 的abortSignal——这正是任务与普通调用的分水岭:任务在会话继续对话时照常运行。关于三种入口点的完整选择逻辑可参考 eve 官方文档 docs/tools/tasks.md 中的"Choose how a call runs"。

2.3 需要持续接收输入的场景改用serve

如果模型在任务运行期间还需要继续向它发送新输入(典型例子:模型会按用户要求反复修订的一份计划),那么task也不够用,应改而定义serve(receive, ctx)。serve是"可恢复任务(resumable task)"入口:每次新调用通过receive()解析,并可用ctx.reply()回复。其语义在 docs/tools/workflows.mdx 的 "Resumable tasks:serve" 一节有完整说明,eve 的 Agent 工具正是以serve工具实现的(详见第五节)。三入口的判定见 docs/tools/tasks.md:

defineWorkflowTool({ /* … */ async execute(input, ctx) {} }); // 回合等待调用结束 defineWorkflowTool({ /* … */ async task(input, ctx) {} }); // 任务:先收据,后结果 defineWorkflowTool({ /* … */ async serve(receive, ctx) {} }); // 可接收更多调用的任务

三、去掉dismissible:新消息现在会中止execute调用

旧版中,ctx.ask()支持dismissible: true,使一个问题在对话继续时可以保持打开。新版移除了该选项——转向消息会中止当前回合等待中的每个execute调用的ctx.abortSignal,从而收回该调用提出的所有问题,效果与旧版dismissible: true一致:

-const answer = await ctx.ask({ prompt, dismissible: true }); +const answer = await ctx.ask({ prompt });

3.1 中止的传导范围

凡是接收ctx.abortSignal的工作都会随之停止,包括:

  • 一个step(步骤);
  • 一次ctx.agent发送(见第四节);
  • 问题(ctx.ask)本身。

调用最终以函数体返回的内容落定;若函数体因中止而抛出异常拒绝,则以{ interrupted: true }落定。模型会在下一条消息中读到这一结果。

3.2 状态值变化:dismissed→cancelled

被收回的问题现在解析为{ status: "cancelled" }(而不是dismissed),相应地input.resolved结果类型中的"dismissed"也改为"cancelled"。任何按旧值做匹配的客户端与渠道都必须更新。这条语义在 docs/tools/tasks.md 的 "Pass signals to the work" 一节有更完整的描述:在serve函数体内,ctx.reply()同样会收回它结算的调用仍挂起的问题;ctx.ask(request, { signal })还支持额外的信号中止。关键是分支逻辑应判断answer.status(answered/cancelled),而不是依赖信号本身——因为"人已经先回答了"时,即使信号已中止,问题仍按answered结算。

3.3 想让问题跨消息保持开放怎么办

把问题移到task中提出(替换为task(input, ctx))即可:task 不受转向消息影响,问题保持开放直到用户回答或任务被显式取消。这也是"何时该用任务"的最典型判据之一——当模型需要一边继续对话、一边等待某个输入或长耗时工作时,就用 task。

四、用ctx.agent(name)打开 Agent 会话

4.1 旧 API 的返回值变成了会话句柄

旧签名ctx.agent(name, { message, agentId })直接返回 Agent 的输出;新签名ctx.agent(name)返回一个会话(session),你需要先send消息、再读取该回合的结果:

-const review = await ctx.agent("reviewer", { message: plan }); +const response = await ctx.agent("reviewer").send(plan, { signal: ctx.abortSignal }); +const { message: review, status } = await response.result(); +if (status === "failed") throw new Error("The review failed.");

要点:

  • agentId参数已被移除;每次ctx.agent(name)调用都开启一个新会话;
  • 在同一个句柄上继续send会延续该会话的对话,直到工作流运行结束;
  • signal: ctx.abortSignal把工作流调用的中止信号传递给 Agent 回合,保持取消语义一致。

ctx.agent的能力边界在 docs/tools/workflows.mdx 的 "Delegate work:ctx.agent" 一节有完整说明。需要强调的是:workflow工具自动生成的程序(generated programs)仍然保留ctx.agent(name, { message, outputSchema? })能力,只有手写工作流工具的调用方式发生了变化。

4.2 使用ctx.agent保证"先审后发"的强顺序

Tasks 体系下 Agent 调用都是任务,模型可以自行决定是否等待,因此"先审核再发布"这类指令只有模型遵守时才成立。若顺序必须无条件成立,应写一个工作流工具:先用ctx.agent跑第一步(如审核),再执行副作用,并且不要把副作用暴露成独立工具。eve 文档 docs/tools/tasks.md 给出了完整的publish_reviewed_notes示例(审核通过才发布、失败抛错、可选tool: false隐藏审核 Agent、需要边聊边审时把execute换成task)。

五、用taskId延续 Agent:每个 Agent 调用都是可恢复任务

这是迁移中模型侧提示词改动最大的一处。新版里每个 Agent 工具都是serve工具,因此每次 Agent 调用都是可恢复任务(resumable task)。模型调用 Agent 工具时,参数从agentId换成taskId:

-{ "message": "Check the Q2 numbers too.", "agentId": "…" } +{ "message": "Check the Q2 numbers too.", "taskId": "researcher-7k2m9q" }

5.1 调用即收据,结果稍后送达

  • Agent 调用立刻返回一个**收据(receipt)**作为工具结果,例如:Started task researcher-7k2m9q. Its result will arrive in a <task_result> message. To send it another message, call researcher again with taskId researcher-7k2m9q.;
  • Agent 的回复随后以一条task.result消息到达(任务 ID 形如"工具名 + 6 个字符");
  • 凡是提示词、指令、evals 中提过agentId、或期望"回复直接作为工具结果返回"的地方,都必须更新;
  • agentRouter()与workflow工具现在也把每次调用当作任务运行。

5.2 错误码的变化

被移除的错误码AGENT_BUSY、AGENT_MISMATCH、AGENT_UNREACHABLE、AGENT_INVOCATION_NOT_ADMITTED没有替代品。取而代之的是两个任务专属错误码:

错误码触发条件
UNKNOWN_TASK调用的taskId指向不存在、或并非该工具开启的未完成任务
TOO_MANY_TASKS调用将开启新任务、或让空闲任务重新工作,而此时已有32个任务在运行

这两个常量定义在 packages/eve/src/protocol/task-tools.ts,抛出逻辑见 packages/eve/src/execution/tasks/start.ts。更多细节(eve__task_cancel对未知任务的反馈、32 个并发工作任务上限、任务无独立超时等)参见 docs/tools/tasks.md 与 "Ownership and limits" 一节。

六、移除后台投递选项:结果只有一种到达方式

旧版有复杂的后台结果投递机制,现在全部收口为一条路径:task.result消息在步骤边界(step boundary)到达模型。需要删除的内容:

  • taskDeliveryPolicy与"投递组(delivery cohorts)"。仓库的检查点迁移代码也印证了这一点——旧运行时会话状态中的eve.runtime.taskDeliveryPolicy键已被清理(packages/eve/src/execution/session/checkpoint-migrations.ts),且旧kind: "execution.background_task"消息被迁移(同文件 L272);
  • session.cancel()的tasks选项。现在session.cancel()一次取消三样东西:当前回合、回合等待中的execute调用、以及所有正在工作的任务;它仍然接受turnId与signal。

模型视角的变化也很明显:不再看到[Task state]或[Agents]便签、散文式任务通知、<eve-empty-delivery/>或结果回合;取而代之的是列出工作任务与空闲任务的[Tasks]便签。BACKGROUND_TASK_FAILED与BACKGROUND_TASK_CANCELLED错误码被移除,失败任务在task.settled事件及其task.result块中报告错误。

七、读取task.*事件,替代subagent.*事件

四个旧事件被移除:subagent.called、subagent.started、subagent.completed、subagent.event。替换关系如下表:

新事件替代旧事件携带数据
task.startedsubagent.calledtaskId、callId、turnId、name、kind
task.settledsubagent.completedtaskId、callId、turnId、name、kind、status,以及(未取消时)output或error
agent.startedsubagent.startedcallId、turnId、taskId、name、sessionId、streamPath

7.1 客户端:跟随子会话的流

subagent.event原本负责转发子 Agent 自身的事件;现在改为在子会话自己的流上读取。session.streamSubagent()更名为session.agent(started).stream(),且入参从旧事件变为agent.started事件:

for await (const event of session.stream()) { - if (event.type !== "subagent.called") continue; + if (event.type !== "agent.started") continue; - for await (const childEvent of session.streamSubagent(event)) { + for await (const childEvent of session.agent(event).stream()) {

仓库测试证实了这一 API 形态:session.agent(startedEvent()).stream({ follow: false })出现在 packages/eve/src/client/session.test.ts 与 packages/eve/src/client/subagent-stream.integration.test.ts 中;会话句柄实现位于 packages/eve/src/client/agent-session.ts。

7.2 Hooks:订阅方式不变,事件名更新

Hooks 用同样的方式订阅新事件,只是名称和守卫条件变化:

export default defineHook({ events: { - async "subagent.completed"(event, ctx) { + async "task.settled"(event, ctx) { + if (event.data.status !== "completed") return;

7.3 evals:calledSubagentAPI 不变

eval 断言t.calledSubagent(name, { status })保留原有 API,但底层改为读取任务事件。实现位于 packages/eve/src/evals/assertions/run.ts,其测试覆盖了task.started/task.settled事件上的状态匹配与计数(packages/eve/src/evals/assertions/run.test.ts)。因此,你的 eval 断言代码大多不需要改动,但读取的底层事实(facts)来源已从 subagent 事件切换为 task 事件(见 packages/eve/src/evals/runner/derive-run-facts.ts)。

八、客户端如何处理开放回合(open turns)

这是行为变化最隐蔽、也最容易造成客户端"提前截断回复"的一节。有任务在工作时,回合不会结束——一个回合可以跨越一次等待(wait)。流用新事件turn.waiting报告每次等待,并携带开放回合的turnId。以下是必须理解的几条规则:

8.1turn.waiting的三种触发场景

  • 持有回合(held turns):模型在任务仍在工作时结束自己的文本,或eve__task_wait尚无结果时,流发出turn.waiting。同一turnId的下一条step.started表示回合恢复。在根会话(root session)中,等待前的文本以正常的message.completed完成;在子会话与调度(schedule)的会话中,该步骤以finishReason: "tool-calls"报告。
  • 调用内部的问题与登录不再结束回合:旧版中,运行中调用内部的问题或登录(如工作流工具的ctx.ask()、ask_question、子 Agent 的问题)会在回合中途发出turn.completed与session.waiting。现在改为先发出input.requested或authorization.required,再发出turn.waiting,用户作答后回合在同一turnId下继续。你作答的那个会话,会为它路由到答案的每个问题发出input.resolved。注意:回合自身请求的工具审批(tool approval)仍然以turn.completed+session.waiting结束回合,这条没变。
  • turn.completed只在回合真正结束时发出,session.waiting永远意味着回合已结束。

8.2 客户端读取结果的新规则

TypeScript 客户端的send(...).result()会越过turn.waiting,返回持有回合的最终回复,而不是等待前写下的文本;它只在"问题待答"时停在turn.waiting,返回status: "waiting"并附带该问题,随后respond()会把同一个回合读到结束。自定义客户端如果满足以下任一情况,都应遵循同一规则(详见 docs/guides/client/streaming.mdx 的 "Aggregate a turn"):

  • 在回合中途以turn.completed或session.waiting结束响应;
  • 把第一条完成的message.completed当作回复展示。

8.3 任务结果不是流事件

任务结果不会作为流事件出现。旧版后台任务结果以message.received且data.kind: "execution.background_task"出现;现在message.received不再有kind,且任务结果只到达模型。每次调用的结果应从task.settled读取。关于流的更多语义(turn.waiting的on: "input" | "tasks"字段、task.settled的cancel.reason等)见 docs/concepts/sessions-runs-and-streaming.md 的 "Task events" 一节。

8.4 消息流版本号:26

消息流(message stream)版本现在是26。TypeScript 客户端接受版本 21~26;只接受到 25 的客户端会以"unsupported-version"错误使流失败。因此升级时请同步更新客户端 SDK,而不是只改服务端。

九、先升级远端 Agent,再升级调用方

远端 Agent 协议升级到了version 2(常量REMOTE_AGENT_PROTOCOL_VERSION = 2定义于 packages/eve/src/protocol/remote-agent-protocol.ts)。升级顺序是硬约束:先把每个远端 Agent(docs/guides/remote-agents.md)部署到新版本,再升级调用它的部署。

9.1 协议 1 的兼容服务

本版本部署的远端 Agent 仍然服务 eve 0.66~0.68 的调用方(它们说的是协议 1),行为包括:

  • 运行调用方的回合,把每个结果发送到调用方的回调;
  • 接受调用方的后续(follow-up)与重置(reset)请求;
  • 把远端 Agent 的工具审批与登录请求发送给调用方,并接受调用方的回答——与 0.66~0.68 的远端 Agent 行为一致;
  • 这一兼容覆盖的是"调用方模型直接调用的 Agent"(它们作为后台任务运行);当调用方自己的工作流工具代码调用 Agent 时,其审批与登录请求停留在远端 Agent 自己的渠道上。

每次协议 1 调用都会记录一条日志serving a remote agent protocol 1 caller(带上调用方来源),实现见 packages/eve/src/eve-channel/index.ts。

9.2 与同版本远端 Agent 的两点差异

  • 调用方的渠道不会在调用下方嵌套展示远端 Agent 的实时工具活动;
  • 远端 Agent 中的ctx.ask()返回unavailable,因为协议 1 的调用方不授予远端 Agent 输入能力——这一点与 0.66~0.68 保持一致。

9.3 调用方侧:协议不匹配即失败

当远端 Agent 部署仍说协议 1 时,本版本上的调用方会在调用开始时失败,并给出同时包含两个版本的错误。协议不匹配错误消息由 packages/eve/src/protocol/remote-agent-protocol.ts 生成:"Remote agent … speaks eve remote agent protocol ${receiverVersion}, but this deployment speaks protocol ${REMOTE_AGENT_PROTOCOL_VERSION}. Upgrade both deployments to the same eve release."。请务必按"先 Agent、后调用方"的顺序完成升级,避免调用中途失败。

十、升级检查清单

迁移完成后,建议按以下清单逐项自检:

  1. 工作流工具:grep确认不再出现execution:与dismissible:;execute/task/serve恰好定义其一(定义时会抛错校验)。
  2. ctx.agent调用:全部改为ctx.agent(name)会话句柄 +send()+result(),不再传{ message, agentId }。
  3. 提示词与 evals:不再出现agentId;Agent 工具参数统一为taskId;不再期望"回复作为工具结果直接返回"。
  4. 客户端:订阅task.started/task.settled/agent.started/turn.waiting,删除subagent.*订阅与streamSubagent()调用;result()能越过turn.waiting读到最终回复;流版本号 >= 21 且支持 26。
  5. Hooks:事件名改为task.settled等,注意status守卫。
  6. 渠道与前端:匹配"dismissed"的地方改为"cancelled";按需适配turn.waiting的界面表现(Slack 渠道已有实时的任务卡片,见 docs/channels/slack.mdx 的 task card 说明)。
  7. 部署顺序:远端 Agent 先升级到本版本,再升级调用方。

如果想进一步理解新体系的完整运行模型(任务如何被模型感知、eve__task_wait/eve__task_cancel的语义、回合如何等待任务、任务归属与 32 任务上限),请继续阅读 docs/tools/tasks.md;工作流工具三种入口点的写作细节见 docs/tools/workflows.mdx。

  • 人工智能
  • AI Agent
  • Agent 框架
  • 后端
  • 工具调用

【免费下载链接】eve

The Open Framework for Building Agents

项目地址:https://gitcode.com/gh_mirrors/eve28/eve
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 13:43:56

微电网模型预测控制(MPC)的Python实现与优化

1. 项目背景与核心价值微电网作为分布式能源的重要载体&#xff0c;正在重塑传统电力系统的运行模式。但风光等可再生能源的波动性和负荷不确定性&#xff0c;给微电网的稳定运行带来了巨大挑战。三年前我在参与一个海岛微电网项目时&#xff0c;就曾亲眼目睹过由于预测偏差导致…

作者头像 李华
网站建设 2026/10/15 13:43:27

企业在线培训系统架构设计与实践指南

1. 在线培训系统的时代价值去年帮一家200人规模的科技公司部署在线培训系统时&#xff0c;他们的HR总监给我算过一笔账&#xff1a;传统线下培训每月要消耗37个工时在场地协调和差旅安排上&#xff0c;而采用我们的系统后&#xff0c;第一季度就完成了全年82%的培训指标。这让我…

作者头像 李华
网站建设 2026/10/15 13:42:55

基于蛋壳公寓投诉数据的文本分析与可视化实战

1. 项目缘起与整体分析框架1.1 为什么选长租公寓投诉数据作为分析标的长租公寓这个行业在过去几年经历了过山车式的变化&#xff0c;头部品牌暴雷、租金贷风波、房东与租客两头受损的新闻层出不穷。我之所以挑蛋壳公寓的投诉数据来做这个分析项目&#xff0c;原因很直接&#x…

作者头像 李华
网站建设 2026/10/15 13:42:13

PSO优化LSTM超参数:MATLAB实现时间序列预测与GUI交互

很多做时间序列预测的朋友&#xff0c;一开始接触到的都是直接用LSTM&#xff08;长短期记忆网络&#xff09;跑数据&#xff0c;调几个参数&#xff0c;看结果。但真正在项目里跑过几轮就会发现&#xff0c;LSTM的效果非常大程度上取决于超参数选得好不好——隐含层节点数、学…

作者头像 李华
网站建设 2026/10/15 13:42:05

DMOA优化CNN-LSTM-Attention超参数:Matlab故障诊断实战指南

做故障诊断这块的同行应该都有体会&#xff0c;模型的骨架搭起来并不难&#xff0c;难的是怎么让它稳定到“能打”的状态。CNN提取特征、LSTM抓时序依赖、Attention分配注意力&#xff0c;这三件套用在轴承、齿轮箱、电机这类旋转机械的故障诊断里&#xff0c;早已是主流打法。…

作者头像 李华
网站建设 2026/10/15 13:41:37

OpenMV与STM32双芯片智能车:串口通信与PID控制实战

简介&#xff1a;面向嵌入式与机器视觉学习者&#xff0c;这是一份基于STM32F407与OpenMV的循迹小车完整工程&#xff0c;可实现矩形、圆形、三角形识别及红绿蓝颜色区分&#xff0c;并内置封装好的视觉与驱动模块&#xff0c;适合有一定单片机基础、希望快速实现视觉循迹的开发…

作者头像 李华