跳到主要内容
非官方简体中文翻译,内容版权归 Mastra 所有,遵循 Apache-2.0 许可。

后台任务

新增于: @mastra/core@1.29.0

后台任务让 agent 可以派发长时间运行的工具调用,而不阻塞 agentic 循环。工具会立即返回确认,LLM 则继续响应。随后任务在后台运行至完成。任务完成后,其结果会写入 memory;如果你使用带 untilIdle 选项的 stream(),agent 会自动被重新调用,从而在同一次调用中处理结果。

何时使用后台任务
何时使用后台任务的直接链接

当工具调用可能耗时较长、用户不应在看到响应前等待时,请使用后台任务。常见情况:

  • 本身会运行多步骤研究或写作的 subagent 委托。
  • 访问慢速外部服务、队列或大型数据作业的工具调用。
  • 由工具调用触发、可能需要数分钟才能完成的 workflows。

对于快速返回的工具调用,使用 agent.stream() 和 agent.generate() 的前台执行更简单。

备注

后台任务需要在 Mastra 实例上配置存储后端。任务会被持久化,因此能在进程重启后保留。

快速开始
快速开始的直接链接

后台任务默认关闭。在 Mastra 实例上设置 backgroundTasks.enabled 来启用它们:

src/mastra/index.ts
import { Mastra } from '@mastra/core'
import { LibSQLStore } from '@mastra/libsql'

export const mastra = new Mastra({
storage: new LibSQLStore({ id: 'storage', url: 'file:mastra.db' }),
backgroundTasks: {
enabled: true,
globalConcurrency: 10,
perAgentConcurrency: 5,
backpressure: 'queue',
defaultTimeoutMs: 300_000,
},
})

完整选项列表请参阅 backgroundTasks 配置参考。

在后台运行工具
在后台运行工具的直接链接

启用管理器本身不会在后台运行任何东西。工具在以下两个层级之一获得资格:

  1. 工具级配置:工具自身声明其支持后台运行。
  2. Agent 级配置:agent 声明其哪些工具支持后台运行。

符合条件的工具默认使用 deferred 执行。若希望资格仅让 LLM 可以选择在后台运行调用,请在任一层级设置 defaultDisposition: 'foreground'。LLM 可以在工具参数中包含 _background 字段,为特定调用选择 foreground、deferred 或 awaited 执行,并覆盖其超时或重试设置。

工具级
工具级的直接链接

在工具定义上设置 background.enabled: true。在此层级选择加入的工具,在被启用了管理器的 agent 调用时具备后台执行资格。其配置的默认处置方式决定每次调用是内联运行还是在后台运行,除非调用中包含 _background 覆盖。

src/mastra/tools/research.ts
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'

export const researchTool = createTool({
id: 'research',
description: 'Run a long research job',
inputSchema: z.object({ topic: z.string() }),
background: {
enabled: true,
defaultDisposition: 'deferred',
timeoutMs: 600_000,
maxRetries: 1,
},
execute: async ({ topic }) => {
// Run the research job for topic
},
})

Agent 级
Agent 级的直接链接

在 agent 上使用 backgroundTasks.tools 选择加入特定工具,或为个别工具覆盖超时,或让所有具备后台资格的工具在后台运行。使用 disabled: true 完全短路该 agent 的后台派发。

src/mastra/agents/researcher.ts
import { Agent } from '@mastra/core/agent'

export const researcher = new Agent({
id: 'researcher',
instructions: 'You research topics and answer questions.',
model: 'openai/gpt-5.6-sol',
tools: { researchTool, summarizeTool },
backgroundTasks: {
tools: {
researchTool: { enabled: true, timeoutMs: 600_000 },
summarizeTool: false,
},
},
})

设置 tools: 'all' 可让 agent 拥有的每个工具都选择加入。

LLM 按调用覆盖
LLM 按调用覆盖的直接链接

当工具注册在启用了后台任务的 agent 上时,模型可以在工具参数中包含 _background 字段,以覆盖该特定调用的已解析配置。模型只需包含它想要覆盖的内容,_background 中的所有字段都是可选的。覆盖内容会在工具运行前从参数中移除。

{
"topic": "solana",
"_background": { "disposition": "awaited", "timeoutMs": 900000 }
}

