구직 도우미 (Job Searcher)
요약
DeepSeek V4 Pro를 교사 모델로, Qwen3-8B를 학생 모델로 활용하여 이력서 기반의 맞춤형 구직 에이전트를 구축하는 기술적 과정을 설명합니다. 쿼리 생성, 검색, 5개 차원의 점수 산정 단계를 거쳐 논리적 근거를 갖춘 최종 후보 명단을 도출합니다.
핵심 포인트
- DeepSeek V4 Pro를 활용한 고품질 레이블 생성 및 지식 증류(Distillation)
- Qwen3-8B 모델을 양자화하여 효율적인 추론 환경 구축
- 기술, 경력, 학력 등 5가지 차원의 정교한 적합도 점수 산정
- LoRA SFT를 통한 학생 모델의 구조화된 추론 능력 학습
각 공고를 *생각(thinking)*하는 비용이 하나의 공고에 제출하는 비용보다 높습니다.
짧은 투어를 확인하세요: 이력서를 제출하고, 쿼리(queries)가 스트리밍되는 것을 지켜보며, 각 직무별 추론(reasoning) 내용을 읽어보세요.
한 번의 실행은 세 단계로 이루어집니다.
쿼리 (Queries). 학생(student) 모델이 이력서와 사용자가 설정한 선호도(직무 유형, 근무 형태, 위치, 자유 형식 메모)를 읽고, LinkedIn 형태의 검색 쿼리 세트를 초안으로 작성하며, 그 과정에서 추론(reasoning)을 소리 내어 수행합니다.
검색 (Search). 해당 쿼리들은 JobSpy를 통해 하나씩 LinkedIn에 전달됩니다.
점수 산정 (Scoring). 각 공고에 대해 모델은 (이력서, 직무) 쌍을 읽고 다섯 가지 차원의 적합도 점수를 작성합니다:
기술 일치도 (skills match)
경력 관련성 (experience relevance)
학력 및 자격증 (education and certifications)
산업 / 도메인 적합도 (industry / domain fit)
연차 정렬 (seniority alignment)
Figure 1. 프레임워크의 엔드 투 엔드 (End-to-end) 단계.
결과로 받는 것은 50개의 역할 목록이 아닙니다. 방어 가능한 추론 근거를 갖춘 소수의 최종 후보 명단(shortlist)입니다. 모델이 왜 2순위 직무가 3순위 직무보다 낫다고 판단했는지 그 이유를 읽을 수 있습니다.
교사(teacher) 모델은 DeepSeek V4 Pro입니다. 구조화된 추론(structured reasoning)에 강하며, 엄격한 출력 스키마(output schema)를 따를 의지가 있고, 대규모 코퍼스(corpus)에 대해 오프라인으로 한 번 실행하기에 충분히 저렴합니다. 이 모델은 추론 시점의 의존성(inference-time dependency)이 아니라 레이블 생성기(label generator)로 사용됩니다.
학생(student) 모델은 Qwen3-8B입니다. Q4_K_M으로 양자화(quantized)하면 단일 ZeroGPU 슬라이스에 들어갈 만큼 작으면서도, 교사 모델의 구조화된 판단을 흡수할 수 있을 만큼 큽니다.
코퍼스는 폐쇄 루프(closed loop) 형태의 이력서 인식 엔드 투 엔드(end-to-end) 방식으로 구축되었습니다:
이력서 (Resumes). Divyaamith/Kaggle-Resume을 기반으로 구축된 2,500개.
쿼리 (Queries). 교사 모델이 먼저 각 이력서로부터 LinkedIn 형태의 검색 쿼리를 초안으로 작성했습니다.
직무 (Jobs). 그다음 JobSpy가 해당 쿼리들이 실제로 반환하는 결과를 LinkedIn에서 스크래핑했습니다. 약 10,000개의 공고가 수집되었으며, 이들은 모두 교사 모델이 해당 특정 이력서를 위해 직접 작성한 쿼리에 의해 노출된 것들입니다.
레이블 (Labels). 그다음 교사 모델은 추론 시 사용되는 것과 동일한 다섯 가지 차원에 대해 결과로 나온 모든 (이력서, 직무) 쌍의 점수를 매겼으며, 각 차원당 한 문장의 추론을 작성했습니다.
모든 것은 build-small-hackathon/job-search-distill 경로에 외래 키(foreign-key)가 깔끔하게 정리된 네 가지 설정으로 제공됩니다.
Modal을 통해 단일 A100에서 각 작업당 하나씩, 총 두 번의 LoRA SFT 실행을 수행했습니다:
어댑터 (Adapter). Rank 16, alpha 16, dropout off, attention 및 MLP 프로젝션(projections).
스케줄 (Schedule). 작업당 1 에포크 (epoch). 전체 실행이 완료되기 전에 부분 실행을 무결성 검사 (sanity-check) 할 수 있도록 200 스텝마다 에포크 중간 체크포인트 (mid-epoch checkpoints) 생성.
출력 (Output). build-small-hackathon/job-searcher-qwen3-8B 경로의 Safetensors, 그리고 llama.cpp 서빙 경로를 위한 build-small-hackathon/job-searcher-qwen3-8B-gguf 경로의 Q4_K_M 베이스 및 LoRA-GGUF 사이드카 (sidecars).
LoraConfig(
r=16,
lora_alpha=16,
...
Space는 HuggingFace ZeroGPU Space에서 사전 빌드된 CUDA wheel을 사용하여 llama-cpp-python을 실행합니다. 중요한 두 가지 설계 선택 사항은 다음과 같습니다:
ZeroGPU는 호출마다 CUDA 컨텍스트 (context)를 재활용하므로, 모듈 수준의 인스턴스는 두 번째 사용 시 죽은 컨텍스트를 보유하게 됩니다. 따라서 @spaces.GPU 내부에서 Llama를 사용합니다.
작업당이 아닌, 제출당 한 번의 GPU 호출. 하나의 제출에 대한 모든 적합성 평가 (fit evaluations) 는 단일 @spaces.GPU 호출 내에서 실행됩니다. 모델은 한 번 로드되어 모든 작업에 대해 이벤트를 생성하며, 게시물마다 새로운 콜드 스타트 (cold start) 및 새로운 프록시 토큰 (proxy-token) 요청 비용을 지불하지 않습니다.
스트리밍 (Streaming)은 OpenAI 형식의 create_chat_completion(stream=True)를 사용하여 추론 결과가 UI에 토큰 단위로 전달됩니다. 라이브 데모는 build-small-hackathon/job-search-assistant에서 확인할 수 있습니다.
이 Space를 구축한 전체 Claude Code 세션은 build-small-hackathon/job-search-assistant-agent-trace에 HuggingFace 에이전트 추적 (agent-traces) 데이터셋으로 게시되었습니다. 가공되지 않은 JSONL 이벤트, 네이티브 HuggingFace 추적 뷰어 (trace viewer) 등을 통해 모든 막다른 길과 복구 과정을 기록했습니다. 정제된 버전을 읽는 대신 이 프로젝트가 실제로 어떻게 구성되었는지 확인하고 싶다면 유용할 것입니다.
huggingface.co/spaces/build-small-hackathon/job-search-assistant에 이력서를 제출하세요. 더 이상 헤매지 마세요.
두 개의 어댑터가 하나보다 낫습니다. 저는 쿼리 생성 (query generation)과 적합성 평가 (fit evaluation)를 하나의 LoRA에 통합하려고 시도했습니다. 하지만 모델은 양쪽 모두에서 포맷팅 오류를 일으켰습니다. 쿼리 작업에서는 JSON 형식이 깨졌고, 평가 작업에서는 산문 (prose) 형식이 깨졌습니다. 이를 동일한 베이스 모델(base model) 위에 두 개의 헤드 (heads)로 분리하고, 호출 시마다 핫스왑 (hot-swapped) 하도록 구성하자 해당 유형의 버그가 모두 사라졌습니다.
교사 (teacher)의 프롬프트는 학생 (student)의 크기보다 더 중요했습니다. 교사의 라벨링 (labelling) 프롬프트를 특정 이력서 세부 사항에 따라 점수를 매기도록 재작성했습니다 (예: "기술적 매칭이 높음" 대신 "Rust 경력 4년; 요구 사항은 5년"). 이 방식은 증류 (distillation) 과정을 통해 전파되었습니다. 학생 모델 역시 동일한 습관을 습득했습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Hugging Face Blog의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기