콘텐츠로 이동

P7-4.2 실패한 결과를 다시 분해하기

Section ID: P7-4.2 Version: v2026.07.22

고객 문의를 환불팀과 배송팀으로 나누는 텍스트 분류기를 만들었다고 해도, 정확도 숫자 하나만으로 검토를 끝내기 어렵습니다. 실패한 결과를 기준선 문제, 입력 표현 문제, 데이터 범위 문제, 구조 문제로 다시 분해해 봐야 합니다.

같은 0.833이라도 어떤 문의는 학습 때 본 단어를 대부분 포함하고 있고, 어떤 문의는 핵심 표현이 거의 처음 등장합니다. 그래서 텍스트 프로젝트에서는 맞았는가만이 아니라 기준선도 같은 곳에서 흔들렸는가, 모델이 실제로 읽은 단어가 얼마나 있었는가, 반복 오답 패턴이 남는가를 같이 남겨야 합니다.

실패 원인을 나누는 기준

  • 실패한 결과를 왜 한 덩어리로 두지 말고 다시 분해해야 하는가?
  • OOV(out-of-vocabulary) 토큰과 낮은 coverage는 어떤 실패를 입력 표현 문제로 읽게 만드는가?
  • 기준선 한계, 입력 표현 한계, 구조 한계를 어떤 순서로 가를 수 있는가?

핵심은 기준선 비교 -> coverage/OOV -> 반복 패턴 순서로 실패를 분해하는 데 있습니다. 정확도 숫자를 입력 표현 기록과 함께 읽어야만 지금 고쳐야 할 것이 기준선 한계인지, 표현 불일치인지, 더 큰 구조 문제인지 갈라집니다.

Part 7에서 토큰화(tokenization), 토큰 커버리지(token coverage), 평가(evaluation)의 경계가 흐려지면 이 절과 개념사전을 다시 함께 확인해, 입력 표현 기록과 실패 해석이 어디서 이어지는지 분리해 두는 것이 좋습니다.

판단 기준

  • 실패한 결과를 기준선 문제, 입력 표현 문제, 반복 패턴 문제로 나누어 볼 수 있습니다.
  • 토큰화와 평가를 분리하지 않고 함께 읽어야 하는 이유를 설명할 수 있습니다.
  • 사전에 없는 토큰과 기존 어휘 포함 비율을 평가 기록에 남길 수 있습니다.
  • 낮은 coverage가 즉시 오답은 아니지만 재검토 신호라는 점을 이해할 수 있습니다.

실패를 한 덩어리로 두면 왜 안 되는가

텍스트 분류 모델이 예측을 잘했다는 말은, 적어도 어떤 단어 구조를 읽고 분류했는지와 함께 나와야 합니다. 같은 환불 문의라도 다음 두 문장은 모델 입장에서 전혀 다를 수 있습니다.

  • 환불 진행 상태 확인
  • 캔슬 후 송장 번호 남아 있어요

첫 번째 문장에는 학습 데이터에 있던 환불, 상태, 확인이 들어 있습니다. 반면 두 번째 문장에서는 핵심 의도인 캔슬이 학습 어휘 밖에 있고, 오히려 송장, 번호가 배송팀 신호로 더 강하게 읽힙니다.

실패를 분해할 때 먼저 붙들어야 할 판단 기준을 표로 고정하면 다음과 같습니다.

질문 짧은 답
왜 실패를 다시 나누는가? 같은 오답도 원인이 다를 수 있어서
무엇이 입력 표현 문제 신호인가? 기존 어휘 포함 비율 저하와 핵심 OOV
무엇이 구조 문제 신호인가? coverage는 충분한데 비슷한 패턴에서 반복 오답이 나는 경우
그래서 문서에 무엇을 남기는가? 기준선 비교, OOV 목록, coverage, 오류 샘플, 다시 볼 질문

실제 운영 문서에서는 실패를 대략 다음 네 칸으로 쪼개 두면 다음 행동이 훨씬 빨라집니다.

