LLM을 사용하여 8,700개의 시험 문제에 태그를 지정하는 방법과 포르투갈어 및 영어 버전이 불일치했던 이유
요약
AWS 자격증 모의 시험 서비스 NaHero를 개발하며 겪었던 기술적 어려움과 해결 과정을 공유합니다. LLM을 활용하여 8,700개 문제에 도메인 태그를 지정하고, 포르투갈어와 영어 버전 간의 일관성을 유지하는 방법을 중점적으로 다룹니다.
핵심 포인트
- LLM을 이용해 대규모 데이터셋(8,700문제)에 도메인 태그를 효율적으로 할당했습니다.
- 두 언어 버전 간의 불일치 문제를 해결하기 위해 검증 절차를 설계했습니다.
- Claude Code의 비대화형 모드(`claude -p`)를 활용하여 반복적인 데이터 라벨링 작업을 수행했습니다.
저는 NaHero(https://nahero.site)를 직접 만들고 있습니다. 이 서비스는 AWS, Azure, Google Cloud 자격증을 위한 시간제 모의 시험 세트로, 브라질 포르투갈어와 영어로 제공됩니다. 총 30개의 시험이 있으며 약 8,700개의 문제가 있고, 모든 시험은 두 언어로 존재합니다. 각 시험은 65개의 문제를 포함하며, 실제 시험의 시간 제한(CLF는 90분, SAA는 130분)과 공식 시험 가이드에 따른 합격 점수를 제공합니다.
제가 이 프로젝트를 시작한 이유는 AWS 자격증을 공부하면서 무료로 모의 시험을 볼 곳을 찾지 못했기 때문입니다.
겉보기보다 어려웠던 세 가지 부분이 있었습니다. LLM을 사용하여 모든 질문에 해당 시험 도메인으로 태그를 지정하는 것, 두 언어 간의 일관성을 유지하는 것, 그리고 모델이 수학 계산을 하도록 하지 않으면서 학습 계획을 생성하는 것이었습니다.
스택 (Stack)
- 프론트엔드: Next.js, Tailwind, react-query
- 백엔드: Spring Boot, Postgres, Flyway
- 결제: Stripe
- 학습 계획 텍스트: DeepSeek V4.1 Flash
- 라이선스: AGPL-3.0, nahero-front 및 nahero-back
도메인이 중요한 이유 (Why domains matter)
공식 시험 가이드는 각 자격증을 여러 도메인으로 나눕니다. 단일 점수는 합격 여부만 알려줍니다. 하지만 도메인별 점수는 어디를 공부해야 하는지 알려줍니다. NaHero는 무료 등급에서 공식 도메인별 결과를 보여주며, 유료 학습 계획은 이 수치들을 기반으로 구축됩니다. 이 모든 것은 8,700개 문제 각각이 올바른 도메인을 가지고 있다는 것에 달려 있습니다.
태그 지정 루프 (The tagging loop)
저는 claude -p (Claude Code의 비대화형 모드)를 사용하여 질문들에 태그를 지정하는 반복 작업을 수행했습니다:
- 한 번 호출당 40개의 문제
- 해당 시험에 대한 도메인 목록을 프롬프트에 포함
- 고정된 도메인 목록과 비교하여 출력을 검증
전체 데이터베이스를 구축하는 데 약 220번의 호출이 필요했습니다.
시험 자체의 도메인 목록을 프롬프트에 넣으면,
일관성 문제
모든 문제는 포르투갈어 버전과 영어 버전, 두 가지 형태로 존재합니다. 덕분에 저는 레이블링된 데이터가 필요하지 않은 검증 절차를 가질 수 있었습니다. 즉, 두 버전을 독립적으로 태그하고 동일한 도메인에 속하는지 확인하는 것입니다.
Google Workspace Admin의 경우, 첫 번째 시도에서 약 73% 정도 일치했습니다.
제품의 관점에서 볼 때, 이는 결함(bug)입니다. 만약 질문의 약 4분의 1이 언어에 따라 다른 도메인에 속한다면, 동일한 답변을 가진 브라질 사용자(포르투갈어 사용)와 영어 사용자가 서로 다른 도메인별 결과를 얻게 되고, 이 도메인별 결과가 바로 전체 제품의 핵심 기반이 됩니다.
이를 해결하기 위해 두 가지 변경 사항을 적용했습니다:
- 프롬프트에
도메인 이름 일치(Matching domain names) 기능은 계획이 시험에 없는 도메인을 공부하라고 지시하는 것을 막아줍니다. 링크 차단(Banning links) 기능은 아무도 확인하지 않은 URL로 이동시키는 것을 방지합니다. 한 번 저장하기(Storing once) 기능을 사용하면 오늘 읽는 계획이 내일도 동일하게 유지됩니다. 실패 기록 저장(Storing failures) 기능은 잘못된 시도가 유료 API 호출의 루프가 되는 것을 막아줍니다.
시도 재개 (Resuming an attempt)
130분짜리 시험이 항상 한 번에 끝날 수는 없습니다. 답변은 초안으로 자동 저장되며, 시도를 다시 열면 마지막 질문부터 이어서 진행할 수 있습니다. '재개(Resume)' 기능은 무료 등급에서 이용 가능합니다.
현재 데이터 현황 (What the data says so far)
2026년 10월 6일 기준 수치:
- 약 95명의 등록 사용자 중 약 75%가 브라질 출신입니다.
- 광고를 집행하지 않았음에도 불구하고 주당 약 30건의 가입이 발생했습니다.
- 대부분의 CLF 시도 점수는 65점 만점에 23점에서 47점 사이에 분포합니다. 합격 기준은 약 46점이므로, 대부분의 시도가 실패하고 있습니다.
- 첫 주에 두 번째 시험을 치른 사용자는 약 15%에 불과했습니다.
이 마지막 두 가지 데이터가 제품을 변화시켰습니다. 누군가가 시험을 보고 실패한 후, 점수를 확인했지만 다음에 무엇을 해야 할지 모릅니다. 그래서 저는 '다음으로 무엇을 공부할지(what to study next)'를 중심으로 결과 화면을 재구축했습니다.
가격 책정 (Pricing)
30개의 모든 시험, 무제한 시도 횟수, 점수, 도메인별 결과 및 재개 기능은 무료입니다. 프리미엄 서비스는 월 R$10 또는 연간 R$90이며, 질문별 설명, 학습 계획(study plan), 그리고 가장 취약한 도메인의 연습 문제 기능을 추가합니다.
피드백을 받고 싶은 부분 (What I'd like feedback on)
만약 여러 언어에 걸쳐 LLM을 분류 작업에 사용해 본 경험이 있다면, 일관성(consistency)을 어떻게 측정했는지, 그리고 의견 불일치(disagreements)가 발생했을 때 무엇을 했는지 알고 싶습니다. 코드는 공개되어 있으니, 위에 링크된 저장소에서 실제로 어떻게 구현되었는지 정확히 읽어보실 수도 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기