Field SOP
Field SOP

Resume Screening Workflow: Score by JD and Route in One Pass

Receiving two to three hundred resumes per JD is slow and error-prone by hand. This n8n workflow funnels resume screening into one pipe: Webhook/email intake -> extract text -> LLM scores skill match/experience/stability/risk against the JD and outputs a tier plus reason -> IF checks whether it clears the bar -> Switch routes to interview queue/talent pool/rejection email -> write to Feishu Bitable or ATS -> notify recruiter. The Prompt explicitly forbids using gender/age/marital status/race/household registration as factors; resume handling must comply with PIPL/GDPR; AI scoring is assistive only and the final call belongs to a human.

Published August 4, 20265 min read
<!-- workflow-resume-screening | resource | Resume Screening Workflow: Score by JD and Route in One Pass -->

Receiving two or three hundred resumes for one job posting is normal during hiring season. HR opens each PDF, eyeballs it against the JD, scores it in Excel, then schedules interviews or sends rejection letters-five minutes per resume on average, twenty-five hours of pure manual work for three hundred, and by the time the round closes half a month is gone. Worse, scoring drifts: the first ten get careful reads, by the hundredth it's "good enough"; the same resume scores 70 in the morning and 55 when the reviewer is tired after lunch; and the candidate's school, gender, or age quietly creep into judgment, making fairness hard to guarantee and harder to prove.

This n8n workflow funnels resume screening into one pipe: resumes arrive via Webhook or email attachment, text is extracted automatically, an LLM scores skill match, experience, stability, and risk against the JD and outputs a reason, an IF checks whether the tier clears the bar, then a Switch routes to interview queue / talent pool / rejection email, writing to a Feishu Bitable or ATS and notifying the recruiter along the way. A resume goes from submission to routing in minutes, and HR spends time only on the interview queue.

Compliance is the floor, not a bonus. The LLM Prompt explicitly forbids using protected attributes-gender, age, marital or parental status, race, household registration, disability, religion, political affiliation-as scoring factors; only skills, experience, and projects are weighed against the JD. Resumes carry personal information subject to China's Personal Information Protection Law (PIPL) and GDPR: get candidate authorization, minimize processing, set retention limits. AI scoring is assistive only; the final interview decision belongs to a human. Laws vary by jurisdiction-treat local law as authoritative.

Workflow Chain

Webhook trigger (careers-site form / email attachment / IM bot forward) -> Code node extracts text (PDF / Word parsed to plain text, formatting noise stripped) -> LLM scores against JD (skill_match / experience / stability / risk four dimensions, outputs score + tier + reason + suggested interview questions) -> IF clears bar (tier is interview or pool) -> Switch routes (interview / pool) -> write to Feishu Bitable or ATS -> notify recruiter; IF below bar (tier is reject) -> send rejection email -> status writeback.

This follows the same shape as our Lead Auto-Collect + Scoring + Notify Workflow (workflow-lead-crm-automation): leads and resumes are both "unstructured input arrives, score by rules, route by score" flows-the scoring dimensions swap to skill match and experience, and the routing exits swap to interview queue and ATS. It shares the "LLM extracts fields + writes to table + notifies" skeleton with our Customer Feedback Analysis Workflow (workflow-customer-feedback-analysis).

Download Template