실패 층위 먼저 확인할 질문
기준선(baseline) 단순 기준선도 같은 유형을 틀리는가
입력 표현(representation) 핵심 표현이 OOV이거나 coverage가 너무 낮은가
데이터(data) 비슷한 표현군이나 사례가 학습 데이터에 비어 있는가
구조(structure) 위 세 가지를 확인한 뒤에도 반복 오답이 남는가

실패를 가르는 비교 사례

P7-4.1의 같은 학습 데이터를 유지한 채 평가 문장을 조금 더 넓혀 봅니다. 핵심은 낯선 표현, 혼합 문의, coverage는 낮지만 정답은 맞은 문의를 함께 두어, coverage를 너무 단순하게 읽지 않는 것입니다.

평가 샘플 실제 팀 왜 넣는가
평가-01 환불 진행 상태 확인 환불팀 높은 coverage의 안정 사례
평가-04 출고 지연 도착 예정 문의 배송팀 배송 신호가 여러 개 겹친 사례
평가-05 캔슬 후 송장 번호 남아 있어요 환불팀 핵심 의도는 환불인데 배송 단어가 더 눈에 띄는 혼합 사례
평가-07 하자 제품 환불 스케줄 알고 싶어요 환불팀 coverage는 낮지만 정답은 맞는 사례

이렇게 두어야 coverage가 낮다 = 무조건 오답처럼 오해하지 않고, coverage가 낮으면 왜 다시 봐야 하는가를 더 정확하게 읽을 수 있습니다.

예를 들어 평가-05평가-07을 함께 보면, 빠르게는 둘 다 coverage가 0.333이므로 둘 다 같은 종류의 실패라고 묶고 싶어집니다. 하지만 실제로는 그렇지 않습니다. 평가-05는 핵심 의도어 캔슬이 OOV라서 오답까지 이어졌고, 평가-07은 OOV가 많아도 환불, 제품 같은 강한 단어 덕분에 아직 정답을 유지합니다. 그래서 더 안전한 다음 판단은 coverage가 낮다 -> 구조를 바꾼다가 아니라, 낮은 coverage가 실제 오답으로 이어졌는가, 표현 정규화로 먼저 줄일 수 있는가를 먼저 가르는 것입니다.

flowchart TD
  A["coverage 0.333 샘플 두 개 발견"]
  B["빠른 판단: 둘 다 같은 실패로 처리"]
  C["오답 여부와 핵심 OOV를 함께 확인"]
  D["평가-05: 오답, 핵심 의도어 OOV"]
  E["평가-07: 정답, 강한 핵심 단어는 남아 있음"]
  F["다음 판단: 구조 변경 전 표현 정규화와 재검토 우선순위를 나눔"]

  A --> B
  A --> C
  C --> D
  C --> E
  D --> F
  E --> F

Python 예제

예제는 각 평가 문장의 토큰 목록, OOV 목록, 기존 어휘 포함 비율을 함께 출력하는 것입니다. 예제에서는 정확도와 함께 coverage가 낮은 샘플, 오류 샘플, 다시 볼 질문까지 묶어 남기겠습니다.

  • 문제 상황: 팀 라우팅 분류 결과를 coverage와 함께 읽는다.
  • 입력: 학습 문의 12개, 평가 문의 7개
  • 기대 출력: 문장별 토큰 목록, OOV 목록, coverage, 검토 대상 샘플
  • 확인할 개념:
  • 토큰화 결과가 그대로 평가 해석 자료가 된다
  • 낮은 coverage는 재검토 신호이지 즉시 오답 판정이 아니다
  • 검토 대상 문장을 명시적으로 남겨야 다음 개선 계획이 쉬워진다

같은 흐름에서 P7-4.1과 같은 p7-4-support-routing-dataset.csv를 그대로 읽습니다. 이렇게 두면 같은 문의 데이터 파일 위에서 기본 분류와 coverage/OOV 평가를 연속해서 확인할 수 있습니다.

