Matching Engine Architecture
RecruitMatch의 매칭은 단일 LLM 호출이 아닙니다. 5단계 결정론적 파이프라인이며, 각 단계의 출력은 다음 단계의 입력 스키마를 만족해야 합니다.
Parse
LLM 추출
Normalize
Skill Graph
Embed
pgvector + HNSW
Score
4축 가중 + LightGBM
Explain
Evidence 링크
Stage 1 · Parse
입력 문서는 형식에 따라 다른 어댑터가 처리합니다. PDF는 layout-aware OCR을 거쳐 텍스트 블록 + 좌표로 변환되고, LLM이 JSON 스키마로 추출합니다.
json{
"candidate_id": "C-1207",
"experiences": [
{
"company": "Coupang", "role": "Senior Backend Eng.",
"start": "2021-03", "end": null,
"achievements": ["Kafka 기반 이벤트 시스템 운영 (14k QPS)"],
"source": { "page": 1, "line_range": [12, 28] }
}
],
"skills": [
{ "name": "Kafka", "proficiency": "expert", "years": 3 }
]
}Stage 2 · Normalize
추출된 raw skill 문자열은 18만 노드 스킬 그래프에 join됩니다. "Kotlin", "kotlin", "코틀린"은 동일 ID로 매핑됩니다.
Title Leveling
"Sr. Eng", "Senior Engineer", "L5 SWE", "책임 엔지니어"는 IC4 노드로 정규화됩니다.
Stage 3 · Embed
JD의 모든 요건 문장과 이력서의 모든 achievement 문장은 text-embedding-3-large(3,072 dim)로 인코딩되어 pgvector에 저장됩니다.
sqlCREATE INDEX ON embeddings
USING hnsw (vec vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
SET hnsw.ef_search = 80;Stage 4 · Score
다음 페이지 (4-axis Scoring) 참조.
Stage 5 · Explain
모든 매칭은 왜 그 점수가 나왔는지 근거를 가집니다. JD의 어떤 문장이 이력서의 어떤 문장과 어떤 강도로 연결되는지 span pointer로 저장됩니다.