원클릭으로
jd-optimization
Optimize and enhance AI-generated job descriptions for SEO, readability, and conversion
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Optimize and enhance AI-generated job descriptions for SEO, readability, and conversion
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Use AWS Bedrock with Nova models for JD generation, embeddings, and agentic workflows
Manage Pinecone vector operations for semantic candidate matching and job similarity
Manage LangGraph workflows, debug state transitions, and handle checkpoints
Test FastAPI endpoints with pytest, including auth, jobs, candidates, and workflow APIs
Safely create, test, and deploy Alembic database migrations for AARLP
Build and optimize Next.js 14 frontend components with TypeScript, Tailwind, and theme support
| name | jd_optimization |
| description | Optimize and enhance AI-generated job descriptions for SEO, readability, and conversion |
This skill helps you optimize AI-generated job descriptions (JDs) for the AARLP platform. It ensures JDs are SEO-optimized, ATS-friendly, and conversion-focused while maintaining the platform's AI-generated quality standards.
Keywords to Include:
Standard JD Structure:
1. Hook (1-2 sentences) - Company mission/value prop
2. Role Overview (2-3 sentences) - What they'll do
3. Responsibilities (5-7 bullet points)
4. Qualifications
- Required (3-5 must-haves)
- Preferred (2-4 nice-to-haves)
5. Benefits & Perks (4-6 compelling points)
6. About Company (2-3 sentences)
7. CTA (Apply now with clear next steps)
# Regenerate JD with specific feedback
POST /jobs/{job_id}/regenerate-jd
{
"feedback": "Add more emphasis on remote work options and salary range. Include specific technologies like FastAPI, LangGraph, Pinecone."
}
# Update specific JD sections
PUT /jobs/{job_id}/jd
{
"title": "Senior Backend Engineer - FastAPI & AI (Remote)",
"responsibilities": [...],
"benefits": [
"Competitive salary: $120k-$160k",
"100% remote work - US timezone",
...
]
}
Run SEO Analysis
Readability Check
Bias Detection
| Issue | Fix |
|---|---|
| Too generic | Add company-specific details, tech stack, projects |
| Too formal | Use conversational tone, "you'll" instead of "candidate will" |
| Unclear expectations | Quantify responsibilities ("manage 3-5 direct reports") |
| Missing benefits | Add at least 4 compelling benefits |
| Poor mobile formatting | Break long paragraphs, use bullet points |
# app/workflow/nodes.py - generate_jd_node
async def generate_jd_node(state: GraphState) -> GraphState:
"""
Node that generates JD and automatically applies optimization rules.
"""
from app.ai.jd_generator import generate_job_description
from app.jobs.schemas import JobInput
# Extract job input from state
job_input = JobInput(**state.jd.input_data)
# Generate initial JD
generated_jd = await generate_job_description(job_input)
# OPTIMIZATION CHECKPOINT: Apply SEO and ATS rules
optimized_jd = apply_optimization_rules(generated_jd, job_input)
return state.model_copy(
update={
"jd": state.jd.model_copy(
update={
"content": optimized_jd.description,
"title": optimized_jd.job_title,
"status": Status.COMPLETED
}
)
}
)
The regenerate_job_description() function in app/ai/jd_generator.py expects specific feedback patterns:
✅ Effective Feedback Examples:
# 1. Specific additions
feedback = """
Add emphasis on remote work flexibility and include salary range $120k-$160k.
Mention that we use FastAPI, LangGraph, and Pinecone in the tech stack.
"""
# 2. Tone adjustments
feedback = """
Make the tone more conversational and less corporate.
Replace 'candidate will be responsible for' with 'you'll get to work on'.
"""
# 3. SEO-focused
feedback = """
Include keywords: 'AI engineer', 'machine learning', 'python developer'.
Add location 'San Francisco Bay Area' for better local search visibility.
"""
# 4. Structural changes
feedback = """
Move benefits section before requirements.
Add a 'What You'll Build' section highlighting real projects.
Break requirements into 'Must Have' and 'Nice to Have' subsections.
"""
❌ Ineffective Feedback (Too Vague):
# Won't produce good results
feedback = "Make it better"
feedback = "Sounds too boring"
feedback = "Add more details"
# 1. Regenerate with optimization feedback (POST /jobs/{id}/regenerate-jd)
async def regenerate_with_seo_focus(job_id: str, auth_headers: dict):
"""
Trigger regeneration with SEO optimization focus.
This updates the workflow state and resumes from checkpoint.
"""
response = await fetch(
f"http://localhost:8000/jobs/{job_id}/regenerate-jd",
method="POST",
headers=auth_headers,
json={
"feedback": """
Optimize for Google for Jobs:
- Add explicit salary range in title
- Include 'Remote' or location in title
- Use job title keywords that match common searches
- Add structured benefits section
"""
}
)
# This triggers the workflow to:
# 1. Load checkpoint from wait_jd_approval state
# 2. Call generate_jd_node with feedback
# 3. Return to wait_jd_approval for re-review
return response.json()
# 2. Manual edit (PUT /jobs/{id}/jd)
async def manual_optimization_edit(job_id: str, auth_headers: dict):
"""
Directly update JD fields without AI regeneration.
Use when recruiter knows exact changes needed.
"""
response = await fetch(
f"http://localhost:8000/jobs/{job_id}/jd",
method="PUT",
headers=auth_headers,
json={
"summary": "Join our mission to revolutionize recruitment...",
"requirements": [
"5+ years Python development (FastAPI, Django, or Flask)",
"Experience with AI/ML frameworks (LangChain, OpenAI SDK)",
"PostgreSQL and vector databases (Pinecone preferred)"
],
"salary_range": "$120,000 - $160,000 + equity"
}
)
# This updates the DB directly, bypassing workflow
# No state change, JD remains in wait_jd_approval
return response.json()
# 3. Check if optimization is needed (GET /jobs/{id}/jd)
async def analyze_jd_quality(job_id: str, auth_headers: dict):
"""
Fetch JD and run optimization checks programmatically.
"""
response = await fetch(
f"http://localhost:8000/jobs/{job_id}/jd",
headers=auth_headers
)
jd = response.json()
# Run checks
issues = []
if not jd.get("salary_range") or jd["salary_range"] == "Competitive":
issues.append("Missing explicit salary range (reduces visibility by 30%)")
if len(jd.get("description", "")) < 200:
issues.append("Description too short for SEO (minimum 200 chars)")
if "remote" not in jd.get("title", "").lower() and "location" not in jd.get("title", "").lower():
issues.append("Title missing location/remote keyword")
return {
"needs_optimization": len(issues) > 0,
"issues": issues,
"suggestion": "Run regenerate with: " + "; ".join(f"Fix: {i}" for i in issues)
}
graph TB
A[create_job API] --> B[generate_jd_node]
B --> C[wait_jd_approval]
C --> D{Recruiter Action}
D -->|regenerate-jd API| E[generate_jd_node with feedback]
D -->|PUT /jd API| C
D -->|approve-jd API| F[post_job_node]
E --> C
style E fill:#f9f,stroke:#333
style C fill:#bbf,stroke:#333
Key Points:
regenerate-jd triggers a full workflow state update and resumes graph executionPUT /jd is a direct DB update without workflow interaction# Add to app/ai/jd_generator.py or create app/ai/jd_optimizer.py
from app.jobs.schemas import GeneratedJD, JobInput
def apply_optimization_rules(jd: GeneratedJD, job_input: JobInput) -> GeneratedJD:
"""
Apply automatic optimization rules to generated JD.
Rules:
1. Ensure title has location/remote
2. Add salary if missing
3. Validate readability
4. Check ATS keywords
"""
optimized = jd.model_copy()
# Rule 1: Location in title
if job_input.location and job_input.location.lower() not in jd.job_title.lower():
optimized.job_title = f"{jd.job_title} ({job_input.location})"
# Rule 2: Salary transparency
if not jd.salary_range or jd.salary_range == "Competitive":
if job_input.salary_range:
optimized.salary_range = job_input.salary_range
else:
# Suggest to recruiter
logger.warning("No salary range provided - reduces application rate by 30%")
# Rule 3: Readability (sentence length)
if optimized.description:
sentences = optimized.description.split('. ')
avg_length = sum(len(s.split()) for s in sentences) / len(sentences)
if avg_length > 25:
logger.info("High sentence complexity detected - consider simplification")
# Rule 4: Benefits minimum count
if len(optimized.benefits) < 4:
logger.warning("Less than 4 benefits listed - consider adding more")
return optimized
# Complete example: Optimize a generated JD
# 1. Job created, JD generated (automatic)
POST /jobs/create
{
"role_title": "Senior Backend Engineer",
"company_name": "TechCorp",
"experience_years": 5,
"key_requirements": ["Python", "FastAPI", "PostgreSQL"],
"salary_range": "$130k-$170k"
}
# Response: job_id = "abc-123"
# Graph runs: generate_jd_node -> wait_jd_approval
# 2. Recruiter reviews generated JD
GET /jobs/abc-123/jd
{
"job_title": "Senior Backend Engineer",
"description": "Join our team...",
// Missing: remote info, specific tech stack details
}
# 3. Recruiter provides optimization feedback
POST /jobs/abc-123/regenerate-jd
{
"feedback": "Add 'Remote - US' to title. Emphasize FastAPI and LangGraph experience. Include equity compensation."
}
# Graph resumes: generate_jd_node (with feedback) -> wait_jd_approval
# 4. Recruiter reviews optimized version
GET /jobs/abc-123/jd
{
"job_title": "Senior Backend Engineer (Remote - US)",
"description": "...FastAPI and LangGraph...",
"salary_range": "$130k-$170k + equity"
}
# 5. Approve and post
POST /jobs/abc-123/approve-jd
# Graph continues: post_job_node -> ...
app/ai/embeddings.py - Test JD embeddingsBefore (Generic):
We are looking for a Software Engineer to join our team.
After (Optimized):
Join our mission to revolutionize recruitment with AI. As a Senior Backend Engineer, you'll architect scalable FastAPI services that power real-time candidate matching for Fortune 500 companies - all while working 100% remotely.
Key Improvements: ✅ Specific role level ✅ Tech stack mentioned ✅ Impact/mission highlighted ✅ Remote work explicitly stated ✅ Social proof (Fortune 500) ✅ Active voice, direct address
regenerate-jd API calls trigger LangGraph state transitions and checkpoint resumption