실행 기록 기준

실패 분해 기록은 오답 하나를 모델이 틀렸다로 닫지 않고, 기준선 비교와 입력 표현 기록으로 다시 나눕니다. 평가 문장의 토큰이 학습 어휘에 얼마나 남는지 예상하고, 낮은 coverage 샘플 중 무엇이 실제 오답이고 무엇이 재검토 후보인지 구분해야 합니다.

기록은 다음 기준으로 나눕니다.

  1. 평가 문장 중 캔슬, 하자, 스케줄처럼 학습 어휘에 없을 것 같은 표현을 표시합니다.
  2. Python 예제를 실행해 샘플별 OOV 목록과 기존 어휘 포함 비율을 확인합니다.
  3. 낮은 coverage 샘플을 오답 샘플과 정답 샘플로 다시 나눕니다.
  4. 각 샘플을 표현 정규화, 데이터 추가, 구조 검토 중 어느 질문으로 넘길지 한 줄로 적습니다.
# 고객지원 라우팅 실패 샘플에서 OOV token, vocabulary coverage, 팀별 점수를 확인해 토큰화 문제를 분해하는 예제입니다.
import csv
import numpy as np
from pathlib import Path

data_path = Path("docs/assets/part-07/chapter-04/p7-4-support-routing-dataset.csv")
rows = list(csv.DictReader(data_path.open(encoding="utf-8")))
for row in rows:
    row["샘플"] = row["sample_id"]
    row["문장"] = row["text"]
    row["라벨"] = int(row["label"])

train_rows = [row for row in rows if row["split"] == "train"]
test_rows = [row for row in rows if row["split"] == "test"]

라벨_이름 = {0: "환불팀", 1: "배송팀"}

def tokenize(text):
    return text.split()

vocab = sorted({token for row in train_rows for token in tokenize(row["문장"])})
token_to_index = {token: i for i, token in enumerate(vocab)}

def vectorize(rows):
    X = np.zeros((len(rows), len(vocab)), dtype=float)
    token_lists = []
    known_counts = []
    total_counts = []
    oov_tokens_per_text = []

    for i, row in enumerate(rows):
        tokens = tokenize(row["문장"])
        token_lists.append(tokens)
        total_counts.append(len(tokens))
        known = 0
        oov_tokens = []

        for token in tokens:
            if token in token_to_index:
                X[i, token_to_index[token]] += 1
                known += 1
            else:
                oov_tokens.append(token)

        known_counts.append(known)
        oov_tokens_per_text.append(oov_tokens)

    return X, token_lists, known_counts, total_counts, oov_tokens_per_text

X_train, _, _, _, _ = vectorize(train_rows)
y_train = np.array([row["라벨"] for row in train_rows])

class_profiles = np.vstack([
    X_train[y_train == 0].sum(axis=0),
    X_train[y_train == 1].sum(axis=0),
])

X_test, token_lists, known_counts, total_counts, oov_tokens_per_text = vectorize(test_rows)
y_test = np.array([row["라벨"] for row in test_rows])

predictions = []
evaluation_records = []
for index, x in enumerate(X_test):
    scores = class_profiles @ x
    pred_label = int(np.argmax(scores))
    predictions.append(pred_label)
    known_ratio = known_counts[index] / total_counts[index] if total_counts[index] else 0.0
    evaluation_records.append({
        "평가 샘플": test_rows[index]["샘플"],
        "문장": test_rows[index]["문장"],
        "토큰": token_lists[index],
        "사전에 없는 토큰": oov_tokens_per_text[index],
        "기존 어휘 포함 비율": round(known_ratio, 3),
        "환불팀 점수": int(scores[0]),
        "배송팀 점수": int(scores[1]),
        "예측 팀": 라벨_이름[pred_label],
        "실제 팀": 라벨_이름[y_test[index]],
        "정답 여부": "예" if pred_label == y_test[index] else "아니오",
        "토큰 검토 필요": "예" if (known_ratio < 0.5 or pred_label != y_test[index]) else "아니오",
    })

