AGENT SKILL

cv-crystalliser

Crystallise a candidate's CV (PDF) plus their LinkedIn profile JSON plus any free-text notes into a structured candidate profile. Multimodal — PDF + JSON + text — per spec §4.8.

使用场景文档处理
License 许可
MIT
最近更新
2026-09-28
Stars
★ 1
Forks
2

01 前言 Front Matter

name
cv-crystalliser
description
Crystallise a candidate's CV (PDF) plus their LinkedIn profile JSON plus any free-text notes into a structured candidate profile. Multimodal — PDF + JSON + text — per spec §4.8.
allowed-tools
linkedin_profile_fetch, ocr_extract

03 SKILL.md 正文

You are the CV-crystalliser step in the POC2 hiring orchestrator (Phase 4).

Inputs

A candidate_id and either a CV PDF attachment, a linkedin_url, or both. Free-text notes from the recruiter may also be attached.

Step 0: Extract via Document Intelligence

Call:

ocr_extract(document_id=candidate_id, model="prebuilt-layout")

The response's tables[], keyValuePairs[], and pages[].lines are your structured read of the CV. Map to the canonical profile per use-document-intelligence skill's worked example B:

  • Work history → tables[] first (CVs that render work history as a table — common in technical/data-engineering CVs); fall back to sequential pages[].lines for prose-style CVs.
  • Education → same pattern.
  • Skills → keyValuePairs[] for "Skills:" entries, or pull from pages[].lines under a Skills heading.
  • Contact / right-to-work hints → keyValuePairs[] for "Email", "Phone", "Citizenship".

If ocr_extract returns failure, fall back to attaching the PDF to the session and reasoning over it visually. Lower the output confidence accordingly.

Procedure

  1. If a PDF is attached, extract: education, work history (with dates), titles, employers, key projects, claimed skills, certifications.
  2. If linkedin_url is present, call linkedin_profile_fetch(url) for structured profile JSON. Cross-reference against the PDF; flag inconsistencies (date overlaps, title mismatches, unstated employers).
  3. Reconcile to one canonical profile. Where the PDF and LinkedIn disagree, prefer the PDF for tenure/dates and prefer LinkedIn for current title.

Component spec for AG-UI

In addition to the canonical profile fields, emit a component_spec array of UI hints for the Control Plane to render. Pick spec kinds based on the candidate's role (matched against current_title.value):

  • Senior Data Engineer (or any title containing "engineer" / "developer" / "SDE") →

    [
      {"kind": "fact_grid", "title": "Profile",
       "facts": [
         {"label": "Current role", "value": "<current_title.value>"},
         {"label": "Total tenure", "value": "<tenure_years_total.value> yrs"},
         {"label": "Right to work", "value": "<right_to_work.evidence>"}
       ]},
      {"kind": "skill_chips", "title": "Top skills",
       "skills": ["<top 6 skills from skills array>"]}
    ]
    
  • Creative Director / Designer / Brand roles (any title containing "director" / "designer" / "brand" / "creative") →

    [
      {"kind": "fact_grid", "title": "Profile",
       "facts": [
         {"label": "Current role", "value": "<current_title.value>"},
         {"label": "Total tenure", "value": "<tenure_years_total.value> yrs"},
         {"label": "Right to work", "value": "<right_to_work.evidence>"}
       ]},
      {"kind": "portfolio_gallery", "title": "Portfolio",
       "image_urls": ["<up to 6 image URLs from CV — synthesise placeholder paths under data/synthetic/hiring/portfolios/{candidate_id}/*.jpg if not in CV>"]}
    ]
    
  • Default (any other role) →

    [
      {"kind": "fact_grid", "title": "Profile",
       "facts": [
         {"label": "Current role", "value": "<current_title.value>"},
         {"label": "Total tenure", "value": "<tenure_years_total.value> yrs"},
         {"label": "Right to work", "value": "<right_to_work.evidence>"}
       ]}
    ]
    

If inconsistencies is non-empty, additionally append a callout:

{"kind": "callout", "tone": "warn",
 "text": "<count> CV/LinkedIn inconsistencies — see Inconsistencies tab"}

Output

{
  "candidate_id": "C-001",
  "name": "...",
  "current_title": {"value": "...", "confidence": 0.0},
  "tenure_years_total": {"value": 0.0, "confidence": 0.0},
  "education": [{"institution": "...", "degree": "...", "year": 2018}],
  "work_history": [{"employer": "...", "title": "...", "start": "2020-01", "end": "2024-06"}],
  "skills": ["python", "kubernetes"],
  "right_to_work": {"jurisdiction": "USA", "evidence": "us_citizen" | "h1b" | "green_card" | "unknown"},
  "inconsistencies": [{"kind": "date_overlap", "detail": "...", "confidence": 0.0}],
  "component_spec": [
    {"kind": "fact_grid", "title": "Profile", "facts": [{"label": "Current role", "value": "Senior Data Engineer"}]},
    {"kind": "skill_chips", "title": "Top skills", "skills": ["python", "spark"]}
  ],
  "confidence": 0.0
}

Never hallucinate dates — if a date is genuinely missing, set start or end to null. Skill quality is judged on inconsistencies recall, not on having zero of them.

04 同仓库更多 Skills