6.10.2 사례 연구 2: 극도의 비정형 텍스트(이력서)의 결정론적 RDBMS 적재 파이프라인 아키텍처

6.10.2 사례 연구 2: 극도의 비정형 텍스트(이력서)의 결정론적 RDBMS 적재 파이프라인 아키텍처

현대의 B2B 엔터프라이즈 관계형 데이터베이스(RDBMS, 예: PostgreSQL, Oracle DB)는 데이터 무결성 보장을 위해 무자비할 정도로 엄격한 스키마 제약 조건(Schema Constraints)을 강제한다. 만약 DATE 타입으로 지정된 컬럼(Column)에 사용자가 입력한 *“작년 늦여름쯤부터 올해 1월 초순까지”*라는 인간의 자연어 스트링 코드가 쿼리 페이로드로 입력되는 순간, 데이터베이스 트랜잭션(Transaction)은 TypeMismatchException을 뱉으며 파이프라인을 즉시 붕괴시키고 롤백(Rollback)해버린다.

채용 플랫폼(HR Tech) 기업의 데이터 인프라 팀이 직면하는 가장 고통스러운 데이터 추출 병목 현상인 **‘이력서(Resume) 파싱 처리’**는, 이처럼 자유도의 극치이자 포맷의 혼돈 그 자체인 비정형(Unstructured) PDF 텍스트 문서 뭉치에서, 한 치의 오차도 허용하지 않는 결정론적 DB 스키마 테이블로 순수 데이터를 예쁘게 발라내어 욱여넣어야(Ingestion) 하는 최고 난이도의 ETL(Extract, Transform, Load) 엔지니어링 작업이다.

과거 레거시 시스템에서는 수만 줄의 하드코딩된 정규표현식(Regex) 트리와 휴리스틱(Heuristic) 텍스트 마이닝 규칙을 동원하여 이름, 전화번호, 경력을 위태롭게 추출하려 했으나 항상 엣지 케이스(Edge Case)에 무너졌다. 그러나 오늘날 강력한 언어 모델의 지능과 구조화 출력(Structured Outputs / JSON Mode) 기술이 완벽히 결합된 Pydantic 오라클 아키텍처는, 단 몇십 줄의 단일 파이썬 스키마 정의만으로 이 혼돈을 물리적으로 정복하고 완벽하게 파싱 문제를 해결해 낸다.

1. 관계형 테이블 스키마와 1:1로 하드 매핑되는 Pydantic 오라클 설계

이력서 파싱 추출 파이프라인 성공의 핵심 비결은, LLM에게 *“정확히 잘 뽑아줘”*라고 비굴하게 긴 시스템 프롬프트(System Prompt) 문장학을 정교하게 쓰는 문과적 접근에 있지 않다. 핵심은 바로 백엔드 RDBMS의 타겟 Candidates 물리 테이블 명세(DDL)와 100% 직결되는 강력한 Pydantic 기반의 DTO(Data Transfer Object) 오라클 검증 클래스를 정적으로 설계하는 공학적 접근에 있다.

from pydantic import BaseModel, Field, field_validator
from typing import List, Optional
import re

class ExperienceRecord(BaseModel):
    company_name: str = Field(description="가장 공식적인 법인명으로 추출")
    is_current_job: bool = Field(description="현재 재직 중이면 True, 퇴사했으면 False")
    # 인간의 자연어('작년 여름')를 RDBMS가 수용 가능한 제한된 ISO 포맷 스트링으로 LLM에게 강제 변환토록 지시
    start_date: str = Field(description="반드시 YYYY-MM 형식의 정규화된 날짜 문자열로 추출할 것")
    end_date: Optional[str] = Field(description="현재 재직 중일 경우 null, 퇴사일 경우 YYYY-MM 포맷")

class ResumeExtractionOracle(BaseModel):
    candidate_name: str
    phone_number: str
    skills: List[str] = Field(max_items=10) # Array 폭주를 막기 위해 최대 요소 10개로 런타임 제한
    experiences: List[ExperienceRecord]

    # 정규표현성(Regex) 검증 로직을 Pydantic 오라클 레벨에 깊숙이 하드코딩 (1차 결정론적 필터링 방어막)
    @field_validator('phone_number')
    def validate_phone(cls, v):
        # LLM이 포맷을 무시하고 자연어를 섞어 반환하면 파이썬이 런타임 크래시를 발생시키도록 의도
        if not re.match(r"^\d{3}-\d{3,4}-\d{4}$", v):
            raise ValueError(f"전화번호 포맷 위반 치명적 에러: '{v}'. 반드시 000-0000-0000 정규 포맷에 일치해야 합니다.")
        return v

