Engineering Notes

Building a Recruitment LLM from Zero to One: A BOSS Zhipin–Style Case Study

A practical open-source blueprint for a recruitment-domain language model: product goals, data governance, continued pretraining, SFT and DPO, RAG, candidate–job matching, evaluation, safety, deployment, and a 12-week delivery plan.

HOUHUIYANG.COM

Scan to continue reading

Generating…

Building a Recruitment LLM from Zero to One: A BOSS Zhipin–Style Case Study

houhuiyang.com/en/notes/building-a-recruitment-llm-from-zero-to-one

If I had to build a language model for a recruitment platform similar to BOSS Zhipin, I would not begin by buying GPUs or debating whether the model should have 7B, 32B, or 100B parameters.

I would begin with three questions:

  1. Which business outcome must the system improve?
  2. What lawful, distinctive, and verifiable data do we have?
  3. Which problems belong to an LLM, and which should remain search, recommendation, or rule-based problems?

The easiest mistake in recruitment AI is to treat “building an industry model” as training a chatbot. A production system is not one model. It is a coordinated system of data, retrieval, matching, generation, risk controls, evaluation, and human decisions.

One factual boundary matters. Public filing information lists “Nanbeige,” operated by the company behind BOSS Zhipin, under filing number Beijing-NanBeiGe-20240102. Its complete data recipe, training pipeline, and internal architecture are not public.Cyberspace Administration of China filing notice

This article therefore does not claim to reconstruct BOSS Zhipin's internal system. It uses a BOSS Zhipin–style platform as a business case and presents an implementable open-source reference architecture.

What “from zero” should mean

Pretraining a general foundation model from random initialization requires trillions of tokens, long-running clusters, mature distributed systems, and substantial compute. For almost every recruitment company, that is the wrong first milestone.

A practical zero-to-one path is:

open-weight base model
    ↓
recruitment-domain continued pretraining (optional)
    ↓
task-oriented supervised fine-tuning
    ↓
preference optimization and safety alignment
    ↓
RAG, business tools, and matching systems
    ↓
offline evaluation, canary release, and feedback loop

“Self-developed” does not have to mean random initial weights. The assets a company should own are its domain data, training recipe, evaluation sets, service architecture, and learning loop.

Training from scratch becomes reasonable only when the company has a very large lawful corpus, stable compute, an experienced training team, and a base-model deficiency in tokenization, language coverage, or core behavior that adaptation cannot fix.

Step 1: turn business goals into evaluable tasks

A recruitment platform serves both candidates and recruiters, whose goals differ.

Candidates need to know which roles genuinely fit, which requirements are hard constraints, how to improve a résumé, how to communicate effectively, and whether a role or company is trustworthy.

Recruiters need to turn ambiguous needs into clear job descriptions, discover qualified candidates, understand skill fit, reduce unproductive conversations, and identify fraudulent résumés, jobs, or accounts.

Version one should not solve everything. I would choose three measurable scenarios:

ScenarioOutputPrimary metrics
JD normalization and rewritingStandard title, skills, experience, location, compensation, and a faithful rewriteField F1, factual fidelity, publish acceptance
Candidate–job explanationMatches, gaps, evidence, and uncertaintyRecall@K, NDCG, evidence accuracy
Recruitment copilotQuestions, replies, and next-step suggestions grounded in the job and résuméReply rate, human acceptance, safety violations

Do not use hiring rate as the only early metric. Hiring is delayed and influenced by compensation, location, employer brand, recruiter behavior, and the economy. Early evaluation needs model-quality metrics, process metrics, and business outcomes together.

Step 2: separate the system instead of asking the LLM to do everything

A recruitment platform needs a layered architecture:

                        ┌─────────────────────────────┐
candidate / recruiter → │ chat, search, recommendation│
                        └──────────────┬──────────────┘
                                       ↓
                        ┌─────────────────────────────┐
                        │ task routing and policy      │
                        │ intent / auth / risk / cost  │
                        └───────┬──────────┬──────────┘
                                │          │
                  ┌─────────────┘          └──────────────┐
                  ↓                                          ↓
       ┌───────────────────────┐                ┌───────────────────────┐
       │ recruitment LLM       │                │ retrieval and ranking │
       │ extract/generate/explain│              │ two-tower/rank/rerank │
       └───────────┬───────────┘                └───────────┬───────────┘
                   ↓                                            ↓
       ┌───────────────────────┐                ┌───────────────────────┐
       │ RAG and business tools│                │ feature/vector platform│
       │ jobs/company/API      │                │ user/job/behavior      │
       └───────────┬───────────┘                └───────────┬───────────┘
                   └───────────────────┬────────────────────┘
                                       ↓
                        ┌─────────────────────────────┐
                        │ governance, eval, audit, loop│
                        └─────────────────────────────┘

