지난 글에서 추론 모델과 프롬프팅을 갈랐는데, 추론 모델을 쓰기로 정하고 나면 곧바로 비용 문제가 따라온다. 사고 토큰이 붙은 큰 모델을 트래픽 전체에 쓰기는 부담스럽고, 그렇다고 작은 모델은 못 푼다. 세 번째 길이 증류다. 큰 모델에게 문제를 풀게 해서 그 사고 과정을 통째로 데이터로 만들고, 그 데이터로 작은 모델을 학습시킨다. 잘되면 작은 모델이 자기 체급을 넘는 문제를 풀기 시작한다.
증류는 모델 압축이 아니라 데이터 작업이다
이름 때문에 오해가 잦다. 고전적인 지식 증류는 교사 모델의 출력 확률 분포를 학생이 따라가게 만드는 기법이었다. 지금 추론 모델 맥락에서 말하는 증류는 그것과 다르다. 확률 분포가 아니라 텍스트를 옮긴다. 교사가 쓴 사고 궤적을 그냥 학습 데이터로 쓰는 것이다. 그래서 API로만 접근 가능한 교사에서도 가능하고, 교사와 학생의 아키텍처가 달라도 된다.
즉 이건 모델 최적화 작업이 아니라 데이터 파이프라인 작업이다.
네 단계 중 실제로 결과를 가르는 것은 세 번째, 필터 단계다. 나머지 셋은 대체로 정해진 일이다.
1단계 — 교사와 문항을 고른다
교사는 강할수록 좋지만, 그 전에 확인할 것이 있다. 출력물을 다른 모델 학습에 써도 되는지를 약관에서 봐야 한다. 상용 API의 약관은 경쟁 모델 훈련 목적의 출력 사용을 제한하는 경우가 흔하다. 사내 용도라도 근거를 남겨 두는 편이 낫다. 오픈 웨이트 추론 모델을 교사로 쓰면 이 문제가 없어서 실무에서 자주 선택된다.
문항 쪽이 더 중요하다. 증류로 옮겨지는 것은 문항이 커버하는 범위 안의 사고 습관이다. 수학 문항만으로 증류하면 수학은 늘고 코드 디버깅은 안 는다. 학생 모델이 실제로 받게 될 요청 분포와 문항 분포를 맞춰야 한다.
문항 수는 생각보다 적어도 된다. 사고 형식을 익히는 데는 잘 고른 수천 건이 마구잡이 수십만 건보다 낫다는 것이 반복해서 확인되는 경향이다. 대신 난도가 고르게 퍼져 있어야 한다. 교사가 100% 맞히는 문항만 모으면 학생은 쉬운 문제의 사고만 배운다.
2단계 — 궤적을 모은다
문항당 한 번만 풀게 하지 않는다. 온도를 올려 k회 샘플링한다. 이유가 두 가지다.
첫째, 필터를 통과할 후보를 여러 개 확보하기 위해서다. 어려운 문항은 교사도 한 번에 못 맞힌다. k=8로 뽑으면 그중 하나는 맞을 확률이 크게 오른다.
둘째, 같은 문항의 서로 다른 풀이가 다양성을 만든다. 한 문항에 한 궤적만 있으면 학생은 그 표현을 외우는 쪽으로 기운다.
저장할 때는 사고 구간과 최종 답을 분리해서 남긴다. 나중에 필터링과 형식 변환을 하려면 둘이 구분돼 있어야 한다.
import asyncio
import json
import anthropic
client = anthropic.AsyncAnthropic()
async def collect(item: dict, k: int = 8) -> list[dict]:
async def once():
resp = await client.messages.create(
model="claude-opus-5",
max_tokens=8000,
temperature=1.0,
thinking={"type": "enabled", "budget_tokens": 4000},
messages=[{"role": "user", "content": item["question"]}],
)
thinking = "".join(b.thinking for b in resp.content if b.type == "thinking")
answer = "".join(b.text for b in resp.content if b.type == "text")
return {
"question": item["question"],
"thinking": thinking,
"answer": answer,
"gold": item["gold"],
}
return await asyncio.gather(*[once() for _ in range(k)])
여기서 비용이 크게 든다. 문항 5,000개에 k=8이면 40,000회 호출이고 각 호출이 사고 토큰을 쓴다. 다만 이건 한 번 치르는 비용이고, 결과물인 데이터셋은 재사용된다. 서빙 비용 절감과 비교하면 대개 몇 주 안에 회수된다.
3단계 — 필터가 전부다
이 단계에서 대부분의 궤적을 버린다. 통과 기준을 넉넉하게 잡고 싶은 유혹이 큰데, 그 반대로 가야 한다.
정답 일치가 1차 관문이다. 최종 답이 정답과 다르면 사고 과정이 아무리 그럴듯해도 버린다. 여기서 "그럴듯한 오답 궤적"이 가장 위험하다. 학생은 그 논리 전개를 그대로 배우고, 나중에 자신 있게 틀린 답을 낸다. 정답 비교가 기계적으로 되는 영역(수학, 코드 실행 결과, 구조화된 추출)이 증류가 잘 먹히는 영역인 이유가 이것이다.
정답이 맞아도 걸러야 할 것이 남는다.
- 답만 맞고 과정이 비어 있는 것. 사고가 두 줄이고 바로 정답이 나온 궤적은 교사가 외운 문항일 가능성이 크다. 학생이 배울 게 없다.
- 끝없이 도는 궤적. 같은 검토를 반복하다 예산이 다 되기 직전에 답을 낸 것. 이걸 학습하면 학생도 장황해진다.
- 한 문항에서 너무 많이 남은 것. 같은 문항의 궤적을 여러 개 남기면 그 문항이 과대 대표된다. 문항당 상한을 둔다(보통 1~2개).
- 답으로 가는 길에 없는 도약. "따라서 답은 24다"가 앞의 계산과 연결되지 않는 궤적. 자동 판별이 어려워서 표본 검수로 잡는다.
def keep(traces: list[dict], per_item: int = 2) -> list[dict]:
correct = [t for t in traces if normalize(t["answer"]) == normalize(t["gold"])]
graded = [
t for t in correct
if 200 <= len(t["thinking"]) <= 6000 # 너무 짧지도 길지도 않게
]
# 짧은 것부터 남긴다 — 같은 정답이면 간결한 풀이가 학습에 낫다
graded.sort(key=lambda t: len(t["thinking"]))
return graded[:per_item]
통과율이 얼마나 나오는지는 문항 난도에 달렸지만, k=8에서 문항의 절반 정도만 살아남는 것이 이상한 수치가 아니다. 버린 만큼 좋아진다고 보면 된다. 필터를 느슨하게 해서 데이터가 세 배로 늘어난 쪽이 성능이 떨어지는 결과는 흔하게 재현된다.
4단계 — 학생 학습
남은 데이터로 작은 모델을 지도 학습한다. 특별할 것은 없지만 두 가지 결정이 있다.
사고를 그대로 학습시킬 것인가, 요약해서 넣을 것인가. 그대로 넣으면 학생도 길게 생각하게 되어 추론 비용이 오른다. 요약해서 넣으면 짧아지지만 되짚기 같은 행동이 덜 옮겨 온다. 학생을 쓸 지연 예산에 맞춰 정한다.
전체 파인튜닝인가 LoRA인가. 사고 형식이라는 비교적 표면적인 행동을 옮기는 작업이라 LoRA로도 상당 부분 옮겨진다. 적은 예산으로 시작한다면 LoRA 쪽이 합리적이다.
학습 후 반드시 확인할 것은 원래 잘하던 것이 망가지지 않았는지다. 추론 데이터만으로 학습하면 일상 대화나 지시 따르기 성능이 떨어지는 일이 있다. 기존 지시 데이터를 일정 비율 섞어 두면 대개 완화된다.
옮겨지는 것과 안 옮겨지는 것
증류의 한계를 정확히 아는 것이 기대치 관리에 중요하다.
| 옮겨지는 것 | 잘 안 옮겨지는 것 |
|---|---|
| 답하기 전 검토하는 습관 | 교사가 가진 지식 자체 |
| 문제를 쪼개는 방식 | 학생 체급을 넘는 긴 계산 |
| 되짚어 확인하는 서술 | 학습 문항 밖 영역의 추론 |
| 답변 형식과 어조 | 새로운 도구를 처음 다루는 능력 |
핵심은 첫 줄 오른쪽이다. 증류는 형식과 절차를 옮기지, 없던 지식을 만들어 주지 않는다. 학생 모델이 모르는 사실은 아무리 좋은 사고 궤적을 학습해도 여전히 모른다. 오히려 위험한 쪽으로 갈 수도 있다. 사고 형식만 배운 모델은 근거 없는 결론을 그럴듯한 검토 과정과 함께 내놓는다. 겉모습이 좋아진 만큼 틀린 답을 걸러내기가 어려워진다는 뜻이다.
그래서 증류한 모델은 반드시 원래 모델과 나란히 정답률로 재야 한다. 사고 궤적이 길고 그럴듯해진 것을 성능 향상으로 착각하기 쉬운데, 그 둘은 별개다.
어디까지 기대할 수 있나
경험적으로 증류가 잘 먹히는 조건은 좁다. 정답이 기계적으로 판정되고, 학생 모델이 그 영역의 기초 지식은 이미 갖고 있고, 실패의 원인이 지식 부족이 아니라 성급함일 때다. 이 셋이 맞으면 작은 모델의 정답률이 눈에 띄게 오른다.
반대로 열린 질문, 문체 판단, 최신 사실이 필요한 영역에서는 기대를 낮춰야 한다. 이런 영역은 필터를 만들 정답이 없고, 정답이 없으면 3단계가 성립하지 않는다.
그리고 증류를 하기로 했으면 데이터셋을 자산으로 관리해야 한다. 모델은 몇 달 뒤 더 나은 것으로 바뀌지만 잘 필터링된 궤적 데이터는 남는다. 다음 학생 모델을 학습시킬 때 그대로 다시 쓴다.
지난 글: 추론 모델과 CoT 프롬프팅: 같은 사고, 다른 자리
다음 글: 추론 벤치마크 읽는 법
읽어주셔서 감사합니다. 😊

