13.5.4 주소 데이터 보정: Google Maps API 또는 우편번호 DB를 활용한 주소 유효성 확인

13.5.4 주소 데이터 보정: Google Maps API 또는 우편번호 DB를 활용한 주소 유효성 확인

물류(Logistics) 배송이나 글로벌 청구(Billing) 트랜잭션이 결합된 비정형 문서 파이프라인에서, ‘주소(Address)’ 필드는 다른 어떤 숫자 데이터보다도 예측 불가능하게 길고 복잡하며 극저의 정형화 수준을 지닌 텍스트 덩어리다.
최신 LLM 에이전트는 도로명 주소, 지번 주소, 영문 주소, 때론 불필요한 건물 층수까지 온갖 노이즈가 뒤엉켜 혼재된 기괴한 문자열 덩어리를, 놀라운 자연어 처리(NLP) 능력을 통해 state, city, street 같은 그럴싸한 JSON 프로퍼티로 잘게 쪼개어 파싱 해내는 데는 타의 추종을 불허한다.

하지만, 여기서 우리는 MLOps 아키텍트로서 매우 차갑고 근본적인 질문 하나를 던져야 한다.
“LLM이 예쁘게 조립해 낸 그 JSON 텍스트 주소가, 실제 지구상에 물리적으로 존재하는 장소인가?”
이 질문에 대한 대답은 결코 파라미터 모델 내부의 수학적 연산망(2단계 오라클)에서는 얻을 수 없다. 가령 ’서울특별시 강남구 테헤란로 99999번지’라는 자연어 텍스트는 1단계 구문 오라클(Type 유효)과 언어적 맥락 구조에서는 그야말로 완벽한 주소의 형태를 갖추고 있으나, 현실의 지도 폴리곤 상에는 구획조차 되지 않은 완벽한 **공간 환각(Spatial Hallucination)**이기 때문이다.

이러한 망상적 주소가 벤더나 배송망 마스터 DB로 삽입되는 참사를 막기 위해, 3단계 오라클 시스템은 이제 문서 안에 갇혀있던 주소 문자열을 들고 문서 바깥으로 뛰쳐나가 글로벌 공간정보(Geospatial) API의 문을 세차게 두드려야만 한다.

1. 지오코딩(Geocoding) API를 매개로 한 실재성 오라클 아키텍처

Google Maps Geocoding API나 한국의 행정안전부 주소 API망은, 인간이 대충 친 입력 텍스트 문자열을 파고들어 위도/경도(Latitude/Longitude) 좌푯값으로 역변환해 주는, 인류가 구축한 가장 완벽한 ‘공간 데이터 진실(Spatial Ground Truth)’ 검증 서버다.

from pydantic import BaseModel, model_validator
import httpx
import typing

class AddressSpatialIntegrityOracle(BaseModel):
    # LLM이 1차로 뱉어낸 (오타와 누락이 가득할 수 있는) 불안정한 자연어 주소 텐서
    raw_address: str 
    
    # 시스템이 필수(Required)로 요구하나 거친 OCR로 인해 누락되었을지 모를 필드
    postal_code: typing.Optional[str] = None
    
    # 런타임에 주입될 글로벌 Geocoding API 엔드포인트 세팅
    _GEOCODING_API_URL = "https://maps.googleapis.com/maps/api/geocode/json"
    _API_KEY = "YOUR_SECURE_API_KEY" # 실제 운영 환경에서는 AWS Secrets Manager 등으로 격리
    
    @model_validator(mode='after')
    def verify_and_normalize_geospatial_address(self):
        """ 추출된 주소 텍스트를 외부 공간정보 API로 타격하여 물리적 실재성을 증명한다. """
        
        try:
            response = httpx.get(
                self._GEOCODING_API_URL, 
                params={"address": self.raw_address, "key": self._API_KEY},
                timeout=2.5
            )
            response.raise_for_status()
            geo_data = response.json()
        except httpx.RequestError as e:
             # 외부 API 타임아웃 발생 시 무조건 기각하지 않고 큐에 남겨 재시도 늪(Retry Swamp) 방어
             # (13.5.6절의 Fallback 기법과 연계됨)
             raise ValueError(f"[인프라 장애] Geocoding API 접속 불량으로 검증 중단: {e}")
             
        status = geo_data.get("status")
        
        # 1. 공간 룩업 1차 관문 심판: 지구상 위/경도에 실재로 존재하는 곳인가?
        if status == "ZERO_RESULTS":
            raise ValueError(
                f"[공간 실재성 검증 실패] 추출된 주소({self.raw_address})는 "
                f"지도 API 상에 존재하지 않거나 완전히 파괴된 OCR 환각입니다. 롤백합니다."
            )
            
        elif status == "OK":
            # 2. 정규화(Normalization): 글로벌 스탠다드가 반환한 깨끗한 공식 주소로 덮어쓰기
            validated_result = geo_data["results"][0]
            
            # 애매하고 더러웠던 raw_address 객체 자체를 글로벌 포맷(formatted_address)으로 강력 치환
            self.raw_address = validated_result.get("formatted_address")
            
            # 3. 결측치 자가 보완: 누락되었을지 모를 우편번호(Zip Code)를 API 결괏값에서 연역적 파싱
            components = validated_result.get("address_components", [])
            for comp in components:
                if "postal_code" in comp.get("types", []):
                    # LLM이 찾지 못한 값을 시스템 오라클이 스캔하여 객체 필드에 은밀히 끼워 넣는다.
                    self.postal_code = comp.get("long_name")
                    break
                    
        return self

2. 오라클의 능동적 자기 치유(Self-Healing)와 데이터 배서(Endorsement) 효과

이 공간 인식 3단계 오라클이 위대한 점은 거름망 역할에 그치지 않는다는 것이다. 즉, 결점이 보일 때 단순히 *“이 주소는 이상해서 안 되겠다”*라고 판결하며 에러를 내뱉고 파이프라인을 멈춰 세우는 수동적인 문지기(Gatekeeper) 역할에만 머무르지 않는다.

만약 영수증 화질 구려 LLM이 입력단에 '서울시 강납구 태해란로 123' 이라는 형편없는 오타를 뱉어내더라도, 지오코딩 API 코어에 내장된 강력한 NLP 퍼지 매치 알고리즘을 시스템이 역차용(Leverage) 하여 OK 사인을 받아낸다. 그리고 최종적으로 Pydantic 객체의 메모리를 '대한민국 서울특별시 강남구 테헤란로 123' 이라는 우편번호 체계의 공식 도로명 주소로 객체 원본 파라미터 값 자체를 완전히 덮어쓰기(Overwrite) 해버리는 무시무시한 능동적 자가 치유(Active Self-healing) 메커니즘을 가동한다.

이렇게 비정형의 더러운 텍스트 페이로드는 ’외부 신뢰 기관(Google/정부)의 API 검증 및 자동 보정’이라는 결정적인 기계적 배서(Endorsement) 과정을 관통함으로써, 마침내 글로벌 물류 배송 트럭을 즉각 물리적으로 출발시켜도 좋을 만큼 완벽하고 성숙한 엔터프라이즈의 마스터 데이터 레코드로 눈부시게 격상(Elevation) 되는 것이다.