LLMs are strong at semantic interpretation, extraction, generation, explanations, and tool orchestration. They are not the right engine for low-latency retrieval across millions of candidates, and they should not make opaque rejection decisions by themselves.

A mature design usually assigns:

A minimal open-source stack

Do not accumulate frameworks merely to claim an open stack. Give each layer one primary implementation and a replaceable boundary:

LayerInitial choiceOutput contract
DataPython/SQL + DataTrove or SparkVersioned Parquet, dataset card, lineage
TrainingPyTorch + LLaMA-Factory/TRL; FSDP or DeepSpeed when scale requires itAdapter/checkpoint and metrics
Lexical/vector searchOpenSearch, or PostgreSQL + pgvector initiallyFiltered candidates and evidence
Embedding/rerankingOpen-weight bilingual embedding + cross-encoderVectors and relevance scores
ServingvLLM or SGLangOpenAI-compatible API
Experiment/evaluationMLflow + private gold sets and regression scriptsVersioned data, model, prompt, metrics

Tool names matter less than interfaces. Training examples, embeddings, retrieval results, generations, and evaluations should carry dataset_version, model_version, prompt_version, and trace_id; otherwise production failures cannot be reconstructed.

Step 3: build a recruitment ontology first

More data creates more contradiction when terms do not share a common meaning.

“Senior Java developer,” “backend engineer,” and “server-side engineer” may belong to the same job family. “LLM experience” may mean calling an API, or it may mean training, evaluation, and inference optimization.

I would first build a versioned ontology:

job family → normalized title → specialization → skill → proficiency
                                                   ├─ required/preferred
                                                   ├─ years of use
                                                   └─ recency

job → industry → company stage → location → work mode → compensation

candidate → experience → project → responsibility → action → result → evidence

The ontology does not force every employer to use the same title. It gives retrieval, training, and evaluation a shared coordinate system. Every mapping should retain the original phrase, normalized value, confidence, and ontology version.

A structured JD example should include evidence:

{
  "source_text": "Hiring a senior backend engineer, 5+ years, Java and microservices required; LLM experience preferred.",
  "job_family": "Software Engineering",
  "normalized_title": "Senior Backend Engineer",
  "required_skills": ["Java", "Microservices"],
  "preferred_skills": ["Large Language Models"],
  "experience_min_years": 5,
  "evidence": {
    "experience_min_years": "5+ years",
    "required_skills": ["Java and microservices required"]
  },
  "confidence": 0.96,
  "ontology_version": "job-ontology-2026-08"
}

The important field is not JSON; it is evidence. Recruitment outputs must remain traceable to source text.

Step 4: create lawful, traceable data assets

Recruitment data is unusually sensitive. Résumés can contain names, contact details, education, employment history, location, and salary expectations. Conversations can reveal family circumstances, health information, and other private details.

I would separate data into four layers:

LayerExamplesMain use
Public knowledgeOccupational taxonomies, public skill documentation, labor rules, public company informationDomain knowledge and RAG
Platform dataAuthorized JDs, de-identified résumés, search and interaction dataContinued pretraining and matching
Expert labelsNormalized roles, skill evidence, fit judgments, preferred responsesSFT, preference optimization, evaluation
Online feedbackAccept, edit, reply, apply, interview, complaintIteration and impact measurement

Every record needs provenance, authorization basis, collection time, owner, sensitivity, permitted tasks, transformation history, retention, and deletion status.

The fact that data exists in a platform database does not automatically authorize model training. Product operation, recommendation, fraud prevention, and training are different processing purposes and require separate review.

Recruitment data pipeline

source registration and permission review
        ↓
parse JDs, résumés, conversations, and event logs
        ↓
remove templates, ads, contact solicitation, and corruption
        ↓
detect language, job family, industry, and content type
        ↓
detect PII, tokenize replacements, isolate identity mapping
        ↓
exact dedup, résumé-version dedup, fuzzy JD-template dedup
        ↓
detect fraud, low quality, discriminatory text, and conflicts
        ↓
quality scoring and evidence-completeness checks
        ↓
split by time, user, and company—not random rows
        ↓
dataset card, version, and audit record