可用的处置方式:

  • foreground:同步运行工具,不产生后台工作生命周期 signals。
  • deferred:派发工具并让 agent 继续。任务仍依附于该运行,使用 untilIdle 的流会等待其协调完成。
  • awaited:通过后台任务管理器派发工具,但暂缓当前分支,直到其权威结果被协调。

为兼容性,_background.enabled: true 选择 deferred,_background.enabled: false 选择 foreground。显式的 disposition 优先于 enabled。

_background 覆盖只会修改开发者已在工具或 agent 层级选择加入的工具。如果工具未选择加入,模型选择的后台处置会被忽略,工具会在前台运行。这可防止确定性的、仅供前台使用的工具(计算器、查询、schema 验证器)被悄悄派发为任务。

解析顺序
解析顺序的直接链接

工具调用被派发时,agent 级和工具级设置决定资格及回退值。对于符合条件的工具,LLM 的 _background 字段会覆盖该调用的相应值。管理器默认值填充仍未设置的超时和重试值。_background 字段无法启用不符合条件的工具。

如果 agent 设置了 backgroundTasks.disabled: true,无论上述层级如何,每个工具调用都会同步运行。

后台任务相关的流 chunk
后台任务相关的流 chunk的直接链接

当工具调用作为后台任务派发时,可能会有两个流为其展示生命周期事件:agent 自身的流和 backgroundTaskManager.stream() SSE 流。每个流涵盖不同的 chunk 类型集合:

Chunk 类型触发时机发出方
background-task-started任务已入队并分配了 taskId。Agent 流
background-task-running任务获取 worker 并开始执行。管理器流
background-task-progress显示正在运行的后台任务数量。Agent 流
background-task-output任务 execute 的流式输出 chunk。管理器流
background-task-completed任务成功完成。payload.result 与最终的工具结果一致。管理器流
background-task-failed任务抛出异常或超时。管理器流
background-task-cancelled任务在完成前被取消。管理器流
background-task-suspended工具在其 execute 内调用了 suspend()。管理器流
background-task-resumed挂起的任务通过 manager.resume(taskId, resumeData) 恢复。管理器流

agent.stream().fullStream 自身只发出 agent 循环 chunk(background-task-started、background-task-progress)。带 untilIdle: true 的 agent.stream() 会发出同样的两个 chunk,并额外订阅该运行 memory 作用域的管理器 pubsub,将七个管理器 chunk(background-task-running、background-task-output、background-task-completed、background-task-failed、background-task-cancelled、background-task-suspended、background-task-resumed)注入同一个 fullStream。

backgroundTaskManager.stream() 只发出七个管理器 chunk。

完整的 payload 结构记录在后台任务 chunk 参考。

使用 untilIdle 保持 agent 流打开
使用-untilidle-保持-agent-流打开的直接链接

即使后台任务仍在运行,agent.stream() 也会在 LLM 发出最终响应后返回。当你希望流保持打开,直到所有已派发的后台任务完成且 LLM 有机会对结果作出响应时,请传入 untilIdle: true:

src/mastra/run.ts
const stream = await agent.stream('Research solana for me', {
memory: { thread: 't1', resource: 'u1' },
untilIdle: true,
})

for await (const chunk of stream.fullStream) {
// chunks from the initial turn AND any continuation turns triggered by
// background task completions flow through here
}

后台任务完成时,结果会注入 agent memory,stream() 会重新进入 agentic 循环,让 LLM 对其作出反应。当没有任务运行且没有排队的完成事件时,流关闭。

传入对象而不是 true 可自定义空闲超时。计时器仅在包装器处于轮次之间时运行,因此缓慢的首个 token 不会关闭流。默认值为 5 分钟:

const stream = await agent.stream('Research solana for me', {
memory: { thread: 't1', resource: 'u1' },
untilIdle: { maxIdleMs: 30_000 },
})

完整 API 请参阅 Agent.stream()。

聚合属性
聚合属性的直接链接

带 untilIdle 的 stream() 返回的 MastraModelOutput 看起来与常规 stream() 调用的输出相同,但 fullStream 自身跨越初始轮次和任何自动延续。聚合属性(text、toolCalls、toolResults、finishReason、messageList、getFullOutput())仍针对第一轮的内部缓冲区解析。如果你需要跨延续的聚合视图,请自行消费 fullStream 并累积。

后台中的 Subagents
后台中的 Subagents的直接链接