predictions = np.array(predictions)

검토_요약 = {
    "토큰화 규칙": "공백 기준 분리",
    "평가 정확도": round(float((predictions == y_test).mean()), 3),
    "검토 대상 샘플": [
        row["평가 샘플"] for row in evaluation_records if row["토큰 검토 필요"] == "예"
    ],
    "낮은 coverage 샘플 수": sum(
        row["기존 어휘 포함 비율"] < 0.5 for row in evaluation_records
    ),
    "오류 샘플": [
        row["평가 샘플"] for row in evaluation_records if row["정답 여부"] == "아니오"
    ],
}

print("검토 요약 =", 검토_요약)
print("읽은 파일 =", str(data_path))
print("샘플별 평가 =")
for row in evaluation_records:
    print(row)

실행 결과 예시는 다음과 같습니다.

검토 요약 = {'토큰화 규칙': '공백 기준 분리', '평가 정확도': 0.857, '검토 대상 샘플': ['평가-05', '평가-07'], '낮은 coverage 샘플 수': 2, '오류 샘플': ['평가-05']}
읽은 파일 = docs/assets/part-07/chapter-04/p7-4-support-routing-dataset.csv
샘플별 평가 =
{'평가 샘플': '평가-01', '문장': '환불 진행 상태 확인', '토큰': ['환불', '진행', '상태', '확인'], '사전에 없는 토큰': ['진행'], '기존 어휘 포함 비율': 0.75, '환불팀 점수': 7, '배송팀 점수': 2, '예측 팀': '환불팀', '실제 팀': '환불팀', '정답 여부': '예', '토큰 검토 필요': '아니오'}
{'평가 샘플': '평가-02', '문장': '배송 조회 언제 가능', '토큰': ['배송', '조회', '언제', '가능'], '사전에 없는 토큰': ['가능'], '기존 어휘 포함 비율': 0.75, '환불팀 점수': 0, '배송팀 점수': 5, '예측 팀': '배송팀', '실제 팀': '배송팀', '정답 여부': '예', '토큰 검토 필요': '아니오'}
{'평가 샘플': '평가-03', '문장': '불량 반품 후 환불 일정', '토큰': ['불량', '반품', '후', '환불', '일정'], '사전에 없는 토큰': ['후'], '기존 어휘 포함 비율': 0.8, '환불팀 점수': 9, '배송팀 점수': 1, '예측 팀': '환불팀', '실제 팀': '환불팀', '정답 여부': '예', '토큰 검토 필요': '아니오'}
{'평가 샘플': '평가-04', '문장': '출고 지연 도착 예정 문의', '토큰': ['출고', '지연', '도착', '예정', '문의'], '사전에 없는 토큰': [], '기존 어휘 포함 비율': 1.0, '환불팀 점수': 2, '배송팀 점수': 5, '예측 팀': '배송팀', '실제 팀': '배송팀', '정답 여부': '예', '토큰 검토 필요': '아니오'}
{'평가 샘플': '평가-05', '문장': '캔슬 후 송장 번호 남아 있어요', '토큰': ['캔슬', '후', '송장', '번호', '남아', '있어요'], '사전에 없는 토큰': ['캔슬', '후', '남아', '있어요'], '기존 어휘 포함 비율': 0.333, '환불팀 점수': 0, '배송팀 점수': 3, '예측 팀': '배송팀', '실제 팀': '환불팀', '정답 여부': '아니오', '토큰 검토 필요': '예'}
{'평가 샘플': '평가-06', '문장': '카드 승인 취소 금액 언제 돌아오나요', '토큰': ['카드', '승인', '취소', '금액', '언제', '돌아오나요'], '사전에 없는 토큰': ['승인', '돌아오나요'], '기존 어휘 포함 비율': 0.667, '환불팀 점수': 5, '배송팀 점수': 1, '예측 팀': '환불팀', '실제 팀': '환불팀', '정답 여부': '예', '토큰 검토 필요': '아니오'}
{'평가 샘플': '평가-07', '문장': '하자 제품 환불 스케줄 알고 싶어요', '토큰': ['하자', '제품', '환불', '스케줄', '알고', '싶어요'], '사전에 없는 토큰': ['하자', '스케줄', '알고', '싶어요'], '기존 어휘 포함 비율': 0.333, '환불팀 점수': 7, '배송팀 점수': 0, '예측 팀': '환불팀', '실제 팀': '환불팀', '정답 여부': '예', '토큰 검토 필요': '예'}