Regular expressions are insufficient for de-identification. Emails and phone numbers fit rules; names, schools, project descriptions, addresses, and identity hints in free text need NER, dictionaries, model-based detection, and sampled review.

Random row splits are also unsafe. Multiple résumés from one person, templated JDs from one employer, or messages from one conversation can leak across train and test sets. Group by person and employer, split by time, and check contamination against public benchmarks.

Step 5: choose a base model by workload, not leaderboard rank

For Chinese recruitment, candidate open-weight families include Qwen, GLM, and Llama. The Qwen ecosystem supports Transformers, vLLM, SGLang, and fine-tuning frameworks such as LLaMA-Factory and TRL.Qwen official repository

Evaluate:

  1. License: commercial and derivative-model terms;
  2. Chinese and mixed-language quality: titles and technical stacks often mix Chinese and English;
  3. Structured output: JSON Schema adherence and field stability;
  4. Long context: full résumés, JDs, and conversations—not just advertised context length;
  5. Tool calling: argument accuracy, recovery, and authorization boundaries;
  6. Serving cost: TTFT, TPOT, throughput, and memory at target concurrency;
  7. Domain baseline: performance on the company's recruitment evaluation suite.

A 7B–14B model is often the right first experiment. Prove the task and data before scaling. Larger models are not automatically better for every classifier or extractor, and stable tasks can later be distilled into smaller models.

Measure the tokenizer on real JDs, résumés, and technical vocabulary: characters per token, truncation rate, and terminology fragmentation. Do not modify the vocabulary unless measured gains justify compatibility and retraining costs.

Step 6: train in stages

Stage A: continued pretraining (optional)

Continued pretraining teaches domain language and relationships using large amounts of unlabeled text. Candidate sources include authorized and deduplicated JDs, de-identified occupational material, public labor rules, high-quality industry documents, and strictly governed business text.

Do not dump all résumés and conversations into pretraining. Apply PII, safety, quality, duplication, and mixture controls first. Mix in some general data to reduce catastrophic forgetting, and use small ablations to determine whether continued pretraining is worth its cost.

If domain text is limited and the base model is already strong, SFT plus RAG is often a better investment.

Continued pretraining still optimizes next-token cross-entropy:

L_CPT = -Σ log Pθ(x_t | x_<t)

Four engineering controls matter:

Each checkpoint needs a data manifest, code revision, random seed, optimizer state, and mixture. Falling domain loss with large general regressions indicates forgetting, not success.

Stage B: supervised fine-tuning

SFT should cover:

A high-quality example includes not only a prompt and response, but task type, source evidence, allowed tools, expected output, risk labels, and dataset version.

{
  "messages": [
    {"role": "system", "content": "You are a recruitment assistant. Use only the supplied job and résumé. Never infer age, marital status, family plans, or health."},
    {"role": "user", "content": "Explain matches and gaps.\n[JOB]...\n[RESUME]..."},
    {"role": "assistant", "content": "{\"matched\":[...],\"gaps\":[...],\"unknown\":[...],\"evidence\":[...]}"}
  ],
  "task": "job_candidate_explanation",
  "risk_tags": ["employment", "personal_information"],
  "dataset_version": "recruit-sft-2026-08"
}

LoRA or QLoRA is appropriate for fast validation. LLaMA-Factory supports continued pretraining, SFT, DPO, and related workflows.LLaMA-Factory

model_name_or_path: Qwen/Qwen3-8B
stage: sft
do_train: true
finetuning_type: lora
lora_target: all
dataset: recruitment_sft
template: qwen3
cutoff_len: 4096
learning_rate: 1.0e-4
num_train_epochs: 2.0
bf16: true
val_size: 0.05
llamafactory-cli train recruitment_sft.yaml

These are starting parameters, not a universal recipe. Learning rate, epochs, sequence length, rank, and mixture require validation and ablation.

Several SFT details are easy to miss:

Whether full fine-tuning beats LoRA depends on dataset size, task breadth, and compute. First use LoRA to prove the data; run a controlled full-tuning comparison only when adapter capacity is a measured bottleneck.

Stage C: preference optimization

Once the model can perform the task but remains inconsistent in style, evidence, or refusal boundaries, collect preferred and rejected responses.

Prefer grounded explanations over unsupported judgments, uncertainty over fabricated experience, capability-related language over age or family proxies, concise action over empty prose, and valid tool calls over invented live job data.

DPO is simpler than traditional RLHF for an initial system. TRL provides SFT, DPO, reward modeling, and other post-training tools.Hugging Face TRL