Subagent 调用在底层作为工具调用派发,因此同样的后台配置适用。推荐模式是在 supervisor 上让每个 subagent 选择加入,这样更清晰,也能在一个地方为每个 subagent 调整 timeoutMs:

src/mastra/agents/supervisor.ts
import { Agent } from '@mastra/core/agent'

const supervisor = new Agent({
id: 'supervisor',
instructions: 'Coordinate research and writing using the available agents.',
model: 'openai/gpt-5.6-sol',
agents: { researchAgent, writingAgent },
backgroundTasks: {
tools: {
researchAgent: { enabled: true, timeoutMs: 900_000 },
writingAgent: { enabled: true, timeoutMs: 900_000 },
},
},
})

const stream = await supervisor.stream('Research AI in education and write an article', {
memory: { thread: 't1', resource: 'u1' },
untilIdle: true,
})

从 subagent 继承
从 subagent 继承的直接链接

如果 subagent 未列在 supervisor 的 backgroundTasks.tools 下,但它自身有具备后台资格的工具(通过工具级 background.enabled: true 或其自己的 backgroundTasks.tools 条目),框架仍会将整个 subagent 调用作为后台任务派发。supervisor 继承 subagent 的意图:subagent 本身成为后台任务,并且可以在其循环内将符合条件的普通工具派发到后台。进一步的委托 agent 调用在前台运行。

用于继承派发的后台配置(例如 waitTimeoutMs)来自 subagent 自己的 backgroundTasks 配置。

src/mastra/agents/researcher.ts
const researchAgent = new Agent({
id: 'research-agent',
description: 'Gathers factual information.',
model: 'openai/gpt-5-mini',
tools: { deepResearchTool },
backgroundTasks: {
tools: {
deepResearchTool: { enabled: true, timeoutMs: 600_000 },
},
waitTimeoutMs: 900_000,
},
})

当从没有为 researchAgent 配置后台任务的 supervisor 委托到该 researchAgent 时,supervisor 仍会将整个 researchAgent 调用作为后台任务派发。

Mastra 支持委托运行内的一层嵌套后台工具:根 agent 可以委托给 subagent,该 subagent 可以在后台派发符合条件的普通工具。第二条委托 agent 边会在前台运行,且不会接收嵌套后台指导。此限制是执行作用域的,不会修改共享的 subagent 配置。

使用哪一层取决于一致性在哪里重要:subagent 级配置随 agent 一起移动,使它在任何 supervisor 下都保持相同的后台行为;而上面的 supervisor 侧选择加入则将这种调整集中在一个地方。该边界止于单层嵌套委托,且没有 workflow 集成。

挂起与恢复
挂起与恢复的直接链接

后台任务可以在执行中途暂停自身,等待外部 signal 后再继续。这适用于人工审批、webhooks,或下一步依赖稍后到达数据的任何流程。

工具在其 execute 内调用 suspend(data),这会:

  • 在任务记录上持久化 status: 'suspended' 和 data payload。
  • 保存 workflow 快照,使运行能在进程重启后保留。
  • 在管理器流上发出 background-task-suspended chunk。
  • 释放并发槽位,以便其他任务可以运行。

使用 mastra.backgroundTaskManager.resume(taskId, resumeData) 恢复任务。resumeData 会在恢复运行的工具有 execute 选项中到达,任务转回 running。

src/mastra/tools/approval.ts
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'

export const reviewTool = createTool({
id: 'review',
description: 'Submit a draft for human review.',
inputSchema: z.object({ draft: z.string() }),
outputSchema: z.object({ approvedBy: z.string(), edits: z.string().optional() }),
background: { enabled: true },
execute: async ({ draft }, context) => {
const { suspend, resumeData } = context.agent
if (!resumeData) {
await suspend?.({ awaiting: 'approval', draft })
return { approvedBy: '', edits: undefined }
}
const { reviewer, edits } = resumeData as { reviewer: string; edits?: string }
return { approvedBy: reviewer, edits }
},
})

execute 的第一次调用看到 resumeData === undefined 并调用 suspend。任务恢复后,运行时以填充了 resumeData 的方式重新启动工具。if 条件为 false。工具返回其真实结果。

要在审批到达后恢复任务:

src/server/approvals.ts
await mastra.backgroundTaskManager?.resume(taskId, {
reviewer: 'alice@example.com',
edits: 'Reworded paragraph 3.',
})

agent 循环会发生什么
agent 循环会发生什么的直接链接

