내 입사 지원 현황을 놓치고 있어서, 이를 해결할 도구를 직접 만들었습니다
요약
구직 과정의 비효율을 해결하기 위해 지원 추적기, 기업 인텔리전스, AI 이력서 분석기로 구성된 3가지 서비스 기반의 AI 생태계를 구축한 사례를 소개합니다. RAG 파이프라인과 상태 머신 기반의 데이터베이스 설계를 통해 단순한 AI 활용을 넘어 실질적인 문제 해결 도구를 만드는 과정을 다룹니다.
핵심 포인트
- 지원 상태를 상태 머신(State Machine)으로 설계하여 단계별 전환을 정밀하게 추적
- LLM을 활용해 직무 기술서를 파싱하고 구조화된 데이터를 추출하는 API 구축
- 환각 현상을 방지하기 위해 RAG 파이프라인을 적용한 이력서 맞춤화 기능 구현
- FastAPI, Next.js, PostgreSQL을 활용한 독립적인 마이크로서비스 아키텍처 구성
"컴퓨터 과학 (CS) 전공 마지막 학년 학생이 2주 만에 혼란스러운 이메일 수신함에서 3가지 서비스로 구성된 AI 생태계로 변화한 과정"
채용 담당자가 업데이트를 요청하는 이메일을 보냈는데, 내가 그들과 어느 단계에 있는지 전혀 모를 때 찾아오는 특유의 공포가 있습니다.
저에게도 같은 주에 그런 일이 두 번이나 일어났습니다.
저는 대부분의 마지막 학년 학생들이 그러하듯 브라우저 탭에 링크를 띄워두고, 포스트잇에 후속 조치 날짜를 적어두며, 몇 주 동안 열어보지 않은 Drive 폴더에 자기소개서 (Cover Letter)를 묻어두는 방식으로 구직 활동을 관리하고 있었습니다. 그래서 저는 일주일 동안 지원을 멈추고, 실제로 저에게 필요했던 도구를 만들었습니다. 저는 그것을 JobRover라고 불렀습니다.
정확하게 정의된 문제점
코드를 작성하기 전에, 저는 모든 구체적인 좌절 요인들을 나열했습니다:
- 각 지원이 어느 단계에 있는지 알 수 없음
- 후속 조치 (Follow-up)를 계속 잊어버림
- 각 자기소개서에 무엇을 썼는지 기억나지 않음
- 이력서 (Resume)가 일반적인 느낌이지만 어떻게 맞춤화해야 할지 모름
- 거절당했을 때, 이유를 알 수 없음
문제 13번은 추적 (Tracking) 문제입니다. 문제 45번은 AI 문제입니다. 이 구분이 전체 아키텍처 (Architecture)를 형성했습니다.
하나가 아닌 세 가지 서비스
저는 JobRover를 세 개의 독립적인 서비스로 나누었습니다:
- P1 — 지원 추적기 (Application Tracker): FastAPI + Next.js + PostgreSQL. 추적 문제를 해결합니다.
- P2 — 기업 인텔리전스 (Company Intelligence): LLM을 사용하여 직무 기술서 (Job Description)를 파싱하고 필요한 기술, 경력 수준, 레드 플래그 (Red Flags)와 같은 구조화된 데이터를 반환하는 REST API입니다.
- P3 — AI 이력서 분석기 (AI Resume Analyser): 실제 경험에 기반하며 절대 환각 (Hallucination)을 일으키지 않는, 이력서 불렛 포인트 (Bullet points)를 맞춤화하고 자기소개서를 생성하며 거절 사유를 분석하는 RAG 파이프라인 (RAG Pipeline)입니다. 각 서비스는 독립적으로 실행됩니다. 각 서비스는 별개의 문제를 해결합니다. 이들이 모여 제가 의존했던 모든 스프레드시트를 대체합니다.
가장 중요한 세부 사항
가장 어려웠던 부분은 AI 레이어 (Layer)가 아니었습니다. 바로 데이터베이스 스키마 (Database Schema)였습니다.
입사 지원은 단순히 상태(Status) 컬럼이 있는 하나의 행(Row)이 아닙니다. 그것은 상태 머신 (State Machine)입니다. 지원은 다음과 같은 단계들을 거칩니다: 저장됨 (saved) → 지원 완료 (applied) → 서류 통과 (screened) → 면접 (interviewing) → 합격 제안 (offer) → 거절 (rejected). 모든 전환 과정은 타임스탬프 (Timestamp)와 함께 기록됩니다. 3주가 지났을 때, 저는 제가 정확히 어느 단계에서 막혀 있는지, 그리고 각 단계가 얼마나 걸리는지를 명확히 볼 수 있었습니다. 이것은 막연한 느낌 (Vibes)이 아니라 실제 신호 (Signal)입니다.
초기에 결정하길 잘했다고 생각하는 또 다른 사항은 팔로업 알림 (Follow-up reminders) 자동 생성 기능입니다. 지원 상태가 "지원 완료 (applied)"로 이동할 때마다, 백엔드 (Backend)는 7일 후의 팔로업 일정을 자동으로 예약합니다. 저는 따로 기억할 필요가 없었습니다. 시스템이 저 대신 기억해 주었으니까요.
RAG 파이프라인 (RAG Pipeline) — 그리고 왜 단순한 AI는 여기서 실패하는가
이력서를 맞춤화 (Tailoring)하기 위한 뻔한 접근 방식은 이렇습니다: LLM (Large Language Model)에게 이력서와 직무 기술서 (JD, Job Description)를 주고 다시 작성하라고 요청하는 것입니다. 이 방식도 어느 정도는 작동합니다. 문제는 환각 (Hallucination)입니다. Kubernetes 경험이 없는 이력서를 주고 Kubernetes를 요구하는 JD를 LLM에게 주면, LLM은 당신을 위해 그 경험을 지어낼 것입니다.
P3는 엄격한 프롬프트 제약 (Prompt constraint)을 통해 이를 방지합니다: 오직 재구성(Reframe)만 할 뿐, 절대 날조(Fabricate)하지 않습니다. LLM은 강조점을 바꾸거나 JD의 용어를 반영할 수는 있지만, 기술이나 프로젝트를 만들어낼 수는 없습니다. 만약 요구 사항이 정말로 누락되었다면, 대신 keywords_missing 필드에 나타납니다. 이는 매끄럽게 다듬어진 거짓말이 아닌, 정직한 격차 분석 (Gap analysis)입니다.
출력 결과는 다음과 같습니다:
{
"tailored_bullets": [
{
...
매칭 점수 (Match score)는 정직합니다. 0.67은 0.67을 의미합니다. 지원했을 때 기분이 좋아지도록 부풀리지 않습니다.
가장 많은 것을 가르쳐준 버그
데이터베이스에는 사용자가 전혀 없는데도 "이미 사용 중인 이메일입니다"라는 메시지와 함께 등록이 계속 실패했습니다.
실제 문제는 CORS였습니다. 3000번 포트의 프론트엔드 (Frontend)가 백엔드에 요청이 도달하기도 전에 차단되고 있었는데, CORS 설정에 이전 설정의 5173번 포트가 여전히 남아 있었기 때문입니다. 에러 메시지는 완전히 오해의 소지가 있었습니다.
교훈: 인증 (Auth)이 미스터리하게 실패한다면, 먼저 네트워크 레이어 (Network layer)를 확인하세요. 당신이 보는 에러는 실제로 일어나고 있는 에러인 경우가 드뭅니다.
다음에 추가하고 싶은 것:
검색 (Retrieval)과 생성 (Generation) 사이의 리랭커 (Reranker). 현재 P3는 ChromaDB에서 상위 5개의 청크 (Chunks)를 검색합니다. 리랭커를 사용하면 20개를 검색한 뒤 관련성에 따라 점수를 매기고, 가장 우수한 5개만을 LLM에 전달하게 됩니다. 이것이 표준적인 프로덕션 RAG 패턴이며, 아키텍처를 변경하지 않고도 출력 품질을 유의미하게 향상시킬 수 있는 방법입니다.
저는 이 도구를 만드는 동안 실제 구직 활동에 JobRover를 사용했습니다. 데모에 사용된 데이터는 합성 데이터 (Synthetic data)가 아닙니다. 12개의 실제 지원 내역, ChromaDB에 임베딩된 12개의 실제 직무 기술서 (JDs), 그리고 제가 잊어버렸을 때 작동한 실제 후속 조치 알림들입니다.
이것이 포트폴리오용 프로젝트와 실제 제품 (Product)의 차이입니다. 당신에게 실제로 필요한 것을 만들고, 그 과정에서 무엇이 놀라웠는지에 대해 쓰세요. 그 외의 모든 것은 자연스럽게 따라옵니다.
세 개의 리포지토리(repos) — jobrover-tracker, jobrover-intelligence, jobrover-analyser — 는 각각 단일 명령어 Docker 설정을 통해 독립적으로 실행 가능합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기