AI Agent UI using Streamlit and CrewAI

Build an AI research agent with CrewAI and Exa search, then display it in Streamlit. The presenter creates a custom search tool, configures an agent to write markdown reports with citations, handles common API errors, and streams live output to a web interface that fetches and formats research on topics like executive orders.
Chapters
All right, cool. And also, I'm not sure if y'all can hear me. So let me see. Maybe y'all couldn't hear me in the beginning, but hopefully now you do. But let me go ahead and find what I'm talking about so I can start building this. Hey dude. Daddy. Yeah, what's up man? All right, so let me check this out. All right, um, cool. Once Okay, I'm back. Um, also let me know if you can hear my audio because I wasn't sure like you guys could hear me. It seems like I forgot to turn on something. I see the mic auxiliary and maybe I can test that also. It's going to have some echo, but let me know. Cool. Let me see. Okay. I'm back. Also let me know if you can hear my audio because I wasn't sure you guys could hear me. It seems like I forgot to turn on something. Okay. So it works. Hey, let's go. So yeah. Anybody in the chat, anybody wants to suggest an idea that we want to build an agent for? If not, let me go ahead and just build an agent here. Real simple one that we can just kind of Oh yeah, Anurag, what's up, man? Good to see y'all here. This is a new thing that I'm trying experimenting with streaming Twitch and also on LinkedIn. So oh not LinkedIn but YouTube. So I want to do these at least every day on what I build so that you can see what I'm building. I think that it might make sense more like streaming me doing my job essentially. That's what I'm trying to do. And if anybody wants to join me in, I mean that's pretty cool as well. So. What I wanted to showcase, and if you're joining in right now, what I want to showcase is how to build an agent that you can actually add a Streamlit app on top of it and make it very easy to work with. So that's what I want to build. But I'm trying to find where I put one of the stuff that I mentioned. Cool. Let me just find it. All right, cool. I think I might have found it. So let me go here. Yeah, so today y'all, y'all, y'all gonna be bored without music, but, um, first time. I'm not sure. I just, I just didn't want to risk having it, um, especially demonetized or not shown at all. So, so trying to put that out there for now. I'm surely going to spend time today to understand how these streaming things work. And then I'll definitely add that on there as well. So what I wanted to build is a— we'll start with the CrewAI first part first, and then we'll add the other sections later. So let's go ahead and build an agent. So the first thing we want to do, since we've already installed CrewAI and we've installed Essentially, Crew AI. That's what we need is we want to go ahead and add. And actually, let me just have a requirements file here because that might make things a little easier. So if you do requirements.txt, and this is where we just store all our requirements in here, I could just say Crew AI and then also Crew AI tools. I believe Exa because I'm going to be using Exa. If you're not familiar with Exa, it's It's essentially a—it's a company. They have an API. They are search engine for AI. That's what they call themselves. And you can—they have several endpoints that you could use to kind of do some really good stuff with it. So the first step you want to do is exa.py. So, so exa slash or dash py. So that's what I want to install exa—the Python version. Okay, cool. I think I got all the requirements, so I can go ahead and reinstall all of them again. So uv pip install -r requirements. So it's going to install all of the missing pieces, which it has. Now the next step is for me to get API keys from Exa, which is something that I need. So I'm gonna just go off for a second so I can save that because I don't want nobody Looking at my API keys, but what I'm going to do first before I even go offline, I'm just going to create what they will look like. So I'm just going to add a .env there and add this extra API key. That's a fake one that it just auto-generated. That's not even what it is. And then let me see what I want to use. Maybe I would use OpenAI API key as well here to To help with some of this stuff. Yeah, for the agents, I'm going to need OpenAI API key as well. And with that, I'm going to have to close off the stream a little bit, at least not share the window. I'm going to hide the window capture so I can save the API key because I don't want that leaking. It's not good. So let me go ahead and find where that is. Cool. If you're interested in this project as well, I will save it on GitHub and you can experiment with it after. So let me save that and make sure that this is not exposed. And now we're back in business. So I'm going to turn this back on. Window capture is back on. Cool. So I've saved all my environment variables in my .env file. And now the next step for me would be to start Building the agent itself. So first of all, we want to import from CrewAI, import exactly that. And it's done a lot of this for us already. So it's already imported what we would need for the most part, loaded environments. Let's just add OS, why not? And it's trying to build it for us and I don't want that to happen. So, all right. Save that. Now we have installed agent task crew, and also we can just add LLM here so that way we can instantiate the LLM that we want to use. So if we do LLM, and it's already kind of going ahead and grabbed what we need, which is great. You know, I like this autocompletes now. It does almost the job for us, and that's already done. Now let me just push this down. The next step is to build the agent itself, and or first of all, there's a tool. We have extra tool in Crew AI, but the one I want to use specifically, I don't think we have a tool for because what I want to use is the answer endpoint that they have. But we don't have answer endpoint. We have the search endpoint. We're just going to search this stuff. But this one is for answering questions. So I'm going to build a class. And this is what we will pass to the one that we want to use. So answer. AnswerTool. And we want to call this, we want to use this, we're going to create a schema from this. And then we're going to need a BaseModel. So it's already kind of doing the work for us here. So cool. Love that. Let's go back, tab up here. And it's going to import what we need. Oh, man, look at that. This is awesome. It's really easy to be a developer now because most of this stuff it does for us. So see, it's already gone ahead and kind of got all the stuff that we would need. And here instead of EXA, it's supposed to be EXAPI. So cool. So that's pretty neat. Actually, let me zoom out a little bit. Hopefully y'all still can see that. So yeah, I think y'all can still see that. So with that, let me just go ahead and— okay, so it's loading. It wants to continue doing this stuff for us, but I just want to make sure that it's correct. In this case, it says answer. I could do query here instead of answer, and it's just semantics. So I know how to add it as a query. And let me see if it's doing what I want it to do. So it's saying query field description. And maybe initially here, I could just add a few. So description is The query for the Exa API. Nah, that's not correct. So this is the question you want to ask Exa. That is the correct field that I want to add there. Now it wants to add Exa directly there. Okay. So I don't want to do that. Let me save that first. And then it becomes the answer tool, which is what I want to add is We definitely need the name and it's a string. Exa tool, that's what I want. And description, use this tool to answer questions. I don't think that's a good description. What I want instead is a tool to answer questions using Exa. I think that's a good description. And then argument schema. I don't think this is correct yet. BaseModel, I think it's missing here. Let's just do type BaseModel. And up here, rather need to add type as well. So from typing import type, which it has already done. Like I mentioned, this is pretty freaking cool. Being a developer these days because it does a lot of the work for you. You really just have to really pay attention to what you're doing. But for the most part, I mean, you can get most of this stuff done. And the next thing is the answer URL because we will need the answer URL for for us to be able to call the agent itself. So not the agent, but essentially the the API endpoint. And for this, I'm just going to pass in the URL exactly what it is. And this one is almost got it correctly. I believe it is api.exa, but I'm going to verify that. Let me check their website here. Yeah. Excuse me. Yeah. So it's api.exa.io and answer endpoint. So that's good. And now let's go to the headers because we'll need to pass in the API keys that we need. And it's already doing the job for us here. So we have authorization. Let me just make sure. We don't need authorization. I think the content type is there, but the way they've set up the API, it needs to be in lowercase for what we need. And authorization, we don't have authorization on them. They have accept, accept, and application/json. That's exactly what they have. And they also have content type. So Cool. A bunch of people in here now. Somebody probably commented somewhere, but I can't see yet. All right. Or is it a follow? One of those. I don't even know what this. Oh yeah, Gulia. Thank you for subscribing to YouTube. Appreciate that. Yeah. And if you haven't subscribed, please go ahead and subscribe. Let's see. Content type is what I meant. And if you're just joining, where I am right now is I'm building a tool that, um, that I'll be able to use to pass it to my agents to search the web and give her some up-to-date information on whatever topic we want. And it's going to have citations on it as well. And the tool that we're going to be using here is one from Exa. So if you're familiar with Exa or not familiar with Exa, they do provide a way for you to search the internet with a lot of information that you would want. And so I think what we need to pass here now is the x-api-key. That's something else that we want to pass here. And I'm looking at their specification here on their website. And this is what they have there. So I'm trying to make sure that that's the correct way we're getting this. So Cool. Now we've gotten that. The next step, we've built kind of like the bare bones up here, which we have. First of all, just recap, we've imported all what we need to import. And now we're building the tool itself. So let me even come up here and add comments. Let me just separate this section. ExaAnswerTool is what we are building here. So that way you kind of know what the steps we were doing here and here. Let's just add LLM config configuration. Yep. So, and before that, I want to answer somebody messaged me here. Yes, let's see. Okay, cool. All right. I was trying to tune a model to use my files to search, relate, and relay information depending on— I feel you, man. You say you're trying to tune a model to use my file to search relate and relate information depending on context last night. Yeah. Do you have any more context on that? Do you have con— like, could you tell me exactly what you were trying to do? Because that might be something that we might do. Um, you know, since I'm going to be streaming almost every day now, that's the plan, you know, fingers crossed. I don't want to jinx it. Um, we could, we could dedicate a day to do that instead. Yeah. I feel you. You said it sucked. Okay. Um, But yeah, let's continue building this app. Right. So we have the run now, which is kind of already instantiated. But what I want to do is I want to try first of all to use a try-catch clause here. And what I want to do here is to be able to try to get a response from Exa. And here it's added extra stuff that I don't need. So I don't need that since I've already added it at the top. But what I need is response. Let me see if you got it right. I'm just giving it stuff. So let me just take that piece out. And I'm just going to type this out myself because I don't think I got that wrong. So response, and I'm going to use the requests library. I don't know if I downloaded requests. And I want to post a message to the API itself. All right. One question I have is We have tons of libraries or frameworks to building agents, but how do we evaluate them? I mean, that's a really good question, Masid. I mean, it's a good question. How do you evaluate frameworks? Right? I think the way I like to think about it is look at what's out there. For example, things like Crew AI, AutoGen, Blank Graph. I mean, there's so many now. There's Bee from IBM. There's Swarm from OpenAI. I mean, that's bare bones. What I would say is like try building stuff with each one of them if you have the bandwidth, of course, but also you can watch other people building stuff with it and then you can kind of tell if that's kind of the vibe you're going for. And I think what gets you to value quicker without much overhead, I think that's the best one you want to go with, the one that has less friction for you to get stuff done, to get to what you want. I'd say that's kind of like the way to go. If you just chase different libraries, it's really hard to catch up with them because things will change in all of them. And that's just a fact. But yeah, that's what I would recommend is just try them out yourself, find one that has the least friction for you, and then just see if that's kind of like your vibe. That's something that you would want to use. If not, you could always build your own. But I always tell folks, It's not going to be as easy to maintain it since, I mean, you probably have other jobs to do and you don't want to be maintaining that all the time. So you maybe would want to have somebody else do that. For example, how do we evaluate output generated by agents? I love that. So thank you for clarifying. Yeah, I think especially for CrewAI, I'll show you when we get to the point where we start building the agents. I know right now we're building the tool. But when we get to the point where we're building the agents as well, I'm going to show you how that works. So let me go back here. Import requests because we didn't import that yet. So let's save that. I'm going to show you how to do that. Essentially what you do is for Korea, at least you have— when you build the agent, there's like parameters that you pass in, right? You have the expected output from the agent. And you can output each value for each of the agents and you can see what they did in their tasks and you can decide yourself if that met the standard. And I think for us on the enterprise platform, we use an agent as a judge or LLM as a judge in that case. So you run the agent, it outputs the task, for example, and whatever it outputs from that specific task, you compare that with the expected output that you passed it to it. You told it, I expect this from you. And you compare that with the output it produced. And maybe you can use an LLM to do that comparison. And you assign a score based on how it achieved. Did it achieve what you were expecting out of it? If not, then maybe consider maybe fine-tuning your prompt, for example, and things like that. So I think that's something that I've seen working in my opinion. Yeah, I have a taxonomy file with work and skills. I want the model to suggest the best work from the skills I would tell it I have, then suggest a path to follow for my level of experience. I'm not sure I fully understand. I wanted the model to suggest the best work from the skills I would tell it I have, then suggest a path to follow for my level. Is this related to job? For a job, like you have specific files for like jobs. Oh yeah, I see it. Yeah. We're using LLM as a judge for RAG-based chatbots. Yeah. If you're using that for that as well, you could use that 100% for the agents as well. Because each of the agents, especially like CrewAI, I'm not speaking for the other ones. You could probably implement it for the other ones, but specifically for CrewAI, that's how you would do it. And I'm going to show you here as well. So there's JSON headers, subheaders, and then we'll just do response, response with status. And let's go ahead and we don't need this piece. And then exception. Yeah, sorry, I'm going to try talking while doing this. But Ambundo, I know you mentioned the work, right? You have specific files. With work and skills, and I wanted to the model to suggest the best work from the skills I would tell it I have. Then suggest a path to follow for my level experience. So you have specific files with work and skills. So this could be like your resume, right? Like I'm assuming the taxonomy files. Although is that your resume, for example, that has your your skills and work that you've done? And you want the model to suggest the best work from the skills. Like basically decide what job you should do in a sense. Is that what you're like decide a career for you? Let me know if that's if I'm in the right, I'm going the right direction there. If that's the case, then I think that's very possible. And let me know. You can remind me again what the issue you were running with into this, what it was. So what I'm gonna do here, I'm gonna do requests, accept requests, exceptions. Let's maybe catch the HTTP error if there's an HTTP error and then as HTTP error. Okay, let's see if we got this right. So it's going to print out, it's going to return that. Actually, I wanted to print it out. Let's just print. And I'm still going to use that f function. And so it's going to log that HTTP error there. And then maybe also we could log the response from, you know, for more details maybe. So we do another print f error message response text. Yeah. So actually it won't be text, it will be content. Cool. And that will give us all the extra context that's on there. And we just of course finish this with raise and exception as error. And we just want to print here as well. So let me just do another print statement. So print error card error. That's just going to log any errors. We don't need an else here. All right, cool. Because we're going to return up there as well. Yeah, let's just leave that. We don't need that for now. Okay, cool. So I think we're almost done with building the tool. And actually, we're done building the tool. Not yet. We just got to get the responses from it now. So if you come here, we're going to do response data. Really, I need some music here, man. Like for tomorrow, I'm definitely going to bring some music because this is almost unbearable. I'm so used to playing some music in the background. So we have that response data. And in this case, it's just going to return data. My issue was simple skill. I don't know Python, so I decided to switch back to Node today. Still struggling to— so took a break. The break brought me here. Well, I guess the stars aligned, right? You came to the right place. I just happened to be streaming today. So thanks for stopping by for sure. Yeah, with Python stuff, man, Happy, happy to help out along the way. Hopefully these streams turn into something while I'm troubleshooting stuff. I'm also able to share some stuff here as well, which is cool. So let's see. Yeah, that's how we're going to get the answer from that now. Oh, come on. And we want to get to citations because This endpoint that we have is going to get citations as well. And from whatever source it's going to capture, it's going to have citations. And if there's no citations, it's just going to return empty, an empty string. So I want to put output here. Answer, answer. It went ahead and did a bunch of stuff here that I didn't want it to do yet. We'll just add another escape there and let's close that. So we have that. It's going to produce the answer. And then we want to check if there's a citation because not all of it has citations. So if citations— and I didn't add citations here. So citations. So if citations I wanted the output concatenate that with citations. And then for citation in citations, the output should be added there. Citation. We want the title of the citation. Man, look at that. It's already kind of inferring from that. And I love this. And then also what I want to add is the URL of citation as well. So cool. And then it's going to return the output. I'm barely doing anything. This thing is just freaking awesome. It's doing most of the work for me. I don't even have to worry about majority of this stuff. It kind of infers from what I've already done up here to find the answers and give me the code. Now the next step here, of course, is create the agents themselves. So I'm going to start with— we've already configured the LLM, have we? Or not. Let's see. We have already configured the LLM up there. So next step would be to get— let's see, did we set the model? I don't know. Let me use O3 Mini. Why not? For reasoning capabilities from OpenAI. So the next step is to build the agents. So Let's go ahead and, uh, all this task configuration, agent configuration, but we'll start with the agent one first because you build the agents and then you assign the task to the agent. So it's going to be a very simple agent. So first one, what we want to do is build a researcher, and the agent is going to be a researcher. So we could call this agent researcher agent, research agent. Boom, look at that! So research agent, research analyst. And that proposed to— so this agent is a research analyst and research the latest trends in the stock— not the stock market. Come on now. So we have the goal for it is to conduct— let's just give it here. I just want to make sure because prompting is pretty important. So I want to tell it to conduct research on the given topic. And I want to put the topic in parentheses or in the brackets here squiggly. So that way I'm able to pass in the topic that I wanted to conduct. Not just conduct, but thoroughly thorough research on a given topic. And that's the goal. And we also need a backstory for this agent. So let's give it a backstory. You're a seasoned research analyst with a knack for finding the most relevant information. Yeah, we'll go with that. That sounds good. And we want to pass in our tool now that we built up here because we built this tool right from, from AnswerTool. And we want to use that tool. We want this agent to use that tool to search the internet and get all that information, latest information that we wanted to. Now we are done with that. Let's go ahead and build a task. So for the task, we can say research task. And it's already doing the work for us now with or without LangChain. Wait, what do you mean without LangChain? You mean— so here I'm using CrewAI just for FYI, James. I'm using CrewAI. If you're wondering if CrewAI is built on top of LangChain, that's still what most people think. It's not built on top of LangChain anymore. And that was removed, I believe, end of last year. But what happened really, what LangChain was being used mostly for was a thin abstraction on top of CrewAI for being able to call models. So if you wanted to add a specific model, we would've used LangChain, something like LangChain import chat OpenAI for something. And then you can hook up a model. But that got taken away and it got replaced by LightLLM. LightLLM, of course, has all these models that you can just use easily. So that's what is being used right now with LightLLM. There was also another aspect of it and there's still some LangChain a little bit if you look in very clearly. And I think it got taken. No, it got taken all of it out. The other piece I was going to say as a caveat was some of the tools that we have use LangChain under the hood, like a LangChain tool, but That got taken off as well. But the cool thing is you can still use tools from LangChain. So if there's a tool on LangChain that you really love, like a LangChain tool, you can use it. Llama Index Tools, you can use Llama Index Tools. So you can interchangeably use that, whatever tool, or you can build your own, like how I just built this custom tool here as well. Because it's just really running an API, build a function that pulls something from an API or sends something to an API. And that's what I just did with this one. And for this task, Of course, we build the agent that conducts the research. Same thing with this. Research the latest trends. So for the description, I want the description for the task to be research the latest trends. Research, not the latest trends, the latest information on the given topic. And actually on this one, let me just take out this. So that, because it will be double that we don't need that. So research the latest and that's the description for it. And then expected output is a detailed report. And for this one, I want it to be more detailed. So I'm going to use the 3 quotation marks so that we can get exactly what I need here. But let's see what it suggested. So a detailed report on the latest trends in the stock market, not the stock market, dude. Come on. All right. The latest. All right. Let me just change this. A comprehensive executive summary of the research findings. What did I do? Tabbing research findings and include the following sections. I need to add some more meat here. So the summary, I just want to tell it to be very concise, should be concise and focus on the most Important, important information. Maybe important aspects of the information. I've overused information. Maybe research. Yeah. On the important aspects of the research. And then I want to tell it to format it in a certain way. So The format should be Markdown. I love Markdown. And I want it without these code blocks. So sometimes when I tell it without code blocks as it is, it just ignores it. So in this case, I want to give like an example. It's like one-shotting it. And include the following sections. So summary, let me just do some summary of the research is good. Key findings, relevant citations, maybe recommendations. Well, let me not do recommendations. Key findings. All right, maybe let's do implications or something. Let's see, implications for. I mean, it could be research about anything, and I don't want to. Bias it to specific implications for business or implications for specific things. So let me just do key finding. Let's just do this simple 3 sections here as expected output from it. And now that's expected output. Now let's assign an agent to this. So agent is our research agent. Also, what I want to do is output the results of this into a markdown file. So Let's do output file and let's do research_report.markdown. So once we run this, it should output the results here on the side. And let me just go through to make sure we got everything. So now let's go ahead and put the crew together. Right. So we have agents and it's already doing this stuff, man. Like, I love this. Look at that. No, we don't need to print that since it's going to be running through that. So In this case, and this is wrong actually. So what we would need to do here is have an input. That's not an input topic. Yeah, we can do that input topic. But in this case, we would do brackets and do inputs. Has to be in a dictionary. So we can do topic. That way we're able to capture what we need to capture. And then we're just passing that into into this. So here we would have to do inputs. And then we pass in the input. So what this will do— oh, first of all, let me just make sure this is— which Copilot are you using? Seems convenient. Seriously, I'm using Cursor and I think I have— let me see what I have. I think I've activated— I think I'm using— yeah, it's using O3 Mini under the hood. But I have not even used the Composer here because the Composer would do the coding for me. It's just doing the auto suggestions. And these are some of the models that they have right now. They have O1, O3 Mini, but I'm using O3 Mini. That's what it's using under the hood. There's DeepSeek, which is pretty good, but I'm not even sure if I'm using any of that right now because this is just auto-suggesting stuff, which it could be O3 suggesting stuff. It's pretty good. Trust me. I think it's something that I love right now. It's making stuff so easy. I think this is our agent. We just built our agent here. But I think there's something not right somewhere because I don't see us using EXO. And I just want to make sure that that's not the case, that I'm missing something. Just come here. Let's make sure that I have that instantiated correctly. Okay. I don't think we need to use it based off of What I'm doing here because I'm using requests. Cool. We'll find out anyway if we did something wrong after. So let's go ahead and check and see if we have. We haven't added everything here that we need. We need to add the process that that we'll be running this, and that it got that wrong. So process we have to use the process that we installed. So let's process with the caps, and then but we didn't. Install. We didn't add the process there. We didn't import. So it did the import for us. So we imported it and we wanted to do that sequentially. So we have one agent in this case. So it doesn't even matter the process in a sense, because you're just going to do sequential. There's one agent really doing the job. But if we have several of them, it would just do sequential, finish the task, pass the next one, so on and so forth. But if we had multiple agents, we want to do hierarchical structure, then we could do that as well. And now let's go ahead and check it out. Let's see what we got. Just kind of sense checking this before I run it. And we should see the outputs that we need. Um, let me just fire up my terminal again to make sure that we got everything. The virtual environment is up and we've passed the task. We've added everything. Now let's go ahead and kick it off. What it should do is when I hit run for this app, it should essentially pop up an input box that asks me to add a topic that I wanted to research and it should go and kick off the research. So let me just go ahead and run this. So let's do Python. And the app we're running is the aiagents.py file. So if we run that, fingers crossed, let's see if we did everything right. We should get an input box in a second here. So it's taking a minute to kick on. Oh, there we go. So enter a topic to research. Let me say, let's enter Find the recent executive orders, presidential executive orders. The recent executive orders. And what— or I'm thinking, is that even the right question to ask? Does any of you have a good question or something that we should— I should research? Because I'm thinking we could find something to research. Let's see, because I want to ask a good question so that we know it's recent enough. So let's say, what are the implications of the recent presidential— can't type today— presidential executive orders on the US economy? Pretty political, but let's try that. So it's kicked off. Now the agent is supposed to be doing research. So let's see what it's going to happen. So it should kick off to Exa. It should generate it like there it does. They did. So it got an error, I think. I don't know what it is. I got an error. We're trying to use the tool. This was the error. Let's see what the error. What's the error about? I mean, it did complete the task, but. Did it hallucinate? That's a question to ask. So it says it got an error. So name resolution failed to resolve api.exa.io. Node name. Okay, max retries. So I think it might be our endpoint that's causing the problem. Okay. Let's just go up here and verify that we got the right. Ah, it's not I O, it's A I. Come on, man. This is a rookie mistake. Let me just go back and let's just clear this again. And this time it did output some research, which. It's just bogus at this point because it's not what we wanted. It just hallucinated. Let's see how correct that is in a way. So he says the summary of the research, key finding, yeah, I just hallucinated the results because it didn't provide any specific relevant citations. It just, yeah, hallucinate. This is total hallucination right there. So let's just, it should provide links. To citations. So let's delete that and let's restart the entire thing and just make sure. I just want to make sure that it's the right endpoint there that I have. API.exe.ai. Yep. Now let me go run this again. All right, it's gonna take a minute. Let's see what we get. Oh, enter topic. Let's ask it again. Find the recent executive presidential executive orders. And research the research, their implications. Let's say to the average U.S. citizen. I've switched it a little bit to say instead of the economy, how does that impact the regular U.S. citizen? How does You know, go do some research on. First of all, find the presidential executive orders and research like what implication that has on like the average American citizen. So you should go do the research on those two, potentially find the executive orders, and then from that determine okay what are the implications to the average citizen based on these executive orders. Just want to see the output that's going to output. So it started. It's taking a minute there. This is kind of like the moment we just wait for the moment of truth. And let's just put the full screen there. Oh man, that's been 50 minutes. Time flies fast when you're streaming. It doesn't feel like it. Okay, that's taking quite a bit. Hopefully it's doing some actual work. All right, let's wait and see. You know, while that is running, anybody got any questions? Oh man, we got another error. Okay, let's see. Is not subscriptable. Argument query description, type string. Okay, just a problem with my typing, but it went ahead and did research regardless. It just had an issue with a simple typing. But it seems to have gone ahead and found exactly what it needed. But that's like 2023. That's not even like recent stuff. So let me just go ahead and let's check out the report that it generated. All right. So it says executive summary of the recent presidential executive orders and the implications. Summary of the research, blah, blah, blah, blah. Environmental regulation, economic measures, public health, citations, whitehouse.gov. I mean, that's just the main landing website. Like, that's just nothing. This is just another hallucination as well. It failed at the tool level. So let me go ahead and delete the report because that's just pure nonsense, um, that is spewed there. So let me go ahead and just check What it's failing here for. Just want to make sure that I capture that pretty well, and it's something with a tool. So it's saying built-in function method objects not subscriptable arguments. So it's the query section. Where's the query string? Yeah. How much networking did you do for your first software dev job? Currently working on my portfolio. And is GPA considered in most cases in tech interviews? Really good question. First of all, I would ask you where you based out of, because just trying to understand the context. For me, I think I took a very non-traditional path into tech, to be honest, because I was in the military for like 7 years in the Army and I got out in 2021. And that was the first time I had worked any job outside the military. So my experience is a little different from what I would typically say. But what I did was, because I was even in healthcare while I was in the military, I was doing healthcare. I was working at a lab, military lab. So I worked at just kind of regular lab where you go get your blood drawn, of course, for like 4 years. And then the last 3 years I was sent to a military research facility for infectious diseases here in Maryland. They have like a— it's called USAMRIID. It's pretty popular. Um, they do like, uh, all the nasty bugs you can think about. So HIV, hemorrhagic fever, um, HIV— I mentioned HIV, uh, even COVID. I was there when COVID broke and we got like one of the first samples to do, to get the vaccines for those. And that was pretty early, early. And when people were doing quarantine, we didn't quarantine, got the first dose of COVID vaccine that came out and things like that so we could work at the lab. But yeah, so for me, switching from that to what I do now, it was pretty radical because in 2020, I wrote my first Hello World with Python actually, believe it or not, in 2020. And you can actually go see on my GitHub. That was like April 2020, I think. And from there, self-taught mostly through Codecademy and then ended up, yeah, and ended up with, ended up going to University of Pennsylvania. They had a program for like non-traditional students. I took like 3 classes there and I was like, this is not for me. So I left, I dropped out. And that's before that I had already got a job. But what I did was I did a little networking for sure. LinkedIn did help quite a lot, like coffee chats with folks and things like that. And just figuring out the lay of the land, like being able to tell a good story about you and why you would be qualified. I think that's really important. And what you've built also, like build stuff in public. I think that's very helpful for me. For me, at least it helped me a lot building stuff in public. That's what I would say. Environmental context, Kenya. Oh yeah. Oh, you're in Kenya. Oh, that's interesting. How's it going back home, man? Yeah, I think Kenya would be different, right? Like I know some people in the tech scene in Kenya, but not enough to know like how people get jobs there in terms of is networking even a thing or do you have to know somebody? Because I know the context there is a little bit. You know, I know I was born there, so I know how the system works there a little bit. But it's a little different when it comes to like I have no experience in tech in Kenya, like working in tech in Kenya. So I don't want to just speak out of my you know whatever. But so I just I really try not to comment if I don't know exactly what I'm talking about. So what I would say, I think the universal thing that applies would be maybe just networking helps quite a lot and just. Like put your work out there because sometimes your work will speak for you. If you do like like freaking good job, man, like nobody's gonna nobody's gonna deny you. People want smart people. They want people that can do the job. So yeah, you put it out there. That's really awesome. Yeah, open source, man. Open source build. But but don't just don't just build and leave it there. Like build it, put it on GitHub, share it. Like exactly what I'm doing right now. Like stream, do things like that because however much it feels like I've I've done in my career, I still feel like there's more that I need to do to get enough. Next level, and this is this is exactly what I'm doing. All right, Masid. See you, man. One a.m. Oh man, that's late. Yeah, man. Absolutely. I'll try to do this almost every day, even if it's just for an hour. But yeah, thank you for coming on, man. And Bruno, what's up, Bruno? Warm regards, man. And you had a question, Bruno. So you said you've been struggling with Crew AI a lot, ensuring the outputs are consistent between different runs? I already set random seed, set LLM temperature to 0, top PE, but still results are different. So by consistent between different runs, do you mean the words or the structure? Because I think that's 2 different things. If it's just the structure, you could use like Pydantic models to structure the output. But in terms of like consistent like wording, over time, I think that's going to be tricky just because the nature of LLMs, they're very non-deterministic or in that case. So it's really hard to kind of like get, and you did a great job by like setting those temperatures to zero and top P, but there's still going to be that little variation that's going to happen. Well, at least that would limit it to the minimum. But if you're talking about structure, for example, for example, this file that we're doing right now, if we wanted to structure it like where we have like the title as like Here, let me just show you. So what we did here, we'd say that the final product should include the following section, like summary of research, key findings, relevant citations. If you wanted to enforce that absolutely, like on all the output it produces, it needs to have these 3 sections and nothing else, then you could use pedantic models to make sure that this is enforced and all of them have this exact same naming and stuff. But if we're just talking about results, like different information, that's a bit tricky. I haven't figured that out myself. I think doing the tips that you're doing, like temperature 0, top P, you could try top K as well. But that's to the extent that I can say, for me, I've tried. But consistent outputs, especially if the wordings are just different, but the content is right, then I wouldn't worry much. But if the content is totally wild and different, then yeah, might just be. And it also depends if it's doing research. You have to keep in mind too, if it's doing research this time and you ask it again to do some research, if it does some other research next time and gets different sources, the output is good. Of course they're going to be different based on those sources that it went and fetched. So that's something also to consider there. All right. I was here trying to fix this problem. Let me see, where was that issue? And actually, this is a perfect time for me to use Composer, right? So let's go ahead and use the Composer. So let's capture that, put that in the Composer and ask it, you know, it encountered error. So let me just tell it got an error and it knows what file it's going to go look through that and it should tell us where the problem is coming from. All right, I think it fixed it. But where did you fix the problem? Oh, here it is. So here's saying where the error is. So what was the error that we were getting? So it's saying the error is due to misuse of dictionary get method in Python. You should call .get with the parentheses rather than using scope. Ah, okay, rookie mistakes, man. This is exactly what I mean. So we got that. So it's just like a I just failed to add a bracket. Goodness. All right, cool. Now let's proceed. Let me just copy this prompt topic so that I don't have to retype that. And let's rerun that. And while we are at that, actually what I'm going to do next also is make sure that we add the year to 2025. So let's see here. Research the latest information at the latest. Information. Let's do here year 2025 in brackets. Hopefully picks that up and knows that it's 2025 that I want the information from. Now let's go ahead and run that and let's see if we get another error. Cool. So let's go to the chat. Do you think chain of thought and TOT techniques work for defining agents' tasks with better quality? I think they do. I think they do. Chain of thought. But the models are much better now, in my opinion, that I don't know if you want to do that locally. In my opinion, I don't know if you want to do that within the agent. You could do it that way. But I feel like that's already— the models are handling most of that. For example, I'm using O3 right now and it does a freaking good job. And let's see if it's going to do it actually here as well. But yeah, I think there's definitely a lot of experimentation. And the good thing that something else that I want to mention as well is a lot of people are doing experimentation, especially with agents. So it's still prime. Nobody has figured out some of this stuff, to be honest. So it's prime for experimentation. Oh yeah, it works now. Look at our code. So we can see the tool output. So it did go here. It generated a query. So latest presidential executive orders, blah, blah, blah, 2025. And it generated the— it used the tool there. As of January 2025, President Trump's administration has issued a series of executive orders that significantly impact various policy areas. So immigration, healthcare, economic policy. So he went and picked 3. Don't know why he picked those, only those 3, but I mean, yeah. Why not? Right? And it said here, summary of research. And this is the summary of the research. It's key findings there. And then there's relevant citations that it did use to where we went and got those information from. So this is pretty good. So we did pretty good on this one. So let's go ahead and check it out. Just go ahead and open that on the side. Okay. That's Not doing it. All right, let's go. Let's do it. Come on. I wanted to use the Markdown editor, but it's not picking it up yet. So while let's just look at this for what it is for now. Let's just take out this line because I think that might be the line that messing up the rendering of the Markdown file. Yes, that's what it was. So if we look at the output here, so it says, you know, in early 2025, several groundbreaking executive orders were issued that continue to shape or reshape US policies across multiple sectors. The presidential administration has taken bold steps in areas such as immigration, healthcare, economic policy, and environmental regulation. There's also the key findings, which is immigration policies. Healthcare, of course, economic policy adjustments, environmental regulations, and judicial impact. Okay. And we have citations now. So pretty good. But let's see, did it? Yeah, it did pretty good. So that's cool. So we got it to do what we wanted it to do. Now I think the next step is just building the Streamlit app on top of this. And I want to build something super basic. But one thing that I want to test before we do that is I want to use the callback handler because when this is running, this, like, you will see this stuff on the terminal, right? But if you're on a Streamlit app, you won't see none of this until the agent finishes all the tasks and you see the final output. So I want to have it in a way where there's a container where you can actually see the output streaming in as you're kind of like looking at it. So instead of just like waiting until the end. So that's what I wanted to do today for this. If I have time, I think I have like 20 minutes. To get this, to get this done. So I'm gonna try to rush through this. Let's see how much we can get done before then. Where's that? That's not it. I'm looking for the right file. So I see questions and questions in the chat. Bruno. Yeah, Richardson, Tree of Thought works much better. Yeah, I'd like to hear more like from you why you think that, because that seems like a very interesting case as well. I haven't played around with it so much, but let's see what we got here. Oh, here it is. Come on. Okay. All right. All right. So just want to implement a quick callback. I don't know if any of you have been using callbacks with CrewAI, but let me just implement this here so you can see what it looks like. So it's a callback handler. So what I would just need here is just a function and then I'll pass it into the tasks as a callback function or callback handler that's going to handle the callback. So let's add here. Yeah, callback function. Why not? And that's not crew state, actually. It's task output. But we need to install task output up here. So that's not way it goes. We would need to do another one down here that I want to add. So do from crew add task import task output. I think it's Task output as well. So we need to do another task. Let's see, and that's tasks. Yeah, let's go. I just fired up startup where I built some crew agents for software application testing. I would love your feedback. Yeah, I mean, 100%. Feel free to share. I'd love to see it. Bruno, I know you have a bunch of questions on there, man. Sorry, I've kind of been—I've kind of got peeled into into building this stuff. I've kind of left you on the side a little bit, but I'm gonna—I'm gonna—I'm gonna switch back and forth. Let's answer one of your questions first before I proceed with kind of building the function here. It's created something, but it's not correct. That's not how it's supposed to look like. But anyway, the one thing I did to improve the output quality is using flows with a separate crew that evaluates the output. And if it's weird or missing sections, it sends it back for the initial crew. Ooh, that's actually really cool. That's something you could 100%, I could see 100% working. And also for any of you, if you build something really cool and it's open source and you want to share it and you want to just publicize it, Feel free to share with me, man. I'll publish it on our blogs. I'll put you out there on blogs, on our social media. Feel free. Always send that to me. Send me just a link to GitHub. If you have a video on it as well, if you have any graphics, like architectural diagrams are amazing. If you can use Excalidraw or Droid or whatever other one you want to use and then share that with me, I'll just blast it on all our socials and get the team, João, and everybody else to reshare it as well. So like that example that you said with that, that'd be awesome to use a crew, a flow. And I love that you're using flows to kind of like using another agent to like another crew to verify the crew, the outputs of another crew. I mean, you could also use human input, which we have, and it will stop, ask you what you'll see the output be like, okay, this doesn't look good, redo it again. And it's going to redo it again until you're satisfied. And then when you say it's good to go, it's going to pass it to the next agent and it's going to continue. So that's another thing you should keep in mind that you're able to do within CrewAI as well. And I always wanted to have someone to discuss CrewAI. Have you noticed any difference in the output length by using Gemini models? I actually haven't experimented with Gemini models a lot. I probably should to just see the length of it. For example, I built that podcast generator thing and I did a workshop yesterday with AI builders. And like you give it a PDF, it generates this. Of course it does the indexing, puts it in, and it generates a transcript or a dialogue script where the 2 people are talking. And then I send it to ElevenLabs, generates like the audio for each. And then I compress all of that into one MP3 and generates like a full podcast. It's pretty cool. So the limitations I had with that was How can I set it in a way that if I want a 1-hour podcast or even like a 25-minute podcast, because the one that it did, and I was using O3 and some of the other models, the longest I ever got I think was like 6 minutes. So I think, and it's very variable, of course you can fix it as much. So I'm going to test it with Gemini and actually see if I get any better output from it in terms of respect to length. Maybe I could also use a guardrail to make sure that it counts. And if it doesn't meet the Number count, it iterates back until it gets to it. That could just be like an endless loop as well if I decide to do that. So for this one, let me just take this out because I don't think this is the right thing to do. And I'm just going to instead of state, it's just output. And I'm going to delete all this except that. And instead of state, We're going to start with agent. I'm just going to print everything the way they are. Space, 1, 2, 3, bracket. Now let's see task output description. I don't think that's correct. It should just be output since I already started with that. So take out the tasks agent output. This should be raw output. I think it should be output raw. And maybe I'll put it as raw output. And then the agent. Actually, let's put the agent before the task. So we have the agent. All right. I think there's task summary as well. There's just task description. And then I need task summary. Output summary. Cool. Agent. I have description. I have summary. I have raw. Okay. That should be all of it. Now I want to come here to the task and I want to pass it as a callback handler. So that's what I'll do here. Add it as a callback function. And then let's save that and let's run it. And we should have something better. We should see something print like this specific one's print here because this will help us. Now when you have the Streamlit app, we just convert whatever comes from that function and put that in a container and you will see those prints before the final output. But if it does it too fast, then it's just almost useless. And you can add that callback handler to each of the agents or each of the tasks and it should output for each task. So enter a topic to research. Let's see what's a trending topic today. Let's go grim a little bit. Find the latest information on the DC plane crash. All right, so he's starting the process on that. While that's going, let's go to the chat. I just fired. Okay, Richardson. I was looking to my own custom lead generation workflow, which scripts LinkedIn and writes custom mails. Oh, that's pretty good. Pretty good use case. Sure. Yeah, ping me through LinkedIn. That's awesome. Is this example you're building? Can you please describe why you're opting for sequential rather than hierarchical? Yeah. So for this one, I'm using sequential because it's just one agent. I don't have a bunch of agents doing this. It was just one agent doing all the work and it's just really just getting the, doing some web research and generating a report. And I just gave it all to one agent. If I wanted to have several agents that do other extra stuff that maybe email me or send it to Slack, for example, the final report, then I could choose to go sequential hierarchical. But I don't know if generate the output and then send it to something like Slack. I don't think that would be perfect for hierarchical because I don't need— the report has to be there first before we send it somewhere. What I would say though is if I had maybe a report finder for this one, it generates a report and then maybe have another agent do research on something else and then add that as a context and then have a final agent that puts it together and then sends it, then maybe I could put hierarchical and then it just chooses based on which agent Could do what based on their job description and whatever? That's an option. So here is it did go ahead and do the research, and it got the information. So the answer there: tragic collision. Preliminary fix indicated that the air traffic controller had alerted the helicopter about the jets present shortly before collision, suggesting that the helicopter may have deviated from its approved path. That may have contributed to the incident. Okay, cool. So it went and did some research. It got the key findings there and casualties, all that information, which is pretty sad. Rest in peace and condolences to their families, of course. But what I wanted to check is this section that we wanted to output that works. So you can see the callback handler works. So we printed out the agent, the task. And then also printed the task summary, which is just kind of feels like it's just literally the same thing, which we're just redoing it here. Maybe you just don't need to add this summary, just app that task by itself. And then we have raw output. So raw output is the final result you got. So summary of the research and boom. So we could do this and have this as part of the Streamlit app. Initially, I had, I've Played around with like this doing it differently, and what I found as well is I can actually get the output from the standard out. Like if I wanted to be in this structure, like just raw as it looks like this on the terminal, I could get those using standard out printed out on the Streamlit app, which has worked as well. I've done that and it worked. But for this case, this is another way to do it in a more clean fashion that you more user friendly for somebody that's not like doesn't want to see all these like. Janky stuff here. But yeah, I have qualms too. I think I prefer this one, although it looks just messed up. But I like it because it just gives me all the details. So that could be one way to do it. But eventually I think there's a way to parse out most of this stuff out and put it back into here. But this is the most cleanest way to do it. But yeah, so we've figured out that that works. So the other part is just really adding the Streamer app. So let's go ahead and add. First of all, let's install Streamlit and then save that. Let's go to terminal and we need to reinstall all our packages. So let's do again uv pip install requirements and it should just pick up Streamlit. There is still them should be good. Cool. That's why I like UV. It's pretty fast. Just a matter of seconds. And I don't know if I might— I don't think I'm gonna have time to finish it, but, um, because I gotta, I gotta jump. I got a bunch of meetings today. But this should be good at this point. We should have like the bare bones at least built out. Um, and up here what we just need to do is import Streamlit as st. And then I could just kind of in between here disperse the Streamlit app as I want. But what I could do here is just set the page configuration because Streamlit is very picky about this. So set page config. And that's what it is. Korea Research Agent. That's what I decided to use. I have no problem with that. And then the next step is here at the input section is something else we could do here. And this is just going to be like super bare bones Streamlit app, to be honest. Instead of input, we could just do st.text_input. There you go. And it should run that. But also I want to be able to to get the container that I need. So if you go to— is that for the callback? Callback. So output from the callback is what I want. So instead of printing this, it could write to the screen. Eventually, I want to have that in So with st status generating research report, and maybe we do as status success, and we just do expanded false. Now this, I used to work at Streamlit, if you're not familiar, I used to be a developer advocate there before I switched over to To crew AI. So if you see me referencing this, it's I think it's all still muscle memory when I used to work there. Cool, which is good. SD right. Maybe we just use SD markdown because then this output's already marked down. I'm sure there's going to be something that fails here. Expanded true, and then it's going to close at the end. So let's do that. Let's let's run this. We do Stimulate run AI agent dot py. So. Let's see what we get, if we get an app. So it's already fired it up on the terminal. You can see we already have the— it's already on 8501, but it's running forever. But I need to share that screen, so that's another window capture that I need to build. And I'm learning this pretty fast, which is good. And it Failed. See, row output topic was not specified. Could you please provide me a research? Oh, okay. So that's what I need to do. Let's add another page capture. Add source. Window capture two. Select an option. Let's go to Streamlit. That should be localhost. Man, I have so many tabs open that it's just confused which one I should use. But in this case, I have a meeting in 4 minutes. So let's see if I could do this pretty quick. Okay, I'm not finding what I need. Agents.py, I have .env. That's not what I want to share. Display link item 0. So what I want to share, dark wallpaper, wallpaper, wallpaper, career research. Ah, I think this is— yay, this is the one. Okay, cool. And hopefully y'all could see what I'm sharing. And it's paused a little bit, which is quite strange. Let's just see. Transform, fit to screen. Boom. All right, it's gonna cut me off a little bit there, but not too bad. Anyway, cool. Now you can see we have an error a little bit on what it is, so I'm gonna need to fix something here. So it started the process up here. So you see, I didn't even put the title and it already kicked it off. So I need for it to wait until I put in the research topic that I wanted to research. So it's just easy as taking this out. And let's just add something here to say input topic. And then we add a button there. Man, I love this. It's awesome. It's doing this stuff for us already. So, and just let's hit save. And we should see the app refresh. So we can actually use it. And now I lost the app. So let me find the app. Now, where did I put my app? All right, running against time and I'm wasting time. All right, I have so many windows open. I'm looking for my 8501 so I can actually refresh it and we can get what we need. Oh, there it is. Cool. Always rerun. So now we're going to rerun that app. And now we have a button. That's what I wanted to have. So one thing that I always like doing as well is I just like having the button to be like a red color. So, and that is the type. Let's do— is it primary? Primary is red. Um, maybe it's just secondary. And let me go back to my app, of which I lost it again. That is not the one. Anyway, I don't think that's important. So Let's go ahead and refresh that. I think it is primary. But anyway, I'm being too cheesy about this. Yeah. So, so let's add a topic here. So let's say research and I can enlarge this page a little bit. So research topic to research, let's say Oh, and another thing also, I think I squished a bunch of stuff on that callback function. That's a lot to put on a callback function. But maybe I shouldn't. Let me get some of this out. I just want to— I'm just trying to make it all pretty and stuff. All right. Now let me refresh that again since we've added some stuff. So let's do some research on— let me see, what do we have as a trending topic today? Let's do breaking news because I want to search something. Well, let's ask it latest news on employee buyout by Trump administration. Alright, let's run it. Now there you go. It's going to start running. It should Create an open window here that we can actually look at. So let's wait and see. And I'm going to be dropping in a few seconds here. There you go. So it's already printed out. So you can see generating research report is still running. It got an error, of course, because I did something. Most of the running complete or oh, I forgot one thing. So it did pretty good actually. So the container did. Good, but the final output didn't do good because I failed to add complete, and state should be complete. Now let's run it. All right. It generated the final report, which is what we needed. So pretty good. We have the agent. We have the task output generated there. We have the key findings and the final report. But what I wanted at the end of the day too is for it to be able to Have that. Oh, it's still running. Never mind. I just jumped the gun. But it says final report generated, but I don't see. Oh, it's just still because of the streamer app. So what I need to do is be able to set it in a way where the final output is printed outside as well, because I don't think I'm printing the the research outside, which is something that I should do. But anyways, we're going to end that. There today. And thank you so much all for joining in. And, you know, for the first stream, I'm going to be doing more of this. So with that, you know, see y'all soon. And, um, you know, we'll see you on the next— hopefully tomorrow. And goodbye.
More from Tony

Summarize Videos and Research Companies with CrewAI + Gemini Models [Quickstart Guide]

How to Make Your AI Agents More Reliable with CrewAI Task Guardrails (Step-by-Step Tutorial)








