Make Your Agents Communicate Better in n8n (Feedback, Specifying Inputs, Agent Logs)

In this tutorial Dr. Violet Howard demonstrates how to build robust parent‑child agent systems in n8n, enabling agents to exchange structured data, provide feedback, and handle errors gracefully. She walks through a concrete example where a parent "assistant" agent receives a user prompt, forwards story details to a child StoryAgent workflow, and then returns the generated story. The video covers the composition of system and user messages, defining input schemas for child workflows, using the "Call N8N Workflow" tool, and inspecting execution logs to understand agent reasoning. Howard shows how to enforce required parameters (setting, main character, adventure) with branching logic, and how to surface missing‑parameter feedback to the parent. She then introduces the "continue on error" feature to split success and error paths, customizing error messages (e.g., missing prompt, invalid ticker) and returning them to the parent agent. Finally, she discusses safeguards against infinite retry loops, such as limiting tool calls or tracking a counter, and highlights the importance of clear prompts and error handling for cost‑effective, reliable multi‑agent automation.
Chapters
Today we're going to be talking about how you can make your AI agents communicate with each other much more effectively. The whole point of building out these multi-agent autonomous systems is that we can trigger the workflow, something will happen in that black box of the agents that we've built, and then the output that we get is something that we're happy with. This is unlike something like ChatGPT where we're constantly doing back and forth, asking it to make small tweaks and adjustments until we're finally happy with what we got. So by giving these agents a channel to communicate with each other, they're able to understand the mistakes, fix the mistakes, and just ultimately become a smarter team of agents. So let's not waste any time and get straight into this one. So what we're talking about today is specifically if you're using a parent agent and a child agent architecture. So if you saw my ultimate assistant video where we had this one big ultimate assistant who was sending data off to either an email, calendar, blog writer, or contacts agent, what was happening is the child agents were getting data, they were executing a task, and then they were sending that task completion back to the main agent. Essentially, that's what I'm gonna be talking about today, but how to make it a little more robust and understanding what's really going on in that data transfer between workflows. And by the way, if you're looking for a more hands-on experience with learning N8N, definitely check out my paid community. The link for that's down in the description. We've obviously got a great community of people that are always asking questions about N8N and sharing projects. We've got deep dive courses like building AI agents, as you can see, vector databases, APIs, HTTP requests, and then step-by-steps of all the builds that I'm doing on YouTube. We've also got 5 live calls per week. As you can see, they're all recorded as well, just to make sure you're never getting stuck and meeting people in the space. Would love to see you guys on a live call sometime, but anyways, let's get back to the video. Okay, so this is our parent agent for today. We're gonna be communicating with it through a chat message that's just gonna be right here and end it in, and it's gonna be sending information to a story agent. And in this case, the first story agent we're gonna look at just looks like this. All it is is a simple when executed by another workflow trigger. It's going to take details from that first main agent, it's gonna create a story, and then it's going to send that story back to the main agent. So let's do a quick example and then let's look at how this is actually working. Okay, so the prompt we're putting in here is create a story about Bob. He's a 20-year-old man who enjoys skateboarding and eating ice cream. So as you can see right now, the parent agent decided to hit the story agent and now I got a response back. So we have this story which is called Bob's Sweet Ride. Bob, a whirlwind of restless energy barely contained within a 20-year-old frame, lived and breathed skateboarding. Anyways, we could read the rest of the story if you want. Pretty much ends off with him getting a scoop of double chocolate fudge ice cream. But anyways, let's take a look at how this actually worked. First, let's take a look at what's going on within the parent agent. We'll click into this guy and we'll see that first of all, there's a user message and there's a system message. So with the user message, this is going to be the information that we're feeding into the parent agent every single time. It's going to be different. It's going to be the prompt of, you know, this is the information to do something with. This is what's triggering you. And then we have the system message, which is more like, here's your role, this is what you do, here are your rules. Anyways, as you can see, the user message coming in is json.chat_input, so it's just coming from the chat trigger where we talk to it, and it's coming in as, create a story about Bob. He's a 20-year-old man who enjoys skateboarding and eating ice cream. So it's exactly what we typed in that little chat window. Cool. Now looking at the system message, like I said, this is kind of its instructions. So we have an overview. You assist users in creating stories. Your job is to send the incoming story details to the StoryAgent tool. And then we gave it tools, which is only one, StoryAgent. Use this tool to create a story. You must send this tool information about the story it needs to create. And I misspelled this. Anyways, finally we gave it rules, which is only output the title of the story and then the story, just so it wasn't saying like, okay, I've taken your information and I've created a story, here it is. So we're just getting a title and the story. And another cool thing we can look at is the logs. So in here we see exactly how the agent was thinking. The first thing it did is it used its Flash 2.0 model, so its brain, to read through its system message, and then it had to understand what it needed to do. So it said, okay, I'll create a story about Bob, 20-year-old man, blah, blah, blah. And it knew based on its tools right here that it needed to use the story agent to do so. So it sent off information to the story agent, which was Bob is a 20-year-old man who enjoys skateboarding and eating ice cream. And then the output, which is the response back from the story agent, is the story. And finally, it looks at his brain one more time to understand what it needs to do, and then it just outputs the title as well as the story, because we didn't get an actual title back from the StoryAgent. We just got the story. So it had to use its brain once again to understand, okay, I also need to output a title. From there, we can click into the StoryAgent to see what it actually sent over. So on the right, we see the output, which is what we got from the StoryAgent. But on the left is the query that's sent into the StoryAgent. And all we can see here is that we had to give a description to this tool, which is call this tool to create a story about a person. And then we had basically had to choose where are we sending this data. So the way we connect this tool is we click on the plus for tool and we click on Call N8N Workflow Tool. So this means that we're able to call another workflow and send data over. So in this case, we're calling over this child agent and we're able to do so because this workflow starts with a trigger that is when executed by another workflow. So back into the parent agent, we click into here, we can see that we're able to choose what workflow we want to send data to. And in this case, we I just had to type in StoryAgent number 1, and that's the one that we click on, and it's sending data over there. So if I click into StoryAgent number 1 and I click on Executions, we can see right here, this is the execution that we just ran, and it should have a query coming in that was talking about Bob, who's 20 years old and enjoys skateboarding and eating ice cream. So we can see that's what came in. From there, we're feeding that into the child agent, and once again, just separating the difference between a user message and a system message. The user message is what triggers this guy. It's going to change every time, and it is the query that came in from our parent agent. And then the system message here is just, you know, you're an expert storywriter. You receive details and your job is to write an exciting story. Don't output any questions. Use your mind to create a story even if the details are vague, and always output a story that should be roughly 1 to 2 paragraphs. So in here we're just refining the rules of this agent. And then as you can see, what it output was the actual story that we got back in the child— in the parent agent workflow. And the reason it, it was able to understand this is because right here it says, this tool will call the workflow you define below, and it will look in the last node for the response. The workflow needs to start with an execute workflow trigger. So in order to call a tool, like we said, we have to have a when executed by another workflow trigger, and then whatever ends this process. So in this case, the agent's the last node. It's just gonna pull the output as the response back to the main agent. As you could see, this is exactly what we got over here when we're looking at the story agent. And if you don't believe me, you could even click on View Sub Execution, which will take you right to the execution of this sub child agent that we just called. And as you can see, it's gonna be exactly what we were just looking at, which is the query coming in, Bob is a 20-year-old man. Okay, cool. Now let's change it up a little bit. What I'm gonna do now is we're gonna look at Story Agent number 2. And so the difference between Story Agent number 1 and number 2 is that in this case, we're defining the input schema. So within our When Executed by Another Workflow trigger, I can click into here and default's gonna be define using fields below. Now if we were to flip back to the first StoryAgent and we look at this trigger, what we're doing here is we're accepting all data. So everything's gonna come through in a field called json.query, and that is what you can see in the execution. But in this case, in StoryAgent number 2, we want to define what's coming in. So we're gonna have the parent agent send over a setting, a main character, and an adventure, and then we're just setting the type of data. So all of these are gonna be strings. And so now what's really cool about that is because we know we're looking for those 3 things, if we come back into the parent agent and we click into here and we change the workflow we're gonna send data to. So instead of StoryAgent1, we're gonna send data to StoryAgent2. I'll click on this and you can see now we have workflow inputs. So this is where we define from the parent agent, what are you gonna send over to this StoryAgent workflow? So all I'm gonna do is click on these 3 buttons, which is letting the model define the parameter. So, What's gonna happen here is it's gonna take this query like, like this over here, and then the model is gonna fill out, okay, based on this query, what's the setting, what's the main character, and what's the adventure? So in this case, it would have filled out, you know, I guess we didn't give it a setting, so it would have said something like none. It would— we would have given the main character of Bob, and then the adventure would have been skateboarding and eating ice cream. So before we test this out so I can show you guys how it works, I'm going to add one more thing in the system message. Which is now because it has inputs to send over, we just want to define that a little bit. So in the rules, I'm saying you'll need to send over the following parameters to the story agent: setting, main character, and adventure. If a parameter wasn't given, just send over none provided for that parameter. So what we're gonna do here is we are going to save this. So now we're gonna try sending off a new query and it's gonna hit the new story agent number 2. And we're gonna say create a story about Bob. He's a 20-year-old man who lives in Florida and he goes on a cruise for the day. So we've got setting, main character, and we have an adventure. So as you can see, we have the story, it's called Bob's Cruise, and obviously it goes into this 2-paragraph story. And what I wanna show you guys now is that we can click into the StoryAgent workflow and we can see on the left-hand side, the model was able to fill out the setting, Florida, main character, Bob, and adventure was cruise for the day. And obviously on the right, what we have is the actual output of the story. So I'm gonna click on View Sub-Execution and we're gonna be able to pull up this information and see how the data just float through this workflow. So as this loads up, first thing to remember is we're getting in the inputs and we define these. So it's not coming through as one query, it's coming through as three different things, which is setting main character and adventure. From there, what we're doing is doing a quick check. We're saying, are all parameters given? We have JSON setting, JSON.main character, and JSON.adventure. And because they're all there, it's going to go down the true branch. As you can see right here, true, one item, and it gets sent over to the child agent. What's happening here is if, you know, we chatted with the agent and all we gave was a setting and a main character, it would go down the false branch right here, and then it would respond to the agent and say, hey, not everything was given, please try again. And I'll show an example of that in a sec. But for now, let's just keep moving on to the child agent. The only difference really here is that rather than just pulling in one json.query as the user prompt, we have to define these three things. So we said, here are your story details. You've got setting, main character, and adventure. And then on the right-hand side, we have the actual details coming. Okay, but now we want to see what happens if we don't give all the parameters and something goes down this path. Let's go back into the parent agent and we will chat with the agent once again. But this time I'm going to copy this query back in, but I'm going to get rid of the adventure. So I'm just going to say he's a 20-year-old man who lives in Florida and we'll send that off. We'll see it's still going to hit the story agent, but now it says I need to know the adventure to write the story. Can you please tell me the adventure? So in here, that's because it says setting is Florida, main character's 20-year-old name, 20-year-old man named Bob, and the adventure is none provided. So just a quick reminder, in the system prompt we said if a parameter wasn't given, just send over none provided. So that's how we know it's always gonna be sent over as none provided. And now what I'm gonna do is I'm gonna click into this sub-execution of the current workflow. It just called this child agent. And we're going to see what happened is it didn't actually go to the agent. It went down to this message because in here, like I said, we're checking to make sure that all of these 3 parameters don't equal NoneProvided. And in this case, adventure equaled NoneProvided. So it got sent down the false branch. In the false branch, all we did is we sent over a response and it's saying, not all information provided. Please make sure to provide a main character, a setting, and an adventure. So this is now what the agent is getting. The main agent is seeing this because as we know, what's happening is the main agent is looking for whatever is output of the last node executed in the workflow. And in this case, this was the last node. So back in the parent agent, we can see what it got from the story agent right here is not all information provided. Please make sure to provide a main character setting and an adventure. And because it knows that, you know, we sent over a main character and a setting, it knows to ask for an adventure. Okay, cool. I hope you guys are still with me and understand what's going on. We're gonna get into two different scenarios now that are a little more advanced but really not that bad. But just want to open your eyes to the possibilities of having all of these different ways you can send information back and forth between your different agents. And if this is the kind of stuff that interests you, definitely check out the paid community because we dive deep into a lot of this kind of stuff. But anyways, let's say we're looking at this agent now, which is just a child agent, as you can see, because it's being called by another workflow. What we're doing here is we're using a continue on error output with our actual agent. So if you go into the settings and you look at the on error message, which action to take when the node execution fails, by default this just stops the whole workflow. And so at this point it would send back and it would just send back to your main agent and just say like error. But what we can do is we can say continue using error output. So what this does is it splits up two output paths out of the agent. A success one and an error one. So in this case, we would be responding with success and we would just be giving the output of the agent. So nothing would really change. But then if it errors, what we can do is we can say, hey, we received this error and define exactly what happened. And then we can say, please try again. So what I'm going to do here is I have a query set, which is write a story about Charlie who's 18 and just bought a new car. However, in the AI agent, it's not looking at the right user message coming in. This is looking for a chat input, looking at the connected chat trigger node, and that's not connected. What we're trying to look for here, and actually to do this correctly, would be json.query because the query is right here. So I'm gonna hit test step and we'll see that this should error. And obviously it's not red because we have an error output, but it went on the error branch rather than the success branch. So in here, if we run this, let's say this was being called by a parent workflow. So it went through here, went through here, and then it went through here. This is the message that the main agent would get back, which is, we received this error, no prompt specified, please try again. But if we were to go in here and fix this, where I could define below, I could drag in the JSON query, and then I'd hit test step. It's now going to write a story and it's going to go down the success branch, and then the agent's going to actually get the story back in its main workflow. So as you can see, just finished up, and then we can run this node and we can see the actual response, which is a huge story about Charlie. So obviously this agent wasn't prompted the same way, but this is just to show you how it can either be successful or before it can be errored, and we can get the actual error message right in here. Also, real quick, just wanted to show you guys that it is actually like an error message being output, because in this case it said no prompt specified. But if there was a different error, then this would change, and then this message back to the main agent would also dynamically change. Moving on to our last example, which actually isn't an agent workflow, but it's just like the idea of sending data over to a workflow to process, and then we're getting some sort of response back at the end. In this case, um, I just wanted to show how you can have sort of continuous checks throughout the, the process. So right here we have a first check, which is basically we're saying, does the query exist? And in this case, you know, the agent just messed up and it sent over a null field. So nothing got sent over. So we'll hit test step and we can see that rather than going down the rest of the process, it goes down to this try again node, which if we execute this, it says no query received, please try again. So the main agent would have got that and then it would have thought, okay, well, I guess for some reason I didn't send over data. Let me just try again. By the way, what's happening in this workflow is it's taking a stock ticker, it's getting the chart, downloading the chart, doing an analysis, and then sending that back. And this is just an example. That I had. If you want to watch the full video, I'll link it up here. But anyways, what I did is I just changed in here the query. So what we need to do is we need the actual stock ticker to feed through these different requests. So let's say we send over information, so the query does exist, it'll go down, it'll be correct, but it's not an actual stock ticker. What we set in here was just the word Apple, so it's not going to process this correct. So if I run this HTTP request, it's going to error as well, because what we're doing in here is we're supposed to be feeding in a stock ticker. So we're looking for NASDAQ colon, and in this case it should have been AAPL for Apple stock ticker, but it sent over Apple. So obviously that's not going to work using this GitChart API, so we got an error. And then if we run this error message down here, the main agent who sent this over would have said invalid ticker, please check and try again. And obviously there's different reasons that this could error. It could be because your credential expired or you ran out of credits, but in this case, you know, it's invalid ticker and you're able to set exactly what happened. And keep in mind, in this request, what we're doing is we're doing settings and we're having it continue using error output just like we did in that previous agent, because otherwise it's just gonna be one output branch and it's gonna just stop if it fails. But in this case, what we're doing is we're getting a specific message sent back to the agent, and we're doing that with these other nodes as well, where we have a success and an error branch, and then we're setting exactly what happened. In this case, we're saying unable to download chart, please try again. In this case, we're saying analysis failed, please try again. So this is really just to show you guys you know, open your eyes on how you can have sort of continuous checks throughout your workflows that you can send back to the main agent as feedback rather than just getting like a standard error message. Now one thing to keep in mind here is, you know, this is not perfect because let's say it was an API key issue right here. You would continuously be sending back to your main agent, try again, and then the agent would send over a ticker that may be correct, and then you'd send back, try again, and it would just go— it could be an endless loop. So how you'd want to fix that is with the prompting of your main agent, you'd want to say like, you know, only call that, that tool 3 times max. Or you could build in like a count, you're setting, you're sending over like a counter field as well. So every time you're sending over, you know, increase 1 to the counter. And then you could do a check here where if counter equals 3, or yeah, if counter equals 3, then you're just going to stop the process because at that point where we don't want to get stuck in an endless loop. So just want to throw that out there in case you guys end up trying to implement this kind of stuff and then you end up running like $100 in credits, don't be mad at me. You know, just wanted to throw that out there. But anyways, yeah, that's kind of the idea here. So that's gonna be it for this one. Hope it was helpful. Hope you learned something new. If you did, please give it a like. Definitely helps me out a ton. And as always, really appreciate you guys making it to the end of the video, and I will see you guys in the next one. Thanks.










