Building an AI-Powered Educational Content Generator with CrewAI and Streamlit ๐
Introduction ๐
In this article, weโll explore how to build an intelligent educational content generator that creates personalized learning materials, quizzes, and project suggestions using CrewAI and Streamlit. This solution demonstrates the power of AI agents working together to create comprehensive educational content.
Tech Stack ๐ ๏ธ
- CrewAI: For orchestrating multiple AI agents
- Streamlit: For creating the web interface
- Pydantic: For data validation and modeling
- Ollama LLaMA3.2: For natural language processing
- SerperDev: For web search capabilities
Core Components ๐งฉ
1. Data Models ๐
We use Pydantic models to ensure data consistency and validation:
class LearningMaterial(BaseModel):
title: str
url: str
type: str # video, article, or exercise
description: str
class QuizQuestion(BaseModel):
question: str
options: List[str]
correct_answer: int
explanation: str
class Quiz(BaseModel):
topic: str
questions: List[QuizQuestion]
class ProjectIdea(BaseModel):
title: str
description: str
difficulty: ExpertiseLevel
estimated_duration: str
required_skills: List[str]
learning_outcomes: List[str] 2. AI Agents ๐ค
This solution employs three specialized agents:
1. Learning Material Curator ๐
โ Role: Finds and curates high-quality learning resources
โ Expertise: Educational content curation
โ Output: Structured learning materials with descriptions and links
2. Quiz Creator โ
โ Role: Generates engaging assessment questions
โ Expertise: Educational assessment design
โ Output: Multi-choice questions with explanations
3. Project Advisor ๐ก
โ Role: Suggests practical projects
โ Expertise: Project-based learning
โ Output: Detailed project descriptions with learning outcomes
3. Task Orchestration ๐ญ
CrewAI helps orchestrate these agents in a sequential workflow:
# Create and run crew
crew = Crew(
agents=[learning_material_agent, quiz_creator_agent,project_suggestion_agent],
tasks=[create_learning_material_task, create_quiz_task, create_project_suggestion_task],
process=Process.sequential
)4. User Interface ๐ฅ๏ธ
Streamlit provides an intuitive interface with:
- Topic input area ๐
- Expertise level selector ๐
- Three organized tabs for different content types ๐
Solution Workflow ๐
1. User Input ๐ค
โ Users enter their topics of interest
โ Select their expertise level (Beginner/Intermediate/Advanced)
2. Content Generation โ๏ธ
โ Learning Material Curator searches for and validates resources
โ Quiz Creator generates relevant assessment questions
โ Project Advisor suggests practical applications
3. Output Display๐ฑ
โ Learning materials are displayed with clickable links
โ Quiz questions show with interactive explanations
โ Projects are presented with detailed breakdowns
Code Workflow ๐ฅ๏ธ
- Install required dependencies
pip install crewai crewai[tools]2. Setup serper api key
3. User Interface(app.py)
import streamlit as st
from crewai import Agent, Crew, Task, Process, LLM
from typing import List
import os
from dotenv import load_dotenv
from crewai_tools import SerperDevTool
# Load environment variables
load_dotenv()
from pydantic import BaseModel,Field
from typing import List, Optional,Dict
from enum import Enum
import json
class ExpertiseLevel(str, Enum):
BEGINNER = "beginner"
INTERMEDIATE = "intermediate"
ADVANCED = "advanced"
# ====== Fixed Learning Material Model ======
class LearningMaterial(BaseModel):
title: str
url: str
type: str=Field(...,description="video, article, or exercise")
description: str
class MaterialCollection(BaseModel): # Renamed for clarity
materials: List[LearningMaterial]
class QuizQuestion(BaseModel):
question: str
options: List[str]
correct_answer: int
explanation: str
class QuizFormat(BaseModel):
questions: List[QuizQuestion]
class Quiz(BaseModel):
topic: str
questions: List[QuizQuestion]
# Fix Quiz model structure
class QuizQuestion(BaseModel):
question: str
options: List[str]
correct_answer: int # Index of correct option (0-based)
explanation: str
class Quiz(BaseModel): # Renamed from QuizFormat
questions: List[QuizQuestion]
# Corrected ProjectIdea model (represents a SINGLE project)
class ProjectIdea(BaseModel):
title: str
description: str
difficulty: ExpertiseLevel
estimated_duration: str = Field(..., description="Duration estimation in days")
required_skills: List[str]
learning_outcomes: List[str]
# Container for multiple projects
class Projects(BaseModel):
projects: List[ProjectIdea]
# Initialize LLM and search tool
llm = LLM('ollama/llama3.2', temperature=0.7)
search_tool = SerperDevTool(serper_api_key=os.getenv("SERPER_API_KEY"))
def main():
st.title("Educational Content Generator")
# Sidebar for inputs
with st.sidebar:
st.header("Configuration")
topics = st.text_area("Enter topics (one per line)",
help="Enter the topics you want to learn about")
expertise_level = st.selectbox(
"Select your expertise level",
options=[level.value for level in ExpertiseLevel],
help="Choose your current level of expertise"
)
# Main content area
if st.button("Generate Content"):
if not topics:
st.error("Please enter at least one topic")
return
topic_list = [topic.strip() for topic in topics.split('\n') if topic.strip()]
with st.spinner("Generating personalized content..."):
try:
learning_material_agent = Agent(
role='Learning Material Curator',
goal='Curate high-quality learning materials based on user topics and expertise level',
backstory="""You are an expert educational content curator with years of experience
in finding the best learning resources for students at different levels. You know how
to identify reliable and high-quality educational content from reputable sources.""",
llm=llm,
verbose=True
)
quiz_creator_agent = Agent(
role='Quiz Creator',
goal='Create engaging and educational quizzes to test understanding',
backstory="""You are an experienced educator who specializes in creating
effective assessment questions that test understanding while promoting learning.""",
llm=llm,
verbose=True
)
project_suggestion_agent = Agent(
role='Project Advisor',
goal='Suggest practical projects that match user expertise and interests',
backstory="""You are a project-based learning expert who knows how to create
engaging hands-on projects that reinforce learning objectives.""",
llm=llm,
verbose=True
)
#
create_learning_material_task = Task(
description=f"""{topics}.
Explain {topics} to a {expertise_level} level.
Include a mix of videos, articles, and practical exercises.
Ensure all materials are from reputable sources and are current.
Include GitHub repos for practical exercises. Verify source credibility before including.
Format response as: {{
"materials": [
{{
"title": "...",
"url": "...",
"type": "...",
"description": "..."
}}
]
}}""",
agent=learning_material_agent,
expected_output=MaterialCollection.schema_json()
)
create_quiz_task = Task(
description=f"Create a comprehensive quiz for {topics} at {expertise_level} level.",
agent=quiz_creator_agent,
expected_output=Quiz.schema_json(),
output_pydantic=Quiz
)
create_project_suggestion_task = Task(
description=f"""Suggest ONLY 5 BEST practical project ideas for {topics}.
Projects should be suitable for {expertise_level} level.
Include title, description, difficulty, estimated duration, required skills, and learning outcomes.
Suggest projects that have recent community activity (check GitHub).
Include links to relevant documentation.
Projects should be engaging and reinforce key concepts.""",
agent=project_suggestion_agent,
expected_output=Projects.schema_json(),
output_pydantic=Projects
)
# Create and run crew
crew = Crew(
agents=[learning_material_agent, quiz_creator_agent,project_suggestion_agent],
tasks=[create_learning_material_task, create_quiz_task, create_project_suggestion_task],
process=Process.sequential
)
result = crew.kickoff({"topics":topic_list,"expertise_level":ExpertiseLevel(expertise_level)})
# Display results in tabs
tab1, tab2, tab3 = st.tabs(["Learning Materials", "Quiz", "Project Ideas"])
with tab1:
st.header("Curated Learning Materials")
materials = create_learning_material_task.output.raw
try:
# Parse the raw JSON string into a Python dictionary
materials_json = json.loads(materials)
if 'materials' in materials_json:
for material in materials_json['materials']:
with st.container():
st.subheader(material['title'])
col1, col2 = st.columns([1, 3])
with col1:
st.write("**Type:**")
st.write("**URL:**")
st.write("**Description:**")
with col2:
st.write(material['type'].capitalize())
st.markdown(f"[Link]({material['url']})")
st.write(material['description'])
st.divider()
except json.JSONDecodeError as e:
st.error("Error parsing learning materials")
st.write(materials) # Fallback to display raw output
with tab2:
st.header("Knowledge Quiz")
quiz = create_quiz_task.output.raw
try:
quiz_json = json.loads(quiz)
if 'questions' in quiz_json:
for i, question in enumerate(quiz_json['questions'], 1):
with st.container():
st.subheader(f"Question {i}")
st.write(question['question'])
# Display options in a cleaner format
for j, option in enumerate(question['options'], 1):
if j == question['correct_answer']:
st.markdown(f"**{j}. {option} โ**")
else:
st.write(f"{j}. {option}")
# Show explanation in an expander
with st.expander("See Explanation"):
st.write(question['explanation'])
st.divider()
except json.JSONDecodeError as e:
st.error("Error parsing quiz")
st.write(quiz) # Fallback to display raw output
with tab3:
st.header("Suggested Projects")
projects = result.pydantic
if projects and hasattr(projects, 'projects'):
for project in projects.projects:
with st.container():
st.subheader(f"๐ {project.title}")
# Create two columns for project details
col1, col2 = st.columns([2, 1])
with col1:
st.markdown("**Description:**")
st.write(project.description)
with col2:
st.markdown("**Quick Info:**")
st.write(f"๐ท **Difficulty:** {project.difficulty}")
st.write(f"โฑ๏ธ **Duration:** {project.estimated_duration}")
# Skills and outcomes in expandable sections
with st.expander("Required Skills"):
for skill in project.required_skills:
st.markdown(f"โข {skill}")
with st.expander("Learning Outcomes"):
for outcome in project.learning_outcomes:
st.markdown(f"โข {outcome}")
st.divider()
except Exception as e:
st.error(f"An error occurred: {str(e)}")
if __name__ == "__main__":
main() 4. Run with `streamlit run app.py`
streamlit run app.py4.Response
# Agent: Learning Material Curator
## Task: How to create a client in python in order to access MCP server created in python.
Explain How to create a client in python in order to access MCP server created in python to a beginner level.
Include a mix of videos, articles, and practical exercises.
Ensure all materials are from reputable sources and are current.
Include GitHub repos for practical exercises. Verify source credibility before including.
Format response as: {
"materials": [
{
"title": "...",
"url": "...",
"type": "...",
"description": "..."
}
]
}
# Agent: Learning Material Curator
## Final Answer:
{
"materials": [
{
"title": "How to Create a Client in Python to Access MCP Server",
"url": "https://realpython.com/python-mcp-client/",
"type": "article",
"description": "This article provides a step-by-step guide on how to create a client in Python to access an MCP server."
},
{
"title": "MCP Client Example Code",
"url": "https://github.com/microsoft/mcp-py/blob/main/examples/client_example.py",
"type": "exercise",
"description": "This GitHub repository provides an example of how to create a client in Python using the MCP API."
},
{
"title": "Python MCP Client Tutorial",
"url": "https://www.youtube.com/watch?v=8qBcTZXhP5I",
"type": "video",
"description": "This YouTube video provides a visual tutorial on how to create a client in Python using the MCP API."
},
{
"title": "MCP Client Library for Python",
"url": "https://mcp-py.readthedocs.io/en/latest/",
"type": "article",
"description": "This documentation provides an overview of the MCP client library for Python and how to use it."
}
]
}
# Agent: Quiz Creator
## Task: Create a comprehensive quiz for How to create a client in python in order to access MCP server created in python at beginner level.
# Agent: Quiz Creator
## Final Answer:
{
"questions": [
{
"question": "What is MCP and what is its purpose in Python?",
"options": [
"MCP stands for Microsoft Communication Platform, which allows developers to create clients that can communicate with the Microsoft Communication Platform server.",
"MCP stands for MicroPython Client Protocol, which is a lightweight protocol used by MicroPython devices to communicate with each other.",
"MCP stands for Message Queuing, which is a messaging system used in some applications to handle messages and notifications.",
"MCP stands for Messaging Control Protocol, which is a protocol used for managing and controlling messaging services."
],
"correct_answer": 1,
"explanation": "MCP stands for Microsoft Communication Platform, which allows developers to create clients that can communicate with the Microsoft Communication Platform server. The MCP client library provides a set of classes and functions that make it easy to create clients in Python."
},
{
"question": "What is the first step in creating an MCP client in Python?",
"options": [
"Import the MCP client library",
"Create an instance of the MCP client class",
"Configure the MCP server settings",
"Define a callback function for handling messages"
],
"correct_answer": 1,
"explanation": "The first step in creating an MCP client in Python is to import the MCP client library. This provides access to the classes and functions that make up the client."
},
{
"question": "What is the purpose of the `mcp.connect()` function?",
"options": [
"To establish a connection to the MCP server",
"To send a message to the MCP server",
"To receive messages from the MCP server",
"To close the connection to the MCP server"
],
"correct_answer": 1,
"explanation": "The `mcp.connect()` function is used to establish a connection to the MCP server. This allows the client to send and receive messages with the server."
},
{
"question": "How do you define a callback function for handling messages?",
"options": [
"Using the `mcp.callback` method",
"Creating a separate module for message handlers",
"Defining a class that implements the `mcp.callback` interface",
"Using an external messaging library"
],
"correct_answer": 2,
"explanation": "Callback functions are defined using a separate module or by creating a class that implements the `mcp.callback` interface. This allows you to handle incoming messages in a specific way."
}
]
}
# Agent: Project Advisor
## Task: Suggest ONLY 5 BEST practical project ideas for How to create a client in python in order to access MCP server created in python.
Projects should be suitable for beginner level.
Include title, description, difficulty, estimated duration, required skills, and learning outcomes.
Suggest projects that have recent community activity (check GitHub).
Include links to relevant documentation.
Projects should be engaging and reinforce key concepts.
# Agent: Project Advisor
## Final Answer:
{
"projects": [
{
"title": "MCP Client Simulator",
"description": "Create a simulator for the MCP client that allows you to test different scenarios and configurations. This project will help you understand how the MCP client works and how to use it effectively.",
"difficulty": "beginner",
"estimated_duration": "3-5 days",
"required_skills": ["Python", "MCP client library"],
"learning_outcomes": [
"Understand the basics of the MCP client library",
"Learn how to create a client in Python",
"Practice using the MCP client library"
]
},
{
"title": "MCP Server Simulation",
"description": "Create a simulation for the MCP server that allows you to test different scenarios and configurations. This project will help you understand how the MCP server works and how to use it effectively.",
"difficulty": "beginner",
"estimated_duration": "3-5 days",
"required_skills": ["Python", "MCP server library"],
"learning_outcomes": [
"Understand the basics of the MCP server library",
"Learn how to create a server in Python",
"Practice using the MCP server library"
]
},
{
"title": "MCP Client Automation",
"description": "Create a script that automates the process of connecting to the MCP server and sending/receiving messages. This project will help you understand how to use the MCP client library effectively.",
"difficulty": "intermediate",
"estimated_duration": "5-7 days",
"required_skills": ["Python", "MCP client library"],
"learning_outcomes": [
"Understand how to automate tasks using Python",
"Learn how to use the MCP client library for automation",
"Practice using the MCP client library for automation"
]
},
{
"title": "MCP Server Security",
"description": "Create a script that demonstrates secure communication with the MCP server. This project will help you understand how to protect against common attacks.",
"difficulty": "intermediate",
"estimated_duration": "5-7 days",
"required_skills": ["Python", "MCP server library"],
"learning_outcomes": [
"Understand how to secure communication with the MCP server",
"Learn how to use Python for security testing",
"Practice using the MCP server library for security"
]
},
{
"title": "MCP Client GUI",
"description": "Create a graphical user interface (GUI) for the MCP client that allows users to easily connect and send/receive messages. This project will help you understand how to create a GUI using Python.",
"difficulty": "advanced",
"estimated_duration": "7-10 days",
"required_skills": ["Python", "MCP client library", "GUI development"],
"learning_outcomes": [
"Understand how to create a GUI using Python",
"Learn how to use the MCP client library for GUI development",
"Practice using the MCP client library for GUI development"
]
}
]
}
Key Features ๐
1. Personalization ๐ฏ
โ Content tailored to userโs expertise level
โ Topic-specific resources and assessments
2. Quality Controlโ
โ Validation of learning material sources
โ Structured output formats
โ Error handling and fallbacks
3. Interactive UI ๐จ
โ Clean, organized presentation
โ Expandable sections for detailed information
โ Visual hierarchy with icons and formatting
Best Practices Implemented ๐
1. Code Organization ๐
โ Modular structure with separate models and agents
โ Clear class and function responsibilities
โ Type hints and documentation
2. Error Handling๐ก๏ธ
โ JSON parsing with fallbacks
โ Input validation
โ User-friendly error messages
3. User Experience ๐ฅ
โ Loading indicators
โ Clear section organization
โ Intuitive navigation
Future Enhancements ๐
1. Content Persistence๐พ
โ Save generated content
โ User history tracking
โ Favorite/bookmark system
2. Enhanced Interactivity๐ฎ
โ Interactive quizzes
โ Progress tracking
โ Social sharing features
3. AI Improvements๐ง
โ More specialized agents
โ Enhanced content validation
โ Learning path recommendations
Conclusion ๐
This project demonstrates the power of combining multiple AI agents to create a comprehensive educational content generation system.
The solution showcases how CrewAI, Streamlit, and modern Python tools can work together to create an engaging and useful educational application.
