Skip to content

사이드 프로젝트 이력서 시각화 서비스 제작기 4편

텍스트에서 의미를 추출하다: AI 분석 엔진 구축

지난 3편에서 전체 설계도와 환경 설정을 마무리했다면, 이제는 서비스의 심장인 analyzer.py를 구현할 차례입니다. 텍스트 뭉치에서 **언제(Date)**와 무엇을(Event) 했는지 찾아내는 것이 이번 단계의 핵심입니다.

1. 에이전트에게 최적의 모델 추천받기

프로젝트 원칙인 로컬 환경 실행무료 오픈소스 모델을 지키기 위해 Antigravity 에이전트에게 모델을 추천받았습니다.

Agent Prompt

파싱된 이력서 텍스트에서 '연도(날짜)'와 '주요 성과'를 추출하고 싶어. 내 노트북의 가상환경에서 무리 없이 돌아갈 수 있는 1GB 미만의 가벼운 Hugging Face 모델을 추천해줘. 한국어와 영어 문맥을 모두 이해해야 해.

에이전트는 망설임 없이 Qwen/Qwen2.5-0.5B-Instruct를 강력하게 추천했습니다.

왜 Qwen2.5-0.5B 인가요?

  • 초경량 크기: 약 950MB 수준으로 1GB 미만 조건을 완벽히 충족합니다.
  • 다국어 특화: 한국어를 포함한 29개국 언어를 지원하며, 특히 지시어 이행 능력이 0.5B 체급 중 최고 수준입니다.
  • 가성비: 4-bit 양자화를 적용하면 메모리를 300~400MB까지 줄일 수 있어 일반 노트북에서도 쾌적하게 돌아갑니다.

2. analyzer.py 구현: LLM 기반의 데이터 추출

단순한 텍스트 나열이 아니라, 전문가급 HR 어시스턴트의 관점에서 데이터를 정제하도록 프롬프트를 구성했습니다. 에이전트와 함께 최종적으로 완성한 analyzer.py의 구조는 다음과 같습니다.

import torch
import os
from transformers import AutoModelForCausalLM, AutoTokenizer

class ResumeAnalyzer:
    def __init__(self, model_id="Qwen/Qwen2.5-0.5B-Instruct"):
        """
        Qwen2.5-0.5B 모델 초기화 (약 950MB)
        """
        self.device = "cuda" if torch.cuda.is_available() else "cpu"
        print(f"Loading model on {self.device}...")

        self.tokenizer = AutoTokenizer.from_pretrained(model_id)
        self.model = AutoModelForCausalLM.from_pretrained(
            model_id,
            torch_dtype="auto",
            device_map="auto"
        )

    def extract_achievements(self, text_list):
        """
        이력서 텍스트에서 기간과 성과를 추출
        """
        full_text = "\n".join(text_list)

        prompt = f"""다음은 파싱된 이력서의 텍스트입니다.
        이 내용에서 각 경력 항목별 '활동 기간(또는 연도)'과 '주요 성과(업무 내용)'를 찾아서 요약해 주세요.

        [출력 형식]
        - 기간: [시작~종료 또는 연도]
        성과: [핵심 성과 위주로 한 문장 요약]

        이력서 텍스트:
        {full_text}
        """

        messages = [
            {"role": "system", "content": "You are an expert HR assistant who extracts key information from resumes in Korean and English."},
            {"role": "user", "content": prompt}
        ]

        text = self.tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=True
        )

        model_inputs = self.tokenizer([text], return_tensors="pt").to(self.device)

        with torch.no_grad():
            generated_ids = self.model.generate(
                **model_inputs,
                max_new_tokens=1024,
                temperature=0.7,
                top_p=0.9
            )

        # 입력 토큰을 제외한 순수 답변만 추출
        generated_ids = [
            output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
        ]

        response = self.tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
        return response

analyzer.py 구현 내용

  • ResumeAnalyzer 클래스를 만들어 모델 로드와 성과 추출 로직을 캡슐화했습니다.

  • parser.py에서 추출한 텍스트 리스트를 입력받아, 모델이 한/영 문명을 이해하고 지정된 형식으로 결과를 반환하도록 프롬프트를 구성했습니다.

  • 주요 특징

    • 메모리 효율: torch_dtype="auto" 및 device_map="auto"를 사용하여 노트북 환경의 자원(GPU/CPU)을 최대한 효율적으로 활용합니다.
    • 구조화된 출력: 기간과 성과를 구분하여 요약된 형태로 출력하도록 지시합니다.
    • 다국어 지원: 한글과 영어 문맥을 모두 처리할 수 있는 시스템 메시지를 포함했습니다

