Human-in-the-loop
有些 workflows 需要在继续之前暂停,等待人工输入。当 workflow 被挂起时,它可以返回一条消息,说明为什么暂停以及继续需要什么。随后 workflow 可以根据收到的输入选择恢复或中止(bail)。这种方式适用于人工审批、拒绝、带门禁的决策,或任何需要人工监督的步骤。
暂停 workflow 以等待人工输入暂停 workflow 以等待人工输入的直接链接
Human-in-the-loop(HITL)输入的工作方式与使用 suspend() 暂停 workflow非常相似。关键区别在于,当需要人工输入时,你可以让 suspend() 返回一个 payload,为用户提供如何继续的上下文或指引。
src/mastra/workflows/test-workflow.ts
import { createWorkflow, createStep } from '@mastra/core/workflows'
import { z } from 'zod'
const step1 = createStep({
id: 'step-1',
inputSchema: z.object({
userEmail: z.string(),
}),
outputSchema: z.object({
output: z.string(),
}),
resumeSchema: z.object({
approved: z.boolean(),
}),
suspendSchema: z.object({
reason: z.string(),
}),
execute: async ({ inputData, resumeData, suspend }) => {
const { userEmail } = inputData
const { approved } = resumeData ?? {}
if (!approved) {
return await suspend({
reason: 'Human approval required.',
})
}
return {
output: `Email sent to ${userEmail}`,
}
},
})
export const testWorkflow = createWorkflow({
id: 'test-workflow',
inputSchema: z.object({
userEmail: z.string(),
}),
outputSchema: z.object({
output: z.string(),
}),
})
.then(step1)
.commit()
提供用户反馈提供用户反馈的直接链接
当 workflow 被挂起时,你可以通过识别被挂起的步骤并读取其 suspendPayload,访问 suspend() 返回的 payload。
src/test-workflow.ts
const workflow = mastra.getWorkflow('testWorkflow')
const run = await workflow.createRun()
const result = await run.start({
inputData: {
userEmail: 'alex@example.com',
},
})
if (result.status === 'suspended') {
const suspendStep = result.suspended[0]
const suspendedPayload = result.steps[suspendStep[0]].suspendPayload
console.log(suspendedPayload)
}
示例输出示例输出的直接链接
步骤返回的数据可以包含原因,帮助用户了解恢复 workflow 需要什么。
{
reason: 'Confirm to send email.'
}
使用人工输入恢复 workflows使用人工输入恢复 workflows的直接链接
与重启 workflow一样,在收到人工输入后,使用带有 resumeData 的 resume() 继续 workflow。Workflow 会从暂停的步骤恢复。
const workflow = mastra.getWorkflow('testWorkflow')
const run = await workflow.createRun()
await run.start({
inputData: {
userEmail: 'alex@example.com',
},
})
const handleResume = async () => {
const result = await run.resume({
step: 'step-1',
resumeData: { approved: true },
})
}
使用 bail() 处理人工拒绝使用-bail-处理人工拒绝的直接链接
使用 bail() 在步骤处停止 workflow 执行,而不触发错误。当人工明确拒绝某个操作时,这很有用。Workflow 会以 success 状态完成,并跳过调用 bail() 之后的任何逻辑。
const step1 = createStep({
execute: async ({ inputData, resumeData, suspend, bail }) => {
const { userEmail } = inputData
const { approved } = resumeData ?? {}
if (approved === false) {
return bail({
reason: 'User rejected the request.',
})
}
if (!approved) {
return await suspend({
reason: 'Human approval required.',
})
}
return {
message: `Email sent to ${userEmail}`,
}
},
})
多轮人工输入多轮人工输入的直接链接
对于需要在多个阶段获取输入的 workflows,挂起模式保持不变。每个步骤定义一个 resumeSchema,以及通常带有原因的 suspendSchema,用于向用户提供反馈。
src/mastra/workflows/test-workflow.ts
const step1 = createStep({...});
const step2 = createStep({
id: "step-2",
inputSchema: z.object({
message: z.string()
}),
outputSchema: z.object({
output: z.string()
}),
resumeSchema: z.object({
approved: z.boolean()
}),
suspendSchema: z.object({
reason: z.string()
}),
execute: async ({ inputData, resumeData, suspend }) => {
const { message } = inputData;
const { approved } = resumeData ?? {};
if (!approved) {
return await suspend({
reason: "Human approval required."
});
}
return {
output: `${message} - Deleted`
};
}
});
export const testWorkflow = createWorkflow({
id: "test-workflow",
inputSchema: z.object({
userEmail: z.string()
}),
outputSchema: z.object({
output: z.string()
})
})
.then(step1)
.then(step2)
.commit();
每个步骤必须按顺序恢复,每个被挂起的步骤都需要单独调用一次 resume()。这种方式有助于管理多步骤审批,并在每个阶段提供一致的 UI 反馈和清晰的输入处理。
const handleResume = async () => {
const result = await run.resume({
step: 'step-1',
resumeData: { approved: true },
})
}
const handleDelete = async () => {
const result = await run.resume({
step: 'step-2',
resumeData: { approved: true },
})
}