M
Mastra•2w ago
radek_sz

I am building e-commerce AI Assistant. Is .network a good choice?

Background: I am building e-commerce AI Assistant. It will use the API of the e-commerce system through the tools. The Assistant can do different things - fetches orders, products, manages promotions etc. Plan: My plan is to create many AI Agents which will handle different areas (order, products etc.) with one supervisor and use the .network. My idea is that user will send the request and supervisor will properly route it to the agent. However, I am facing couple of problems: 1) I want to format the output from every agent to one format for UI. I am asking supervisor agent to route all messages to Formatting Agent but he is not doing it. Is it ok to expect that .network will work in that way? 2) Some requests from user might expect calling couple of APIs ("Get me all products with at least 1 order). Is it something what supervisor can do? It will route firstly to one agent, then to another? Right now I am facing the issue that supervisor returns me only the statement that job is done (for one agent). Is it possible that supervisor will summarize me the job and return the summarized result? TLDR: How exactly .network works? Can supervisor call different agents and summarzize the response? Or he can only call one agent (just choosing)? Can I somehow include result from agents/agent in summary which will supervisor do? How to architecture it?
9 Replies
Edgar
Edgar•2w ago
Hey @radek_sz , if you use agent network, then the task orchestration is fundamentally non-deterministic. I am not sure about your usecase, as ecommerce can require both deterministic and non-deterministic approaches, but I would first start exploring a deterministic one, because you are aware of the usecases and actions. Check out the supervisor pattern here: https://mastra.ai/examples/agents/supervisor-agent In order to enforce input/output format you can set input and output schemas to the tools themselves through which you would call the agents. Example here:
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
import { RuntimeContext } from "@mastra/core/runtime-context";

export const contentEditorTool = createTool({
id: "edit-content",
description: "Calls the content editor agent to adjust the body according to the rules.",
inputSchema: z.object({
title: z.any(),
body: z.string()
}),
outputSchema: z.object({
pass: z.boolean(),
summary: z.string(),
requiredChanges: z.array(z.string())
}),
execute: async ({ context, mastra }) => {
const { title, body } = context;

const agent = mastra!.getAgent("contentEditorAgent");

const runtimeContext = new RuntimeContext<EditorAgentRuntimeContext>();
runtimeContext.set("draft", body);
runtimeContext.set("title", title.toLowerCase());

const result = await agent!.generate(
`Execute according to the given title and body.`,
{
runtimeContext,
structuredOutput: {
schema: z.object({
pass: z.boolean(),
summary: z.string(),
requiredChanges: z.array(z.string())
})
},
modelSettings: {
topP: 0.2,
temperature: 0.1
}
},
);

return {
pass: result.object.pass,
summary: result.object.summary,
requiredChanges: result.object.requiredChanges
};
},
});
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
import { RuntimeContext } from "@mastra/core/runtime-context";

export const contentEditorTool = createTool({
id: "edit-content",
description: "Calls the content editor agent to adjust the body according to the rules.",
inputSchema: z.object({
title: z.any(),
body: z.string()
}),
outputSchema: z.object({
pass: z.boolean(),
summary: z.string(),
requiredChanges: z.array(z.string())
}),
execute: async ({ context, mastra }) => {
const { title, body } = context;

const agent = mastra!.getAgent("contentEditorAgent");

const runtimeContext = new RuntimeContext<EditorAgentRuntimeContext>();
runtimeContext.set("draft", body);
runtimeContext.set("title", title.toLowerCase());

const result = await agent!.generate(
`Execute according to the given title and body.`,
{
runtimeContext,
structuredOutput: {
schema: z.object({
pass: z.boolean(),
summary: z.string(),
requiredChanges: z.array(z.string())
})
},
modelSettings: {
topP: 0.2,
temperature: 0.1
}
},
);

return {
pass: result.object.pass,
summary: result.object.summary,
requiredChanges: result.object.requiredChanges
};
},
});
Example: Supervisor Agent | Agents | Mastra Docs
Example of creating a supervisor agent using Mastra, where agents interact through tool functions.
Edgar
Edgar•2w ago
Regarding you second question, you can ask supervisor agent to chain tools or call them according to the certain conditions. Sample prompt:
You are a publisher agent that first calls the copywriter agent via copywriterTool, then calls editor agent via contentEditorTool. If contentEditorTool returns pass == true - stop and return the original JSON, else - call contentReviserTool.
- Always ask for body and title. Do not continue without these parameters.
- Return raw JSON without changes.".
You are a publisher agent that first calls the copywriter agent via copywriterTool, then calls editor agent via contentEditorTool. If contentEditorTool returns pass == true - stop and return the original JSON, else - call contentReviserTool.
- Always ask for body and title. Do not continue without these parameters.
- Return raw JSON without changes.".
in your case you might describe the tools (fetch order, manage promotions) instead and it should work.
radek_sz
radek_szOP•2w ago
thank you @Edgar ! I did not know that I can use .generate function and still have many agents talking to each other - that's good news! According to your description - does it mean that architecture would look like this:
radek_sz
radek_szOP•2w ago
No description
radek_sz
radek_szOP•2w ago
I am thinking also about this:
No description
radek_sz
radek_szOP•2w ago
so what is a real difference between .network and .generate in such architecture? I mean in both cases SupervisorAgent decides where to route, right?
Edgar
Edgar•2w ago
You can call agents in Mastra using supervisor pattern in the way you have described in the screenshot number 1, there is always a tool layer between supervisor agent and the other agents (unless the network case). In the scenario I have described YOU provide decision guidelines where to route - you can specify the guidelines loosely enough so the supervisor still can decide if needed on what to call - so it can be both deterministic and non-deterministic. In the network scenario supervisor decides where to route instead, this is why this is always non-deterministic in the classical sense. I would say according to your screenshot, the supervisor pattern would work better, where everything goes through the supervisor agent and the other agents do not directly talk to each other. So create a supervisor agent and call the order/product agents via tools with strictly defined schemas.
radek_sz
radek_szOP•2w ago
I really appreciate your response, thank you! All clear for me now šŸ™‚
Mastra Triager
Mastra Triager•2w ago
šŸ“ Created GitHub issue: https://github.com/mastra-ai/mastra/issues/10615 šŸ” If you're experiencing an error, please provide a minimal reproducible example whenever possible to help us resolve it quickly. šŸ™ Thank you for helping us improve Mastra! šŸ“ Created GitHub issue: https://github.com/mastra-ai/mastra/issues/10616 šŸ” If you're experiencing an error, please provide a minimal reproducible example whenever possible to help us resolve it quickly. šŸ™ Thank you for helping us improve Mastra!

Did you find this page helpful?