LLM이 생성한 플래시카드가 대개 품질이 낮은 이유와 이를 선별하는 방법
요약
LLM을 활용한 플래시카드 생성 시 발생하는 품질 저하 원인을 분석하고, 이를 해결하기 위한 구조적 파이프라인 구축 방법을 제시합니다. 단순 프롬프팅 대신 추출과 작성을 분리하여 원자성을 보장하는 전략을 강조합니다.
핵심 포인트
- 복합 질문, 모호한 프롬프트, 과도한 빈칸 채우기 등 주요 실패 패턴 식별
- 단순 지시가 아닌 구조적 제약 조건을 통한 원자성(Atomicity) 확보 필요
- 추출(Claim Extraction)과 카드 작성 단계를 분리하여 품질 개선
- 대명사 해결(Pronoun Resolution)을 통해 문맥 없는 카드의 모호성 제거
저는 많은 팀이 문서에 LLM을 덧붙이고 그 결과물을 플래시카드 (Flashcards)라고 부르는 것을 보아왔습니다. 이는 데모용으로는 훌륭하지만, 학습용으로는 형편없습니다. 생성된 카드들은 문법적으로 맞고, 주제에 부합하며, 형식이 올바른 등 그럴싸해 보이지만, 실제 학습자가 6주 후에 복습하려고 시도하는 순간 무너져 버립니다.
핵심 문제는 "이것을 Q&A 쌍으로 요약해줘"라는 명령이 "회상하기 쉽고 속이기 어려운 항목을 생성하라"는 목적과는 다른 목표를 최적화한다는 점입니다. 이 두 가지는 빠르게 갈라집니다. 복습 대기열(review queue)을 견뎌낼 수 있는 생성 파이프라인을 구축하며 제가 배운 점은 다음과 같습니다.
실패 모드는 예측 가능하다
단순한 생성 방식은 네 가지의 잘못된 카드 형태를 반복해서 만들어냅니다.
복합 질문 (Compound questions). "TCP 3-way handshake란 무엇이며 왜 존재하는가?"와 같은 질문입니다. 이는 트렌치코트를 입은 두 명의 사람과 같습니다. 학습자는 절반만 기억하고 "좋음"으로 평가하며, 스케줄러는 이제 두 사실을 모두 알고 있다고 믿게 됩니다. 당신은 스케줄링 신호 (scheduling signal)를 오염시킨 것이며, 이는 카드가 아예 없는 것보다 더 나쁩니다.
모호한 프롬프트 (Ambiguous prompts). "그것이 몇 년도에 일어났는가?" — "그것"이 명확했던 문단에서 추출된 질문입니다. 카드 상에서는 문맥이 없기 때문에 유일한 답이 존재하지 않습니다. 학습자는 실패하고 "다시 (Again)"를 표시하며, 카드는 내일 똑같이 실패하기 위해 돌아옵니다. 이는 제가 보는 가장 흔한 결함인데, 모델은 컨텍스트 (context)를 윈도우 (window) 안에 가지고 있어 카드가 컨텍스트를 가지고 있지 않다는 사실을 알아차리지 못하기 때문입니다.
잔여 신호가 너무 적은 빈칸 채우기 (Cloze deletions). "미토콘드리아는 세포의 발전소이다"라는 문장을 예로 들어봅시다. 주어를 비우면 합리적인 카드가 됩니다. 하지만 두 구간을 비우면 두 번째 구간은 종종 문법만으로도 유추가 가능해집니다. 구문 (syntax)만으로 풀 수 있는 빈칸 채우기는 아무것도 학습시키지 못합니다.
패턴 매칭이 가능한 답변 (Pattern-matchable answers). 만약 독일어 명사 덱 (deck)의 모든 카드 답변이 "der"로 시작한다면, 학습자는 학습 자료가 아니라 덱의 패턴을 배우게 됩니다. 이는 덱 수준에서만 나타나기 때문에 카드별 평가로는 절대 잡아낼 수 없습니다.
원자성 (Atomicity)은 프롬프트 지시 사항이 아니라 구조적 제약 조건이다
모델에게 "카드를 원자적(atomic)으로 만들어라"라고 말하는 것은 부분적인 준수만을 이끌어낼 뿐, 아무런 보장도 해주지 않습니다. 확실한 방법은 파이프라인이 구조적으로 복합적인(compound) 카드를 생성할 수 없도록 만드는 것입니다. 즉, 추출(extraction) 단계와 카드 작성(card-writing) 단계를 분리해야 합니다.
1단계에서는 엔티티(entity)가 이미 해결된(resolved), 독립적인 명제인 _주장(claims)_을 추출합니다. 2단계에서는 하나의 주장을 하나의 카드로 변환합니다. 입력값이 단일 주장이라면 카드는 복합적일 수 없습니다.
CLAIM_SCHEMA = {
"subject": str, # 해결된 엔티티, 대명사 사용 금지
"predicate": str, # 정확히 하나의 단언(assertion)
...
두 번째 이점은 대명사 해결(pronoun resolution)이 원문 단락을 여전히 참조할 수 있는 주장 추출 단계에서 이루어진다는 점입니다. 카드를 작성할 때쯤이면 주어는 이미 고유 명사로 되어 있으며, "그것이 몇 년도에 일어났는가"와 같은 유형의 버그는 단순히 권장되지 않는 수준을 넘어 구현 자체가 불가능해집니다.
특히 빈칸 채우기(cloze)의 경우, 저는 모델이 삭제 구간(deletion span)을 자유롭게 선택하도록 두는 것을 중단했습니다. 대신 다음과 같은 방식을 사용합니다: 주장을 추출하고, 어떤 토큰이 주장의 정보 페이로드(information payload)를 담고 있는지 식별한 뒤(보통 술어의 목적어나 수치적 한정어), 해당 부분을 삭제합니다. 만약 문장에 정보량이 높은 구간이 없다면, 빈칸 채우기 카드가 되는 대신 질의응답(Q&A) 카드가 되거나 아예 생성되지 않습니다.
인간 없이 카드 품질을 선별하기
학습자에게 도달하기 전에 저렴한 결정론적 검사(deterministic checks)를 통해 대부분의 결함을 잡아낼 수 있습니다. 다음은 그 가치를 증명한 방법들입니다:
def screen(card, deck):
issues = []
...
그다음, 토큰을 투자할 가치가 있는 두 가지 모델 기반 검사 방법이 있습니다:
출처 없는 답변 가능성 (Answerability without source). 새로운 모델에게 문서 없이 카드 앞면만 제공하고 답변을 요구합니다. 만약 모델이 예상되는 답변을 내놓지 못한다면, 프롬프트가 불충분하게 지정된 것입니다. 만약 학습자가 이미 알고 있어야 할 내용에 대해 너무 쉽게 답변을 내놓는다면, 프롬프트에서 정보가 유출(leaking)되고 있는 것입니다. 이를 생성 작업당 배치(batch) 단위로 처리하십시오. 여러 카드에 대해 한 번의 호출로 해결할 수 있습니다.
덱 수준의 차별성 (Deck-level distinctness). 모든 앞면(front)과 뒷면(back) 쌍을 임베딩(embedding)하고 코사인 유사도(cosine-similarity) 임계값 이상인 항목에 플래그를 지정하십시오. 서로 다른 뒷면을 가졌으나 앞면이 거의 중복되는 경우, 간격 반복 (spaced repetition)에서 가장 고약한 실패 사례입니다. 학습자는 자신이 어떤 카드를 보고 있는지 구분할 수 없게 되고, 대기열(queue) 위치를 보고 추측하기 시작합니다. 괜찮은 문장 임베딩 (sentence embedding) 상에서 매우 유사한 것들은 병합되거나 다시 작성됩니다.
스크리닝 레이어 (screening layer)는 생성된 원본 데이터의 상당 부분을 거부하며, 이 거부율 (rejection rate)은 소스 자료에 대해 우리가 가질 수 있는 가장 유용한 신호임이 드러났습니다. 거부율이 높은 장(chapter)은 대개 추출 가능한 주장(claims)이 적은 서사적 산문(narrative prose)인 경우가 많습니다. 이는 해결책이 카드 프롬프트 (card prompt)가 아니라 청킹 (chunking) 전략에 있음을 의미합니다. 이 '추출-스크리닝-재생성' 루프 전체가 SmartRecall의 카드 생성 뒤에 자리 잡고 있으며, 이를 제대로 구현하는 데 가장 오랜 시간이 걸린 부분이기도 합니다. 초기의 "LLM에게 플래시카드를 만들라고 프롬프팅하기" 버전은 단 한나절 만에 끝났습니다.
다음에 내가 생략할 것들
나는 학습된 품질 분류기 (learned quality classifier)를 만드는 데 너무 많은 시간을 소비했습니다. 결정론적 스크리닝 (deterministic screens)과 하나의 답변 가능성 체크 (answerability check)만으로도 분류기가 잡아낼 수 있는 거의 모든 것을 포착할 수 있으며, 이 방식은 디버깅이 가능합니다. 즉, 카드가 거부되었을 때 어떤 규칙 때문에 거부되었는지 지목할 수 있습니다.
또한, 빈칸 채우기 (cloze) 생성은 기본적으로 꺼둔 상태로 출시하겠습니다. 질의응답 (Q&A) 카드는 실패할 때 요란하게 실패합니다. 즉, 학습자가 답을 할 수 없게 됩니다. 반면 잘못된 빈칸 채우기는 조용히 실패합니다. 학습자가 문법(syntax)을 통해 답을 맞히게 되어 스스로 생산적이라고 느끼게 만들기 때문입니다. 요란하게 실패하는 모드(loud failure mode)를 먼저 출시하십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기