LLM 분류를 위한 이메일 분류 체계 (Email Triage Taxonomies)
요약
효과적인 이메일 분류 에이전트 구축을 위해 모델 성능보다 중요한 것은 응답 의무(response obligations) 기반의 분류 체계(taxonomy) 설계임을 강조합니다. 레이블을 주제가 아닌 구체적인 행동 단위로 정의하여 제어 흐름을 단순화하고 정확도를 높이는 방법을 제시합니다.
핵심 포인트
- 분류 체계 설계 시 레이블은 주제가 아닌 '응답 의무'를 기준으로 정의해야 함
- 카테고리 개수는 모델의 혼동을 방지하기 위해 4개가 가장 적절함
- 각 레이블은 반드시 하나의 명확한 행동(Action)에 매핑되어야 함
- 분류(temperature=0)와 초안 작성(temperature=0.7)의 설정을 분리하여 운영할 것
이메일 분류기에서 가장 중요한 설계 결정은 모델이 아니라 레이블 세트(label set)입니다. 그리고 제가 계속해서 되돌아오게 되는 방식은 바로 이것입니다:
당신은 이메일을 다음 네 가지 카테고리 중 하나로 분류합니다:
URGENT (긴급) — 운영 장애, 경영진 요청; 1시간 이내에 회신할 것
...
이것은 Nylas 이메일 분류 레시피에서 사용하는 작업 프롬프트이며, 거의 모든 줄이 분석할 가치가 있는 분류 체계 설계(taxonomy-design)의 교훈을 담고 있습니다. 이메일 에이전트를 구축하는 대부분의 사람들은 모델 선택과 프롬프트 문구에 집착합니다. 이 레시피의 조용한 논지는 레이블 세트 자체가 핵심적인 역할을 한다는 것입니다. 분류 체계(taxonomy)를 제대로 설정하면 저렴한 모델도 분류를 잘 수행하지만, 잘못 설정하면 어떤 모델도 당신을 구할 수 없습니다.
왜 4가 마법의 숫자인가
레시피는 이를 단호하게 명시합니다. 4가 적절한 숫자라고 말이죠. 3개는 충실도(fidelity)를 잃습니다. 모든 중요한 사항이 과부하된 하나의 버킷으로 붕괴되어, 결국 추가 단계가 붙은 이진 분류기(binary classifier)를 만든 꼴이 됩니다. 5개가 되면 모델이 카테고리를 혼동하기 시작하는데, 이는 인접한 레이블 사이의 경계가 정의로 표현하기에 너무 얇아지기 때문입니다.
이 네 가지가 작동하는 방식을 주목하십시오. 이것들은 주제(topics)가 아니라, _응답 의무(response obligations)_입니다. URGENT는 "1시간 이내에 회신"을 의미하고, ACTION은 "오늘 중 회신", FYI는 "회신 필요 없음", NOISE는 "보관(archive)"을 의미합니다. 각 레이블은 정확히 하나의 행동에 매핑됩니다. 이것이 제가 모든 이메일 분류 체계에 적용하는 테스트입니다. 만약 두 레이블이 동일한 행동으로 이어진다면 병합하십시오. 만약 하나의 레이블이 내용에 따라 두 가지 다른 행동으로 이어진다면 분리하십시오.
분류 체계는 디스패치 테이블(dispatch table)이다
레시피는 이를 문자 그대로 구현합니다. 전체 액션 루프(action loop)는 읽지 않은 메시지에 대해 각 레이블당 하나의 분기를 갖는 for 문으로 구성됩니다:
for msg in fetch_unread():
cat = classify(msg)
if cat in ("URGENT", "ACTION"):
...
여기에는 겉보기보다 더 큰 역할을 하는 두 가지 세부 사항이 있습니다. 첫째, 에이전트는 절대 직접 전송하지 않습니다. URGENT(긴급)와 ACTION(조치 필요)은 사람이 검토할 _초안 (drafts)_을 생성할 뿐입니다. 잘못된 전송(잘못된 대상, 잘못된 어조)의 비용이 클릭 한 번을 더 하는 번거로움보다 훨씬 높기 때문입니다. 둘째, 이 루프는 구조적으로 멱등성 (idempotent)을 가집니다. --unread 메시지만 가져오기 때문에, 이미 분류된 항목은 별도의 중복 제거 (dedup) 테이블 없이도 다음 실행 시 제외됩니다. 이 분류 체계 (taxonomy)는 단순히 메일을 분류하는 데 그치지 않고, cron을 통해 무인으로 실행할 수 있는 제어 흐름 (control flow)을 형성했습니다.
초안 작성 (Drafting) 또한 분류 (classification)와는 다른 설정으로 실행됩니다. 분류기의 temperature=0과 달리, 초안 작성은 "최대 세 문장"이라는 지침과 함께 temperature=0.7을 사용합니다. 결정론적인 결정 (Deterministic decisions)과 자연스러운 산문 (natural prose)의 조합입니다. 동일한 파이프라인이지만 두 가지 서로 다른 작업이며, 여기서 문장 수 제한이 핵심적인 역할을 한다는 점은 명확합니다. 이 제한이 없다면 지나치게 예의를 차리려 애쓰는 인턴처럼 보이는 초안을 얻게 될 것입니다.
정의는 형용사가 아니라 예시여야 합니다
프롬프트를 다시 살펴보십시오. URGENT는 "매우 중요하고 시간이 촉박한"이라고 정의되지 않았습니다. 대신 "운영 장애 (production incidents), 경영진 요청 (executive requests)"라고 정의되어 있습니다. 추상적인 특성이 아닌 구체적인 사례 (concrete instances)입니다. LLM은 형용사보다 예시를 통해 패턴 매칭 (pattern-match)을 훨씬 더 잘 수행하며, 모호한 형용사는 분류기가 표류 (drift)하게 만드는 원인이 됩니다. 한 모델의 "중요한"이 다른 모델에게는 "일상적인" 것일 수 있기 때문입니다.
마감 기한 주석("1시간 이내 회신", "당일 회신")은 결정적인 판단 기준 (tie-breakers) 역할도 겸합니다. 메시지가 두 범주 사이에 걸쳐 있을 때, 모델은 "이것이 한 시간 내에 답변이 필요한가, 아니면 하루 내에 필요한가?"라는 암묵적인 질문을 던질 수 있습니다. 이는 주제 유사성 (topical similarity)보다 훨씬 더 날카로운 판별 기준이 됩니다.
진심을 담아 출력을 제한하십시오
분류 체계 (Taxonomy) 설계는 응답 형식까지 확장됩니다. 이 레시피는 temperature=0, max_tokens=10 설정으로 분류를 수행합니다. 즉, 결정론적 (deterministic) 출력, 하나의 카테고리 이름만을 생성하며, 설명 문단이 들어설 여지를 주지 않습니다. 그러면서도 검증 과정은 거칩니다. 코드는 응답을 네 가지 유효한 문자열과 대조하며, 인식되지 않는 항목에 대해서는 FYI로 대체(fallback)합니다. 이는 LLM이 가끔 존재하지 않는 카테고리를 만들어내기 때문입니다. 인식되지 않는 레이블을 "그대로 두기"로 기본 설정하는 것이 안전한 실패 (safe failure) 방식입니다. 만약 NOISE로 기본 설정한다면 실제 메일을 소리 없이 아카이브해 버릴 것입니다.
입력값 또한 매우 공격적으로 제한됩니다: 발신자, 제목, 그리고 200자 이내의 스니펫 (snippet) — 본문 전체는 절대 포함하지 않습니다. 이는 이 작업에서 90% 이상의 정확도를 확보하기에 충분하며, 비용을 거의 무시할 수 있는 수준으로 유지해 줍니다. 레시피의 계산법은 다음과 같습니다: GPT-4o-mini는 입력 토큰 100만 개당 약 $0.15가 소요됩니다. 스니펫과 프롬프트를 합치면 대략 150 토큰이므로, 이메일 100통의 비용은 약 $0.002입니다. 초안 작성 (Drafting)에는 더 비싼 GPT-4o를 사용하지만, 이는 URGENT 및 ACTION 하위 집합 — 보통 편지함의 20% 미만 — 에만 적용됩니다. 따라서 하루에 200통의 메일을 대량으로 처리해도 비용은 약 5센트(a nickel) 정도입니다. 저렴한 분류 덕분에 이 전체 패턴은 아껴 써야 하는 귀중한 자원이 아니라, 15분마다 실행되는 크론 잡 (cron job)으로서 실행 가능한 구조가 됩니다. 인프라 외부로 나갈 수 없는 메일의 경우, 레시피의 개인정보 보호 모드(privacy mode)를 통해 로컬 Ollama 엔드포인트로 교체할 수 있습니다. Llama 3.1은 이 작업에서 GPT-4o-mini만큼이나 우수한 분류 성능을 보여주지만, 70B 이상의 파라미터 모델을 사용하지 않는 한 초안 작성 품질은 떨어집니다.
반론: 경직된 버킷은 정보를 손실한다
제가 듣는 반론은 다음과 같습니다: 고정된 분류 체계는 미묘한 차이 (nuance)를 버린다는 것입니다. 왜 모델이 자유 형식의 태그를 반환하거나, 여러 축을 따라 점수 (scores)를 매기도록 하지 않느냐는 것이죠. 솔직히 말해서, 때로는 그 말이 맞습니다. 만약 고객 지원 편지함에 대한 분석 도구를 구축하고 있다면, 더 풍부한 구조 (며칠간 지속되는 고객 지원 패턴에서 사용하는 카테고리 + 긴급도 + 신뢰도 조합처럼)는 그 복잡성을 감수할 가치가 있습니다. 하류 (downstream)의 소비자(데이터 활용 주체)들이 이를 집계할 수 있기 때문입니다.
하지만 직접 _행동(act)_해야 하는 에이전트에게 자유 형식의 출력(free-form output)은 부담(liability)입니다. 모델이 생성할 수 있는 모든 고유한 출력은 당신이 처리해야 하는 코드 경로(code path)이며, "처리한다"는 것은 곧 테스트해야 함을 의미합니다. 4개의 레이블은 추론, 부하 테스트(load-test), 그리고 감사가 가능한 4개의 분기(branch)를 의미합니다. 반면 40개의 창발적 태그(emergent tags)는 사실상 또 다른 모델 호출과 다름없는 라우팅 계층(routing layer)을 의미합니다. 폐쇄형 어휘집(closed vocabulary), 검증된 출력(validated output), 레이블당 하나의 동작(one action per label)이라는 이 레시피의 규율은, 에이전트의 동작을 실제 메일함에서 무인으로 실행할 수 있을 만큼 충분히 예측 가능하게 만들어 줍니다. (에이전트에게 분류를 위한 전용 수신함을 제공하는 Agent Accounts는 현재 베타 버전입니다. 분류 체계(taxonomy) 패턴은 모든 메일함에 적용됩니다.)
계획 단계에서 고려할 만한 한 가지 개선 사항은, 분류 체계(taxonomies)는 보편적인 것이 아니라 수신함(inbox)별로 결정된다는 점입니다. 이 레시피는 엔지니어링 수신함이 영업(sales) 수신함과는 다르게 '긴급(URGENT)' 상황을 처리한다는 점을 언급합니다. 따라서 커스터마이징해야 할 부분은 카테고리의 개수가 아니라 카테고리의 정의입니다.
20분 정도 소요되는 다음 연습을 해보세요. 에이전트가 관리할 수신함에서 최근 메시지 50개를 가져와 위에서 언급한 4개의 버킷(buckets)으로 직접 레이블을 지정해 보십시오. 망설여지는 부분이 있다면 그 이유를 적어두세요. 그 망설임은 카테고리의 경계가 더 날카로운 예시 목록을 필요로 한다는 신호입니다. 당신의 수신함은 어떤 레이블을 추가하도록 강제했나요? 그리고 그 레이블들은 어떤 동작(action)으로 매핑되었나요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기