Agent.network()
Agent.network()
introduces a flexible, composable and non-deterministic way to orchestrate multiple specialized agents and workflows, enabling complex, reasoning and task completion.
There are two main problem areas that this system is designed to solve:
- Scenarios where a single agent is insufficient, and tasks require collaboration, routing, or sequential/parallel execution across multiple agents and workflows.
- Scenarios where the task is not fully defined and is initiated with unstructured input. A network allows your Agent to figure out which primitive to call and turn unstructured input into a structured task.
Differences from Workflows
- Workflows are linear or branched sequences of steps. This creates a deterministic flow of execution.
Agent.network()
adds a layer of non-deterministic LLM-based orchestration, allowing dynamic, multi-agent collaboration and routing. This creates a non-deterministic flow of execution.
Important details
- Providing memory to the Agent when using
network()
is not optional, as it is required to store the task history. Memory is the core primitive used for any decisions on which primitives to run, as well as determine task completion. - Any available primitives (agents, workflows) are used based on their descriptions. The better the description, the better the routing agent will be able to select the right primitive. For workflows, the input schema is also used to determine which inputs to use when calling the workflow. More descriptive naming yields better results.
- When primitives with overlapping capabilities are available, the agent will use the most specific primitive. For example, if both an agent and a workflow can do research, it will use the input schema of the workflow to determine which primitive to select.
Turning an Agent into a Network
As an example, we have an Agent with 3 primitives at its disposal:
agent1
: A general research agent that can do research on a given topic.agent2
: A general writing agent that can write a full report based on the researched material.workflow1
: A workflow that can research a given city and write a full report based on the researched material (using both agent1 and agent2).
We use the network
method to create a task that requires multiple primitives. The Agent will, using memory, figure out which primitives to call and in which order, as well as when the task is complete.
import { Agent } from '@mastra/core/agent';
import { createStep, createWorkflow } from '@mastra/core/workflows';
import { RuntimeContext } from '@mastra/core/runtime-context';
import { Memory } from '@mastra/memory';
import { openai } from '@ai-sdk/openai';
import { LibSQLStore } from '@mastra/libsql';
import { z } from 'zod';
const memory = new Memory({
storage: new LibSQLStore({
url: 'file:../mastra.db', // Or your database URL
}),
});
const agentStep1 = createStep({
id: 'agent-step',
description: 'This step is used to do research and text synthesis.',
inputSchema: z.object({
city: z.string().describe('The city to research'),
}),
outputSchema: z.object({
text: z.string(),
}),
execute: async ({ inputData }) => {
const resp = await agent1.generate(inputData.city, {
output: z.object({
text: z.string(),
}),
});
return { text: resp.object.text };
},
});
const agentStep2 = createStep({
id: 'agent-step-two',
description: 'This step is used to do research and text synthesis.',
inputSchema: z.object({
text: z.string().describe('The city to research'),
}),
outputSchema: z.object({
text: z.string(),
}),
execute: async ({ inputData }) => {
const resp = await agent2.generate(inputData.text, {
output: z.object({
text: z.string(),
}),
});
return { text: resp.object.text };
},
});
const workflow1 = createWorkflow({
id: 'workflow1',
description:
'This workflow is perfect for researching a specific city. It should be used when you have a city in mind to research.',
steps: [],
inputSchema: z.object({
city: z.string(),
}),
outputSchema: z.object({
text: z.string(),
}),
})
.then(agentStep1)
.then(agentStep2)
.commit();
const agent1 = new Agent({
name: 'agent1',
instructions:
'This agent is used to do research, but not create full responses. Answer in bullet points only and be concise.',
description:
'This agent is used to do research, but not create full responses. Answer in bullet points only and be concise.',
model: openai('gpt-4o'),
});
const agent2 = new Agent({
name: 'agent2',
description:
'This agent is used to do text synthesis on researched material. Write a full report based on the researched material. Writes reports in full paragraphs. Should be used to synthesize text from different sources together as a final report.',
instructions:
'This agent is used to do text synthesis on researched material. Write a full report based on the researched material. Do not use bullet points. Write full paragraphs. There should not be a single bullet point in the final report.',
model: openai('gpt-4o'),
});
const routingAgent = new Agent({
id: 'test-network',
name: 'Test Network',
instructions:
'You are a network of writers and researchers. The user will ask you to research a topic. You always need to answer with a full report. Bullet points are NOT a full report. WRITE FULL PARAGRAPHS like this is a blog post or something similar. You should not rely on partial information.',
model: openai('gpt-4o'),
agents: {
agent1,
agent2,
},
workflows: {
workflow1,
},
memory: memory,
});
const runtimeContext = new RuntimeContext();
console.log(
// specifying the task, note that there is a mention here about using an agent for synthesis. This is because the routing agent can actually do some synthesis on results on its own, so this will force it to use agent2 instead
await routingAgent.network(
'What are the biggest cities in France? Give me 3. How are they like? Find cities, then do thorough research on each city, and give me a final full report synthesizing all that information. Make sure to use an agent for synthesis.',
{ runtimeContext },
),
);
For the given task (research 3 biggest cities in France and write a full report), the AgentNetwork will call the following primitives:
agent1
to find the 3 biggest cities in France.workflow1
to research each city one by one. The workflow usesmemory
to figure out which cities have already been researched and makes sure it has researched all of them before proceeding.agent2
to synthesize the final report.
How It Works
- The underlying engine is a Mastra workflow that wraps the single call
generate
workflow. - The workflow will repeatedly call the network execution workflow with a
dountil
structure, until the routing model determines the task is complete. This check is used as thedountil
condition.