All posts
12 min read

Building a Multi-Agent AI Pipeline: How 6 LLM Agents Collaborate to Tailor Your CV

We didn't build one AI prompt. We built six specialized agents that work like a team. Here's why a pipeline of focused agents beats a single mega-prompt for resume tailoring.

architectureai-agentsllmengineering

The Problem with Single-Prompt AI

Every AI resume tool we tried does the same thing: take your resume and a job posting, run it through one big prompt, return a rewritten version. The output is always mediocre.

Why? Because a single prompt is trying to do too many things at once: understand the job, understand your experience, reorganize content, match keywords, assess fit, and format output. Each of these is a distinct cognitive task that benefits from focused attention.

The Hypothesis

What if we broke the problem into specialized agents — each focused on one step — connected by a pipeline with structured contracts between them?

This is the same principle behind microservices, Unix pipes, and assembly lines: specialized components connected by clear interfaces outperform monolithic systems for complex tasks.

Architecture Overview

CV Tailor uses 6 sequential agents orchestrated by a state machine:

Job Posting → [Job Interpreter] → JobBrief
                                      ↓
Your Profile → [CV Selector] → Draft CV
                                    ↓
                           [Fit Validator] → FitReport (score + gaps)
                                    ↓
                    score < threshold? → [Interviewer] → Questions
                                              ↓
                         Your Answers → [Facts Updater] → Updated Profile
                                              ↓
                                        (loop back to CV Selector)
                                    ↓
                    score >= threshold → [LaTeX Agent] → PDF

Each agent is a pure function with Zod-validated input/output schemas. No agent knows about the others — they communicate only through structured data.

Agent 1: Job Interpreter

Input: Raw job posting text (plain text or HTML) Output: Structured JobBrief (Zod-validated JSON)

The Job Interpreter's job is to extract signal from noise. A job posting contains a mix of real requirements, nice-to-haves, company boilerplate, and legal disclaimers. The agent parses this into structured fields: role title, seniority, key requirements, preferred skills, company context, and hiring signals.

The critical insight: extracting implicit requirements is as important as stated ones. "Fast-paced startup environment" implies adaptability and comfort with ambiguity. "Cross-functional collaboration" implies communication skills and stakeholder management.

Agent 2: CV Selector

Input: User's profile facts + JobBrief Output: Tailored CV in Markdown

This agent doesn't rewrite your resume — it selects and reframes. Given your full profile (achievements, projects, skills, context) and the structured job brief, it picks the most relevant experiences and frames them in the language of the target role.

We chose Markdown as the intermediate format because it's human-readable, easy to diff, and cleanly separates content from presentation. The LaTeX formatting happens later.

Agent 3: Fit Validator

Input: Draft CV + JobBrief Output: FitReport — score (0-100) + structured gap list

This is where semantic scoring diverges from keyword matching. Instead of counting keyword overlaps, the Fit Validator evaluates structural alignment:

Each gap is returned as a structured object with the requirement, what's missing, and why it matters for this role.

Agent 4: Interviewer

Input: FitReport gaps + user profile Output: Targeted questions

This is CV Tailor's most unique feature. When the Fit Validator identifies gaps, the Interviewer generates specific questions designed to surface relevant experience the user forgot to include.

Not "Tell me about your leadership experience" — but "The role requires stakeholder management. You led the payment integration at [Company]. Can you describe a time you presented technical decisions to non-technical leadership during that project?"

The specificity matters. Generic questions get generic answers. Targeted questions unlock real experiences.

Agent 5: Facts Updater

Input: Interview answers + existing profile facts Output: Merged, updated profile facts

The user's answers need to be integrated into their profile without overwriting existing data. This agent handles the merge: adding new facts, enriching existing ones, and maintaining the structural integrity of the profile.

Agent 6: LaTeX Agent

Input: Final CV Markdown Output: LaTeX source + compiled PDF

The last agent converts the Markdown CV into professional LaTeX, then compiles it to PDF using Tectonic. The result has real typographic quality — proper kerning, ligatures, and layout — that HTML-to-PDF converters can't match.

The Iteration Loop

After the Fit Validator scores the draft, the pipeline checks: is the score above threshold (default: 75)? If not, it loops through agents 4-5 (interview + update), then re-runs agents 2-3 (draft + score). This continues until the fit score exceeds the threshold or max iterations (default: 3) are reached.

Each iteration produces a measurably better CV because the profile gets richer with each round of questions.

State Machine Design

The pipeline is orchestrated by a state machine in runner.ts. Each state maps to an agent, and transitions are determined by the agent's output:

Progress is streamed to the client via Server-Sent Events (SSE), so users see real-time updates as each agent completes.

Structured Output with Zod

Every agent that returns JSON uses Zod schemas as contracts. The LLM call wrapper (llmJsonCall) forces the model to produce valid, schema-conforming output. If the output doesn't parse, the retry mechanism kicks in with the validation error in the prompt.

This eliminates an entire category of bugs: malformed JSON, missing fields, wrong types. The schema IS the contract between agents.

Client-Side-First Architecture

All user data lives in the browser's IndexedDB via Dexie.js. The server is completely stateless — it receives facts and a job posting, processes them through the agent pipeline, and returns results. It never stores, logs, or caches user data.

This wasn't just a privacy decision (though it is a strong privacy guarantee). It eliminated massive architectural complexity: no user table, no auth system, no database migrations, no GDPR compliance headaches. Each browser session owns its own data.

Lessons Learned

1. Clear contracts between agents are everything. Zod schemas aren't just validation — they're the API between agents. When we added a new field to JobBrief, every downstream agent that consumed it got type-checked automatically.

2. The interview loop was the highest-leverage feature. We expected the multi-agent pipeline to be the key differentiator. In practice, the interview step — asking the human for information instead of guessing — produced the largest quality improvement.

3. Client-side storage eliminated more complexity than expected. No auth, no database, no user management, no data retention policies. The simplicity compounded at every layer.

4. LaTeX is fragile but worth it. Tectonic compilation fails on edge cases (unusual characters, deeply nested lists). But the output quality is visibly superior to any HTML-to-PDF approach.

5. Start with structured output from day one. Retrofitting Zod schemas onto agents that were returning free-form text was painful. Structured output should be the default for any multi-agent system.

Try It

CV Tailor is free to use. Paste a job posting, import your CV, and see how 6 agents collaborate to build a tailored version.

Your data never leaves your browser. No account required.

Try CV Tailor free

No account required. Your data stays in your browser.

Start tailoring