Autonomous AI Agent in Python from Scratch (ChatGPT Function Calling)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hi there in today's video I will show you how you can create your own autonomous AI agent using python now I have created my own AI agent previously which is called GPT autopilot and this can write files to the file system and read files and do all kinds of cool stuff and you can use it to create full coding projects by just prompting chat gbt but we are not going to implement this fully in today's video because this is too much code to go over in a video but the basic functionality for an AI agent using the function calling of the openai API it's fairly simple so we will go through that in today's video so let's get started right away so the first thing we will do is we will just create a new file let's call this agent dot pi and in the agent dot Pi we will import open AI which is the official library for the open AI API and to use use this you have to run pip install open Ai and if you have this already but you have the old version you have to say upgrade to upgrade the latest version because only that one supports the function calling but I have that installed already so I'm not going to do that next we have to define the open AI API key so that we are going to do by saying openai dot API key equals and then you can just paste in your API key here or you can read it from a file or you can read it from the environment variables I will read it from the environment variables right now if I remember how to do it I do not it's something like OS end or get end of something like this open AI API key and then of course we have to import OS but this is probably not the right way let's do Python 3 and import OS and print OS get and open AI API key okay maybe it is get end so we'll use get n and then I will export it here export open AI API key equals and I will paste in my open air API key here and then I will have it there so you will not see it all right I have done that now so I should have the API key here and then how we send a message to chat GPT is we say open AI dot chat completion dot create and here we have to pass in the message sorry messages which will be some array of messages which we will Define next and we have to set the model so we will use the GPT 3.5 turbo 0613 because we have to use this version if we want to use the function calling API and then to send the actual function definitions we have to say functions equals functions which again will be an array which I will Define soon and we have to say function call is auto now this can also be a specific name of a function if you wanted to call a specific function every time and sorry it is not actually just the name of the function then it has to be like a dict of the name will be the function name and you will have arguments which will be maybe a list I'm not sure Arc one and so on just the name of the arguments that you have to pass in it but we will use Auto because we want chatgpt to decide which function it is going to call and then the way you get your response from this you have to actually set this to response equals that and then you will have something in there I will just print that response for now because I don't remember this like something like choices zero message content something like this but I don't quite remember so I will just print the response and we will see what is in there now we have to Define these messages and functions so let's do that let's say here messages is a list and it's a list of dicts so we will have to put here the role of the message which we will set to user and the content of the message which we'll set to something so for now let's hard code this let's just say tell me three jokes so we will send this message to chat gbt and then we will Define the functions so if we say functions equals a dictionary and this will sorry it will be at least again of a dictionary which will have a name which will be the function name so in this case when we want some jokes then we could make a joke function so let's do tell jokes and we will give a description and it will be tell jokes to the user and then we will have parameters which will be an object or addict in Python and it will have properties it will actually have type object and it will be properties and here we will have all the parameters that the function tell jokes takes so this will take a parameter of chokes and it will have a type of list sorry it is an array in this case because this is according to the Json schema and then when we have an array we have to define the items so what are the types of the items that we will pass in this array and what we will pass in here is a string so we again have to say type is string and then we have to also set required and this is a list of all the required parameters so if we have multiple parameters here then we might want to say that only some of them are required so in this case we say jokes is required so what this does is this tells the activity okay you can call the tell jokes function which tells jokes to the user and you can pass in a jokes parameter which will be an array of strings so they will be the jokes and in fact I can add here a description of this description and it is going to be an array of jokes and now if we run this code then hopefully the answer from chat TPT will be please call tell jokes with an array of three jokes so let's see if that works so let's run Python 3 agent dot pi and here is our response so we have choices zero message function core name tell jokes arguments jokes why don't scientists just atoms because they make up everything why couldn't the leopard play hide and seek because he was always spotted why don't skeletons fight each other they don't have the guts so it worked just as we expect now in order to parse these arguments from here we have to use the Json parser so let's first see how can we get the actual message so let's say that the message will be response choices index 0 and message that will be the message and then in the message we will have the role the content and perhaps a function call if it is a function call so then we can say this if function call in message that means we had a function call that means just dpd wants to call a function then we can get the name of the function so we can say that the function to call or just call it function call equals message function call and then we can get the name and the arguments so we can say function name equals function call name and function or just arguments arguments equals function call arguments now this is a Json string so we can directly get the jokes from here so we have to call Json dot dumps sorry Json dot Json dot loads so we will convert it into a dictionary and then there are multiple different ways of calling a function now you can do it something like there's some Global function and then you can get the function name and then you can call star star arguments but this is a bit dangerous because you can call any Global function so how I did this in my GPT autopilot which might still not be the best way is that I created another module so I will create here GPT function turns dot pi and I will Define all the functions here so then I can say if has Adder I think this is the way to do it if GPT functions has the attribute of function name then we will call GPT functions to be S here and this is probably get atter function name and then we do this star star arguments to unpack or whatever the right word is to take this Json object and take all the keys and the values and pass them into the arguments of this function and then we're going to add an else here and we can just print error called unknown function because this activity can actually do this sometimes it calls a function that doesn't exist so now we can Define the function in rgbt functions so let's go here and let's define tell jokes which takes the chokes and then from here we need to return something that we will then pass to chat gbt so it will be the answer from this so this can be Json data but it can be just a string it doesn't really matter and in my GPT all the part I just return a string just a message so I'll just return from here thanks for the jokes and this is just a message that then will be passed to captivity so that it knows that the function was called and we have to import now our GPT functions module and we have to import Json so we can actually parse the Json and then since we are returning something from the function we can set that to the function response and then what we can do is we can say Well for now let's just print and see what is the function response so print function response and I will print this response from the activity up here now I'm not quite sure about this syntax because this is all new to me I'm not really a python developer but I think it's something like this now you should handle errors here as well because not only the function name can be hallucinated by chat CPT the arguments can be invalid Json so in fact already this you should add like try here and then accept and if you get an exception then you can say that the function response is error invalid arguments and then you could pass this to chat GPD so it knows that it was called but right now I will just print this and I'll actually just do sys dot exit one and I'll do the same here and I have to import this so we'll just exit the script right now if something goes wrong so now if we run this and assuming I didn't make any mistakes then it should return the same thing as before but also thanks for the jokes so let's run this and see what happens okay we got an error GPT functions has no attribute get actor so I will check how I did it in my gbt autopilot project so I will go to chatgpt.pi and where is my arguments sorry it is in gbt autopilot dot pi okay get at your GPD functions okay it's that way so it is not a method it is a function so I will have to do it this way get Adder from get Adder from gbd functions the functionally so that is the right way of doing it so let's run this again and see if this works this time yes we got thanks for the jokes now if you didn't already understand what these arguments thing does here in this Json loads then let me remove this response printing here and now if I go to that tell jokes function and if I print here the jokes then perhaps you understand that the jokes from the activity will be passed into this actual function so if I run this then I will only get the array of jokes or list of jokes and thanks for the jokes so this is an actual python array python list of jokes so it will always be in the correct format so it's easy to do something with it because if you just ask chat GB to tell you three jokes they might be like comma separated or one per line or in a list or in a table or whatever but this is always in the right format now how do you make this an AI agent right now it is an agent that can tell jokes but it is not really an agent and it is not autonomous so we should be able to tell it to do something because now we are just setting it here tell three jokes so how can we make it so that we can ask it to do something it will do it and then we can adequately do something else well we need a loop and it is beneficial for us to create a function first from this because now all of this is just procedural so let's define a function and let's call this run conversation and now what do we need in here we need the message that the user sent but we also need to keep track of the messages because we want to keep them in the history so that you can refer to something else that has happened in the past and if you want to tell it to do something that involves multiple functions then it has to remember what functions it has called already so let's pass in the message and messages and let's move all this stuff in there so we'll do that and the messages will be moved outside and in fact since we have a message then this will be the message so we will say message is that and messages is empty because there's nothing at first now we could add a system message which we will do but not at the moment and we can actually set the messages to be an empty list in the beginning and now we could move these function definitions into the GPT functions file so we don't have to have them here so we can just then say GPT functions. let's call it definitions and then we can add them here so we have the actual functions and then we have definitions which will be that so now what we can do is first of all we have to add to the messages the latest message which we get from here which will be this so we will say that messages don't append message and then we send the request and we get the message and then we check if it's a function call then we do the function call and we get the function response and then how we respond to chat gbt from a function call is we do this let us in fact say that function response will be that here and function response will be that here and we probably could move this into its own function so it will be a little bit better so we will say that if there is a function call in the message then the function response will be parse function response from that message so this will simplify things a little bit so we can Define here parse function response which will take the message and then we will do all this stuff in here and then we can just return this return error invalid arguments and here we can also return the result from the function and here we can return error called unknown function so this way it's a bit easier to handle this because we don't have to then check down here do this only if we didn't get this error because now we just return it so that makes it more simple and then what we have to do here is we have to add the response to the messages so we will say that messages dot append and we will add a specific type of message for chat gbt which will have a row of function and we will have a name which will be the function name and the content which will be the response from the function so it will be the function response and then since chat GPT can answer without a function call then we could handle that case here so else what do we want to do then well we would want to tell the user that activity said something so we will just print GPT and we could add here the message called that and then we could ask the user to provide their next response to activity so we could make this like an input and we can say that the user message will be input gbt says that and a new line and you say this and then we can pass this user message to the messages so we will the same thing as with the function but this will be roll user and we don't have a name we have just a Content which will be the user message so if we get a function call we run the function and send it to chat gbt otherwise we show the user what chat typically said and ask for an answer back and then we send that answer back and then we have to make this function recursive so we will actually call it again so we'll send the messages and then go back here and call it again so let's do that let's say run conversation and now we will pass in the message actually so I will in fact do this message will be that and here I will also do message will be that we don't append it because we will append it here so we just pass one of these messages to the Run conversation function again and we pass the messages as well so this will include the message that we added here previously so then we can keep track of the messages all the time now we don't want to hard code this tell three jokes message so instead what we will do is we will go down here and we will add here this input again so we will say that user message is GPT and let's add here just what do you want to do and then we say that the message is role user and the user message and then we call run conversation with the message and we don't have to pass the messages because it will be empty at first by default so we would add something here to print print GPT called function and get there actually I should put it up here because I don't have the function name until I get here called function this and I will add here the function name and in here we are returning thanks for the chokes and we are printing the job so that's fine let's do this and let's see what happens now so if we now run this again it will say what do you want to do so we can say anything now I can just say hello and it should answer me with the regular chat DBT answer which will be how can I assist you today yes so it will answer me but if I say tell me three jokes then it will call the function hopefully okay it did call the function but we got some sort of error function name is not defined that's right because we parse it over here so let's make it a tuple so we can get both of them so let's take function name and function response and we will return here function name and this Earth there's not the best way to do this but but let's do it like this for now and this will be the same thing so we return the function name and the response and here we also say function name and response now this is a lot of duplication I really should have here like return function name and function response but then I'm back into this that I'm setting it here so I have to say function response is that but then I will have the problem that we shouldn't go into this if we have the function response already now I could move all of this up here but then if there is a error in this one we still go the same exception which might not be the worst thing but I might want to have a different error for the invalid Json and the invalid arguments but whatever let's do it like this so now we should always have function response whatever happens and then we return function name and function results and let's try to run this again tell me three jokes now what happened here is that we told jativity tell three jokes and then it called tell jokes function with these jokes and then we send back the response thanks for the chokes and then it responded sure here are three jokes for you now this is kind of weird and we are kind of doing this backwards because this really should be like get jokes so we could do this the opposite way so we could say get jokes and we could say that this is gets jokes from the choke database and then this could be number of jokes and we could pass this as the property or the parameter and the type will be number and we don't have the items here anymore and the description would be get the specified number of jokes and we might say that the required is number of jokes and then if we return jokes from this function then they will be passed to activity and then it will respond with those jokes so if I would then return from this Json dot dumps which will convert list into a Json string and I would add the jokes here so I would add some jokes from here let's just copy these and I'll paste them in here now we should return a specific number of jokes but for this example it doesn't matter we are returning these all the time and just to show that it actually uses the jokes we defined here and not some random jokes then we can change these default jokes because it usually returns always these jokes so if we just say all the things here instead of that and how did the computer get wasted and why don't skeletons fight other skeletons and we save this and then we run this again then what should happen now is if we say tell three jokes then it should return those three jokes so it will call the get jokes function and then it will okay something went wrong it just keeps getting the jokes get jokes gets jokes from the joke database let's print the messages here so we can actually see what we are sending tell three jokes okay invalid arguments so did I Define something wrong number of jokes number of jokes type number ah the error comes from my function because I did not import Json here and that that's kind of the problem with doing this catch-all exception because we don't know what exception comes from here so let's try this again and if we say tell three jokes then it should tell three jokes exactly so here what happened is we told tell three jokes so we sent that message to the activity and then chat DVD answered with get jokes and then we returned with these jokes and then chat gbd responded sure here are three jokes for you and these are our jokes why don't scientists trust atoms because they make up all the things and how did the computer get wasted it took screenshots and why don't skeletons fight other skeletons they don't have the guts so now we can give the activity some content of our own and it will format it in a nice way so now we could actually say something like put the jokes in a markdown table so now it could actually format this in a different way so now here we have a markdown table of the jokes and here it didn't call the function because it is already in the history but if I close this and I start over and I say put three jokes in a markdown table then it should call the get jokes again yes we called get jokes and then it will answer with a markdown formatted table like this so we have a joke heading and then we have all the jokes here and they are our jokes so now all there is left to do is just Implement different functions that chat TPT can do so let's do something like that so let's first remove our print statements from somewhere where did I put them here we won't print the messages anymore and we can go to our GPT functions and we can just add more functions to do something so in my GPT autopilot I created a write file function so that it can write to the file system so we could do that we could say Define write file and we get the file name and the code and then what we will do is we will just say with open file name in write mode as f f dot write content and then we can just return successfully written file file name and then we have to Define this in the definitions so we actually give chat GPT information about this function so we will call this write file just the same as it was here now you can use different names but then you just have to map them when the function call comes function activity so this is just an easy way so that you can Define it the same way but we will say that this will write to a file rights content to a file and then it will take the file name which will be a string of the file name to write to and then we can pass in also the content which will be the content to write to file and we have file name as required and content as required and that is all you need now we can write two files and when we can write defaults we can do all sorts of things so let's try this out now you need to be careful with this because it can write to any file right now so I will in fact add some question here so I will say sure is input do you want to write to file name and then if sure is yes and I'll add here yes or no and if the sure is yes then we do this and otherwise we will return something error you are not allowed to write to this file so now we have a question so we don't actually write to some bad file so if we run this now and we will say something like write a story about a man named Mike into Mike's story.txt then what we'll do is it will say call function write file do you want to write the file Mike story.txt and I'll say yes and then we will do that and it will probably answer something like okay I did that hopefully okay it did not answer with that so maybe I did something wrong but let's cancel this and let's see we actually have a mic store here so if we say code Mike's story then here we have a story about a man named Mike in my story.text now I wonder why it's called the right file function again perhaps gbd 3.5 is just a bit stupid so it needs a system message so let's do that we could initialize the system message in here to say if the messages is empty then we add a system message or we can just add it down here so we would pass in here the messages and we could say that messages is an array with a system message so we can say here role system and content will be you are an AI bot that can do everything using function calls when you are asked to do something use the function calls you have available and then respond with a message confirming what you have done so let's see if that will work and I might actually want to do something like with open messages.json w s f f dot right Json dumps messages so we can inspect messages.json afterwards and I will add indent 4. so it will be nicely formatted so we can see what messages we are sending if it does something weird so let's run this and say write uh well we could say write three jokes to a file called jokes dot text then it will call get choke function and then it will call write file function so it will call them sequentially and then I say yes I want to write to that file and then it should tell me what it has done now for some reason it does not do that so let's inspect what we have in the messages I'm probably sending something wrong so we have a system message we have a user message write three jokes and then we get the jokes and then we write file and where's the other one okay the problem is we are missing the call from chat gbt so we have only the result of the function we don't have the testibility calling the function so it thinks it didn't call it already so all I have to append the function somewhere pause function response yes so we have to append the message from chat gbt so this one to the messages so we have to say messages don't append message and then it will work so now if we close this and we run it again and we say write three jokes to a file called real jokes dot text then now it will do call function get jokes called function write file do you want to write the file realchoks.txt yes and then it will write it and then it says I have written three jokes to a file called real jokes dot text and then we can continue and if we take a look we should have here real jokes dot text and we have the jokes in here and now we should be able to ask it to do something like change the format of the file to be HTML so then it will probably change this and it should update automatically because vs code will update it when I say yes then actually it will make another file now so it made real jokes at HTML so if we open this then here we have some jokes in HTML format so now you can actually write code with this so I can say like create a JavaScript client side Shopping Cart app in index.html script.js and style.css and make it save the products to local storage and if we do that then it will do something it wants the right to index.html so I'll say yes and then it wants to write the script.js so we'll say yes and then we want to write to style.css and we will say yes I have created a JavaScript client-side Shopping Cart app in three files the products added to the shopping cart are saved to the local storage so let us see if we actually have done that so let's open the containing folder and let's open index.html and here we have a shopping cart app product one add to cart and it was added to cart now now it still says no items in cards so it doesn't work perfectly but we can add these things in here and it works and presumably if we refresh well it didn't work now since this is an AI agent and it remembers the history then we can say that you forgot to implement loading the products from local storage and then it hopefully understands that okay I have to update script.js to load the stuff from the logo storage and yes it wants to write the script.js I will say yes and it has written something the script.js and it says apologies for the oversight so if we refresh this now then now we have them here and we have some object object here because I have been playing around with my gbt autopilot and we probably have something in the local storage that is not supposed to be in there so I will remove everything and if I now add these things in here and I refresh they stay there so now it works and that's all you have to do and it took me one hour and seven minutes to create this so if you like this video give it a thumbs up and subscribe to my channel and let me know in the comments what do you want me to make this AI agent do next and then I will do it and if you want to play around with this code I will post it on my GitHub and you can go there and download it and try not to destroy everything on your machine with this thing anyway thanks for watching and I will see you in the next one
Info
Channel: Unconventional Coding
Views: 775
Rating: undefined out of 5
Keywords:
Id: 49zOSDZ65Y8
Channel Id: undefined
Length: 36min 55sec (2215 seconds)
Published: Fri Jul 07 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.