The End of the Manual Resume: Building a Career Agent with LangGraph
Why traditional resumes must die and how I used AI to build a system that manages my professional identity with integrity and precision.
Manual Resumes Must Die (And No, I'm Not Talking About AI Lying)
Nobody enjoys writing resumes. It's a mechanical task: repeating the same thing over and over, making minor adjustments to try and fit into an automated system. It's frustrating, and above all, it's a waste of human time.
That's why I built a Resume Agent. But I did it with an unwavering rule: truth is non-negotiable.
The Problem of "Lying AI"
Many fear that AI will invent information to force a fit with a job opening. My design focuses on the opposite: the agent knows exactly when your experience matches and when it doesn't. If there's no "match," no data is fabricated. The agent isn't a fiction writer; it's your most honest representative.
The Future: Peer-to-Peer Relationships
Today we are in transition, but the future is inevitable: we won't be sending resumes; our agents—who know us inside and out—will handle the initial "digital handshake." We will move from a "boss-employee" model to a service provision between professionals, where technology manages the noise and we focus on impact.
Under the Hood: Architecture with LangGraph
For those who want to know how the machinery works, here's an explanation of the orchestration behind this application co-pilot. I decided not to use a simple chain, but a stateful graph to allow for review cycles.
graph TD
Start((Job Input)) --> Scraper[node: Scraper]
Scraper -->|job_description| Parser[node: Parser]
Parser -->|parsed_job| Match[node: Matching Engine]
Match -->|gap_analysis & dashboard_md| Tailor[node: Tailors]
Tailor --> Verify{Verification Edge}
Verify -->|Incomplete / cycle < 2| Tailor
Verify -->|Complete / Valid| Exporter[node: Exporter]
Exporter -->|tailored_cv.tex| End((Final Output))
subgraph "External Loading"
MasterCV[(Master CV)] -. Loaded .-> Match
MasterCV -. Loaded .-> Tailor
end
style Verify fill:#f9f,stroke:#333
style Exporter fill:#dfd,stroke:#333
style Scraper fill:#bbf,stroke:#333
Why LangGraph?
Instead of a linear flow, LangGraph allows for building cyclic applications. This is vital because it enables the agent to make mistakes, review them, and decide if it needs to try a task again (a "self-critique loop").
The system is divided into five main nodes:
- Scraper Node (
scraper.py): Extracts raw information from job posting URLs. - Parser Node (
parser.py): Usesgemini-flash-lite-latestandPydanticOutputParserto transform messy text into a clear structure of requirements (Must-haves vs. Nice-to-haves). - Matching Engine (
matching_engine.py): Compares the Master CV against the requirements to generate a "Gap Analysis" and a compatibility score. - Tailor Node (
tailor.py): Optimizes the candidate's summary and achievements under strict "zero hallucination" constraints. - PDF Exporter (
exporter.py): Native generation using LaTeX and Jinja2, avoiding the instability of converting HTML to PDF.
The Verification Loop (Self-Correction)
The power of the graph lies in the Conditional Edge. If the model forgets to include a mandatory section, the system detects it and sends it back to the previous node:
# Verification logic in the Graph
def verify_tailored_sections(state: GraphState):
# If the section is incomplete, retry (max 2 times)
if is_incomplete(state) and state["cycle_count"] < 2:
return "tailor"
return "exporter" # If everything is fine, generate the PDF
Final Thoughts
Building stable autonomous agents requires strict state design (Pydantic) and ultra-fast inference engines. By using Gemini Flash-Lite, latency is minimal, allowing what once took hours of manual editing to now be delivered in seconds with complete integrity.
Are you ready to let an agent manage your next job opportunity, or do you prefer to maintain manual control?
Author's note: I wrote this post using AI. However, now that I have it at hand, I feel it's lacking a bit of "life." For the next posts, I'm going to modify how I do it; I think I'll go back to a more manual process so it doesn't feel soulless. It's not flashy.