3. 의존성 업데이트

모델 구동을 위해 requirements.txt에 필요한 패키지들을 추가했습니다. 에이전트에게 현재 가상환경에 맞춰서 최적화해줘라고 하니 accelerate 같은 병렬 처리 라이브러리까지 포함해 주네요.

python-docx
python-pptx
transformers
torch
accelerate
라이브러리역할
transformersHugging Face의 AI 모델을 로드하고 실행하는 핵심 도구
torch모델 연산을 담당하는 딥러닝 프레임워크 (PyTorch)
accelerate로컬 자원(CPU/GPU)을 효율적으로 배분하여 실행 속도 향상

4. 테스트 코드로 확인하기

이제 위에서 작성한 analyzer.py가 잘 작동하는지 확인하기 위한 임시 테스트 코드를 작성하고 실행하여 확인해봅니다.

from analyzer import ResumeAnalyzer
import torch

def run_test():
    # 1. 분석기 초기화
    # (처음 실행 시 여기서 모델 다운로드가 진행됩니다. 약 950MB)
    print("="*50)
    print("ResumeAnalyzer 초기화 중...")
    analyzer = ResumeAnalyzer()
    print("모델 로드 완료!")
    print("="*50)

    # 2. 테스트용 Mock 데이터 (김철수 님)
    mock_resume_data = [
        "김철수 | 백엔드 개발자",
        "2021.03 - 2022.12: (주)망고소프트 인턴 및 주임",
        "파이썬 기반 레거시 시스템 리팩토링 및 API 성능 개선",
        "Redis 캐싱 도입으로 데이터 조회 속도 25% 향상",
        "2023.01 - 2025.02: 파인애플 테크놀로지 대리",
        "MSA 기반 결제 서비스 마이크로서비스 설계 및 구축",
        "Kafka를 활용한 실시간 결제 로그 수집 파이프라인 개발",
        "2025.03 - 현재: 스타트업 '오렌지랩' 백엔드 리드",
        "클라우드 아키텍처 최적화 및 주니어 개발자 멘토링"
    ]

    # 3. 분석 수행
    print("\nAI 분석을 시작합니다. 잠시만 기다려 주세요...\n")
    try:
        result = analyzer.extract_achievements(mock_resume_data)

        print("최종 분석 결과")
        print("-" * 30)
        print(result)
        print("-" * 30)

    except Exception as e:
        print(f"분석 중 오류가 발생했습니다: {e}")

if __name__ == "__main__":
    run_test()

실행

가상환경이 활성화된 상태에서 아래 명령어들을 순차적으로 입력합니다.

pip install -r requirements.txt

설치가 완료되었다면 아래 명령어를 입력해 확인합니다.

pip list
  • 결과
Antigravity-LifeGraph>pip list
Package           Version
----------------- ---------
accelerate        1.12.0
annotated-doc     0.0.4
anyio             4.12.1
certifi           2026.2.25
click             8.3.1
colorama          0.4.6
filelock          3.24.3
fsspec            2026.2.0
h11               0.16.0
hf-xet            1.3.2
httpcore          1.0.9
httpx             0.28.1
huggingface_hub   1.5.0
idna              3.11
Jinja2            3.1.6
lxml              6.0.2
markdown-it-py    4.0.0
MarkupSafe        3.0.3
mdurl             0.1.2
mpmath            1.3.0
networkx          3.6.1
numpy             2.4.2
packaging         26.0
pillow            12.1.1
pip               26.0.1
psutil            7.2.2
Pygments          2.19.2
python-docx       1.2.0
python-pptx       1.0.2
PyYAML            6.0.3
regex             2026.2.28
rich              14.3.3
safetensors       0.7.0
setuptools        82.0.0
shellingham       1.5.4
sympy             1.14.0
tokenizers        0.22.2
torch             2.10.0
tqdm              4.67.3
transformers      5.2.0
typer             0.24.1
typer-slim        0.24.0
typing_extensions 4.15.0
xlsxwriter        3.2.9

이제 사용하고자 하는 라이브러리가 설치된 것을 확인했으니 아래 명령어를 입력해 테스트 코드를 실행합니다.

python test.py
  • 결과