2. 결측치(Missing Values) 처리의 결정론적 타입 제어(Type Control)

이력서라는 양식 문서의 구조는 세상에 존재하는 형태만큼이나 결코 일관되지 않다. 이메일 주소만 덜렁 있고 정작 제일 중요한 전화번호가 빠져있는 이력서도 있으며, 특정 경력의 시작일은 있는데 종료일이 완전히 누락된 경우도 부지기수다.

전통적인 오픈소스 프롬프팅 방식에서는 *“만약 정보가 텍스트에 없으면 ‘없음’ 혹은 ’Not Found’라고 문자열로 답해라”*라고 유도 지시를 내렸지만, 이는 백엔드 DB 단에서 치명적인 파싱 에러(예: ’없음’이라는 문자열이 강제로 Date 타입 컬럼에 삽입 시도됨)를 즉각 유발하여 500 Internal Server Error 서버 다운을 일으킨다.
하지만 최신 구조화 출력(Structured Outputs) 스키마 파이프라인에서는 Optional[T] 유니온(Union) 타입 힌트 선언이 이 결측치 핸들링 역할을 우아하고 완벽하게 대신한다. JSON 스키마 명세에 명확히 Optional(Nullable) 상태가 바인딩되어 있으면, 모델은 자신이 분석한 텍스트에 요구되는 정보 요소가 물리적으로 누락되었을 때 억지로 텍스트를 지어내거나(Hallucination) ’없음’이라는 딕트(Dict)를 만들지 않고, 가장 기계적이고 확신에 찬 태도로 JSON의 순정 null 객체를 반환한다. 이는 곧바로 파이썬 백엔드 ORM의 타입 세이프한 None 객체로 매핑되며, 최종적으로 백엔드 데이터베이스의 NULL 컬럼 값으로 가장 우아하고 결정론적으로 매핑 적재(Insert)된다.

3. 중간 전처리를 파괴하는 ORM 직행 적재 체계 (Direct-to-DB Pipeline)

런타임에 LLM이 생성한 응답 텍스트가 위의 ResumeExtractionOracle Pydantic 스키마 밸리데이션 층(Validation Layer)을 무사히 통과했다는 것은 시스템 엔지니어링 관점에서 도대체 무엇을 의미하는가?

그것은 연락처 전화번호가 완벽한 한국 정규식 포맷(000-0000-0000)을 математически(수학적으로) 만족시켰고, 기술 스택 skills 배열 리스트는 DB 컬럼 용량 한계인 10개를 물리적으로 초과하지 않았음을 보장한다. 또한 모호한 재직 기간 날짜 형식은 DB 파서 엔진이 별도 변환 없이 그대로 삼켜 받아들일 수 있는 YYYY-MM Date 문자열 형식을 최소한 구문상으로 100% 준수하여 생성되었음을, **파이썬 인터프리터 시스템이 런타임 객체 지향 레벨에서 수학적, 결정론적으로 완벽히 보증(Guaranteed)**한다는 위대한 뜻이다.

따라서 백엔드 개발 서버는 어제까지 필수적이었던 온갖 잡다한 문자열 예외 처리(Try-Catch), 스플릿(Split), 치환(Replace) 등 지저분한 레거시 추가 전처리 데이터 파싱/클렌징(Parsing/Cleaning) 파이썬 로직을 코드베이스에서 모조리 영구 삭제 폐기(Deprecate)해 버릴 수 있다.
추출되어 튀어나온 유효한 JSON 인스턴스 객체를, SQLAlchemy 모델 클래스나 Node.js의 Prisma ORM 엔진 객체에 그대로 타입 변환 없이 다이렉트 패스 스루(Pass-through)로 꽂아 밀어 넣고(Insert) 즉시 session.commit() 트랜잭션을 실행해 버릴 수 있게 된다.

구조화 출력(Structured Outputs) Pydantic 오라클이, 날뛰는 LLM 텍스트 생성의 무한한 무작위성 혼돈(Stochastic Chaos)의 흐름을 백엔드 서버 앞단에서 완벽히 방어하고 정제해 내는 **‘견고하고 단단한 수학적 데이터 인프라스트럭처 방벽(Mathematical Infrastructure Barrier)’**으로 완벽하게 진화하여 작동한 것이다.