مرور حافظه عامل0:00
All right, think about this, whenever you meet somebody new, you start to form memories about them, right? What do they look like? What's their name? What do they work? What do they like to do for fun? So we collect these memories for each person we meet. Kind of cool. Now wouldn't it be interesting if our agents could effectively do the exact
Introducing Agent Memory0:15
Kind of cool. Now wouldn't it be interesting if our agents could effectively do the exact same thing? It could remember key facts from previous conversations or previous sessions. So how exactly do we allow for that? Let me show you one way. Now you might be surprised to find that we can implement this memory feature as a tool. It's just a tool available to our agent. All right, so let's take a look at the interface.
Defining the Memory Tool0:38
It's just a tool available to our agent. All right, so let's take a look at the interface. It consists of the definition itself, that signature, as well as use to use the tool. All right, let's go ahead and implement this interface. I'm going to call it memory. Now for the definition, forgive me, this is just way too much to write by hands . Let me paste this in. It's just the standard definition that we've worked on in previous episodes.
Let me paste this in. It's just the standard definition that we've worked on in previous episodes. So it's going to be a function. We'll give it a name of remember, but remember, remember, that can be anything you want. And the description, well, let's go to full screen, is just a long prompt and I 'll give you the gist of it. Save a stable long term fact about the user or their project. Use this tool only for information that will remain useful across future
Save a stable long term fact about the user or their project. Use this tool only for information that will remain useful across future sessions. Yeah, so just like real memory, is this something that might make sense for me to remember? What are your children's names, you know, what do you like to do, what your, what kind of coffee do you like? Is this something that would be helpful for me to remember in the future? If so, we're going to remember this fact.
Is this something that would be helpful for me to remember in the future? If so, we're going to remember this fact. Otherwise, if it's not important, we can, we can ignore it. And here are some examples, like what are your preferences? Do you like this tool or that tool? What is your identity? What's your project context? Do you usually work with airbell, if so, then we should remember that. But also do not use this tool for, yeah, just little things like he said, hello , is that
But also do not use this tool for, yeah, just little things like he said, hello , is that something you need to remember? Absolutely not. Also don't use it for anything you've already remembered. We don't need to be redundant. Cool, phrase the memory as a concise third person statement that will make sense in a future conversation without context, right, makes perfect sense. So here are the parameters.
Planning Memory Storage2:15
future conversation without context, right, makes perfect sense. So here are the parameters. We're going to record a fact, remember, think of this as like the parameter or the argument that you're sending to this function. So give us the fact that we want to remember and then our tool will be responsible for handling how that fact is remembered. So let's scroll down and let's work on that right now. So at this point, we should have fact equals arguments fact, right?
So let's scroll down and let's work on that right now. So at this point, we should have fact equals arguments fact, right? That's going to be passed in and it has to be passed in by the way because we set strict to true. So let's write this out. What do we need to do first? Maybe something like fetch our existing memory store if we have one and then maybe update the store with or to include the new fact.
maybe update the store with or to include the new fact. So as you can imagine, there's a number of ways we can do this. We could simply just write a new bullet point to a markdown file. We could store information in a database or JSON file. I'm just going to stick with simple markdown so that we can mimic the structure of our guidelines file from the previous episode. But as you can imagine, there needs to be some logic to say, okay, this is the fact you
But as you can imagine, there needs to be some logic to say, okay, this is the fact you want to remember. Look through the existing memory to see if you've already remembered this fact and if so, we can ignore it entirely. We could do string matching, but that's going to be wildly brittle. So instead, I think we could just make another AI call to say, all right, here 's our current memory.
's our current memory. Here's the new fact updated accordingly. And if that fact is already included, then we don't need to do anything at all. Okay. At the very end, once we've done all of that, we'll say something like, yeah, this is pretty good. Return that we remembered this fact. So ultimately, maybe we're returning something like a string and we're going to
Return that we remembered this fact. So ultimately, maybe we're returning something like a string and we're going to build this on the fly. Okay. So fetch our existing memory store. Again, remember, maybe we start with Markdown and then later we graduate to something a lot more complex or a collection of Markdown files or something like that. So with that in mind, knowing that we're just going to do file get contents
Building the Memory Store4:21
lot more complex or a collection of Markdown files or something like that. So with that in mind, knowing that we're just going to do file get contents here, maybe I should still go ahead and extract this to a dedicated memory store. So with that in mind, let's do this in the, let's comment that up in the sidebar. Let's add a new directory here and I'm going to call this memory. All right. And for now, it's just going to have a single class called store. This is our memory store.
And for now, it's just going to have a single class called store. This is our memory store. So we're going to, what do I want to call this? We have our memory store retrieve fetch get. What do we want to do here? How about fetch? And then what about when we want to write to it, maybe updates, update your memory, refresh your memory updates fine. All right.
your memory updates fine. All right. So let's return to our tool. And now we're going to inject this. So right up here, let's inject the store and maybe we can do property promotion here. So protected store, store, but also maybe we can initialize it by default. So you can give us your own store and in the future, we could turn that into an interface. So you could give us your own implementation of store.
interface. So you could give us your own implementation of store. Otherwise, we'll just default to what we have here. Yeah. That's a refactor we can make in the future, but we don't have to do it at the beginning. Okay. So now I could say fetch our existing memory store. Here's our memory or our current memory if you want, and then we'll shorten it later.
Here's our memory or our current memory if you want, and then we'll shorten it later. So why don't we say, and I can do this in line for now, we're going to refresh our current memory. Yeah, let's just take it to memory actually. Let's refresh our memory to include this new fact. Yeah, maybe refresh is not quite right, but we can start there. All right. I'm going to put this in line, and this is where we will make our call to AI
Using AI to Merge Memory6:11
All right. I'm going to put this in line, and this is where we will make our call to AI and say, all right, here's our current memory. Here's this new fact. I want to, I want you to send me the new memory and that will get saved to our markdown file. All right. And once again, I'm just going to paste this and trust me, you don't want to see me write
And once again, I'm just going to paste this and trust me, you don't want to see me write that out. Okay, let's import our HTTP, there we go. So we're going to make once again a call to open AI that responses API, and here are the instructions. All right. So instructions, you maintain a small markdown scratch document of long term facts about
So instructions, you maintain a small markdown scratch document of long term facts about a user. Great. Here's the existing markdown and a new candidate fact. Give me a new fully updated markdown file that follows these rules. Yeah. So if it's new information, add it. If it's already represented, then just return the existing markdown unchanged. Don't don't update anything.
If it's already represented, then just return the existing markdown unchanged. Don't don't update anything. Also do not editorialize. If the candidate contradicts an existing fact, replace the old fact with the new one because maybe the user's opinions or preferences have changed. Okay. So now we've given it a prompt, but we didn't supply it to the input. So we do that down here, right? And this is where you do like role equals user and the content is going to be,
So we do that down here, right? And this is where you do like role equals user and the content is going to be, and let me write this out, I need to know what the existing memory is as well as the proposed, as well as the proposed back to which AI remembered. Okay. Existing facts memory. I'm going to change this to existing memory and then the new fact here. Okay.
I'm going to change this to existing memory and then the new fact here. Okay. So once we're done, I'm going to temporarily dump the response. And then we'll actually, we'll just dump for now. Okay. So how is this looking and actually before I do this real quick, temporarily, and I'm going to show you how to do reporting here, but temporarily, I will say running the memory tool just so we can see it directly in the console.
the memory tool just so we can see it directly in the console. And then later, whenever we use a tool, I will show you how to report it to the console. All right. So when this tool gets used, we accept the fact we fetch the existing memory. We refresh the memory and all that's going to do is make an AI query and instantly dump the response and not return anything at all other than this. So now let's open up one of our agents here about chat bot agent.
Testing and Persisting Memory8:19
the response and not return anything at all other than this. So now let's open up one of our agents here about chat bot agent. And right down here, we will add our new memory tool. Yeah. Isn't that cool? That's all that's necessary here. We include it as a tool. And now the AI can determine, hmm, is this necessary? Is this something that I should remember for the future? All right.
Is this something that I should remember for the future? All right. Let's give it a run. HP artisan agent. Hi there. Remember, it's sarcastic by default. I have changed my name to Joe. So let's see if that's enough for it to remember, hey, I should, yes, there it is. So you saw that's a key thing.
is. So you saw that's a key thing. I updated my identity. And if I scroll up, we ran the memory tool. We made that AI call. And here's the instructions, let's see if we can find the output. So don't forget, as always, we go into the output, get the first item, get the content, get the first item, get the text. And in this case, we don't have any memory yet.
get the first item, get the text. And in this case, we don't have any memory yet. So we just get a bullet point that says user goes by Joe. And that would be written to our long-term memory that would persist across sessions. Cool. All right. So now that it's working, let's scroll down. We don't need that anymore. Here is the response.
We don't need that anymore. Here is the response. Let's go ahead and return it. So response, output, content, zero, text, I think that's right. Now one thing we might want to do is on the off chance, like something happens here. Why don't we just return the existing memory? Just as a fallback. If for some reason we didn't get a response, then return the existing memory from the refresh
If for some reason we didn't get a response, then return the existing memory from the refresh method. Let's add our response here. This will give us the new memory or updated or refreshed memory. Next we want to update the store, so I can say this store update, and I'm going to give it our refreshed memory. Cool. So let's see.
Cool. So let's see. How do we fetch the existing memory? We would do file get contents. And yeah, again, for the series, we're assuming a Laravel project like this agent we build lives within the context of a Laravel project. So we would have access to things like storage path. But of course, if we're building a general purpose agent, we would never want to use
But of course, if we're building a general purpose agent, we would never want to use something like this. Instead, just use basic PGP helper functions, and maybe we could write this memory to like a temporary file on your system or a dot folder. In this case, it's fine though. And we'll say, how about something like in the storage directory agents, or how about Larry memory?
about Larry memory? Yep, and that should do it. That would return a string. Now if the file does not exist, it will return false. So we could do like does the file exist, or we could just swallow this kind of down and dirty, but we could swallow any warnings and then just return an empty string either way. Yeah, if you don't want to do this, then check if the file exists first before
either way. Yeah, if you don't want to do this, then check if the file exists first before we're turning it. Okay. That's how we fetch. And then for update, of course, we would do file, put the contents in this case . Storage path, Larry memory, of course, we could extract that entirely. And this is going to be updated with the new memory.
Storage path, Larry memory, of course, we could extract that entirely. And this is going to be updated with the new memory. And maybe just to be careful, we should lock it. I don't think, I don't think there's a case where, let's just do it to be safe. We're going to lock it while we're updating. That way two calls can't update the files simultaneously. All right. So there's your memory store. It's about as basic as we could possibly get. The only thing we might want to do here is this could be a constant or a method
It's about as basic as we could possibly get. The only thing we might want to do here is this could be a constant or a method . I'm just going to make it a quick method. Yeah, now we have a single method that points to the path to where our store is . All right, let's go back to our tool. All right. So we fetch the existing memory, we make an AI call to update that memory that will return
So we fetch the existing memory, we make an AI call to update that memory that will return the updated memory or the refreshed memory. And then we call update on our store to basically overwrite that file with the new memory. And then we return the fact that was remembered. Now actually on this note, one thing is we're just assuming that we've remembered a fact. So what about the situation where we didn't remember because it was already included?
So what about the situation where we didn't remember because it was already included? Maybe what we could do is up here, we could say, well, if the refreshed memory equals the original memory, then nothing was already changed. Yeah, fact already known, otherwise we can update the store and say this new fact was remembered. And this is kind of brittle, maybe we should trim it, but it's okay. It's good enough for a video.
And this is kind of brittle, maybe we should trim it, but it's okay. It's good enough for a video. All right, so we have our tool, yeah, it'll do the trick. So now think about it, let's switch back to our chatbot agent. We have this list of tools, but here's a cliffhanger. We now have a situation where we can have child agents, but they must now declare basic functionality. It's basic tools that really should be available to any agent. Ideally, this should be results for only tools that are very uniquely related
It's basic tools that really should be available to any agent. Ideally, this should be results for only tools that are very uniquely related to this agent. Otherwise, it should inherit list files and read file and memory. Otherwise, yeah, think about it. As soon as I use our dumb little grammar assistant agent here, well, this agent does not have access to those tools, so it's not going to work. So yeah, in the next episode, why don't we figure out a way to update agents to include
So yeah, in the next episode, why don't we figure out a way to update agents to include a set of default tools that we then load whenever we interact with the AI. I'll show you how to do that in the next episode.