Do not adopt GRPO simply because it is fashionable. Reinforcement learning is most dependable when rewards are verifiable—schema validity, SQL execution, code tests, or deterministic rules. Subjective employment judgments should never be reduced to one reward model.

DPO directly increases the relative probability of a preferred response over a rejected one:

L_DPO = -log σ(β[(log πθ(y+|x)-log πref(y+|x))
                 -(log πθ(y-|x)-log πref(y-|x))])

β controls deviation from the reference model. Bucket by task, length, and risk, and verify that “preference improvement” is not merely verbosity. When recruitment experts genuinely disagree, retain annotator distributions or send the case to review instead of inventing one truth.

Step 7: use RAG for changing facts and tools for actions

Job availability, compensation, employer information, and application status change continuously. They should not be memorized in model parameters.

The retrieval layer can include current jobs and versions, verified employer data, skill knowledge, policies, labor rules, and only the résumés or conversations the current user is authorized to access.

question
   ↓
intent and authorization
   ↓
structured filters: location, salary, experience, status
   ↓
hybrid retrieval: lexical + vector
   ↓
reranker
   ↓
evidence compression and citations
   ↓
generation or business-tool call
   ↓
factuality, authorization, and safety checks

Recruitment search cannot be vector similarity alone. Location, compensation, experience, job status, and access are hard filters. Semantic retrieval handles differences such as “AI platform engineering” versus “LLM infrastructure.” A reranker then scores a small candidate set.

Do not add raw BM25 and vector scores directly; they usually have incompatible scales. Reciprocal Rank Fusion is a robust first implementation:

RRF(d) = Σ 1 / (k + rank_i(d))

Retrieve lexical and dense Top-K lists separately, fuse their ranks, and send the best 50–200 records to a cross-encoder. Enforce tenant_id, status, location, compensation, freshness, and authorization filters in the index or service before evidence reaches the LLM—not by redacting after generation.

Write actions—submitting a résumé, sending a message, or editing a JD—need typed schemas, server-side reauthorization, idempotency keys, preview and confirmation, timeout and compensation behavior, and audit logs. The model may propose an action; it must not bypass business permissions.

Step 8: train matching as a separate system

Large-scale job matching remains a retrieval and recommendation problem.

Use a two-tower model to encode candidate and job representations for ANN retrieval. Apply a cross-encoder or learning-to-rank model to the retrieved set, then rerank for freshness, diversity, deduplication, and business constraints.

candidate profile → candidate tower ─┐
                                     ├─ similarity → ANN Top-K
job profile       → job tower ───────┘
                                           ↓
                            cross-encoder / learning-to-rank
                                           ↓
                         rules, freshness, diversity, fairness
                                           ↓
                              LLM-generated explanation

An LLM can enrich features, produce weak labels, and explain results. It should not iterate over millions of jobs at inference time.

Labels also need care. A click is not ground truth. Exposure is controlled by the previous model; clicks respond to titles and compensation; conversations depend on recruiter activity. Use layered events—impression, click, save, apply, reply, interview, hire—and account for position bias, negative sampling, and delayed outcomes.

Two-tower retrieval can use a contrastive objective. For candidate vector u, positive job v+, and jobs in the batch:

L_retrieval = -log exp(sim(u,v+)/τ) / Σ_j exp(sim(u,v_j)/τ)

Random negatives are often too easy. Add hard negatives such as the same title at a different seniority or the same skill set in an incompatible location. An exposed but unclicked job is not necessarily negative—it may have appeared too low—so preserve exposure position and filter likely false negatives.

The ranker can combine semantic crosses, structured compatibility, freshness, and behavior. LLM explanations must read the factual features and source evidence used by the final ranking, avoiding one mechanism for ranking and an invented story for explanation.

Step 9: build evaluation before large training runs

Without a private recruitment benchmark, the team cannot know whether domain training helped.

Understanding and generation

CapabilityMetrics
Field extractionPrecision, recall, F1, schema-valid rate
JD rewritingFactual fidelity, completeness, violations, acceptance
Fit explanationEvidence precision, omissions, unsupported-claim rate
RAGRecall@K, citation correctness, groundedness, abstention
Tool useArgument accuracy, execution success, unauthorized calls, duplicates
SafetyPII leakage, discriminatory language, prompt-injection success

Matching and ranking

Freeze the test set by time and exclude future feedback from training. General leaderboards cannot replace domain evaluation.

