더 많은 컨텍스트가 분류기를 더 나쁘게 만들었다: 기계가 유지 관리하는 실패 분류 체계(Failure Taxonomy) 구축하기
요약
AI 모델 평가 시 발생하는 실패 사례를 수동으로 관리하는 대신, Claude Code 스킬을 활용해 구조화된 피드백 루프를 구축하는 방법을 다룹니다. 실패 유형을 체계적으로 추출하고 조직화하여 프롬프트 개선으로 이어지는 자동화된 워크플로의 중요성을 강조합니다.
핵심 포인트
- 단순 정확도 측정보다 실패 유형을 진단하고 개선하는 피드백 루프가 핵심임
- 수동 메모 방식은 데이터의 휘발성과 비구조화 문제로 인해 지속 불가능함
- Claude Code 스킬을 활용해 반복 가능한 사후 평가 분석 워크플로 구축 가능
- 실패 사례에서 트레이스, 예측, 추론 등 구조화된 데이터를 추출하는 것이 중요
평가(eval)를 실행했습니다. 대시보드에는 정확도(accuracy)가 80%라고 나옵니다. 이제 무엇을 해야 할까요?
대부분의 팀에게 그 답은 놀라울 정도로 수동적입니다. 누군가가 실패 사례를 내보내고(export), 몇 가지 예시를 문서에 복사하고, 메모를 작성하고, 아마도 티켓을 한두 개 생성한 뒤 다음 단계로 넘어갑니다. 다음 평가를 실행할 때쯤이면 그 메모들은 이미 오래된 정보가 되어 있습니다. 실패 유형은 변했고, 새로운 유형이 나타났으며, 특정 문제가 실제로 새로운 것인지 아니면 몇 주 동안 계속 나타나고 있는 것인지 아무도 기억하지 못합니다.
병목 현상은 평가를 실행하는 것이 아닙니다. 피드백 루프(feedback loop)를 닫는 것입니다.
실패 → 진단 → 프롬프트 개선(prompt improvement)으로 이어지는 구조화된 경로가 없다면, 평가는 엔지니어링 도구가 아닌 단순한 점수판이 됩니다.
최근 저는 개발자의 작업 세션을 Jira 티켓으로 매핑하는 로컬 MLX 기반 분류기(classifier)를 작업하면서 정확히 이 문제에 직면했습니다.
이 분류기는 40개의 수동 작성된 개발자 세션으로 구성된 골든 데이터셋(golden dataset)을 대상으로 평가됩니다. 각 세션은 특정 실패 모드(failure mode)를 목표로 합니다: 강력한 미끼(hard decoys), 오버헤드 작업(overhead work), 추적되지 않는 활동(untracked activity), 모호한 증거(ambiguous evidence), 그리고 실제 엔지니어링 환경에서 나타나는 기타 에지 케이스(edge cases)들입니다.
몇 번의 반복(iteration)을 거친 후, 저는 세 번의 평가를 실행했습니다. 또한 62개의 실패 사례를 확보했습니다.
하지만 저에게는 다음과 같은 기본적인 질문에 답할 수 있는 신뢰할 수 있는 방법이 없었습니다:
- 어떤 실패가 계속 나타나는가?
- 어떤 프롬프트 변경이 도움이 되었는가?
- 실패는 무작위인가, 아니면 동일한 근본 문제의 발현인가?
- 다음에 수정해야 할 가장 영향력 있는(highest-leverage) 작업은 무엇인가?
전통적인 방식인 수동으로 메모를 유지하는 방법은 거의 즉시 무너집니다. 메모는 두 번째 실행 이후 바로 구식이 됩니다. 일관된 구조가 없습니다. 아무도 재발을 추적하지 않습니다. 그리고 수십 개의 실패 사례를 검토하는 것은 매번 법의학적 조사(forensic exercise)처럼 변합니다.
핵심 통찰 (The key insight)
평가는 이미 제가 필요로 하는 모든 것을 생성하고 있었습니다. 모든 실패에는 구조화된 증거가 있었습니다: 트레이스(trace), 스팬(span), 모델의 예측(prediction), 기대 정답(expected answer), 분류기의 추론(reasoning). 문제는 해석이 아니었습니다. 문제는 추출(extraction)과 조직화(organisation)였습니다.
그 지점에서 저는 Claude Code 스킬 (skill)을 사용하기 시작했습니다. Claude Code 스킬은 본질적으로 반복 가능한 워크플로(workflow)를 포함하는 마크다운 (markdown) 파일입니다. 즉, 일부 프론트매터 (frontmatter), 절차 (procedure), 그리고 허용된 도구 세트 (set of allowed tools)로 구성됩니다. 저의 경우, 스킬은 다음과 같이 수동으로 호출됩니다:
/eval-feedback
이것은 자율 에이전트 (autonomous agent)가 아니며 지속적으로 실행되지도 않습니다. 이는 단순히 반복 가능한 사후 평가 분석 워크플로 (post-eval analysis workflow)이며, 분류기 실패 (classifier failures)를 평가하는 데 완벽하게 부합합니다.
데이터 구조 (The data structure)
가장 중요한 설계 결정은 스킬 그 자체가 아니었습니다. 그것은 스킬이 기록하는 데이터 구조, 즉 FEEDBACK.json이라 불리는 기계 유지 관리 파일 (machine-maintained file)이었습니다.
'기계 유지 관리'가 중요한 부분입니다. 인간은 실패 로그 (failure logs)를 최신 상태로 유지하는 데 매우 서툽니다. 구조화된 JSON (Structured JSON)은 그런 문제가 없습니다. 누군가가 수동으로 큐레이션 (curating)할 필요 없이, 실행 전반에 걸쳐 쿼리 (query), 차이 비교 (diff), 집계 (aggregate), 분석 (analyse)이 가능합니다.
이 파일은 세 개의 최상위 배열 (top-level arrays)을 포함합니다:
{
"runs": [],
"observations": [],
...
runs는 평가 수준의 메타데이터 (metadata)와 지표 (metrics)를 저장합니다. observations는 개별 실패 증거 (failure evidence)를 저장합니다. failure_classes는 여러 실행에 걸쳐 지속되는 명명된 패턴 (named patterns)을 저장합니다.
세 가지 설계 결정 (Three design decisions)
첫째: 린-리드 (lean-read) 패턴. 매번 파일 전체를 컨텍스트 (context)에 로드하는 대신, 스킬은 jq를 사용하여 최근 실행 (recent runs), 열려 있는 실패 클래스 (open failure classes), 일치하는 관찰값 (matching observations), 요약 통계 (summary statistics)와 같이 타겟팅된 슬라이스 (slices)만을 가져옵니다. 이를 통해 대량의 컨텍스트를 소비하지 않고도 파일이 무한히 커질 수 있습니다. 현재 사용량을 기준으로, 실행당 약 20 KB의 추가 데이터가 발생합니다.
둘째: 작은 Python 추가 워크플로 (append workflow)를 통한 업데이트 — 로드(load) → 변형(mutate) → 쓰기(write) 방식입니다. 스킬은 JSON을 직접 편집하지 않습니다.
셋째, 그리고 가장 가치 있는 것: 모든 관찰값 (observation)은 failure_class_id를 포함합니다. 이 단일 필드가 개별 실패를 지속적인 실패 패턴 (persistent failure pattern)에 연결합니다. 동일한 패턴이 다시 나타나면 발생 횟수가 자동으로 증가합니다. 반복되는 문제는 수동 우선순위 지정 (manual prioritisation) 없이도 상단으로 올라옵니다.
분류 체계가 밝혀낸 것 (What the taxonomy revealed)
세 번의 실행 결과, 시스템은 62개의 관찰 사례(observations) 전반에 걸쳐 10개의 명명된 실패 클래스(failure classes)를 식별했습니다. 그중 한 클래스가 다른 모든 것을 압도했습니다. 저는 이를 optimism-bias라고 불렀습니다. 이 클래스는 세 번의 실행 모두에서 총 27번 나타났습니다.
패턴은 일관적이었습니다. 분류기(classifier)가 인접한 신호(signal)—문서 내 언급, 관련 기사, 일치하는 키워드, 또는 주제적으로 유사한 파일 경로—를 마주할 때마다, 해당 세션을 높은 확신(confidence)을 가지고 타겟 작업(target task)에 속하는 것으로 분류하는 경향을 보였습니다.
더욱 흥미로웠던 점은 컨텍스트(context) 실험 중에 일어난 일이었습니다. 저는 추가적인 컨텍스트가 정확도를 향상시킬 것이라 기대하며 2,500자의 OCR 절단 제한(truncation limit)을 제거했습니다. 하지만 정반대의 결과가 나타났습니다. 성능이 더 나빠졌습니다. 분류기는 잘못된 예측에 대해 더 높은 확신을 갖게 되었는데, 이는 추가된 컨텍스트가 느슨하게 관련된 증거를 찾을 수 있는 더 많은 기회를 제공했기 때문입니다.
구조화된 교차 실행 뷰(cross-run view)가 없었다면, 저는 아마도 모델에 더 많은 데이터가 필요하다는 결론을 내렸을 것입니다. 하지만 증거는 완전히 다른 곳을 가리키고 있었습니다. 문제는 데이터의 양이 아니라, 프롬프트 디자인(prompt design)이었습니다.
더 넓은 교훈 (The broader lesson)
AI 시스템은 종종 다른 AI 시스템의 실패를 분석하는 데 매우 뛰어난 성능을 보입니다. 분류기의 추론 출력(reasoning output)은 전체 파이프라인에서 가장 풍부한 신호임이 드러났습니다. 이는 모델이 어떤 증거에 과도한 가중치를 두는지, 그리고 왜 모델의 관점에서 특정 예측이 합리적으로 보이는지를 정확하게 노출했습니다.
추론 흔적(reasoning traces)을 읽고 이를 반복되는 실패 모드(failure modes)로 클러스터링(clustering)하는 것은 정확히 LLM이 탁월한 역량을 발휘하는 종류의 작업입니다. 일단 이러한 패턴이 구조화된 형식으로 포착되면, 동일한 시스템이 특정 실패 클래스를 겨냥한 프롬프트 변경 사항을 생성할 수 있습니다.
재현 방법 (How to replicate this)
많은 것이 필요하지 않습니다:
- 구조화된 흔적(structured traces)을 방출하는 평가(eval) 도구 (OpenTelemetry 또는 유사한 도구)
- 예상 출력값이 포함된 골든 데이터셋(golden dataset)
- 실행 전반에 걸쳐 관찰 사례를 유지할 수 있는 저장 공간
이 기술 자체는 워크플로우(workflow), 스키마(schema), 그리고 가드레일(guardrails)을 설명하는 수백 줄 정도의 마크다운(markdown)에 불과합니다. 이 근본적인 아이디어는 분류기(classifier)를 훨씬 넘어 광범위하게 적용될 수 있습니다. 반복적인 실험을 수행하는 모든 시스템은 시간이 지남에 따라 증거를 축적하는 지속적인 실패 분류 체계(failure taxonomy)로부터 이익을 얻을 수 있습니다.
왜냐하면 정확도가 95%에 도달했다고 해서 루프(loop)가 종료되는 것은 아니기 때문입니다.
루프는 실패 분류 체계가 다음 프롬프트 수정(prompt revision)을 주도하기 시작할 때 비로소 종료됩니다.
주요 결과 (Key findings)
- 62개의 관찰 사례(observations) 전반에 걸쳐 10개의 명명된 실패 클래스(failure classes) 식별
optimism-bias가 그중 27개를 차지함- 더 많은 컨텍스트(context)가 정확도를 개선하는 것이 아니라 오히려 악화시킴
- 해결책은 더 많은 데이터가 아니라 프롬프트 디자인(prompt design)이었음
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기