Transcription
Hello, katana. I have prepared absolutely bombastic material for you today. I highly recommend watching until the end for those who are involved in development, for those who professionally write software. So, a spoiler right away. We are not going to hype about the fact that artificial intelligence can write code, that it will supposedly, you know, change the world of development, software engineering, that it will relieve businesses of the need to hire programmers, blah-blah-blah. This is not what we are talking about at all. Behind all this hype, the emperor has no clothes, because those people who will professionally develop software, including with the help of large language models, oh my god, they will still be called programmers. It's just that to the necessity of mastering those, that knowledge and that technological stack that programmers have now, will be added the necessity of mastering one more tool and nothing more, dear friends. But, you know, uh, in the topic of artificial intelligence and large language models, there is something much more interesting, something much deeper and much more important, something that will truly change development and provide new opportunities. And these are iagents. What is this? So, to put it simply, an iagent is a system based on a large language model that is capable of solving a task on its own, interacting with the external world, and making decisions independently. That is, there is a model that understands human language. It's a bit dumb, but it understands human language and has some basic knowledge about the world, about the fact that the Earth is round, and functions in Python are defined using the `def` keyword. We give this model specific tools to solve our task. That is, essentially, we give it the ability to call our specific code, which we will provide to this model. And the model, pay attention, decides for itself when to call our code and what parameters to pass to this code. What arguments to pass to our function? Once again, it's no longer us writing `if else` to determine which function to call, but the model itself makes the decision and calls the right function with the right parameters at the right moment. Imagine that this, in fact, is a huge paradigm shift. And this is something that is already working now. I will further show how it works and how to use it in practice. But let's try to comprehend what is actually happening, what this paradigm shift actually gives, and whether it is a paradigm shift at all. Yes, essentially, what are the programs that we have been writing until recently, for the last 80 years. According to various sources, the first program was written and executed on a computer either in 1943, 1943, or in 1944. Well, 80 years. The very first program that was written was written in the 10th century, by Lovelace, but there was nowhere to execute this program, so we take programs that were written and executed, yes, that's 80 years of programming. And essentially, for these 80 years, we have been writing programs that are not so different from each other. All these programs are built on three basic capabilities, right? Capability one is the ability to store and modify data. That is, we want to be able to write something into a memory cell, read something from it, and change what is stored there, right? Capability two is to make logical branching. That is, `if else`. If a condition is met, we call one piece of code. If a condition is not met, we call another piece of code. Logical branching. And capability three is the ability to repeat logic, for example, through loops, through `goto`, or any other means. And that's it. This is enough. These three very simple capabilities are enough to write any algorithmizable task, right? That is, any programming language that provides these capabilities is a Turing-complete programming language and allows the implementation of any algorithmic task. There are no complex data types here, as you may notice, right? There are no complex data structures, no functions, no object-oriented programming, no, you know, nice syntactic sugar, right? But, using these three basic capabilities, everything that can be solved algorithmically can be implemented using these three basic capabilities. That is, you can write any little program, right? Of course, more high-level, more convenient programming languages have been created, on which you can write faster, right? On which it is easier to develop programs, on which many features are already implemented, all necessary libraries are connected, right? There is a large amount of syntactic sugar, but internally all this is implemented and all this is based on these three very basic capabilities: the ability to store and modify data in memory, the ability to make logical branching, and the ability to repeat logic, for example, through loops or by other similar means through `goto` and so on, right? And what can the appearance of large language models change in this entire model? In fact, it can change a lot, dear friends, it can change a lot. We have essentially acquired a dummy that understands ordinary human language. I use the word "understands" in context, of course, for a large language model. It's just important to understand again what a large language model is. A large language model is an advanced text auto-completion mechanism. "Advanced" is a nine. Okay, this is a crude analogy, but let's use it anyway, right? A large language model, LLM, is a tool that selects the most relevant next word, then selects the most relevant next word, then the next word, and so on. Yes, of course, taking semantics into account, yes, LLM tokens are not exactly words. Yes, of course, there are many caveats, but in general, it's roughly like that. It's just selecting the most relevant next text based on the previous text. So, with these caveats, let's say that an LLM understands ordinary human language in Russian or English. Yes, it's like a child who is not very good at some complex activity, but they understand you when you tell them, "Please, my friend, give me a fork" or "close the door" or ask how they are doing, they will understand you, and they will be able to interpret your words correctly and do what you ask. And with more complex things, you can ask them to call you, you understand? That is, if a child doesn't know how to do something, you can tell them: "My friend, when you need this, please call me, and I will come and do it." Do you understand? And this "call me" can be a call to your code, any arbitrary code in any programming language, for example, in Python. And this code can do anything, right? The model will know about the existence of this code. You explain in the comments to this code, literally in the docstring, what this code does, what this code takes as input, what this code outputs. And the model understands this information because it understands ordinary human language, right? And then the model will request the necessary data itself. Again, it can request it from the user in the chat, it can request it from your other Python function, without any problem, right? And at the right moment, it will call your Python code, pass the necessary arguments to it, and solve the task that you are setting for this system. That is, you can literally write, for example, in Python or, in fact, as I repeat, in any other programming language, code that does something, what you need, exactly according to the algorithms that have existed for 80 years, with the same `ifs`, data storage, modification, and loops. And this function takes some arguments as input. They can be of complex types. It can be some nested data class. This function can return something, something complex too, also some data classes with some data structure, and so on. And the model will understand all this, and it will know when it is necessary to call your code, with what arguments it is necessary to call your code, and will do it. Yes. And what does this mean then? It means that, if you think about it a little, it means that you are no longer the one branching the logic with `if else` in your wonderful programming language, but the model itself branches the logic within itself, the model itself makes the decision about what to do, right? Ask for missing data from you or from some other Python function, clarify something, go somewhere for data, collect the necessary data to call your code. And it will call your code when it is necessary. Yes. So, uh, I will now show how this works in practice. I am an entrepreneur and I often need to prepare accounting documents, invoices, acts, reports for various clients, and so on. I don't consider it right for myself to hire assistants on staff for such tasks yet. I'm not sure if I can load an assistant for 40 hours a week, but someone has to do these tasks, and I'm doing them now. It's not rocket science, but it's quite tedious and boring. And I thought, what if I write an iagent that will help me do this? How does it happen? So, someone sends me their details by email, and I need to issue, for example, an invoice for payment or prepare an act of work performed based on these details. Yes, the details are sent in different formats. Sometimes it's a PDF document, sometimes it's a Word document, sometimes it's an Excel file, sometimes the details are just written in the text of the email. And all this in different formats. somewhere in a table, somewhere as text, somewhere comma-separated, generally in complete chaos. And I need to, accordingly, manually select different pieces of these details from there, cut them out of this document, and insert them into my template for an invoice, act, or any other document, and at the end, assemble a PDF, and send this PDF somewhere. I thought, why don't I create an iagent for this task, so that it can independently extract the details from this arbitrary document, pass them to my Python function, and my Python function generates a PDF. Here, of course, it's possible to have the language model itself generate the PDF. But, firstly, I want to control this process, so that only my template is used. And secondly, I want to control my details. I want my details to be correct. If I issue, for example, an invoice for payment, then I want to be sure that in the final document, which I will send somewhere, my details will be strictly correct, because, well, a model is still a model, right? And it's a probabilistic thing. It can make a mistake somewhere, right? If it makes a mistake in the counterparty's details, well, there won't be a big problem, right? But I want my details to be accurate, right? Therefore, I want my function to generate the PDF. My function will take the counterparty's details as input and will generate a beautiful, wonderful PDF with my correct details and the counterparty's details, which it received from the large language model. And as the model, I decided to use Sber's GigaChat. OpenAI models don't want to process requests from Russian APIs even on paid accounts. And I don't want to solve this problem by messing with VPNs, proxies, and so on. Well, and of course, I was interested if a Russian model could handle this task. Those who are already reaching out: "I see everything, I see everything, damn it, you're trying to write that this is an advertisement." Yes, of course, guys, this is an advertisement. Well, damn it, what did you expect? I'm going to make a lot of money from this video. Yes, this is Sber's advertisement, of course. This is an advertisement. So, what do we have here? Huawei, right? Here's an advertisement for Huawei. So, here's another advertisement for Huawei. Pay attention, right? This is Huawei. So, here I have an advertisement for Huawei too, of course. So, what else do we have? Advertisement, advertisement for Woop, a brand of bracelets, advertisement for Pineray. So, advertisement for Logitech, right? Advertisement for this Henderson. Advertisement for Henderson. Well, I also talk about Python in almost every video. Guido van Rossum, of course, also pays me for this. That's why, uh, envy, envy. Silently, dear friends. Here. Although, in reality, if you're interested in how this happens in practice, I spent several days developing this video and will earn exactly 0 rubles and 0 kopecks from it. I'm recording it now on Saturday, midnight, by the way, well, it's 23:59 now, right? Therefore, accusations of advertising are always, so to speak, very pleasant to me. Here, guys, One love. One love. Yes, in reality, a big sincere thank you to those who buy training, educational programs from me. I have a course called hardcore web development. And those who come to study there, guys, this is all thanks to you. Thank you very much. Yes, the link is in the description of this video. You can also take a look, maybe it will interest you. Well, so, by the way, about GigaChat. It is the only purely Russian trained model at the moment. Well, at least, as far as I've Googled and studied, right? It used to be called RU GPT, and now it's called GigaChat. And it was trained on Sber's supercomputer Christofari, unexpectedly, which is named after the first owner of a savings book in the 19th century, right? Yandex GPT version 5, it seems, uses N in some capacity, right? Tinkoff's model also seems to be on Quanta. There's some LLM from MTS, it seems to be their own, but I understood that it's not sold externally, it's used internally in some of their own tools. There's also VK, which made its own LLM last year, but I understood that they don't publish it either and use it internally for some tasks. I don't have much information about them. So, let's use GigaChat. Let's create an iagent that will cheerfully and energetically solve the task of creating accounting documents according to my template by calling my code. So, we will use GigaChat with their advanced model, GigaChat 2 Max. This is the current, most powerful model from GigaChat at the moment, around mid-May. After registration, you get 50,000 tokens for free. Then you can buy a million tokens for 1,950 rubles. For the development and testing of the initial version, the first free 50,000 tokens were enough for me, but then I bought a package for further use. So, all the source code is on GitHub for what I got. The link is, of course, in the description. You can look at it right away. And I will show you more or less step-by-step how I did it. It's interesting. We create a directory, navigate into it. We do `uv init venv .` and `git init`. Initialization has occurred, including the Git repository. In the new version of `uv`, for some reason, you now need to pass `vcs git` to initialize the Git repository as well. Well, okay. We immediately add the necessary packages: `langchain`, `langchain-gigachat`, `langgraph`, and `python-dotenv`. To receive confidential data from environment variables. We open `main.py` and add the necessary imports here. So, let's activate the virtual environment immediately so that my VS Code picks everything up. Excellent. So, here are the necessary imports that we will use in our development process. We load environment variables and create the GigaChat model. We take the most powerful model, GigaChat 2 Max. Nicely done. Also, let's create a `.env` file and insert the credentials for GigaChat into it, i.e., the API key. I named it `gigachat_credentials`, and here we insert your wonderful key. On the right here, by the way, is the act that we should get as a result, right? So, here the customer is inserted, which is taken from the counterparty's details, right? All these are the counterparty's details, who signs this thing. And my details, they are hardcoded into the template of this document. And here there can be one or more lines with works. Accordingly, the entire cost is summed up and finally written at the end of this document. Next, we need to create a function that takes the counterparty's details as input and creates a PDF file as output, saving it somewhere on disk. So, I will create the PDF with the `typst` tool. This is a modern replacement for LaTeX. I will talk about it in more detail in a separate video. It's a great tool. I really liked it for typesetting and layout. Yes, of course, all this can be done with pure Python libraries, like `reportlab`, `fpdf`, and a huge number of other libraries for working with PDFs. But it's more convenient for me to use `typst` for this task now, so I will use `typst`. Therefore, here I create a `typst` directory. In the `typst` directory, I will have several documents. Well, let me show you what's in that directory. The main thing is `act.typ`, right? This is the document template according to which the PDF will be created. This PDF consumes data from a JSON object. And the task of my Python function will be to assemble this JSON object. Something like this, well, essentially, just a JSON with the counterparty's data and their bank details. Yes. Well, one more library written in `typst` is used here, because `typst` even has a built-in scripting programming language, unexpectedly. So, this is regarding `typst`. Next, for our wonderful function to work, let's create data classes, a data structure. Yes, we have bank details. Bank details have a bank name. Here you go. Yes, for Sberbank, there's BIC, there's a settlement account, a correspondent account. There's `customer` - this is our counterparty, right? They have a name, full legal name, OGRN, signatory, and bank. This is also a data class, nested, according to the corresponding bank structure. Yes. And there's `job`. There can be several `jobs`, right? These are the projects that we include in the invoice or act. Well, in this case, we are preparing, preparing the creation of an act. Let's sketch out a basic function that will generate these PDFs for us in the future. I call it `generate_pdf_act`. Of course, the function name should be understandable, so that the model can understand it too, right? The function takes `customer` of type `Customer` as input, and the model will also understand this, of course, because it will call this function, and it should understand what needs to be passed to it as input, right? And it takes a list of `jobs` for forming this table with works. It doesn't return anything. And pay attention, in the comment, I write everything here, right? Generates a PDF act with filled-in client data, their bank details, and also completed tasks. And what arguments of what types, what it returns. And here for now, it's just a print, right? Later, we will implement the call to the necessary logic. Now, let's make it so that the model calls our function right now, and we can verify this through this wonderful print. To do this, I've put together this code: the `LLMAgent` class, the `main` function, which communicates with the LLM agent. And here it is launched. We'll look at how this code works a little later. And now, let's just check its operation, dear friends. Yes, it also needs the `requisites_file` variable. This is a file where the wonderful details are located. Yes, I have uploaded this file. Requisites for PAO MTS. Let me show you what this file looks like. I'll open this wonderful document. This is what the file looks like, right? This is a regular Word document with PAO MTS details. They bought my course. And, accordingly, I have this file with their details. I'm preparing an act for them now. Well, I was preparing an act when I was developing this system. Yes, great. So, let's call this thing. `python main.py`. `python main.py`. Hoppah. Ah, `requisites_file`, of course, yes, it needs to be specified. The file with the details is specified, and we call it. The LLM tells us: "Please specify what works need to be included in the act. Write the names of the tasks and their cost." Well, let's write. CRM system development 200. Well, let's say 2.5 million. Let's write it like this. Like this. And our function was called. Pay attention. That is, this `print(generate_pdf_act)` is called from our wonderful function that we wrote here. Here it is, please. Here, this print worked. That is, now the LLM called our `generate_pdf_act` function, which we wrote here. Here it is, please. Notice, it was called with these arguments, right? That is, a data class of the correct structure was passed, right? That is, it really read the Word file that I showed you, and really extracted all the correct details from there for Mobile TeleSystems, the address, right? All the bank details, and so on. And here are my details, which I provided here. CRM system development, price 2.5 million. It correctly selected everything from there. Let's exit from here with Ctrl+C. The program even prints "Goodbye." What a polite, good program, right? And let's look in more detail at the code I put together. Well, the entry point to the program is `if __name__ == "__main__":`, right? The main function is `main`. Let's go into it. The model, by the way, doesn't need to be created at the top anymore. That's an old version. So, here the `system_prompt` is set, the system prompt. That is, this is the prompt with which our thing is launched, right? Your task is to generate an act. To do this, you need to get the counterparty's details from the attached file, and also request the works to be included in the act, the name of the tasks, their cost. There can be several works. Do not invent any data. Strictly request everything necessary from the user. Shorten the first and middle name of the signatory to one letter, for example, Ivanov AE. Enclose the company name in quotation marks like "fir-tree", for example, OOO Horns and Hooves. That is, put an opening "fir-tree" before the company name and a closing "fir-tree" after the name. The model is the same as we created before, right? GigaChat 2 Max. The model, in principle, can be any, right? That is, the `Langchain` tool is used here, right? And there can be OpenAI, and others. All of them have APIs and connectors to this `Langchain` tool. So, here our `LLMAgent` class is created. Let's dive into it, see what's happening here, right? It takes the model and `tools` as input. What are `tools`? `Tools` are the instruments that we give to the model to perform our tasks. In this case, we give one tool, `generate_pdf_act`, that is, the function that generates a PDF, but for now, it just prints. Later, we will implement the actual generation, it's not difficult. It's already clear how it works, right? So, this `LLMAgent` class saves the model internally, creates an agent using the built-in function in `LangGraph`, `create_react_agent`, passes the model to it, passes the `tools`, and passes `checkpoint` so that all messages in this chat are saved. In this case, they are saved in memory. For production use, of course, you need to save the context, i.e., the communication history in a specific chat, somewhere in PostgreSQL. Again, there are connectors for saving history in PostgreSQL. All this can be used without problems. And in the `config`, which will be passed further in the chat, the identifier of this chat is passed, right? Because for the model to use previous communication in this chat, it needs access to this communication, and specifically to this communication, not some other, right? Therefore, each communication, each chat, right, that you create in the web interface for working with the model, which you have surely seen, these interfaces, right, in ChatGPT and so on, each chat has its own identifier. In this case, with each output, a UUID of version 4 is generated. And within the scope of this session, i.e., within the execution of this script, this identifier will be the same, because it is saved here in `self.config`. This LLM agent has several methods, well, essentially only two methods, right? Method one: `upload_file`, that is, uploads a file from a local computer to the LLM model, in this case, to GigaChat. And `invoke` is a call to the API to get a response, that is, sending a message to the chat and receiving a response, right? The `invoke` function creates a message, and optional attachments are passed to this message if they exist. The role is `user`, from whom the message is sent, right? And `content` is the content that we ask the model to send. It returns the message and as a string, right? It returns it externally. A completely simple, elementary class, right? Accordingly, we set the system prompt in the main function, created the model, initialized the agent, uploaded the file, right, which I showed you earlier, right? This is a Word document, `requisites_file`. And then we call it, pass the system prompt with this file to this model. And the model answers us, saying, "Please enter the details," right? And then `while True`, we have communication with the chat. Moreover, this communication can be anything. That is, we can, in principle, create an act, and then ask something else, right? And, well, yes, this communication will take into account previous communications. That is, the first message about preparing the act, it can have some influence on future communication, but what I mean is that this is a regular LLM, GigaChat, and we can communicate, in general, on other topics as well. That's why the chat is implemented here as an infinite loop. As long as we don't exit with Ctrl+C from the chat, everything will work, and we can continue communication with this wonderful chat. Also, the temperature is set somewhere here, right? The default temperature is 0.1. So, to make the model fantasize more, you need to set a higher temperature. To make the model
It provided more deterministic answers; to achieve this, smaller values should be set, for example, 0.1. In this case, I don't want it to fantasize; yes, I want the answers to be as deterministic as possible, so I set a small temperature of 01. So, well, that's pretty much it. Let's implement the `generate_act` function now. Here's its implementation, which is quite simple, right? We simply, you know, form a JSON. We write the JSON to `filter.json`. This JSON contains the counterparty's data and their bank details. And then we simply call `types` via `subprocess` for compilation, meaning for generating the PDF document. And, well, that's it, we have a PDF document. Yes, let's, let's run this whole thing again, and see, let's see how it will work. Please specify what work needs to be included in the act. Specify the names of the tasks and their cost. Well, let's say, ERP system development. Let's write it like this. 2 million rubles. Okay. And let me open the PDF file that was generated right here. It's located in the `types` directory. Note, ERP system development, 2 million rubles. Total cost of work, 2 million rubles. Everything works perfectly as we intended. But, dear friends, this is an LLM, and in reality, we can use it in a more complex way. Yes, add another project for 1.5 million rubles. Telephony system refinement. Let's see how the model handles this. On the right, we will have the updated PDF document because it will be saved here as well. Note, telephony system refinement, 1.5 million rubles. It understood that 1.5 million is this much, right? And everything is calculated correctly here. 3.5 million. Everything works wonderfully. Remove the first, the first job from the act, right? The first job is ERP system development. The second job is telephony system refinement. Let's see how the model handles this. It handled it wonderfully, right? Telephony system refinement. Change the cost of the work to, it's currently one and a half million, to one million. Let's write it like this. Change the cost of the work to one million. Will the model understand us or not? Note, it understood us. It was one and a half million, now it's one million. Yes, and this all, like, works. This is how simply everything works. Dear friends, imagine, imagine, say it's cool. Say it's cool. And these are precisely the capabilities that an LLM gives us, right? The ability to understand ordinary human speech and, at the right moment, call our code that performs our necessary tasks with the correct parameters, which the model took from the user or from another Python function of ours. Imagine, imagine, and this is what truly inspires me, this is truly a paradigm shift. This truly offers new possibilities because we don't write if-else statements; the model makes the decision when to call our code, with what parameters, and it does it. And it does it very beautifully. When I created this thing, I thought about the possibilities it offers and considered the following: why not ask the agent to find the details file itself? Because now I give this file to it myself, right, it's on my disk, I provide the path to this file, and consequently, the model doesn't have a question about where to get the details. I directly ask, get the details from the file, right, but the details are somewhere in my email. What if we ask the model to go to my email, to my mailbox, right, and find the details there? Exactly like that. Find the details there for generating the act. I set myself this task and thought about how to do it. Yes, what is needed for this? For this, we need to write two additional functions. Function one. This is a Python function that will go to my mailbox, retrieve emails from my mailbox for a certain number of recent days, and return them as a list of data classes. This data class will contain, accordingly, the necessary data for each email, right, the subject, the email text, and the attachments. All attachments need to be downloaded to your local computer, where this Python code is executed. And the path to this file also needs to be returned in this data class, right? And we need to implement another tool, another Python function, that uploads a file from a local computer to the servers of a large language model, right? So, we need to add two more tools. Right now, we have one tool that we pass to our AI agent. This tool generates a PDF act. So, we need to create two more tools. One tool will go to the email, retrieve emails, and the second tool will upload some attachment to the large language model servers. Let's do it. I'll show you how it works. What have I done here? I've added the `mail.py` file. This is a file responsible for email communication. So, what's happening here? We have `imaplib` and `imap.yandex.com`. These are not needed. I used them for debugging. All this can be removed. So, we have the `Email` data class. A list of these data classes will be returned from our function that retrieves the email, right? We have `subject`, `body`, `attachments`, a list of local `filenames`, and the `date` of the email. Here are a few utility functions for working with dates on the server, right? A few exceptions, again, clearly named. `Incorrect variables`. Environment variables are used here to get, you know, the credentials for the email, right? They are not passed as input to this function because this function needs to know this data internally. Or you can simply set them here using variables, or simply retrieve this data within the function, right? An empty `emails` array is created. And so, we just go, basically, to the email and for the specified number of days passed into the function, right, here it's set to 3, so for these 3 days or for these 4 days, 5 days, with whatever parameter we call this function, we retrieve the emails, and they are simply returned, right? We form an `emails` array, in which we add an email, right, `subject`, `body`, `attachments`, and `date`. And we return these emails. This is regarding, you know, this `mail.py` file. From this `mail.py` file, `fetch_recent_emails`. Yes, load recent emails here. And, note, we were passing one tool to the agent, `generate_pdf_act`, and now we are passing two additional tools. Yes, the first tool is `fetch_recent_emails`, for getting the latest messages from the email. And the second tool is `upload_email_attachment_file_to_llm`, for uploading a file to, you know, the LLM. Moreover, the files that are uploaded to the LLM, I print them here to see which files will be uploaded to the LLM, because there are actually several attachments. There are actually several attachments. Dear friends, well, basically, yes, let's print this out too, so you can be convinced. Well, here in `mail.py`, when we have a `filename`, I will print it, that we have such an attachment, just so we can see how many attachments there are in the email, and compare it with the files that the model decides to upload. This is interesting. This is interesting, how it will work. We have also changed the prompt here, of course. I have commented out the old prompt. It can be used. So, the new system prompt, right? Your task is to generate an act. To do this, you need to find the company's details, the counterparty's details in my email. They can be in the email text or in an attached file. Do not search for or request my details; they are in my code. For the act, you need to request the work, the names of the tasks, and their cost. There can be multiple jobs. Do not invent any data. Strictly request everything necessary from the user. The name and patronymic of the signatory. Similarly, shorten to one letter. Enclose the company name in curly quotes. Well, basically, as it was before. And, well, that's it. And, well, that's it. So, we've just added, added two tools, slightly changed the system prompt, and that's it. Let's see how this will work. I've closed the PDF for now. First, I need to get access to your email to extract the necessary counterparty company details. Specify the number, please specify for how many recent days you need to view the email, and also tell me what specific work. Ah, 4 days. Ah, 4 days, and work. Ah, for example, ERP system creation, 3 million rubles. Hopa! Let's see. Ah, 4 days specified, right? 17 emails found in the last 4 days. It understands that there are several attachments here, one, two, three, and it uploads them to itself. Note, it uploads only the file with the details. This picture file it does not upload, meaning it understands that in this email, there are likely details, right, and it uploads only this file with the details for analysis, right? Let's, let's open it and see what kind of PDF it generated. Hopa! Yes, ERP system creation, 3 million rubles. Yes, everything is absolutely magnificent, dear friends. However, dear friends, I see that the details here are incorrect. The signatory is Ivanov, but the signatory is not Ivanov in the details file, and for some reason, Unicredit Bank is shown, not Unicredit Bank. So, we see a classic hallucination problem here. A classic hallucination problem. Therefore, we need to, you know, clarify to the model that it should not invent details under any circumstances. It should strictly take details only from the file in the email. So, basically, right at the moment of recording, we caught a hallucination. The model had incorrect details, which the model simply made up, right? The surname and patronymic of its signatory were incorrect, and so on. Basically, I've now studied it and realized that if many actions occur within one AI agent, meaning within one agent, searching for an email, uploading that email to the model's servers, analyzing the details from that email, from that uploaded file, right, and generating a PDF act, then the model starts to hallucinate. I couldn't find a prompt that would solve this task within a single AI agent. Therefore, I simply broke the task into two AI agents that work sequentially. The task of the first AI agent is to find the file with the details in the email, and the task of the second agent is to generate the correct act with the details taken from the local file, and the second agent knows nothing about where this file came from. And in this configuration, it works wonderfully, dear friends. Ha, basically, how it works, right? We have the first agent, its prompt is this: Your task is to find a file containing company details in one of the emails. Find the name of this file in your email and output it as the answer. In the answer, only the filename or the word "no" if not found. Accordingly, the model is exactly the same. We create the first agent. It has access to only one tool. This is `fetch_recent_emails`, right? Meaning, just downloading the latest emails. It doesn't even get the ability to download any file for analysis. It just looks at emails and searches for details based on them. We get the answer and save it immediately to `filename`, because we asked the model to respond either with the filename or the word "no" if not found. If, accordingly, the word "no" is returned, then we exit; nothing worked, we couldn't find the details in the email, right? Otherwise, we create a new agent, right? This is the second agent, which, accordingly, has access to only `generate_pdf_act`, only the PDF act generation function. So, we then upload the file that we received from the first agent to this agent. Here is the `filename`, right? And, well, that's it, we set a new prompt. This is exactly the same prompt that we had before. Your task is to generate an act. To do this, you need to take the counterparty's details from the attached file, right? Accordingly, we attach the file to this prompt, which was previously uploaded. And thus, everything works. Dear friends, let's, let's run this whole thing and see, and see how it will work. `main.py` found 17 emails in the last 3 days. Now it didn't even ask me for how many days to download emails. Okay. Work composition, for example, ERP development. Well, some amount of rubles, a lot of rubles. The act has been successfully created. ERP development, 10 million rubles. Everything is precise, dear friends. Change the cost to 2 million. Moreover, the details are now correct, right? Charaeva. This is the correct signatory, the correct bank, MTS Bank, and so on. Well, here it is, 2 million rubles, the cost has changed here. So, two AI agents wonderfully solved this task, although one AI agent why it didn't solve it, right? Meaning, we can create chains of AI agents. Each AI agent performs some simple task, but the overall story can be quite complex. Dear friends, it's cool, it's cool. Well, just think about what we've done. We've created an AI agent that goes to email, finds details there, and creates an automatic act from these details. Imagine how we would solve this task with if-else statements, dear friends, how we would solve this task with if-else statements. And AI agents give us this possibility. Imagine, imagine, that, basically, we describe the business logic in ordinary Russian language, and we write our code in the format of connectors, right? There can be any logic. It can be complex logic, but in this task, they are simply connectors to the external world. Meaning, an AI agent must interact with the external world to provide some practical benefit, to solve some practical task, and not just be a chatbot, right? And we, accordingly, write our Python code for connectors to the external world, and the business logic is described, in fact, simply in ordinary, ordinary Russian language. So, there used to be such systems, BPM systems, but they existed. There are Business Process Management systems, systems for managing business processes. And there is even such a notation, BPMN, Business Process Management Notation, probably, right? There are all sorts of diagrams drawn there, right? And with the help of these things, we can automate business processes, right? And a BPM system will call those very connectors to the external world within itself, right? Create a meeting, ping an employee, ask for approval of a document from a manager, and so on. So, basically, now with LLMs, we have the opportunity to discard all of this and simply describe the business logic in ordinary words. In ordinary words, just in Russian or in English, as we prefer. And those very connectors to some external world will also be written in Python or in a programming language familiar to us. And this is the first thought. The second thought is that, note, we haven't created any interface here. The interface is the chat, but because at the core of the chatbot is this kind of dummy that understands ordinary language, it can serve as an interface, right? So, once again, right, add another job. CRM development, let's say, 3 million. And it will do it now. And it will do it now, meaning it will add another project. We had one project, ERP development. Now another project, CRM development, will be added here. Note, 3 million. The total cost, it became 5 million, and we didn't write any interface for this. What if we had to write an interface for this now? Well, how else can this be used? Well, like, an interface is needed, right? Accordingly, we would need a frontend. On the frontend, we would need some design. Okay, we could take some ready-made template, but we have to think about it. We have to look for a ready-made template too. Bootstrap, not Bootstrap, what's popular now, right? We would need some JavaScript binding, how would we add these jobs, these items, right? So, there would need to be a button to add an item, click this button, and some form appears. In this form, we enter the item name and its cost. Items can be edited, right? Meaning, after adding, this information needs to be edited. So, on the frontend, there should be an edit button, right? There should be a delete button. If we want to delete an item from here, we simply write "delete some line," right? And it will delete it. And on the frontend, all of this would need to be written. We would need to write frontend code for this, certainly JavaScript code, whether it's React or not, whatever. And we would need to write backend endpoints that would process this, that would handle creation, deletion, updates, and so on. But here, we don't need to do any of that. We simply get, in fact, a frontend in the form of a chat. And it just works. Moreover, this thing, well, here it just generates acts, but we can also create an agent that generates both acts and invoices. For example, one AI agent will generate acts, another will generate invoices, and a third will coordinate their work, for example, right? And then we can ask the agent that coordinates the work to do both the act and the invoice at once. Yes? And again, we won't need to do anything for this, because we already have an agent that does the act, we have an agent that does the invoice. And our coordinating agent will simply call one agent first, then call the second agent, and we will get the result. And on the frontend, we would again have to create some logic for this, create some frontend, some button, because we have a "create act" button, a separate "create invoice" button, and then we would need some third button, "create invoice and act." But here, nothing like that needs to be done. Here, we simply do everything we need in Russian. Moreover, note, for example, for some reason, right, we've created an act, and they reply: "Damn, sorry, but the signatory is incorrect in our details, the signatory is not Charaeva Yuven, but Pupsik Ivan Vasilyevich, right?" Our interface might not have such logic, well, we didn't design it. Well, we didn't design it, right? Well, like, why? The data comes from somewhere, whatever the person entered, that's what will be there, right? But here, we don't even need to design that, we can simply replace it. Replace the signatory with Pupsik Ivan Vasilyevich. Hopa! And this will likely replace it now. Yes, indeed. Here Pupsik Ivan Vasilyevich appeared. Well, say it's cool. Say it's cool. And this truly offers new possibilities. This truly offers new possibilities. Yes. It's not about artificial intelligence being able to write code. Once again, all of this is secondary, it's all nonsense. But this is cool, this is cool, this is useful. And if you listen to Zuckerberg's speeches, listen to the head of Nvidia's speeches, they all say that in the coming years, we will experience a total boom in AI agents. By the twenty-something year, it is expected that the number of AI agents developed and functioning will be greater than the number of people living on our planet. And I easily believe this. I easily believe this because this is something that truly offers new possibilities, truly changes the paradigm in which we create software and in which we have been creating software for the last 80 years. Now it can be done with the help of AI agents, and new possibilities can be obtained. M, it's cool. Yes. I want to show you one more thing, dear friends, that this thing works normally with different documents. I have a bunch of company details here that I recently worked with, to whom I issued invoices. There's Yandex, an employee is studying with me, Rosbitex Astra, a Linux developer, Astra is studying with me, Promstandart, RTK IB, VK Digital Technologies, MTN Integration, MTS, the one I showed you. All these companies paid for employee training in my hardcore web development course. By the way, you can also ask your manager to pay for your company, pay for the course, and come to me to study, if you suddenly want to. Ah, well, yes, let's check that this will all work normally with these files, that this won't stumble anywhere and everything will be fine. For this, I have reverted the changes with searching for details in the email. And simply, yes, we take, we take the file that is in `constants.py` and work with it, with this wonderful file. Well, let's try RTB. This is also a docx file. Let me open it and show you what it looks like. Well, Rostelecom. Company Rostelecom Group, RTK Information Security. Let's check if everything will work precisely with this file. Precisely. UV run. Because I didn't copy the DocX. Docx, yes. Okay, like this. Uvrunmain. Running. Well, let's. Student training, 170,000. Employee training should be written. Well, never mind. Wonderful. RTK IB, Nester, and NN UGRN. Everything was picked up wonderfully. Running with this file. Well, let me just copy from here. Act successfully formed. Here, OPM standart, Kochetkova for Sberbank. Everything also worked wonderfully. Let's go further. YadroLaps. Let's check employee training at Yadro. Yes, wonderful. YadroLaps, Marshin. Everything worked magnificently. BittechAstra. Let's check. Well, you see, here are different doc, docx, pdf formats, yes, everything works wonderfully. And the details are extracted correctly. Say it's cool. Say it's cool. Moreover, the format of these documents is, like, completely different. The information is presented differently in all these files, but everything works wonderfully. For example, Bittech. Let's see how the details are here, here in such a table, right? And the previous file we were analyzing, well, in such a table, right? And a PDF with a bank, dot, right? Such a table, right? Promstandart, well, such a file, right? Here in this form, but with all these formats, everything works wonderfully. Here, Rosbit Astra, please. Everything, everything, also beauty. Well, let's try VK as well. Will it work with VK? Everything is precise. Let's check. Hopa! Hopa! Let's restart. What are VK's details? Let's, you know, Bagudina Elena Evgenyevna, signatory, and INN. Let's copy this. Yes, Bagudina and the INN are correct. Well, everything works wonderfully exactly as we want. It's cool. These are the wonderful AI agents, changing our world in real-time, practically here and now. And you can use this, it's available to you. You can really use it right now. Imagine? Think about where you can apply this. Think about what you can do with this. What pet project can you create with this? What can you add to your GitHub, what can you add to your resume, or maybe you'll even start a business with this. There are actually a huge number of possibilities. And think, think. Thank you for watching, and let's stay in touch. Until the next episodes. Bye-bye. Bye-bye.