본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 05. 17:28

정규 표현식(Regex)과의 사투를 멈추고 LLM으로 데이터를 추출하게 된 과정

요약

정규 표현식(Regex)의 한계를 극복하기 위해 LLM을 활용하여 비정형 텍스트에서 데이터를 추출하는 과정을 다룹니다. Pydantic과 OpenAI의 JSON 모드를 결합하여 유지보수가 용이한 데이터 파이프라인을 구축하는 방법을 제시합니다.

핵심 포인트

  • 정규 표현식은 복잡하고 가변적인 비정형 데이터 처리에 취약함
  • LLM의 함수 호출(Function Calling)을 통한 구조화된 데이터 추출 가능
  • Pydantic을 활용한 JSON 스키마 정의로 데이터 검증 강화
  • 프롬프트 엔지니어링을 통한 데이터 추출 파이프라인의 유지보수성 향상

고객 이메일을 파싱하기 위해 정규 표현식(Regex) 괴물을 만드는 데 사흘을 보냈습니다. 47개의 패턴을 만들었는데, 각 패턴은 이전 것보다 더 취약했습니다. 공백 하나만 빠져도 전체가 망가졌습니다. 4일째 되는 날, 저는 노트북을 창밖으로 던져버리고 싶었습니다.

그때 저는 완전히 다른 시도를 해보기로 했습니다. 대규모 언어 모델(LLM)이 힘든 일을 대신하게 하는 것이었습니다.

이것은 제가 정규 표현식 지옥에서 벗어나 LLM을 사용하여 깔끔하고 유지보수가 가능한 데이터 추출 파이프라인을 구축하게 된 이야기이며, 왜 제가 비정형 텍스트를 위해 수동으로 패턴을 만드는 방식으로 돌아가지 않을 것인지에 대한 이야기입니다.

문제: 지저분하고 사람이 작성한 텍스트

저는 지원 티켓을 처리하기 위한 내부 도구를 만들고 있었습니다. 고객들은 다음과 같이 작성하곤 했습니다:

  • “주문 번호 #12345가 지연되었습니다. 배송비를 환불해 주실 수 있나요?”
  • “안녕하세요, SKU-9876 품목에 대한 교환이 필요합니다. 제 주문 번호는 54321입니다.”
  • “제 패키지는 어디 있나요? 주문 번호 98765입니다, 도와주세요!”

모든 이메일은 표현 방식이 다르고, 정보의 순서가 다르며, 가끔 오타도 있었습니다. 저는 주문 ID(order ID), 의도(intent: 환불, 교환, 추적), 그리고 언급된 모든 SKU를 추출해야 했습니다.

처음 시도했던 것 (그리고 실패한 것)

정규 표현식 (Regex)

정규 표현식으로 시작했습니다. 일반적인 변형에 대해 패턴을 작성했습니다:

import re

order_pattern = r'order\s*[#:]?\s*(\d{5,8})'
...

이것은 이메일의 약 20% 정도에서만 작동했습니다. 그러다 현실의 벽에 부딪혔습니다:

  • 일부 주문에는 문자(예: ORD-2024-001)가 포함되어 있었습니다.
  • SKU는 때때로 item 1234와 같이 작성되었습니다.
  • 의도(Intent) 단어가 _“환불하지 마세요(don’t refund)”_와 같은 구절 속에 나타났습니다.

저는 계속해서 패턴을 추가했습니다. 제 코드는 전방 탐색(lookahead)과 선택적 그룹(optional groups)이 뒤엉킨 엉망진창이 되었습니다. 어느 시점에는 아무것도 매칭되지 않으면서도 에러를 발생시키지 않는 정규 표현식이 생겼습니다. 그냥 모든 것에 대해 조용히 빈 문자열을 반환할 뿐이었습니다.

NLP 라이브러리

다음으로, 저는 spaCy와 맞춤형 NER (개체명 인식, Named Entity Recognition)으로 눈을 돌렸습니다. 200개의 주석이 달린 예시로 모델을 학습시키는 데 또 다른 하루를 보냈습니다. 하지만 일반화가 잘 되지 않았습니다. 모델은 order를 개체로 라벨링했지만 실제 주문 번호는 놓쳤습니다. 게다가 새로운 의도를 추가하려면 모델을 다시 학습시켜야 했습니다.

LLM 접근 방식: 프롬프트 엔지니어링 (Prompt Engineering) + 구조화된 출력 (Structured Output)

한 동료가 "LLM에게 JSON으로 추출해달라고 요청하는 건 어때요?"라고 제안했습니다. 저는 회의적이었습니다. LLM은 말이 많지, 정밀하지는 않으니까요. 하지만 그 후 OpenAI API의 **함수 호출 (function calling)**과 **JSON 모드 (JSON mode)**에 대해 알게 되었습니다. 핵심 아이디어는 모델에게 원하는 필드를 정확히 알려주면, 모델이 유효한 JSON을 반환한다는 것입니다.