결과를 어떻게 읽는가

이번 결과에서 가장 중요한 점은 coverage가 낮은 두 샘플이 서로 다르게 끝났다는 사실입니다.

샘플 coverage 결과 읽어야 할 점
평가-05 캔슬 후 송장 번호 남아 있어요 0.333 오답 핵심 의도인 캔슬은 OOV인데 송장, 번호가 배송팀 신호로 더 강하게 읽혔다
평가-07 하자 제품 환불 스케줄 알고 싶어요 0.333 정답 coverage가 낮아도 환불제품처럼 강한 핵심 단어가 남아 있으면 맞을 수 있다

이 비교가 중요한 이유는 다음과 같습니다.

  • 낮은 coverage는 바로 틀린다는 뜻이 아니다.
  • 하지만 낮은 coverage는 이 문장은 다시 봐야 한다는 강한 신호다.
  • 따라서 coverage는 정확도 옆에 붙는 부가 통계가 아니라, 실제 오류 분석 우선순위를 정하는 기준이다.

평가-05를 더 자세히 보면, 모델이 틀린 이유를 단순히 분류 규칙이 약하다로만 적기 어렵습니다. 이 문장에서는 환불 의도를 드러내는 핵심 표현이 캔슬인데, 학습 데이터는 취소만 알고 있었습니다. 반대로 송장, 번호는 배송팀 단어로 강하게 남아 있었기 때문에, 모델은 배송 문의로 기울었습니다.

즉, 이 사례는 오답이면서 동시에 표현 불일치 사례입니다. 실제 운영 회고에서는 이런 문장을 보고 동의어 확장, 표현 정규화, 토큰화 방식 보강, 학습 데이터 추가 중 무엇부터 할지 결정하게 됩니다.

실행 결과는 다음 세 줄로 요약할 수 있습니다.

  • 정확도 0.857만으로는 무엇이 위험한지 충분히 보이지 않는다.
  • 낮은 coverage 샘플은 맞았든 틀렸든 다시 봐야 한다.
  • 텍스트 프로젝트의 평가는 점수표가 아니라 점수 + OOV + coverage + 오류 사례 묶음으로 읽어야 한다.

결과 해석 기준

이번 결과에서는 낮은 coverage 자체보다 낮은 coverage가 어떤 결과로 이어졌는가를 봅니다. 같은 0.333이라도 평가-05는 오답이고 평가-07은 정답이므로, 둘을 같은 실패로 묶으면 다음 조치가 흐려집니다.

관찰할 것 기록할 질문
핵심 OOV 의도를 드러내는 단어가 학습 어휘 밖에 있는가?
낮은 coverage 정답 아직 맞았지만 다음 반복에서 위험해질 표현은 무엇인가?
우선 조치 표현 정규화, 데이터 추가, 구조 변경 중 무엇을 먼저 해야 하는가?

프로젝트 기록 예시

기록은 다음 형식으로 실패 분해 기록을 압축할 수 있습니다.

