[Android] 온디바이스 AI 삽질기 - 2편: 학습 데이터 5만건, Gemini CLI로 하루 만에 만들기
파인튜닝을 하려면 데이터가 필요하다. 그런데 데이터가 없다.
학습 데이터 문제
모델도 정했다. 이제 학습을 돌리면 되는데, 문제가 하나 있었다.
학습 데이터가 없다.
파인튜닝은 이런 입력이 오면 이렇게 답해라, 라는 예시 쌍을 대량으로 먹여서 모델의 행동을 바꾸는 작업이다. 텍스트 요약 특화를 하려면 (원문, 요약) 쌍이 수천~수만 건 필요하다.
실제 사용자 데이터를 쓰면 되지 않나 싶지만, 개인정보 문제로 불가능하다. 사용자의 텍스트를 학습에 쓰는 건 개인정보 처리방침 위반이다.
그래서 합성 데이터를 만들기로 했다. AI로 가짜 데이터를 만들어서 AI를 학습시키는 구조.
데이터 설계
목표는 총 5만건. 카테고리 20종 × 세트당 500건 × 5세트.
카테고리는 실제로 자주 오는 텍스트 유형을 기준으로 잡았다.
1
2
3
회의 일정 조율 / 업무 보고 / 요청 및 승인 / 계약 및 견적
채용 및 인사 / 공지사항 / 클레임 대응 / 프로젝트 협업
일정 및 마감 안내 / 긴급 공지 / 예산 처리 / 출장 안내 ...
그냥 5만건 한 번에 만들지 않고 1만건씩 5세트로 나눈 이유가 있다. 세트별로 스타일을 다르게 해서 다양성을 확보하고, 학습 후 세트별로 품질을 비교해서 나쁜 세트는 빼거나 재생성할 수 있도록.
| 세트 | 스타일 |
|---|---|
| Set 1 | 일반 격식체 (300~600자) |
| Set 2 | 구어체 섞인 단문 (100~300자) |
| Set 3 | 장문 상세 (600~1200자) |
| Set 4 | 긴급/감정 있는 표현 (200~500자) |
| Set 5 | IT/스타트업 스타일, 영어 혼용 (200~500자) |
출력 포맷은 학습에 바로 쓸 수 있는 .jsonl로.
1
2
3
4
5
{
"instruction": "다음 텍스트를 2~3문장으로 요약해주세요.",
"input": "제목: ...\n발신: ...\n\n(본문)",
"output": "(2~3문장 중립 서술체 요약)"
}
Gemini CLI로 생성한 이유
처음엔 Claude API를 쓰려고 했다. 그런데 5만건을 API 호출로 생성하면 비용이 꽤 나온다. 무료로 쓸 수 있는 방법을 찾다가 Gemini CLI로 방향을 틀었다.
Gemini CLI는 구글 계정 연동으로 쓸 수 있는데, headless 모드로 스크립트에서 호출할 수 있다. 나는 gemini-2.5-flash를 사용했다.
1
2
# Gemini CLI headless 호출
gemini -p "프롬프트 내용" --model gemini-2.5-flash
이걸 파이썬 스크립트에서 subprocess로 반복 호출하는 방식으로 생성했다.
근데 엄청 느렸다
무료인 대신 rate limit이 있었다. 분당 호출 횟수 제한 때문에 중간중간 계속 대기가 걸렸다.
5세트 전체를 생성하는 데 결국 하루 가까이 걸렸다. 스크립트 돌려놓고 퇴근했다가 다음 날 확인하는 식으로.
그리고 JSON 파싱 실패가 꽤 났다. 모델이 가끔 JSON 형식을 어기고 설명을 붙여서 반환하거나, 배열이 중간에 잘리는 경우가 있었다. 재시도 로직을 넣어서 처리했다.
1
2
3
4
5
6
7
8
9
10
11
# JSON 파싱 실패 시 재시도
for attempt in range(max_retries):
result = call_gemini_cli(prompt)
try:
start = result.find("[")
end = result.rfind("]") + 1
data = json.loads(result[start:end])
break
except json.JSONDecodeError:
time.sleep(2)
continue
한 번에 많이 요청하면 JSON이 깨질 확률이 높아서, 한 번 호출에 5건씩 나눠서 생성했다.
생성 결과 검증
5만건을 그냥 다 쓰면 안 된다. 품질이 들쑥날쑥한 데이터로 학습하면 모델도 들쑥날쑥해진다.
자동 검증 기준:
| 항목 | 기준 |
|---|---|
| 요약 길이 | 2~3문장 |
| 말투 | 중립 서술체 (~했습니다, ~했으며) |
| 빈 필드 | input / output 빈 값 제외 |
| 이슈율 5% 이하 | → 학습 사용 |
| 이슈율 15% 초과 | → 해당 세트 재생성 |
검증 돌려보니 Set 2 (구어체 단문)에서 말투 이슈가 좀 많이 나왔다. 구어체 텍스트인데 요약도 구어체로 나오는 경우. 기준 미달 항목만 걸러내고 나머지는 사용했다.
최종적으로 약 4만 7천건 정도가 학습 가능한 상태로 남았다.
AI로 AI 학습 데이터를 만드는 게 맞나
솔직히 이 방법에 대해 반신반의했다. AI가 만든 데이터로 AI를 학습시키면 품질이 계속 희석되는 거 아닌가 하는 걱정.
실제로 이 우려는 ML 커뮤니티에서도 Model Collapse라고 부르는 현상으로 알려져 있다.
그런데 우리 케이스는 조건이 다르다. 완전히 AI 생성 데이터만 쓰는 게 아니라, Phase 1에서 실제 뉴스 데이터(사람이 쓴 텍스트)로 먼저 학습하고, Phase 2에서 도메인 적응 용도로만 합성 데이터를 쓰는 구조다. 그리고 목표가 창의적인 글쓰기가 아니라 정해진 포맷으로 요약하기라는 단순 태스크이기 때문에 합성 데이터로도 충분히 패턴을 학습할 수 있다고 판단했다.
실제로 학습 결과가 어땠는지는 뒤에서 얘기한다.
정리
- 실제 사용자 데이터 → 개인정보 문제로 불가
- Gemini CLI headless 호출로 합성 데이터 생성
- Gemini CLI + 구글 계정 연동, rate limit으로 하루 소요
- 5만건 목표, 검증 후 약 4.7만건 학습 사용
- JSON 파싱 실패 대비 재시도 로직 필수
다음 편에서는 실제 학습 환경 세팅이다. M1 Mac Mini로 로컬에서 직접 돌렸다.
3편 - M1 Mac Mini로 LLM 파인튜닝 환경 세팅하기 에서 계속