Antigravity-LifeGraph>python test.py
==================================================
ResumeAnalyzer 초기화 중...
Loading model on cpu...
config.json: 100%|███████████████████████| 659/659 [00:00<00:00, 659kB/s]
e:\local_git\Antigravity-LifeGraph\.venv\Lib\site-packages\huggingface_hub\file_download.py:129: UserWarning: `huggingface_hub` cache-system uses symlinks by default to efficiently store duplicated files but your machine does not support them in C:\Users\wooer\.cache\huggingface\hub\models--Qwen--Qwen2.5-0.5B-Instruct. Caching files will still work but in a degraded version that might require more space on your disk. This warning can be disabled by setting the `HF_HUB_DISABLE_SYMLINKS_WARNING` environment variable. For more details, see https://huggingface.co/docs/huggingface_hub/how-to-cache#limitations.
To support symlinks on Windows, you either need to activate Developer Mode or to run Python as an administrator. In order to activate developer mode, see this article: https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development
  warnings.warn(message)
tokenizer_config.json: 7.30kB [00:00, 7.30MB/s]
vocab.json: 2.78MB [00:00, 10.4MB/s]
merges.txt: 1.67MB [00:00, 10.8MB/s]
tokenizer.json: 7.03MB [00:00, 17.0MB/s]
model.safetensors: 100%|██████████████| 988M/988M [02:07<00:00, 7.77MB/s]
Loading weights: 100%|| 290/290 [00:00<00:00, 4135.80it/s, Materializing
generation_config.json: 100%|███████████████████| 242/242 [00:00<?, ?B/s]
모델 로드 완료!
==================================================

AI 분석을 시작합니다. 잠시만 기다려 주세요...

최종 분석 결과
------------------------------
- **경력 항목**:
  - 2021.03 - 2022.12: ()레몬소프트 인턴 및 주임

    - 활동 기간: 2021년부터 2022년까지
    - 주요 성과: 파이썬 기반 레거시 시스템 리팩토링 및 API 성능 개선, Redis 캐싱 도입으로 데이터 조회 속도 25% 향상

- **경력 항목**:
  - 2023.01 - 2025.02: 파인애플 테크놀로지 대리

    - 활동 기간: 2023년부터 2025년까지
    - 주요 성과: MSA 기반 결제 서비스 마이크로서비스 설계 및 구축, Kafka를 활용한 실시간 결제 로그 수집 파이프라인 개발

    - 성공적인 활동: 클라우드 아키텍처 최적화 및 주니어 개발자 멘토링

- **경력 항목**:
  - 현재: 스타트업 '오렌지랩' 백엔드 리드

    - 활동 기간: 2025년까지
    - 주요 성과: 클라우드 아키텍처 최적화 및 주니어 개발자 멘토링

    - 성공적인 활동: 클래스 제안 및 프로그래밍 교육 제공

**총 경험**: [모든 경력 항목의 핵심 성과]
------------------------------

1GB도 안 되는 초소형 모델임에도 불구하고, 단순 요약을 넘어 "활동 기간: 2021년부터 2022년까지"와 같이 문장을 생성하고 성과를 분류하는 추론 능력을 보여주었습니다. Antigravity 에이전트가 왜 이 모델을 '체급 대비 최고'라고 추천했는지 알 수 있는 대목입니다.

윈도우 사용자라면?

실행 로그 중 HF_HUB_DISABLE_SYMLINKS_WARNING 관련 경고가 뜰 수 있습니다. 윈도우 환경에서 심볼릭 링크 권한 문제로 발생하는 경고인데, 분석 결과에는 지장이 없으니 안심하고 진행하셔도 됩니다. (완전히 없애고 싶다면 관리자 권한으로 실행하거나 개발자 모드를 켜면 해결됩니다!)

회고

단순히 글자를 읽어오는 것에서 한 걸음 더 나아가, AI가 문맥을 이해하기 시작하니 프로젝트가 생동감을 얻는 느낌입니다. Antigravity 에이전트가 모델의 성능뿐만 아니라 로컬 노트북 사양까지 고려해 Qwen을 골라준 덕분에, 무거운 GPU 서버 없이도 제 컴퓨터에서 분석기를 돌릴 수 있게 되었습니다.

다음 5편에서는 결과값에 포함된 "25% 향상", "최적화" 같은 키워드를 정량적인 점수(Scoring)로 변환하는 알고리즘을 고민해 보겠습니다. 드디어 우리의 인생을 그래프로 그릴 수 있도록 텍스트가 데이터가 되고, 데이터가 그래프가 되는 과정을 진행해보겠습니다.