항목 기록
오답 샘플 평가-05는 coverage 0.333이고 배송팀으로 잘못 예측되었다.
핵심 OOV 환불 의도어 캔슬이 학습 어휘 밖에 있었다.
재검토 정답 평가-07은 맞았지만 coverage 0.333이라 다음 후보로 남긴다.
우선 의심 구조 변경보다 동의어 정규화와 데이터 보강을 먼저 본다.
다음 실험 캔슬 -> 취소, 스케줄 -> 일정 치환 후 coverage와 예측을 다시 비교한다.

실패를 어디서부터 의심할 것인가

텍스트 분류 프로젝트를 읽다 보면 틀렸으니 모델 구조를 바꾸자로 너무 빨리 뛰기 쉽습니다. 하지만 이 예제처럼 범위가 제한된 실습에서도 그 전에 먼저 갈라야 할 질문이 있습니다.

flowchart TD
  A["오답 또는 위험 샘플 발견"]
  B{"기준선도 같은 유형을 틀리는가?"}
  C["기준선 한계 또는 라벨 분포 문제부터 확인"]
  D{"coverage가 낮거나 핵심 OOV가 있는가?"}
  E["표현 정규화, 토큰화, 데이터 coverage 먼저 확인"]
  F{"비슷한 표현군에서 반복 오답이 나는가?"}
  G["구조 또는 특징 표현 부족 가능성 검토"]
  H["경계 사례 또는 라벨 애매성으로 기록"]

  A --> B
  B -- 예 --> C
  B -- 아니오 --> D
  C --> D
  D -- 예 --> E
  D -- 아니오 --> F
  E --> F
  F -- 예 --> G
  F -- 아니오 --> H

이 절차의 핵심은 무조건 모델 구조부터 의심하지 않는다는 점입니다.

  • 기준선도 같은 종류의 샘플을 자주 틀리면 데이터 분포나 라벨 기준부터 다시 봐야 합니다.
  • 기준선은 맞추는데 현재 분류기만 흔들리고, 동시에 coverage가 낮으면 표현 불일치와 토큰화 문제가 먼저입니다.
  • coverage는 충분한데 같은 패턴군에서 반복 오답이 나면 그때 구조나 특징 표현 부족을 더 강하게 의심할 수 있습니다.

즉, coverage 기록은 단순 보조 통계가 아니라 어디부터 고칠지를 고르는 첫 분기점입니다.

이 사례를 판단 절차에 대입하면

위 흐름을 이번 고객 문의 사례에 그대로 대입하면 다음처럼 읽을 수 있습니다.

샘플 기준선과 비교 coverage/OOV 우선 의심할 곳 지금 적을 회고
평가-05 기준선은 맞고 현재 모델만 틀림 coverage 0.333, 캔슬 OOV 표현 정규화, 토큰화, 동의어 coverage 구조 변경보다 표현 불일치를 먼저 다룬다
평가-07 기준선도 맞고 현재 모델도 맞음 coverage 0.333, 하자, 스케줄 OOV 미래 위험 신호로 기록 당장 오답은 아니지만 다음 정규화 후보로 남긴다
평가-04 기준선은 틀리고 현재 모델은 맞음 coverage 1.0, OOV 없음 baseline 한계 확인 완료 입력 문장을 실제로 읽는 모델 이득이 있었다

이 표를 보면 coverage가 낮다는 사실 하나만으로도 결과가 세 갈래로 나뉩니다.

  • 평가-05는 실제 오답을 만들었으므로 즉시 수정 후보입니다.
  • 평가-07은 아직 정답이므로 다음 반복 우선순위 후보입니다.
  • 평가-04는 오히려 coverage 문제가 없고 baseline 한계를 보여 주는 샘플입니다.

따라서 실패 해석은 오답인가 아닌가 한 줄로 끝나지 않고, 기준선 비교 -> coverage/OOV -> 반복 패턴 순서로 닫는 편이 더 안전합니다.

평가 문서에 추가할 항목

텍스트 분류 프로젝트라면 정확도 외에 다음 항목을 함께 적어 두는 편이 좋습니다.

