👋 Hey there, Tech Enthusiasts!
I'm Sarvar, a Cloud Architect who loves turning complex tech problems into simple solutions. I've worked with AWS, Azure, DevOps, Data, Analytics, Generative-AI and Agentic-AI building real systems for real companies. In this article series, I'll share what I've learned in a way that's easy to follow, whether you're experienced or just getting started.
Let's get into it! 🚀
Hey, welcome back.
In the
How it works:
User opens the Streamlit web UI in their browser and pastes a job description, resume, and experience level
Streamlit (running on EC2) passes the inputs to the CrewAI orchestrator
crew.py loads the agent configuration (agents.yaml + tasks.yaml) and constructs the prompt- The prompt is sent to Amazon Bedrock Nova Pro a foundation model that does the actual analysis
- Bedrock returns the analysis skill gaps, career guidance, and tailored resume
- Results flow back through CrewAI → Streamlit → displayed to the user
The entire stack runs on a single EC2 instance (t3.medium). The only external service is Amazon Bedrock, which handles the LLM inference. No databases, no queues, no complex infra just a Python app talking to a foundation model.
Setting Up the Environment
First, SSH into your server. If you're working locally, skip this.
ssh -i your-key.pem ec2-user@your-server-ip
Install uv
uv is a fast Python package manager. CrewAI uses it under the hood for dependency management. Think of it like npm for Python, but faster.
curl -LsSf https://astral.sh/uv/install.sh | sh
Install CrewAI CLI
This gives you the crewai command the tool you'll use to create projects, install dependencies, and run agents.
uv tool install crewai-cli --python python3.11 --with crewai
That's it. Environment is ready.
Creating the Project
CrewAI has a scaffolding command that creates the entire project structure for you. No need to create folders manually.
crewai create crew resume_tailor --classic
Model: Choosebedrock/us.amazon.nova-pro-v1:0(option 28)
This creates a folder called resume_tailor with everything you need.
Now let's go into the project:
cd resume_tailor
Configuring the Agent
Open src/resume_tailor/config/agents.yaml. This is where you define WHO your agent is.
Replace everything in the file with this:
resume_tailor:
role: >
Senior Resume Tailor & Career Advisor
goal: >
Analyze the job description, compare it with the candidate's resume,
identify skill gaps, and rewrite the resume to match the job requirements.
backstory: >
You're a seasoned career advisor with 15+ years of experience in tech recruiting.
You've reviewed thousands of resumes and job descriptions. You know exactly what
hiring managers look for, can instantly spot skill gaps, and you rewrite resumes
that get interviews. You're direct, practical, and never give generic fluff.
Three things here:
Role - tells the agent who it is. "Senior Resume Tailor & Career Advisor" not just "helper" or "assistant." The more specific the role, the better the output.
Goal - tells it what to achieve. This is the finish line.
Backstory - gives it personality. "15+ years in tech recruiting" makes it write like someone who's actually done this, not like a generic chatbot.
Think of it like hiring a contractor. You wouldn't say "do some work." You'd say "You're a senior plumber. Your job is to fix the kitchen leak. You've been doing this for 20 years." Same idea.
Wiring It Up - crew.py
Open src/resume_tailor/crew.py. This is where you connect the agent to the task.
Replace everything with this:
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai.agents.agent_builder.base_agent import BaseAgent
@CrewBase
class ResumeTailor():
"""ResumeTailor crew"""
agents: list[BaseAgent]
tasks: list[Task]
@agent
def resume_tailor(self) -> Agent:
return Agent(
config=self.agents_config['resume_tailor'], # type: ignore[index]
verbose=True
)
@task
def tailor_resume_task(self) -> Task:
return Task(
config=self.tasks_config['tailor_resume_task'], # type: ignore[index]
output_file='tailored_resume.md'
)
@crew
def crew(self) -> Crew:
return Crew(
agents=self.agents,
tasks=self.tasks,
process=Process.sequential,
verbose=True,
)
What's happening here:
@CrewBase- tells CrewAI this class is a crew. It automatically loads your YAML configs.
@agentmethod - creates the agent from the YAML config. The method nameresume_tailormust match the key in agents.yaml.
@taskmethod - creates the task from the YAML config. Same ruletailor_resume_taskmust match tasks.yaml.
output_file='tailored_resume.md'- saves the result to a file. Nice for reviewing later.
Process.sequential- tasks run one after another. We only have one task, so this doesn't matter much here. But if you add more agents later, this controls the order.
verbose=True- shows you what the agent is thinking while it works. Great for debugging. Turn it off in production.
That's it. The model to use and the AWS region.
If you're on EC2 with an IAM role attached, you don't need AWS keys the SDK picks up credentials automatically from the instance profile. Don't put AWS access keys in this file if you're using an IAM role it's unnecessary and a security risk. If you're running locally without an IAM role, make sure your AWS CLI is configured:
aws configure
This creates a uv.lock file and installs everything the project needs.
Now add Bedrock support if you already updated your pyproject.toml to include crewai[bedrock,tools], you can skip this step. Otherwise, add it now:
uv add "crewai[bedrock]"
You'll see the agent start up, show you what it's thinking, and then produce the output. The whole thing takes about 20-30 seconds.
Create the UI
Create a file called streamlit_app.py in the project root (not inside src/):
import streamlit as st
from resume_tailor.crew import ResumeTailor
st.set_page_config(page_title="Resume Tailor Agent", page_icon="📄", layout="wide")
# Header
st.markdown("""
<h1 style='text-align: center;'>📄 Resume Tailor Agent</h1>
<p style='text-align: center; color: gray; font-size: 1.1em;'>Paste a job description → Get career guidance, skill gaps, and a tailored resume in seconds.</p>
<hr>
""", unsafe_allow_html=True)
# Input section
st.subheader("📥 Input")
col1, col2 = st.columns(2)
with col1:
job_description = st.text_area("Job Description *", height=250, placeholder="Paste the job description here (required)...")
with col2:
resume = st.text_area("Your Resume (Optional)", height=250, placeholder="Paste your resume here leave empty if you don't have one yet...")
col3, col4, col5 = st.columns(3)
with col3:
years_experience = st.number_input("Years of Experience *", min_value=0, max_value=40, value=3)
with col4:
expertise_level = st.selectbox("Expertise Level *", ["Fresher", "Junior", "Mid-Level", "Senior", "Lead", "Architect"])
with col5:
st.markdown("<br>", unsafe_allow_html=True)
analyze_btn = st.button("🚀 Analyze", type="primary", use_container_width=True)
# Info box
if not job_description:
st.info("💡 **Tip:** Even without a resume, you'll get JD analysis, key technologies, and a career path to follow.")
# Process
if analyze_btn:
if not job_description:
st.error("⚠️ Please paste the job description to continue.")
else:
st.divider()
st.subheader("📊 Analysis Results")
with st.spinner("🤖 Agent is analyzing... this takes about 30 seconds."):
inputs = {
"job_description": job_description,
"resume": resume if resume else "Not provided",
"years_experience": str(years_experience),
"expertise_level": expertise_level,
}
result = ResumeTailor().crew().kickoff(inputs=inputs)
st.success("✅ Analysis complete!")
st.markdown(result.raw)
# Download button
st.download_button(
label="📥 Download Results",
data=result.raw,
file_name="resume_analysis.md",
mime="text/markdown",
)
# Footer
st.divider()
st.markdown("""
<p style='text-align: center; color: gray; font-size: 0.85em;'>
Built with CrewAI + Amazon Bedrock Nova Pro | By <a href="https://sarvarnadaf.com">Sarvar Nadaf</a>
</p>
""", unsafe_allow_html=True)
Paste a job description on the left, your resume on the right, click the button, and watch the agent work.
2. Matching Skills
4. Career Guidance
Why This Test Matters
You might be wondering - why pick two slightly different skill sets? The resume is an AI Engineer. The JD is a Senior GenAI Developer. They overlap, but they're not identical.
That's the point. I wanted to see how the agent handles the gap between "close but not quite" - and the results are genuinely impressive. It identified exactly where the resume falls short, suggested a clear path to bridge the gap, and rewrote the bullet points to speak the JD's language.
And here's the thing - you can customize the output further. Want exactly 8 tailored resume points? Add that to the task description. Want the career guidance to focus only on certifications? Tweak the prompt. The agent does what you tell it to. You control the output by controlling the instructions.
What Just Happened
Let's step back and look at what we built:
- One YAML file to define the agent (who it is, what it's good at)
- One YAML file to define the task (what to do, what the output should look like)
- One Python file to wire them together
- One Python file for the web UI
Four files. That's a working AI agent with a web interface.
The agent reads the job description, compares it to the resume (if provided), identifies key technologies to highlight, lists skill gaps as clean bullet points, gives a career roadmap, and rewrites the entire resume to match all in one pass, in about 30 seconds.
Even without a resume, it still delivers value JD analysis, key technologies, and a preparation path. So anyone can use it, whether they have a resume ready or not.
No training data. No fine-tuning. No complex pipelines. Just a well-written prompt, a good LLM, and a framework that handles the plumbing.
Source Code
The complete source code for this project is available on GitHub:
AI agent that analyzes job descriptions, identifies skill gaps, and tailors your resume - built with CrewAI and Amazon Bedrock.
📄 Resume Tailor Agent
AI-powered resume tailoring — paste a job description, get a perfect match in seconds.
⭐ If this helped you, give it a star! It helps others find it.
•
🤔 The Problem
You're job hunting. Every company wants something slightly different. You've done the work — but your resume doesn't say it in the JD's language. ATS systems scan for keywords before a human ever sees your application. Wrong framing = filtered out automatically.
One application = 30 minutes of tweaking. Multiply that by 10+ applications.
This agent does it in 30 seconds.
✨ What It Does
One agent. One pass. Five powerful outputs.
🎯 With JD + Resume
|
Happy Learning 🚀
Community-Analysen & Experten-Meinungen 0
Verwandte Story-Cluster & Quellen (Vektor-KI)
Ähnliche Beiträge
Auch interessante Nachrichten Build Your First AI Agent in 30 Minutes - CrewAI + AWS Bedrock
Thematisch verwandte Begriffe: Build, Your, First, Agent · 6 Treffer
Apple accuses OpenAI of destroying evidence as trade-secrets fight intensifies
GPT-6 Astra Release Today? OpenAI’s Next Major AI Model Is Almost Here
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
Beiträge werden geladen ...
Videos werden geladen ...
SOCIAL SHARE CARD GENERATOR