Setup Steps

  1. Import: n8n -> Workflows -> Import from File, pick workflow-resume-screening.json
  2. Webhook node: copy the Production URL, wire it to your careers-site submission form or email-forwarding rule. Resumes can arrive as attachments or base64; the next node normalizes both
  3. Extract text node (Code): parse PDF / Word into plain text. n8n's built-in Extract from File node handles PDF; for Word, convert to .txt upstream or call a third-party parsing API. Strip header/footer dividers, email signatures, and special characters-keep only structured blocks: name, contact, education, work history, projects, skills. Generate a dedup key from contact info or name plus source
  4. LLM scoring node: fill in Kimi / DeepSeek / Qwen key; 8k context is enough. Prompt below; the model outputs skill_match (0-100), experience (0-100), stability (0-100), risk (low/medium/high), score (composite 0-100), tier (interview / pool / reject, one of three), reason (within 100 words), interview_questions (2-3 suggested follow-ups). Hard constraint: the Prompt explicitly forbids using gender / age / marital status / race / household registration as factors; the model looks only at skills and experience
  5. IF clears bar node: take tier equal to interview or pool into the pass branch; otherwise (reject) into the rejection branch. Threshold logic is encoded in the Prompt's tier definition: score>=80 interview, 60-79 pool, <60 reject. Tune by role tightness-raise the interview floor to 85 for core roles, drop to 50 for pipeline roles
  6. Switch route node: split the pass branch-tier interview to interview queue, pool to talent pool. The pool is not a rejection; it's "revisit when a slot opens"
  7. Write to Feishu / ATS node: HTTP Request to Feishu Bitable API or an ATS (Moka / Beisen / Greenhouse) write API. Fields: name, contact, score, risk, reason, interview_questions, source, submission time, route. This is the foundation for funnel analytics and post-mortems
  8. Send rejection email node: tier reject lands here. HTTP Request to an email API (Resend / Alibaba Cloud DirectMail), templated reply-thank them + a generalized mismatch reason (no specific score, no commentary on personal attributes) + notice that the resume is retained in the talent pool with an opt-out link. Run the wording by legal; don't promise "priority consideration in the future"
  9. Notify recruiter node: when the interview queue is hit, push a card via Slack / Feishu / DingTalk group bot carrying the candidate name, role, score, risk, and interview_questions so the recruiter can decide at a glance whether to grab a slot
  10. Status writeback node: HTTP Request PATCH back to the ATS, marking status=screened + score + tier + risk + screened_at. The closure of the loop-resumes no longer sit at "received" but carry a clear routing result
  11. Test run: manually submit three test resumes-one clearly matching, one borderline, one clearly mismatched-and verify they land in interview queue, talent pool, and rejection email respectively, that the Feishu table has records, and that the recruiter got the notification

Companion Prompt (LLM Resume Scoring by JD)

Prompt
You are a hiring assistant. Score the candidate's resume against the JD and output JSON:
- skill_match: 0-100, how well skills match JD keywords
- experience: 0-100, fit of years of experience and project history to role requirements
- stability: 0-100, job-hopping frequency and career continuity (frequent hops deduct)
- risk: low / medium / high, risk signals (long employment gaps, severe mismatch with JD, contradictions in the resume)
- score: composite 0-100
- tier: interview (score>=80) / pool (60-79) / reject (<60), pick one of three
- reason: within 100 words, cite facts from the resume
- interview_questions: 2-3 suggested follow-up questions for the interview
Rules: judge only on skills, experience, projects, and career history; forbid using gender, age, marital or parental status, race, household registration, disability, religion, or political affiliation as scoring factors-ignore any such information that appears in the resume; do not fabricate facts not in the resume; when info is severely insufficient, default score to 50, tier to pool, and prefix reason with [insufficient info].
JD: {{jd}}
Resume text: {{resume_text}}

Advanced

  • Dynamic thresholds: different roles and levels use different cutoffs. Store the tier score boundaries in a Feishu table or config center; the Code node fetches boundaries by role name, then the LLM outputs only the raw score and the Code node computes tier-so you don't republish the Prompt every time the threshold changes
  • Dedup anti-spam: same email or phone resubmitting in a short window-query the ATS first in the Code node; if a hit exists, update the score without creating a duplicate record, preventing score-farming and double rejections
  • Human-review layer: scores within 5 points of a boundary are a gray zone-don't route directly, queue for human review. These edge cases are the most valuable; accumulating them feeds back into Prompt tuning
  • Pre-generated interview questions: the LLM's interview_questions go straight to the interviewer, saving prep time. Flag that these are AI suggestions for reference only; the interviewer owns the actual assessment
  • Funnel analytics: all routing results land in Feishu Bitable, broken down by role, source, and score band-submissions / screened / interviewed / offered. "Which channel yields the highest-quality resumes" beats "which channel yields the most resumes"

Pitfalls

  • Pin anti-discrimination constraints in the Prompt: "score objectively" is not enough-protected attributes must be listed item by item as forbidden. By default the model will fold "35 years old," "female," "single" into consideration; without an explicit ban, discrimination goes implicit and is impossible to disprove after the fact. This is a compliance red line, not an optimization
  • Don't rely on a single parser: PDF resumes come in every shape; scanned PDFs return empty text from Extract from File. Add an IF on text length and route too-short results to an OCR fallback (call a cloud OCR API)-otherwise a matching candidate gets scored zero
  • Don't put specific scores in rejection emails: "Your profile was a lower match for this role" is enough; don't write "You scored 42." Specific scores are unprofessional and invite disputes
  • Mind retention limits by law: resumes carry ID numbers and home addresses-PIPL requires minimized processing and a clear retention period. Don't keep rejected resumes indefinitely; set 30-day or 6-month auto-delete per your jurisdiction. Pool candidates need an opt-in before retention, with an opt-out link
  • AI scoring is not the final say: score is assistive; the recruiter makes the interview call. Keep "AI recommendation" and "recruiter decision" as separate columns in the ATS and reconcile periodically-whether AI-approved candidates actually got hired, how AI-rejected candidates fared when interviewed anyway, all feeding back to calibrate the Prompt
  • Don't let the workflow replace communication: automation handles routing and logging, not decisions. For key roles, have a human eyeball the rejections too, to avoid false kills-an LLM scoring error on one resume costs a candidate months of waiting