항목 왜 필요한가
토큰화 규칙 공백 기준인지, 부분 단어(subword) 기준인지 기록해야 해석이 가능하다
사전에 없는 토큰 어떤 표현이 실제로 읽히지 않았는지 알 수 있다
기존 어휘 포함 비율 문장이 학습 어휘를 얼마나 공유하는지 보여 준다
검토 대상 샘플 다음 반복에서 먼저 다시 볼 사례를 고정한다
오류 샘플 메모 단순 오답인지, 표현 불일치인지 분리해 기록한다

같은 내용을 운영 판단 기준으로 다시 묶으면 다음과 같습니다.

기록 묶음 지금 남기는 이유
현재 토큰화 규칙 다음 실험에서 무엇을 바꿨는지 비교하기 위해
OOV 목록과 coverage 입력 표현이 실제로 얼마나 읽혔는지 남기기 위해
검토 대상 샘플 다음 반복에서 우선순위를 정하기 위해
회고 문장 점수 변화와 표현 한계를 함께 요약하기 위해

프로젝트 회고 예시

프로젝트의 회고를 한 문단으로 적으면 다음처럼 쓸 수 있습니다.

이번 고객 문의 라우팅 분류 실습에서 정확도는 0.857이었다. 그러나 캔슬 후 송장 번호 남아 있어요는 coverage가 0.333이었고, 핵심 의도인 캔슬이 학습 어휘 밖에 있어 환불 문의를 배송 문의로 잘못 보냈다. 반면 하자 제품 환불 스케줄 알고 싶어요도 coverage는 0.333이었지만 환불제품이 강한 신호로 남아 있어 정답을 맞혔다. 따라서 낮은 coverage 자체를 즉시 오답으로 읽기보다, 낮은 coverage 샘플을 우선 재검토 대상으로 남기고 동의어 확장과 표현 정규화를 다음 실험 후보로 잡는 편이 적절하다.

이 문단에서 독자가 익혀야 할 형식은 다음과 같습니다.

  • 어떤 샘플이 낮은 coverage였는가
  • 그중 무엇이 틀렸고 무엇이 맞았는가
  • 오답을 규칙 문제로 볼지 표현 문제로 먼저 의심할지
  • 다음 개선을 어디서 시작할지

직접 바꿔 보며 확인할 것

OOV와 coverage 해석이 중심이므로, 실행 뒤에는 표현을 일부러 바꿔 coverage를 흔들어 보는 편이 좋습니다.

  1. 평가-05캔슬취소로, 평가-07스케줄일정으로 바꿔 봅니다. 관찰할 점: coverage가 올라가면 토큰 검토 필요 상태와 오답 여부가 어떻게 달라지는가?

  2. 기존 문의에 전혀 없던 새로운 동의어를 하나 더 넣어 봅니다. 관찰할 점: 낮은 coverage 샘플이 늘어날 때 회고 문장이 모델 문제보다 표현 정규화 필요 쪽으로 더 기울어지는가?

핵심 확인 기준은 정확도가 몇 점인가보다 표현 변화가 검토 우선순위를 어떻게 바꾸는가입니다.

체크리스트

확인할 것 스스로 답할 질문
점수 정확도만 적고 멈추지 않았는가?
입력 표현 OOV와 coverage를 함께 기록했는가?
오류 샘플 오답의 핵심 표현이 학습 어휘 밖이었는지 확인했는가?
재검토 신호 낮은 coverage 정답 샘플도 다음 반복 후보로 남겼는가?
다음 개선 동의어 확장, 표현 정규화, 토큰화 방식 변경, 데이터 추가 중 어디부터 볼지 적었는가?

이 다섯 칸이 비어 있으면 새 모델을 붙이기 전에 토큰화 규칙, OOV 목록, coverage, 검토 대상 샘플을 먼저 문서에 남겨야 합니다.

출처와 참고 자료

이 절의 텍스트 데이터는 개인정보가 없는 실습용 고객 문의 예시를 위해 직접 구성한 synthetic 데이터입니다.