핵심 기술은 다음과 같습니다:

1. JSON 스키마 (JSON schema) 정의 (검증을 위해 Pydantic 사용)

from pydantic import BaseModel
from typing import Optional

...

2. 규칙을 설정하는 시스템 프롬프트 (system prompt) 작성

system_prompt = """당신은 데이터 추출 어시스턴트입니다. 
사용자의 이메일에서 다음 필드들을 추출하여 오직 유효한 JSON 객체로만 반환하세요.
필드:
...

3. response_format을 json_object로 설정하여 API 호출

import openai

response = openai.chat.completions.create(
...

그게 전부입니다. 단 몇 줄의 코드가 47개의 정규 표현식 (regex) 패턴을 대체했습니다.

예외 케이스 처리 (Handling Edge Cases)

LLM은 강력하지만 완벽하지는 않습니다. 신뢰성을 높이기 위해 제가 추가한 사항들은 다음과 같습니다:

  • 검증을 통한 재시도 (Retry with validation): JSON이 스키마와 일치하지 않으면, 에러 메시지와 함께 프롬프트를 다시 보냅니다.
  • 퓨샷 예시 (Few-shot examples): 까다로운 의도(intents)의 경우, 시스템 프롬프트에 2~3개의 예시를 포함했습니다.
  • 모든 실패 사례 로깅 (Logging all failures): 추출에 실패한 모든 이메일을 로깅하여 시간이 지남에 따라 프롬프트를 개선할 수 있도록 했습니다.
  • 비용 의식 (Cost awareness): 속도가 빠르고 비용이 저렴한 gpt-4o-mini를 사용했습니다. 단일 추출 비용은 약 0.01센트입니다.

이 접근 방식을 사용하지 말아야 할 때

  • 대량의 데이터, 낮은 복잡도 (High volume, low complexity): 텍스트가 매우 구조화되어 있다면 (CSV 파일처럼), 정규 표현식 (Regex)이 더 빠르고 저렴합니다.
  • 실시간 시스템 (Real-time systems): LLM 추론 (Inference)은 500ms~2s의 지연 시간 (Latency)을 추가합니다. 실시간 처리가 필요하다면 더 작은 모델이나 전통적인 NLP를 고려하십시오.
  • 개인정보 보호 제약 (Privacy constraints): 고객의 이메일을 제3자 API로 전송하는 것은 규정 준수 (Compliance)를 위반할 수 있습니다. 이 경우 로컬 LLM (Llama 3 등)이나 자체 호스팅 서비스를 사용해야 합니다.
  • 결정론적 요구사항 (Deterministic requirements): 매번 정확히 동일한 출력이 필요하다면, LLM은 확률적 (Probabilistic)입니다. 재시도 시 서로 다른 결과를 얻을 수도 있습니다.

교훈 (Lessons Learned)

  • 프롬프트 엔지니어링 (Prompt engineering)은 새로운 정규 표현식입니다. 하지만 유지보수 측면에서 훨씬 뛰어납니다. 프롬프트는 몇 초 만에 변경할 수 있지만, 정규 표현식 패턴을 변경하면 종종 다른 부분을 망가뜨리곤 했습니다.
  • 검증 (Validation)은 필수입니다. 항상 출력을 타입이 지정된 모델 (Typed model)로 파싱하고 오류를 잡아내야 합니다.
  • 가장 단순한 LLM부터 시작하십시오. 처음에는 GPT-4를 시도했지만, GPT-4o-mini로도 충분했으며 비용은 20배 더 저렴했습니다.
  • 전통적인 추출 방식과 결합하십시오. 예를 들어, 이메일에 ORD-12345와 같이 명확하게 형식이 지정된 주문 번호가 포함되어 있다면, 정규 표현식으로 더 빠르게 추출하고 모호한 부분에만 LLM을 사용할 수 있습니다.

다음에 다시 한다면 다르게 할 점

추출 로직을 변경하지 않고도 LLM 제공업체를 교체할 수 있도록 작은 추상화 계층 (Abstraction layer)을 구축하겠습니다. ai.interwestinfo.com과 같은 서비스는 내장된 검증 기능을 갖춘 유사한 추출 엔드포인트를 제공합니다. 프롬프트 유지보수를 직접 하고 싶지 않다면 이러한 전용 API 사용을 고려할 것입니다.

하지만 현재로서는 저의 파이프라인이 원활하게 작동하고 있습니다. 하루에 수백 개의 티켓을 95%의 정확도로 처리하고 있으며, 나머지 5%는 수동 검토를 위해 로그로 남깁니다. 더 이상 정규 표현식의 악몽은 없습니다.

만약 취약한 파싱 방식과 싸우고 있다면, LLM을 시도해 보세요. 간단한 프롬프트로 시작하여 반복 개선해 나가십시오.

지저분한 텍스트에서 데이터를 추출하기 위한 여러분만의 비결은 무엇인가요?

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0