当任务在带 untilIdle 的 stream() 中途挂起时,包装器将其视为当前迭代的终止并关闭。一旦恢复 payload 可用,请调用 agent.resumeStream(resumeData, { runId, toolCallId, memory, untilIdle: true }) 立即继续。恢复的后台任务会完成,并在 agent 于同一 SSE 连接上运行后续轮次之前将其结果加入消息列表。若要在带外驱动恢复,请直接调用 mastra.backgroundTaskManager.resume(taskId, resumeData)。其结果仍会写入 thread,供下一用户轮次使用。

恢复时重新注册执行器
恢复时重新注册执行器的直接链接

管理器将工具执行器保存在进程内存中。如果任务挂起期间进程重启,执行器闭包已不存在,resume() 的调用方必须先通过 manager.registerTaskContext(taskId, ...) 重新注册它。在同一进程内派发和恢复的任务不需要这样做。

取消挂起的任务
取消挂起的任务的直接链接

manager.cancel(taskId) 对挂起任务的作用与对运行中任务相同。行会变为 cancelled,workflow 快照会被清理。随后触发 task.cancelled 事件。

生命周期回调
生命周期回调的直接链接

每一层都可以注册终态回调。它们不会互相替换,成功/失败钩子会针对各自的结果触发:

  • 工具级 background.onComplete / onFailed:作用域为单个工具。
  • Agent 级 backgroundTasks.onTaskComplete / onTaskFailed:作用域为该 agent 派发的所有任务。
  • 管理器级 onTaskComplete / onTaskFailed:全局作用域。
src/mastra/index.ts
export const mastra = new Mastra({
storage,
backgroundTasks: {
enabled: true,
onTaskComplete: task => {
logger.info('Background task complete', { taskId: task.id, toolName: task.toolName })
},
onTaskFailed: task => {
logger.error('Background task failed', { taskId: task.id, error: task.error })
},
},
})

流式传输
流式传输的直接链接

订阅所有任务事件
订阅所有任务事件的直接链接

传入 allResources: true 可接收系统中跨所有资源的每个任务事件。连接时,流会发出所有正在运行任务的快照,然后转发实时事件。

src/mastra/run.ts
const bgManager = mastra.backgroundTaskManager;
if (!bgManager) throw new Error('Background tasks are not enabled');

const controller = new AbortController();
const stream = bgManager.stream({ allResources: true, abortSignal: controller.signal });

for await (const chunk of stream) {
switch (chunk.type) {
case 'background-task-running':
console.log('started', chunk.payload.taskId, chunk.payload.toolName);
break;
case 'background-task-completed':
console.log('done', chunk.payload.taskId, chunk.payload.result);
break;
case 'background-task-failed':
console.error('failed', chunk.payload.taskId, chunk.payload.error);
break;
}
}

流会保持打开,直到调用方的 AbortSignal 触发。请始终传入 abortSignal,以便干净地断开连接。

注意

allResources: true 会投递每个用户的任务参数和结果。仅在可信的服务器端代码中使用,切勿用于服务单个用户的请求。如果既没有 resourceId 也没有 allResources,stream() 只会投递没有 resourceId 的任务。带 memory 派发的 agent 任务始终有 resourceId,因此不会出现在该流中。

过滤流
过滤流的直接链接

传入任意组合的过滤选项来收窄接收的事件。过滤器同时应用于初始快照和实时事件订阅。

const stream = bgManager.stream({
agentId: 'researcher',
threadId: 't1',
resourceId: 'u1',
abortSignal: controller.signal,
})
过滤器描述
agentId仅来自该 agent 派发的任务的事件
runId仅来自该特定 agent 运行的事件
threadId仅来自作用域为该 memory thread 的任务的事件
resourceId仅来自作用域为该资源的任务的事件
taskId仅单个任务的事件
allResources省略 resourceId 时包含来自所有资源的任务。仅限可信服务器端代码
abortSignal信号中止时关闭流

直接查询任务状态
直接查询任务状态的直接链接

若只需一次性查询而不是实时流,请使用 getTask 和 listTasks:

const task = await mastra.backgroundTaskManager?.getTask(taskId)
const { tasks, total } = await mastra.backgroundTaskManager?.listTasks({
status: 'running',
agentId: 'researcher',
})

这些方法从存储而不是 pubsub 流读取,因此适用于分页列表和详情视图。

相关内容
相关内容的直接链接