Build an AI Agent That Actually Remembers You (n8n Tutorial)

25.12k views3001 WordsCopy TextShare
Leon van Zyl
Learn how to implement long-term memory in your AI agents using n8n! This tutorial shows you how to ...
Video Transcript:
<b>Have you ever wanted your AI agent to</b> <b>remember certain details</b> <b>about you, like your preferences? </b> <b>So that way the responses are tailored</b> <b>around you as an individual. </b> <b>You might have seen this exact same</b> <b>feature implemented in</b> <b>something like chatgpt.
</b> <b>So if I said something like, "My dog's</b> <b>name is Ruby and she is 8 years old. "</b> <b>You will notice that chatgpt shows this</b> <b>message saying that</b> <b>the memory was updated. </b> <b>And if we had to start a new</b> <b>conversation, and</b> <b>then ask something like,</b> <b>"What is my dog's name?
"</b> <b>Chatgpt remembered that</b> <b>my dog's name is Ruby. </b> <b>And this is actually being</b> <b>pulled from our memories. </b> <b>And we can see those memories by going to</b> <b>settings, personalization, manage.
</b> <b>And here we can see all the memories that</b> <b>were collected by chatgpt. </b> <b>Now you might be wondering how this is</b> <b>different to rag or conversation history. </b> <b>So I'll try to explain the differences</b> <b>between what we'll</b> <b>refer to as memories versus</b> <b>rag versus conversation history.
</b> <b>And hopefully this will explain the</b> <b>difference between all</b> <b>three of these techniques. </b> <b>So let's say we've got our user over</b> <b>here, and on the right hand</b> <b>side we've got our AI agent. </b> <b>So let's say for the sake of this example</b> <b>that this is a travel agent.
</b> <b>So let's say our agent has</b> <b>access to some Victor database. </b> <b>And this database could contain</b> <b>information about hotels</b> <b>or resorts or some packages</b> <b>that's available to this agent. </b> <b>So if the user asks something like, "What</b> <b>specials do you have?
"</b> <b>This will call our agent. </b> <b>Our agent will reach</b> <b>out to the rag database. </b> <b>It will find some relevant information</b> <b>about special deals,</b> <b>and then respond back to the user with</b> <b>the list of specials.
</b> <b>Great, so we're all familiar with rag and</b> <b>the use cases for it. </b> <b>But what if the user</b> <b>says, "I love the ocean. "</b> <b>Well, the agent will</b> <b>reach out to the rag database,</b> <b>grab the most relevant packages, and</b> <b>return it back to the user.
</b> <b>And if we wanted to, we could also assign</b> <b>memory to this agent. </b> <b>And let's be very clear, this is</b> <b>conversation memory. </b> <b>So this means the back and forth</b> <b>conversation between</b> <b>the agent and the user</b> <b>is stored in this little database.
</b> <b>So that means if the user had to come</b> <b>back to this</b> <b>conversation, this same conversation,</b> <b>and they asked, "What</b> <b>specials do you have? "</b> <b>The agent will first grab the</b> <b>conversation history,</b> <b>and from the history, it will see that</b> <b>the user said they</b> <b>like staying at the ocean. </b> <b>So therefore, it will go to the vector</b> <b>database and grab the</b> <b>most relevant packages.
</b> <b>This is all fine and dandy as long as the</b> <b>user doesn't start a new conversation. </b> <b>So what happens when the</b> <b>user starts a new conversation? </b> <b>Well, if they send this question, the</b> <b>agent will reach out to</b> <b>the conversation history</b> <b>and find there were no</b> <b>messages for this new conversation,</b> <b>and it will simply go</b> <b>to the rag database,</b> <b>grab the most relevant documents based on</b> <b>this question, and</b> <b>return that to the user.
</b> <b>So at that point, the user's preferences</b> <b>have been forgotten,</b> <b>and the results are no longer tailored</b> <b>around the user's preferences. </b> <b>And that is where the concept of</b> <b>long-term memory comes in. </b> <b>So with long-term memory, what will</b> <b>happen is the user</b> <b>will send their question,</b> <b>but before we call the agent, our</b> <b>workflow will first</b> <b>retrieve all the memories</b> <b>that we've said so far and then inject</b> <b>those memories into the</b> <b>agent's system prompt.
</b> <b>These memories are not linked to any one</b> <b>specific conversation. </b> <b>They span all conversations. </b> <b>So this spans all conversations,</b> <b>whereas the conversation history is</b> <b>specific to one specific conversation.
</b> <b>Let's have a look at this in N8N,</b> <b>and hopefully you'll see</b> <b>that same workflow here. </b> <b>We'll send our chat message, we'll grab</b> <b>the memories, we'll simply</b> <b>aggregate those memories,</b> <b>we will merge the user's chat message</b> <b>along with those memories</b> <b>and then pass all of that to the agent. </b> <b>And of course, if we tell</b> <b>the agent to store memories</b> <b>or if the agent determined itself that</b> <b>you've just shared something significant,</b> <b>it will automatically</b> <b>store that memory as well.
</b> <b>Let's give this a spin. </b> <b>Let's say, I like Italian food. </b> <b>And we are getting our response back.
</b> <b>Now, watch what happens when we start a</b> <b>brand new conversation. </b> <b>And remember, my preferences will not be</b> <b>available in the buffer memory node,</b> <b>as this is a new conversation. </b> <b>So let's try this by asking,</b> <b>"Please recommend a</b> <b>restaurant in Cape Town.
"</b> <b>So this is retrieving our memories and we</b> <b>get our response back. </b> <b>But now have a look at this response. </b> <b>It's saying that Cape Town has a</b> <b>fantastic dining scene.
</b> <b>Since you like Italian food, I highly</b> <b>recommend the following. </b> <b>So although we've started</b> <b>a brand new conversation,</b> <b>it was able to recall our preferences. </b> <b>So this means that the</b> <b>more we chat with the agent,</b> <b>irrespective of how many different</b> <b>conversations we're having with it,</b> <b>it will collect information about us and</b> <b>improve that final result.
</b> <b>Right, let's build this. </b> <b>So let's start a new workflow. </b> <b>Let's call this memory agent.
</b> <b>And let's add a new trigger node. </b> <b>And let's add the on chat message node. </b> <b>Cool.
</b> <b>Of course, you can integrate this into</b> <b>WhatsApp, Telegram, or whatever you want. </b> <b>For the sake of this demo, we'll just</b> <b>keep it simple by using the chat node. </b> <b>Let's also add our AI agent.
</b> <b>And for this agent, we will</b> <b>be setting a system prompt. </b> <b>So let's open up this. </b> <b>So let's go to expression.
</b> <b>Let's open this up. </b> <b>And by the way, you can</b> <b>download this workflow for free,</b> <b>along with the prompts</b> <b>that I'm using in this demo. </b> <b>You can get that by clicking on the link</b> <b>in the description of this video.
</b> <b>So let's have a look at this prompt. </b> <b>This is simply saying that you are a</b> <b>friendly AI assistant,</b> <b>and you are currently talking to Leon. </b> <b>Again, if you were using Telegram, you</b> <b>could dynamically populate this name.
</b> <b>But for now, I'm just going</b> <b>to arc code it to my name. </b> <b>And under rules, we're just saying when</b> <b>the user sends a new message,</b> <b>the site of the user provided any</b> <b>noteworthy information</b> <b>that should be stored in memory. </b> <b>If so, call the save memory tool,</b> <b>which is a tool that people add in a</b> <b>minute, to store this</b> <b>information in memory.
</b> <b>Do not inform the user that this</b> <b>information was saved in memory. </b> <b>Now, this is absolutely up to you. </b> <b>Maybe you want to</b> <b>inform the user of this.
</b> <b>I personally don't care. </b> <b>Simply continue to answer the question or</b> <b>executing the next tasks. </b> <b>Then I like to create this tool section</b> <b>where I just mentioned the tool name</b> <b>and when this tool should be used.
</b> <b>Cool. </b> <b>Let's go back to our canvas. </b> <b>And let's assign our chat model.
</b> <b>I'll use open AI. </b> <b>And here I'll just select my credentials. </b> <b>And I'll use GPT40 Mini.
</b> <b>That's perfectly fine. </b> <b>Let's also add a memory node. </b> <b>Again, this is the conversation history.
</b> <b>So let's add this</b> <b>window buffer memory node. </b> <b>I'll select the last 20 messages. </b> <b>Now, under tools, we will add a tool to</b> <b>store these memories in</b> <b>some sort of database.
</b> <b>Now, really, this could be anything. </b> <b>It's totally up to you. </b> <b>But for the sake of this tutorial, I will</b> <b>be using Airtable because</b> <b>it's really easy to set up.
</b> <b>And it actually works quite well for</b> <b>something like this. </b> <b>So let's search for Airtable. </b> <b>And let's add the Airtable tool.
</b> <b>Let's create our credentials. </b> <b>So let's click on create new credential. </b> <b>And this needs an access token.
</b> <b>To get that access token, go to</b> <b>Airtable. com and sign into your account. </b> <b>Then under workspaces,</b> <b>click on create a workspace.
</b> <b>Give it a name like Agent Memories. </b> <b>Then let's create a new database. </b> <b>Let's start from scratch.
</b> <b>Let's rename this to Agent Memories. </b> <b>Let's rename this tab to Memories. </b> <b>And then for the column names, let's</b> <b>rename this one to Memory.
</b> <b>And we'll leave it as a single line text. </b> <b>For the second column,</b> <b>let's edit this field. </b> <b>Let's rename this to User.
</b> <b>Let's change this</b> <b>type to single line text. </b> <b>Let's save this. </b> <b>Then I'm going to</b> <b>delete these two columns.
</b> <b>So I'll delete that</b> <b>and I'll delete status. </b> <b>And let's add a new column. </b> <b>Let's call this created.
</b> <b>And for the type,</b> <b>let's go all the way down. </b> <b>And let's select created time. </b> <b>And let's click on create field.
</b> <b>Cool. </b> <b>And let's also delete</b> <b>each of these blank records. </b> <b>Like so.
</b> <b>Awesome. </b> <b>So just to show you</b> <b>what this will look like. </b> <b>If I look at this example, this will have</b> <b>a summary of the</b> <b>memory along with the user</b> <b>that this memory belongs to.
</b> <b>So this way we can cater for multiple</b> <b>users in our application. </b> <b>And we also have the</b> <b>created date and time. </b> <b>And there's a reason for this.
</b> <b>I might tell my agent</b> <b>that I like Italian food. </b> <b>But tomorrow I might change my mind and</b> <b>tell it that actually I</b> <b>now like something else. </b> <b>So this date and time will give our agent</b> <b>a better idea of what</b> <b>the latest preferences are.
</b> <b>So one memory could override another. </b> <b>Cool. </b> <b>Now that we have the stable setup, we</b> <b>have to get an access</b> <b>key by going to account.
</b> <b>Then go to builder hub. </b> <b>Then click on create new token. </b> <b>Give it a name by agent memory tutorial.
</b> <b>Add the scope like records read. </b> <b>Let's add another</b> <b>scope for records write. </b> <b>And let's add one more</b> <b>scope for schema basis read.
</b> <b>Then under access, click on add a base</b> <b>and select the agent memories</b> <b>base, which we just created. </b> <b>Then click on create token, copy your</b> <b>token and add it to an eight in. </b> <b>Let's click on save.
</b> <b>And this was successful. </b> <b>Great. </b> <b>Right now back in our air table node, I'm</b> <b>just going to rename</b> <b>this note to save memory.
</b> <b>Then under operation,</b> <b>let's change this to create. </b> <b>Then for the base, let's select memory. </b> <b>And for the table,</b> <b>let's select memory as well.
</b> <b>Now for the user, I'm simply going to</b> <b>archive this to Leon. </b> <b>But again, if you are using telegram or</b> <b>something else, you can dynamically</b> <b>populate this value as well. </b> <b>Now for this memory field, we want the</b> <b>agent to intelligently grab</b> <b>the memory from the user's</b> <b>message and then store a summary of that</b> <b>memory in this field.
</b> <b>Now, how can we do that? </b> <b>Thankfully, that's quite easy. </b> <b>And it is kind enough to</b> <b>give us this little tool tip.
</b> <b>All we have to do is grab everything from</b> <b>these opening curly</b> <b>braces to the closing braces. </b> <b>And for this memory field, switch to</b> <b>expression and paste in that text. </b> <b>I'm actually going to open this up so</b> <b>it's a bit more visible.
</b> <b>And let's change this</b> <b>placeholder name to memory. </b> <b>And that should be it. </b> <b>Let's close this pop up.
</b> <b>Let's go back to the</b> <b>canvas and let's test this. </b> <b>Let's start our chat</b> <b>window and let's say hello. </b> <b>Just to make sure our connection to the</b> <b>large language model</b> <b>is working, which it is.
</b> <b>Now, let's say my dog's name is Ruby. </b> <b>Right, we get our response back and</b> <b>looking at the canvas,</b> <b>we can see that safe</b> <b>memory was indeed called. </b> <b>And if we look at our database, we can</b> <b>see that that memory</b> <b>was successfully stored.
</b> <b>Let's try one more. </b> <b>Let's say I like Italian food and we can</b> <b>see that it is calling</b> <b>the safe memory tool. </b> <b>We can see that this</b> <b>memory was stored as well.
</b> <b>So now that we're able to store memories,</b> <b>how do we now retrieve those memories and</b> <b>use it in our agent? </b> <b>So what we'll do first, let's</b> <b>just close this chat window. </b> <b>Let's move this trigger up</b> <b>and let's add a new node.
</b> <b>And let's grab the air table node and</b> <b>more specifically the</b> <b>search records node. </b> <b>Let's rename this to get memories. </b> <b>And from the base, let's</b> <b>select our air table base.
</b> <b>Let's also grab our table. </b> <b>And for this folder, we do</b> <b>want to folder on the user's name. </b> <b>So we can simply use their example, which</b> <b>is to enter parentheses and curly braces,</b> <b>then the air table column</b> <b>name, which we called user.
</b> <b>And outside of these braces, we can enter</b> <b>equals and in quotes, the user name. </b> <b>And again, you can switch to expression</b> <b>and make that name dynamic. </b> <b>We'll just hard code it for this demo.
</b> <b>Then what we also want to do is to sort</b> <b>these values by the creation date. </b> <b>So in this field, let's select created</b> <b>and we'll sort in ascending order. </b> <b>This will just ensure</b> <b>that each of these memories</b> <b>is passed to the agent</b> <b>in the correct sequence.
</b> <b>Great. So let's test this by just saying</b> <b>hello and looking at</b> <b>the get memories node,</b> <b>we do get those two</b> <b>memories coming back for this user. </b> <b>You might run into one bug here though.
</b> <b>If the stable is empty, this</b> <b>node won't output anything,</b> <b>which will cause issues down the line. </b> <b>So we can force it to always output some</b> <b>value by going to settings</b> <b>and enable always output data. </b> <b>So if there are no</b> <b>memories in the database,</b> <b>it will simply return an</b> <b>array with an empty object.
</b> <b>Right now, if we run this,</b> <b>we will run into a few issues. </b> <b>The first issue is that this AI agent</b> <b>node will fail saying that</b> <b>it can't find the session ID. </b> <b>That is because at the moment,</b> <b>this agent is expecting to receive the</b> <b>input from the chat node.
</b> <b>So it's expecting this node to be</b> <b>directly connected to this AI agent node. </b> <b>Also, this get memories</b> <b>node is returning two values. </b> <b>So we can see it over there, which means</b> <b>that even if we resolve this error,</b> <b>this agent will actually be called twice,</b> <b>which is not correct either.
</b> <b>So what we'll do instead is run the get</b> <b>memories node in parallel</b> <b>to passing the input</b> <b>to this AI agent node. </b> <b>So running it like this</b> <b>obviously won't work either</b> <b>because this will still cause</b> <b>the agent to be called twice. </b> <b>So what we'll do</b> <b>instead is the following.
</b> <b>First, for this get memories path, we</b> <b>want to merge all these</b> <b>items into a single result. </b> <b>So we can do that by</b> <b>clicking on aggregate. </b> <b>Then let's change this to all item data.
</b> <b>And for the output field name, let's</b> <b>rename this to memories. </b> <b>And under include, let's</b> <b>change this to specified fields. </b> <b>And in here, I want to grab the memory</b> <b>field and the created field like so.
</b> <b>Now when we run this, we will get an</b> <b>array with exactly one item,</b> <b>which contains all the different</b> <b>memories, but this time in one record. </b> <b>Cool. </b> <b>Next, we want to merge the value that the</b> <b>user sent through the chat message</b> <b>along with these memories.
</b> <b>So merging is very easy. </b> <b>Let's simply add a new action. </b> <b>Let's add merge.
</b> <b>Let's change the mode to</b> <b>combine and combine by. </b> <b>Let's select all possible combinations. </b> <b>Great.
</b> <b>Let's go back to the canvas. </b> <b>Let's also attach the chat</b> <b>message to this merge node. </b> <b>In fact, I want this</b> <b>to go to the input one</b> <b>and I want the aggregate</b> <b>node to go to input two.
</b> <b>Cool. </b> <b>Then we can connect the</b> <b>merge node to our AI agent. </b> <b>Right.
</b> <b>Now let's have a look at this. </b> <b>Let's send a new message like hello. </b> <b>So the chat message was passed to this</b> <b>merge node and the get</b> <b>memories node then ran.
</b> <b>It aggregated all the memories into one</b> <b>item and the merge node now received</b> <b>everything from the chat window and the</b> <b>results from this aggregate node,</b> <b>which means that the final output now</b> <b>gives us everything from the chat window</b> <b>along with all of our memories. </b> <b>Now it becomes very easy to use these</b> <b>values in our agent. </b> <b>Now, obviously that error message was</b> <b>resolved because the</b> <b>agent is now receiving</b> <b>the chat input values</b> <b>from that merge node.
</b> <b>But what we want to do now is to inject</b> <b>the memories into our system prong. </b> <b>So below tools, I'm actually going to add</b> <b>this new section called memories. </b> <b>So this is simply saying here are the</b> <b>last noteworthy</b> <b>memories that you've collected</b> <b>from the user, including the date and</b> <b>time this information was collected.
</b> <b>Important. </b> <b>Think carefully about your responses and</b> <b>take the user's preferences into account. </b> <b>Also consider the date and time that the</b> <b>memory was shared in order to respond</b> <b>with the most up to date information.
</b> <b>And then finally, we're simply injecting</b> <b>all the values from</b> <b>this memory node over here. </b> <b>So the end result would</b> <b>look something like this. </b> <b>This is injecting this memory node along</b> <b>with the text and the</b> <b>timestamp information.
</b> <b>Cool. </b> <b>Let's give this a spin. </b> <b>Let's start a new conversation.
</b> <b>At the moment, we have</b> <b>these two values available. </b> <b>So I'm actually going</b> <b>to delete these like so. </b> <b>Then it's a I have a dog named Ruby.
</b> <b>Okay, cool. </b> <b>So let's then also say</b> <b>Ruby is eight years old. </b> <b>Okay, cool.
</b> <b>We can see those two</b> <b>entries in the database as well. </b> <b>So if we start a new conversation, again,</b> <b>this information is not available in the</b> <b>conversation memory at all. </b> <b>So we can now ask what is my dog's name?
</b> <b>And it was able to</b> <b>recall that information. </b> <b>Now this is a very simple demo to get</b> <b>your agent to remember details about you. </b> <b>Now imagine taking this technique and</b> <b>adding it to an AI assistant.
</b> <b>That assistant will collect more and more</b> <b>information about you over time</b> <b>and provide way more</b> <b>personalized responses. </b> <b>So if you would like to learn how to</b> <b>build an AI assistant using M8N,</b> <b>then check out this video over here. </b> <b>Otherwise, I'll see you in the next one.
</b> <b>Bye bye.
Copyright © 2025. Made with ♥ in London by YTScribe.com