Release through shadow traffic first: generate outcomes without affecting users, compare against production, then progress through a small canary only after safety, quality, latency, and cost gates pass.

Step 10: production is more than starting vLLM

Open-source engines such as vLLM and SGLang provide efficient serving, but production also requires gateways, routing, caching, degradation, and observability.vLLM

API gateway
   ↓
identity, quota, length, and risk checks
   ↓
task router
   ├─ small model: classification, extraction, rewriting
   ├─ larger model: complex analysis and dialogue
   ├─ embedding/reranker: retrieval and matching
   └─ rule service: constraints and safety
   ↓
batching, KV cache, timeout, circuit breaker
   ↓
schema, citation, and safety validation
   ↓
logs, traces, cost, and quality sampling

Observe time to first token, time per output token, total latency, queue time, token counts, GPU utilization, cost per task, timeout, cancellation, retry, fallback, JSON failures, tool failures, and unsupported claims—split by model, task, language, and version.

A model upgrade is not one file replacement. Prompts, tokenizers, retrieval, tool schemas, quantization, and decoding parameters all affect behavior and need coordinated versioning.

A first capacity approximation is:

replicas ≈ peak QPS × P95 service time
           ÷ safe concurrency per replica × headroom

Correct it with load tests using real input and output lengths. Benchmark short extraction, long-résumé analysis, and multi-turn dialogue separately; averages hide long-tail out-of-memory failures. Compare BF16, FP8/INT8, and lower-bit quantization on the recruitment gold set before production—throughput alone is not an acceptance test.

The safety line in recruitment

Recruitment is not ordinary text generation. A bad recommendation wastes time; an opaque rejection can affect a person's livelihood.

China's Personal Information Protection Law requires transparency and fairness when personal information is used for automated decision-making.Personal Information Protection Law

At minimum:

  1. Do not use sex, age, ethnicity, family status, or health as matching features without a lawful and justified basis;
  2. test proxy effects from school, address, career gaps, and similar attributes;
  3. never let the LLM make final hiring or rejection decisions alone;
  4. ground important recommendations in job and résumé evidence;
  5. provide human review, correction, opt-out, and appeal paths;
  6. enforce résumé authorization at retrieval, prompt, log, and cache layers;
  7. audit dataset, model, prompt, and tool-call versions;
  8. complete applicable security assessment, algorithm filing, or model registration before public launch.

Removing a name does not make a model fair. Schools, postal codes, employment years, and writing style can become identity proxies. Fairness review requires lawful subgroup analysis and joint ownership across legal, ethics, recruitment, product, and ML teams.

An executable 12-week plan

PeriodGoalDeliverable
Weeks 1–2Tasks and baselinesThree scenarios, gold evaluation set, production baseline, compliance checklist
Weeks 3–4Data and ontologyOntology v1, lineage, de-identification pipeline, dataset v1
Weeks 5–6Open-model PoCThree-model benchmark, LoRA SFT, error taxonomy
Weeks 7–8RAG and matchingHybrid retrieval, reranker, two-tower baseline, citations
Weeks 9–10Preference and safetyDPO set, safety suite, red team, authorization and audit
Week 11Shadow and canaryShadow report, latency/cost report, 1–5% canary
Week 12ReviewBusiness impact, regression report, decision on scale and model size

Define release gates in advance: extraction F1, schema validity, unsupported-claim rate, zero severe PII or authorization failures, P95 latency and cost budgets, and a statistically credible lift in acceptance or valid conversations.

Exact thresholds must come from the business baseline, not another company's blog post.

Seven common failure modes

  1. Train first, search for a use case later: the result is a demo chatbot without a business outcome.
  2. Treat database access as training consent: résumé, conversation, and behavior purposes are ignored.
  3. Randomly split rows: users and templates leak into test data and inflate scores.
  4. Build only an LLM: no scalable retrieval, high latency, and high cost.
  5. Trust general benchmarks: the model solves math but cannot extract salary evidence consistently.
  6. Treat clicks as truth: the new system learns the old system's exposure and position bias.
  7. Automatically reject candidates: no evidence, explanation, human review, or fairness control.

My conclusion

The moat in a recruitment model is not renaming an open model or maximizing parameter count.

It comes from:

Without these five elements, a self-developed model is an expensive chatbot.

With them, even a 7B–14B open-weight model can create real value in version one.

Building a recruitment LLM from zero to one is not writing a Transformer from zero. It is building, from zero, a system that connects recruitment knowledge, business data, model capability, and real outcomes.

References

Back to Engineering Notes