References

This article is AI-assisted and human-edited. Last updated: 2026-08-04

Related

Field SOP

No app switching: JianYing Hub from storyboard to final cut

A hands-on SOP for JianYing Hub that starts with a fitness check, giving three cases where it fits (you need a full asset-to-final-cut chain, you want batches of the same storyboard for A/B tests, or you dislike repeated export and import across apps) and four where it does not (you only lack one generated shot, you need fine multi-cam editing, your assets and data must stay local, or your budget must be precisely predictable), and noting that if data-on-premises or avoiding ecosystem lock-in is the priority you should look at an open-source route instead. It then walks the official 14-step onboarding path all the way to multi-track refinement: confirm the entry and asset source (keeping the same JianYing account so Jimeng and Xiaoyunque assets import in one click), generate key assets and a storyboard script, wire assets to script, let asset management auto-complete characters, props and scenes, batch-generate storyboard prompts (with two copy-ready prompt templates, one for product ads and one for talking-head video), pick models such as Seedance 2.5 to generate each storyboard clip, preview the assembled cut, use "More Editing" to jump straight into JianYing's multi-track timeline, apply local edits, AI extend, and AI post-editing (upscaling, frame interpolation, color grading, removal, vocal separation), call Skills through the JianYing Assistant in text, and import ByteDance assets back in. It adds three batch-production methods (deriving multiple versions from one product for A/B, a talking-head batch pipeline, and size and platform adaptation), a line-by-line pre-launch checklist and a six-row pitfall table covering script drift, local edits breaking consistency, audio-video desync after AI extend, human review of proper nouns in subtitle fixes, version and font mismatches after import, and rigid pacing from over-reliance on auto-assembly. Pricing, free quota, concurrency, credits, regional availability and duration or resolution limits are all unpublished and stated as following the official app, and JianYing Hub is noted as a closed-source commercial product that is neither open source nor free.

Sep 22, 20268 min read
Field SOP

Same voice, 2.3s lag: ship Qwen3.8 live-translate in your app

A deployment SOP for Qwen3.8-LiveTranslate that starts with a fitness check: if you need a conversation to be understood as it happens, use simultaneous interpretation, and if you can translate slowly afterwards, start with offline. It then pins down the two most commonly misused figures, that 2.3 seconds is average lag (LAAL) rather than end-to-end first-packet latency, and that 60 is recognition input while 29 is speech output, two different units with the remaining 31 text-only. Credentials and environment come next: keys belong only in environment variables, never in source, repositories or front-end bundles, since committing one puts it into version history and the shipped bundle, and the only correct response to a leak is to revoke the old key immediately and rebuild and rotate it. It also warns up front about the trap that a browser cannot set an Authorization header during a WebSocket handshake, so the front end must never connect directly and the correct shape is a server holding the secret. The article then walks through a minimal streaming loop and an event-driven WebSocket skeleton, opening a long connection, receiving session.created, pushing audio and draining events, covering speaker diarization with voice reproduction, same-frame bilingual output and long-context disambiguation, and closes with concurrency limits, cost accounting, observability, failure fallbacks and a pre-launch checklist. Pricing, rate limits, concurrency and regional availability that are not public are all marked as following the Qwen AI platform and Alibaba Cloud Bailian documentation rather than invented.

Sep 21, 20267 min read
Field SOP

One Sentence to a Live App With a Database: Qoder Sites SOP

A hands-on SOP for building and shipping with Qoder Sites from a single sentence: version checks (desktop v0.3.3 or newer, CLI v1.1.54 or newer) and the /sites entry, a five-part prompt template (goal, data model, interaction, style, deploy now) with two copy-ready build prompts, first publish covering preview, sharing and permissions, three post-publish permission checks, three persistence checks for the auto-provisioned database plus a checklist form, then binding Cloud Agents in one sentence to give the page agent ability (including when to bind and when not to). It closes with three landing scenarios (prototypes, dashboards, campaign pages), four boundaries to avoid, and a four-pitfall quick check. Database type, capacity, billing and regional rules that are not public are all marked as following the client interface and official announcements rather than invented.

Sep 20, 20267 min read