Welcome back! In the previous lesson, you learned how to create a simple Mastra workflow that could truncate a string. That was a great first step. However, in real-world applications, you often need to do more than one thing with your data. For example, you might want to both truncate a string and store it in a database, or summarize an email and determine what the email is about (its intent).
Chaining multiple agents in a workflow allows you to perform several tasks in sequence, all within a single workflow. This makes your smart email assistant more powerful and efficient. In this lesson, you will learn how to chain two agents together: one to classify the intent of the email, and another to summarize the email using that intent.
Before we dive in, let’s quickly remind ourselves of some key concepts from the last lesson:
- Workflow: This is the main structure that defines how your data moves and is processed.
- Step: Each workflow is made up of steps. Each step does a specific job, like summarizing text.
- Agent: An agent is a tool or model that performs a specific task, such as generating a summary or classifying intent.
In the last lesson, you created a workflow with a single step and a single agent. Now, you’ll see how to add more steps and agents to handle more complex tasks.
In this lesson, we'll be using two agents that have already been defined and registered with Mastra: IntentAgent and SummaryAgent. Let's briefly understand what these agents do:
IntentAgent:
- Classifies the intent of an email (e.g., "question", "complaint", "request", "feedback")
- Takes the email content as input and returns a classification
SummaryAgent:
- Generates a concise summary of the email content
- Can incorporate additional context (like the intent) to produce better summaries
Both agents are instances of Mastra's Agent class, configured with specific instructions and connected to an AI model (like OpenAI's GPT). When you call mastra.getAgent("IntentAgent") or mastra.getAgent("SummaryAgent"), you're retrieving these pre-configured agents that have been registered with your Mastra instance.
Let’s start by setting up a workflow that can handle both summarizing and intent classification. The first thing you need to do is define what kind of data your workflow will take in and what it will produce as output.
Here’s how you define the input and output schemas for this workflow:
Explanation:
inputSchemaexpects an object with a single field:emailContent, which is a string containing the email text.outputSchemadefines that the workflow will return an object with three fields:summary(the email summary),intent(the classified intent), anddraftReply(a suggested reply).
By setting up these schemas, you ensure your workflow knows what to expect and what to produce.
Now, let’s add the steps that will process the email. Each step will use an agent to perform its task. In this approach, you define each step separately using createStep, specifying their input and output schemas.
Explanation:
- This step is called
classify-intent. - It takes the
emailContentfrom the input data. - It uses the
IntentAgentto classify the intent of the email. - It returns both the original
emailContentand theintent, so the next step can use both.
Explanation:
- This step is called
summarize-email. - It takes both the
emailContentand theintentfrom the previous step. - It uses the
SummaryAgentto generate a summary, including the intent in the prompt for better context. - It returns the
summaryand theintent. - Note that this step's output doesn't include
draftReply. Since the workflow'soutputSchemamarksdraftReplyas.optional(), it's okay for a step to not provide it. The.optional()modifier tells Mastra that this field may or may not be present in the final output.
When chaining steps in a workflow, it’s important to ensure that the output of each step matches the input expected by the next step. This is how data flows smoothly from one step to the next.
- The input to the first step must match the workflow’s
inputSchema. - The output of each step n must match the input of step n+1.
- The output of the last step must match the workflow’s
outputSchema.
If the output and input schemas do not match between steps, the workflow will not work as expected. This design enforces a clear contract between steps and helps catch errors early.
For example, in the workflow above:
- The first step (
classify-intent) outputs{ emailContent, intent }, which matches the input expected by the second step (summarize-email). - The second step outputs
{ summary, intent }, which should match the next step’s input if there is one, or the workflow’soutputSchemaif it’s the last step.
Now, you can chain these steps together using the .then() method, and finalize the workflow with .commit():
Explanation:
.then(classifyIntentStep)adds the intent classification step first..then(summarizeEmailStep)adds the summarization step, which uses the output of the previous step..commit()finalizes the workflow definition.
Remember: the output of classifyIntentStep must match the input of summarizeEmailStep, and the output of the final step must match the workflow’s outputSchema.
You may have noticed that the execute function for each step receives a mastra parameter:
How is mastra provided?
- The
mastraparameter is automatically injected by the Mastra workflow engine when your workflow runs. - The instance of
mastrathat is passed to each step is the same instance that was used to start or invoke the workflow. This means any configuration, agent registration, or state on the caller’smastrainstance is available inside your step. - You do not need to manually pass or manage the
mastrainstance in your workflow or step definitions. The framework handles this for you, ensuring that your steps always have access to the correct context and registered agents.
Why is this useful?
- This makes it easy to access agents and other resources that are registered on the caller’s
mastrainstance. - It ensures consistency and avoids bugs that could happen if different steps used different agent registries or configurations.
Example:
If you run your workflow like this:
Then, inside each step’s execute function, and will refer to the agents registered on the same instance that was used to start the workflow run.
Let’s look more closely at how each agent is connected to its step:
- In the
classify-intentstep, you usemastra.getAgent("IntentAgent")to get the intent classification agent, and call itsgenerate()method with the email content. - In the
summarize-emailstep, you usemastra.getAgent("SummaryAgent")to get the summarization agent, and call itsgenerate()method with a prompt that includes both the email content and the intent.
This approach makes it easy to swap out agents or add new steps as your workflow grows.
In this lesson, you learned how to chain multiple agents in a single Mastra workflow using the createWorkflow and createStep approach. You saw how to:
- Define a workflow that takes in email content and produces both a summary and an intent.
- Create and chain steps so that each agent performs its task in order, passing data from one step to the next.
- Ensure that the output of each step matches the input of the next, with the workflow’s input and output schemas defining the boundaries.
- Connect the right agent to each step and combine their outputs.
- Use the automatically injected
mastraparameter to access agents and resources from the caller’s context.
This approach allows your smart email assistant to handle more complex tasks, making it much more useful in real-world scenarios.
Next, you’ll get a chance to practice building and running your own multi-agent workflows. This will help you reinforce what you’ve learned and prepare you for even more advanced workflows in the future. Good luck!
