Skip to content

Chapter 7 · Workflow Basics and .then() ​

Chapter goals: Understand the division of labor between Workflow and Agent, master createStep / createWorkflow / .then() to build serial pipelines.

7.1 Agent vs Workflow: When to Use Which ​

AgentWorkflow
Execution pathModel decides autonomously, unpredictableExplicitly defined, deterministic graph structure
Suitable tasksOpen-ended questions ("help me write a plan")Deterministic flows ("scrape → clean → store")
ReliabilityDepends on prompts and model capabilityStep schemas provide strong constraints, predictable results
DebuggingView the full Trace reasoning processGraphical view of each step's input/output

Rule of thumb: use Workflow for predictable paths, embed Agents only where model judgment is needed. The two are often used in combination.

7.2 createStep: Defining Steps ​

Steps are the building blocks of a Workflow. Each step declares input/output schemas with Zod, forming a type-safe pipeline interface:

typescript
// src/mastra/workflows/article-workflow.ts
import { createStep } from '@mastra/core/workflows';
import { z } from 'zod';

// Step 1: receive topic, produce an outline
const outlineStep = createStep({
  id: 'outline',
  inputSchema: z.object({
    topic: z.string().describe('Article topic'),
  }),
  outputSchema: z.object({
    outline: z.string(),
    topic: z.string(), // passthrough to downstream
  }),
  // execute's inputData type is auto-derived from inputSchema
  execute: async ({ inputData }) => {
    const { topic } = inputData;
    // In production, call an LLM, API, or any function here
    return {
      outline: `Three-part outline for "${topic}": Background → Analysis → Conclusion`,
      topic,
    };
  },
});

7.3 createWorkflow + .then(): Chaining Execution ​

typescript
// Same file: step 2 consumes upstream output
const draftStep = createStep({
  id: 'draft',
  inputSchema: z.object({
    outline: z.string(),
    topic: z.string(),
  }),
  outputSchema: z.object({
    article: z.string(),
  }),
  execute: async ({ inputData }) => ({
    article: `《${inputData.topic}》\n\nBased on the outline, draft the body: ${inputData.outline}`,
  }),
});

// Assemble the workflow: declare overall input/output → link steps → commit
export const articleWorkflow = createWorkflow({
  id: 'article-workflow',
  inputSchema: z.object({ topic: z.string() }),
  outputSchema: z.object({ article: z.string() }),
})
  .then(outlineStep) // Run outlineStep first
  .then(draftStep)   // Its output auto-becomes the next step's input
  .commit();         // Must call — locks the flow definition

Key mechanism: .then() passes the previous step's outputSchema as the next step's validated input — if the two steps' schemas don't match, it errors at assembly time. This is the value of "schema as contract."

7.4 Registration and Triggering ​

typescript
// src/mastra/index.ts —— register the workflow
import { Mastra } from '@mastra/core';
import { articleWorkflow } from './workflows/article-workflow';

export const mastra = new Mastra({
  workflows: { articleWorkflow },
});
typescript
// Trigger method 1: create a run instance directly in code
const run = await mastra.getWorkflow('articleWorkflow').createRun();
const result = await run.start({ inputData: { topic: 'Large Language Models' } });
console.log(result.results); // Each step's output

You can also manually fill trigger parameters in Studio's Workflows tab and observe each step's flow graphically.

7.5 Chapter Summary ​

  • Open-ended tasks go to Agents; deterministic flows go to Workflows; complex systems combine both;
  • createStep uses Zod to bidirectionally declare input/output; execute only writes business logic;
  • .then() chains serially and auto-checks schema compatibility; .commit() locks the flow;
  • Workflows also need to be registered on the Mastra instance; supports both code createRun and Studio manual trigger.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. Which type of task is best suited for Workflow over Agent?

2. When linking steps with .then(), how does the framework ensure step compatibility?

3. After defining a createWorkflow, which method must be called last?

4. How does a workflow step's execute function correctly access upstream data?

🛠️ Hands-On Exercises ​

  1. Add a third step reviewStep to articleWorkflow: takes the draft as input, outputs a scored structure.
  2. Intentionally mismatch draftStep's outputSchema with reviewStep's inputSchema fields; observe the assembly-time error message.
  3. Open your workflow in Studio; screenshot the Graph view and compare it against the .then() order in code.

Next: Chapter 8 · Branching and Parallel Execution