How to Build a UI for Your CrewAI AI Agent using Streamlit

Build a Streamlit UI for a CrewAI research agent that takes a query, searches the web via Exa.ai, and generates a cited report. The demo shows the agent researching AI news in February 2025, streaming live progress to the interface, and outputting a downloadable Markdown file with sources.
Chapters
So you build your AI agents using CrewAI, but you kind of feel limited by just interacting with those agents using the terminal. And you're wondering, can I build a UI to actually interact with these agents? Well, yes. In this video, we'll be going over how you can actually build one of those UIs using Streamlit and be able to actually use it locally. So let's get started. And like always, we usually start with going over the architectural design of the project so you understand how everything kind of fits together before we actually jump into the code. So in this architecture diagram, what we're doing with this agent, first of all, is a very simple agent that does basic research on what's actually happening and just outputs the output on the Streamlit UI so you can actually see what's happening. There's a cool component to the Streamlit UI, which I'll show you, which essentially we're getting all the actions that usually happen on a terminal. So when you see those agent tasks being completed on the terminal, we're getting all that output and putting it on the Streamlit UI so that way you can track and see what's happening at what stage with the agent. It's doing research, it's doing this and that. So that's the key part here. So if we go through this architecture diagram, you're the user, you're interacting with the Streamlit app. So assume there's a Streamlit app here as well, and you're asking an agent to do some sort of form of research. And the agent here does research, is using LLMs as the brain of it to think about the actions it's supposed to take, and then also using it to generate some of the output that's generated. The agent also, uses Exa, which if you don't know about exa.ai, they're a company that powers— they have an AI engine that you can use for searching. It's an engine for search that AI agents can use. Check them out at exa.ai. They're not sponsoring this video, but just want to mention that they're really cool and you can actually use their endpoints there. And what the agent is going to use Exa for is for answering your question. So they have an answer endpoint, they have a search endpoint, they have several endpoints there that they have, and some of them they're releasing pretty soon as well. Is the agent takes in your query, decomposes it to make it a better question, asks EXA. EXA goes and does some research on that question that you just asked. It's going to do research on the topic and it's going to gather also the citations and gather all of them together. But it pushes it to the LLM. The LLM is going to generate the final response, edit it properly the way you want it, and it's going to output that on the Streamlit UI. And you also have another option to download the Markdown version of that final report that it generates. So That's just pretty quick and simple. The big part being, I'm just showing you how to actually implement this portion of the Streamlit UI with your AI agent. So let's get to the next section of going over the code. So this is our code base. I'm actually using Cursor. And if you have VS Code, any of those different type flavors, you know, feel free to use it. But in this case, first of all, this image is what I've added here on the image. I took a screenshot of the app, the final app, that how it looks like. So this is the app itself. And you can see we have it laid out, which is pretty cool. We have the title here. We have the box here where you actually be able to enter your input as a user, and then you hit start research. And this research kind of carousel here, expander. If you expand it, you'll see the thoughts that went through the agent while he was kind of doing the research, you know, doing this and that. And you'll see it when we start running it. And then there's options here for you to pick an LLM provider that you want to use. You have Ollama, Groq, and OpenAI. For Ollama, of course, there's caveats that most of the local models that you will use are really terrible at function calling. So they won't be able to call the function to actually use EXA to do the search. So it's just a bummer. It's most of them are not really good, but I'm sure if you look through there, you might find some that will work really good. And then there's Groq. It just provides really fast inference. And also the way I've laid out the code is easy for you to add other LLMs if you, If you want as well. And there's also OpenAI there. It's pretty self-explanatory. And you add your API keys here and you're able to kick off this app. What I'll do, I'll try deploying this app after, and you can actually go ahead and just input your keys and you can run the same things here that I can. So let's go ahead and look at the code structure first of all, of how we've laid out everything on our code base. So we have the Streamlit here. Dot Streamlit, which is where we'll save all our secrets, our API keys. So in this case, it will be— we have Exa API, which is what you will need to get from Exa. And if you look at here, Exa API, you have OpenAI API key and Groq if you're using, and others if you're using maybe something like Cerebras, SambaNova. The list is really endless at this point. So this is an example of how it looks like on my secret. Of course, I don't want to open my secrets because you'll see my API keys. That's that. And you can also just set it as .env and have them in there. But in this case, I've added that if you want to deploy that Streamlit app somewhere so other people can use it, that's the right way to do it. And of course, virtual environment, like pretty self-explanatory there. And then I have source and under source you have components and I've just separated all these things to make it more modular and kind of best practices. And I have researcher.py, which actually holds all our AI agent code. It has the tool for the tool that we'll use, which is Exa. So here we have, we created the tool itself. We have the answer schema there, and then you have the answer tool and we're passing in the API key. Of course, this is just the entire POST message. And we have the application and we have the endpoint here, which is that xx.ai/answer that we will use to send our POST message here. And we'll send your query, and we want it to return as text, and we want that to return as true. And here we're just catching all the errors in case there's an error with HTTP errors during the process. And we are getting the response back here from the API with the answers of what you asked. And we're extracting the answer, just the answer to your question. It will be in text. And then there's also citations. Like I mentioned, it does research. It also brings in citations that it got for the answer that you gave you. So we're getting all those because we need those as well. And then the final output that we'll actually output from this tool itself, which is a tool that the agent will use, we want it to finally output citations and the answer, the answer and then the citations that it generated. And we want that output. So when the agent is asking the tool, hey, I want you to actually run this query from the user and answer it for me, it'll go ahead and do the research. Find the answers for you first and also make sure that it cites where you got it from. And then it sends it back to the agent to decide what it wants to do with it. So if there's other processes downstream, it would pass it to another agent. But since this is for our case, it's just an agent that does research and outputs the output. It doesn't need to pass it to anybody else. It actually returns it to the agent and then the agent generates the final report, of course, with connection to the LLM. Then we have the LLM research agent. Now this is the agent that does our work. So we have to instantiate the LLM that we want to use and then also build the agent. So in this case, this is self-explanatory there. What we're doing here is just setting the provider and the model. And if the provider is Groq, of course, pass in the Groq API key and also the model that the user will choose from the dropdown. Same thing here with Ollama. We're just using localhost because it's going to be local. And then Ollama model that we will— the user will pick. It just gets added in there. Otherwise, if the model is GPT, whatever, all these OpenAI models, it will go ahead and set whatever OpenAI model that you picked and also passing the API key. You can also have custom where you actually just write in the agent, the LLM itself. You're not restricted to picking from this option, so you can actually just type it in exactly how it looks like. We build our agent. Here, the agent we have here is It's called Researcher, just the word Researcher. This is the entire agent right here. If you look through this, this is the entire agent. What we have, the role for the agent is the Researcher Analyst because you have to tell it the role. It's a person, maybe assume it's a person working at the company. They have a name, they have a role, their job title. Then they have the goal, which is what did they do? What's the job description? Then you have backstory, which is essentially their experience. What are they good at? Then the tool that they will be able to use here is the ExaAnswer tool, which is just built up there. They're able to use that Exa tool to go find answers for us. And so you as a— if you're a human being, for example, tool would be equivalent to maybe a laptop, internet access for you to actually get your job done at your workplace, for example. And then we have the LLM, which you instantiated up here. Whatever LLM you pick is going to be passed to the agent here. And the LLM is more of like the brain of the agent because that's what is able to think through and generate answers and also decide what actions to take. And then verbose equals to true. Essentially what we're doing with this is whatever what it's doing, we want it to show us what it's doing. So essentially just speak up and so we can see what you're doing kind of thing. And then we just return the agent there because it's a function. And then we build the tasks for the agent because each agent needs to have a task the same way each employee needs to have a role and explanation of what they need to do. And here's what we're doing that. So description, we Put this as a task description. And we're taking that somewhere up here. We will instantiate that there. So task description is essentially what the agent wants— you want the agent to do. And then we have the expected output of what the agent itself is expected to produce after the entire process, what it does. So in this case, we wanted to generate a full report. And this is all the explanations we gave it to make sure that it generates a report we want. So we want to generate a comprehensive research report for the year 2025 to make sure that it's current year and doesn't just hallucinate any other time period. And also we want the report to be concise and focusing on significant impact and impactful findings. And this is how we want it to structure the report. So it should be an executive summary section, key findings section, analysis section, future implications section, recommendations and citations section. And then we just gave it extra information there to make sure that it's relevant to 2025 and specific dates and numbers if anything is added in there. And then we pass in the agent that needs to do these tasks. So this is assuming you've had so many other agents. You would pick which agent we want to do this specific task. So for this one, we're just putting it as researcher, which is our research agent up there. And then once it's done doing its research and generating the findings, we want it to output the final output to our folder called output. And under that, it should name that report as research_report.md.markdown. So it should be in markdown format. And then we have the agent, we have the task, and we have the tool. So now we put all of them together. That way they form a crew that can actually get the job done. So here we have the crew and under the crew we have the agents. We have one agent. If we had so many others, we would just add them here in a list. Same thing with tasks, one task. If there were so many tasks, we would just add them on the list as well. And then for both crew, same thing as above, tell us exactly what you're doing as a crew. And then the process, this is how we want the job to be accomplished. In this case, it's only one agent, so we want it sequential. If it was maybe you wanted a manager that delegates to others, it would be hierarchical. And so forth. And then after that, we just want to kick off the entire process. So that returns the kickoff. So that's our research.py. Now we get to the Streamlit side. So on the Streamlit side, this is the sidebar. So on a Streamlit app, like we mentioned earlier, there's going to be a sidebar, which— that's where you have all your configurations for LLMs and API keys. So this is what handles that. So we have the alarmer section there. We have the sidebar here as well that kind of handles all those sections, picking the LLM and putting the API keys. This is what all this does and that's really it. That finishes the sidebar. Now component is done. Let's go to utilities. On utils, this is where the magic happens in terms of what I mentioned. When you run it, usually the output shows up in a terminal here. Usually you see, okay, it's done this step, it's going to the next step. Well, for this case, we want to capture all that output that goes into the terminal and this is on standard out. Capture that, and then pass it over to Streamlit to be able to show it on the UI aspect of it. So we're doing some regex gymnastics here a little bit, and we just, for example, here we have to create the class for Streamlit process output, and we have to clean the text and remove all the anti-escape codes from the output that comes in from the process. And that's what we're doing with all this code right here. And then we have removing any bugs that we get from this, from like sometimes LiteLLMs throw some error messages. We don't want to show that on the output screen. So we take that out and then we clean some of the formatting errors that usually comes in with it. It usually shows some timings, how much it took for this and that. It looks a little tacky when you leave it in. So I took those out and then writing the clean text there. And then we are splitting each line, especially for whatever output comes in. We want to split that. And then for each line, we want to strip some extra stuff that we don't need. And now we have the new lines. For each output, after each output, we want to add a space line so it's readable for the user. And then we just want to flush it and just continue doing that. Now we have the context manager here and it just captures the output directly from the terminal like we mentioned, and then redirect it to the Streamlit container that we will have to show that output there. So that's all that we do on that output handler. And now if you're wondering about this .init files, which are empty, Technically you put them where you have functions that you want Python to think of them as packages so that you can use it within other files as well. Now we have .gitignore. This just ignores all the stuff we don't want to commit to our GitHub repository, like API keys and all that. And the image I mentioned earlier, license, of course, README for all the instructions that you would need to run this example. And then the requirements file, like I mentioned. And then we have the final Streamlit app here that kind of puts everything together. This is because I know we covered Sidebar. Now we go to the main body of the Streamlit app itself. Now we have here the page configuration. So this sets the page title at the top and the icon and all that, all the fancy stuff with Streamlit. And then adding this on the sidebar here, we're adding the CrewAI logo. So when you see it here, this is this right here. And so that captures that. And then the next step here is just split into 3 columns, the entire page. And then on the first section, we just want to add in the middle portion, we want to add this title as CrewAI Researcher. So this section here, so this is in the middle. We don't want it to be— if we didn't put this in the middle, it probably would be here. We're just styling the page really in a sense. Then here we're just checking if the API keys are set. If not, it should warn the user, hey, put in the API keys first before you proceed, before you do anything. Just checking if it's Ollama, it passes in Ollama the way it's supposed to. Then here we create another 3 columns as well. And in this first column, we have just a text area. This is where you input your message, what you want the agent to do here. And we set the height of it to 68. You can adjust this as you need to, but that's what happens here. And then we have another column. Of course, we set up 3 other columns here, and this is for the research button. So this is this button, this is this text area and this button here. So those are— that's what we are doing there. And then the next section here is once you hit the research button What's supposed to happen. This is what captures that. So first of all, we set a status container and this is what we'll open up as a container. And when that container opens, essentially what we're doing is we're capturing all the stuff that we redirected from the standard out. We're redirecting that to this container so that way it shows you what's happening step by step. And this is what we're doing in this section right here. So it goes through that, captures everything that we need to and keeps outputting. Once it's done, outputting everything and we're done, it should now close. Everything should be research complete, close the container, we're done. If it errors out as well, it should close it still. Well, we're not closing, it's just showing the error message and showing you what happened and it doesn't close. And then here we're just getting all the results from the agent, making sure they are strings. And then we are putting that in Markdown and it should output on the body of this Streamlit app. And then after that we have here the It's just a divider just showing you if you want to download the output that you got from the research, this is what you do. We just added a button there for you to click download. It should download that MD file for the entire research. And here's just attributions, just created by me using Korea Exa and Streamlit. That's all it is. So now the next step now is let's run the app and actually see it working. And to run the app, you only need to do streamlit run and then the name of the app that you're trying to run, which is this file here. Streamlit app.py and you hit enter, it should open up on host 8501. Now the app is up and running on 8501. There you go, on localhost. So I already loaded the keys that I need, which is OpenAI key and my API key. So you would go to exa.ai and go to the dashboard, get an API key from there. I think they have free credits that you could use. Absolutely. So go ahead and do that. We've already set here. I can set— let's just set this to O3 Mini. Because it's a bigger, better model. So we've already set those pieces. We don't need that section anymore. Now here we put a topic that we need. So the topic that I put here is research the latest AI agent news in February 2025 and summarize each one. Okay, now let's run that and see what happens. So here is with the container that I was talking about. The status container opens up and it's starting to show you exactly what's happening. So previously you would have seen this on the terminal, but now you're seeing this on the Streamlit app. So it's outputting everything as you see. So the research agent is busy in doing research now. So it's getting ready here, setting everything up. And you should start seeing some other stuff coming up here. And there you go. So now it's saying here, using the tool Exa, ask Exa a question. And then the tool input, what it's giving to the tool is provide a comprehensive summary of the latest. Oh, and it's done. That was pretty quick. But it's asking the tool provide a comprehensive summary of the latest AI agent news in February 2025. Include major developments, notable events. Statistics, market trends, blah, blah, blah. It gave it a lot of details. So this is not a question I initially asked, and you can tell it did reframe my question better and asked Exa. And then Exa here went ahead and did the research. You can see it's already jumping in, and then it got the answers here as the task output. You can see it generated some numbers, some citations from some of them where you got that information, and it kept going and generated the final output there. And then we have the final output. It kept going, did some research, extra research until it got to the final document here. And when it was done, it closed it up and it also outputted here the final summary that we can read through. So it says in February 2025, the landscape of AI agents is undergoing transformative revolution marked by rapid technological advancements. I don't want to read the whole thing, but you get the gist. It goes, does research, brings it to you, and it gives you some really relevant stuff that's happening. So major discoveries, analysis of what it found, and then future implications of what it found. And then there's recommendations, strategic suggestions for stakeholders, invest in the development integration of proactive multimodal AI agents. There's R&D programs, risk mitigation, and then there's investment focus areas like healthcare, finance, customer service, where agents can significantly enhance operational efficiency. That's okay, but you know, could be better. Investment in regulatory technology oversight to ensure safe and responsible innovation. That I dig, and then the citations, of course, of where it got all the information. This is all arranged properly. And then we have the final here, you know, download the report. So if I want to download report, I would hit download, and you could see here it's already downloaded the report. And if I open the report, that will take a minute to open. But once that opens, like you already have the same version of report that you had on your system. So this is you know final. You would have that already on your on your desktop. So. That's it. Very quick and dirty. And I'll add the repo in the comment section so that way you can share it. So that's the whole demo. And I know there's some— maybe you have some more questions. If you do have questions, please put them in the chat. And also some things that I noted that, you know, to keep in mind. I know you might be wondering, could we convert this into a chat application instead where you chat with the agents? Yes, that's possible. Can you add more agents? Yes, that's possible. But you also have to keep in mind that The more agents you add and the more in-depth research they have to do, then the longer you have to wait on the chat, for example, compared to this where you just put it in and you just sit around and wait until it's done. You can add on top of that so many processes. Of course, this is a basic skeleton version to just get you started. If you're looking for the code for this demo, please look into the description below. You'll be able to find the code, play around with it. If you run into any issues, of course, let me know. I'll try to help you out as much as I can. And also if you haven't subscribed, you should already be subscribed. This is the good content that I keep creating here and I'll be sharing more. I'm also experimenting with live streams. So if you check those out, that'd be cool as well, but play around with it. I want to see more stuff that you built with this. If you end up building something really cool, tag me on socials. Also tag CrewAI and some of the other providers that I've mentioned here. We'll be happy to repost your stuff. So with that, thank you and see you in the next video. Bye.
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)








