Documents
Home>Documents>AI>LLM>Train & Tune

도메인 특화 Fine-Tune은 왜 실패하는가

14 min readJun 15, 2026Jun 15, 2026

LLM을 처음 다루면 fine-tune을 굉장히 직관적인 기능으로 오해하기 쉽다. 우리 회사 문서, 의료 도메인 용어, 게임 설정집, 법률 판례를 넣고 몇 epoch 돌리면 모델이 그 지식을 배워서 답할 것처럼 느껴진다. 이름부터 그렇다. fine-tune. 이미 좋은 모델을 우리 데이터로 살짝 조정한다는 뉘앙스가 있다.

실제로는 훨씬 난폭한 작업이다.

LLM은 토큰 다음에 올 토큰의 확률 분포를 예측하도록 훈련된 거대한 패턴 학습기다. 문장을 이해한다는 표현은 편리하지만, 모델 내부에서 일어나는 일은 수많은 문맥 패턴에 대해 다음 토큰 분포를 만들어 내는 계산이다. post-train까지 끝난 모델은 이미 방대한 텍스트, instruction 데이터, 선호 데이터 위에서 이 분포를 아주 예민하게 맞춘 상태다. 그 위에 작은 도메인 데이터셋을 밀어 넣는 일은 빈 노트에 새 내용을 적는 작업과 거리가 멀다. 이미 조율된 악기를 특정 곡 하나에 맞추려고 줄 장력을 다시 잡는 쪽에 가깝다.

줄 하나만 건드렸다고 생각해도 전체 음정이 흔들린다.

대규모 언어 모델이 다음 토큰을 예측하는 구조
대규모 언어 모델이 다음 토큰을 예측하는 구조

LLM의 fine-tune은 저장소에 지식을 추가하는 작업보다 next token 분포를 다시 조정하는 작업에 가깝다.

Fine-tune이 실제로 바꾸는 것

언어 모델은 입력 토큰 시퀀스를 받아 다음 토큰의 확률 분포를 낸다. “서울의 수도는” 같은 문맥이 들어오면 모델은 다음 위치에 올 수 있는 후보 토큰마다 점수를 계산한다. 이 점수에 softmax를 적용하면 확률 분포가 된다. 학습은 정답 토큰의 확률을 높이는 방향으로 파라미터를 조금씩 움직이는 과정이다.

간단한 그림으로 보면 이렇다.

문맥: "환자의 혈압은"

학습 전 분포:
  "정상"   0.31
  "높"     0.18
  "낮"     0.11
  "측정"   0.06
  ...

도메인 데이터 한 배치:
  "환자의 혈압은 stage 2 hypertension 기준에 해당한다"

gradient update 이후:
  "stage"  0.27
  "정상"   0.19
  "높"     0.12
  ...

문제는 이 변화가 해당 문장 하나에만 갇히지 않는다는 데 있다. 트랜스포머의 파라미터는 수많은 문맥을 공유한다. “환자의 혈압은”에서 바뀐 가중치는 “환자의 상태는”, “혈압은 정상이나”, “stage라는 단어가 나오는 프로그래밍 문서”에도 영향을 준다. 모델은 key-value 형태로 지식을 행 단위 저장해 두는 데이터베이스가 아니다. 어느 한 패턴을 올리면, 그 패턴과 얽힌 주변 분포가 같이 움직인다.

fine-tune이 새 지식을 넣는 버튼이라는 오해는 여기서 생긴다. 학습 로그에는 loss가 줄어든다. eval set에서도 정확도가 오른다. 특정 프롬프트에는 원하는 답이 나온다. 그래서 “학습됐다”고 느낀다. 그런데 그 성공은 대개 좁은 분포 안에서만 관찰된다. 같은 의미를 조금 다른 표현으로 물으면 답이 흔들리고, 일반 질의 품질이 내려가고, instruction following이 무뎌진다. 작은 모델일수록 더 자주 보이고, 이미 post-train이 잘 된 모델일수록 이 손상이 더 아깝게 느껴진다.

직접 튜닝을 반복해 보면 가장 먼저 망가지는 부분은 지식 그 자체보다 말하는 습관이다. 답변이 짧아지거나, 특정 포맷에 집착하거나, 안전하게 모른다고 말해야 할 곳에서 데이터셋에 있던 문체를 흉내 낸다. 도메인 코퍼스가 보고서체면 모델도 보고서체로 굳는다. QA 데이터가 “정답은 A입니다”만 반복하면 모델은 복잡한 추론에서도 그 표면 패턴을 끌고 온다. 이것이 fine-tune의 무서운 점이다. 우리는 지식을 넣고 있다고 생각하지만, 모델은 토큰 패턴 전체를 다시 맞추고 있다.

패턴 인식기라는 관점

LLM을 패턴 인식기로 보면 많은 현상이 덜 신비롭다. 모델은 “이 문맥 다음에는 이런 토큰들이 자주 왔다”는 엄청나게 고차원적인 규칙을 압축한다. pre-training에서는 웹 문서, 코드, 책, 논문 같은 거친 분포를 배운다. instruction tuning에서는 질문에 답하고 지시를 따르는 패턴을 더한다. RLHF나 DPO류의 선호 최적화는 사람이 좋아하는 응답 쪽으로 분포를 밀어 준다.

이 과정을 거친 모델은 단순히 많은 지식을 가진 상태가 아니다. “질문을 받으면 어떤 길이로 답할지”, “확실하지 않을 때 어떻게 말할지”, “코드 요청이면 설명을 얼마나 붙일지”, “수학 문제에서 중간 과정을 드러낼지” 같은 행동 분포까지 학습한 상태다. 사용자가 체감하는 모델의 품질은 이 행동 분포에서 나온다.

도메인 fine-tune은 이 섬세한 분포 위에 좁고 강한 신호를 넣는다. 데이터셋이 작을수록 신호는 더 편향된다. 병원 상담 로그 5천 건에는 병원에서 자주 쓰는 말투와 생략이 들어 있다. 사내 문서 2만 문장에는 사내 약어, 특정 팀의 표현, 특정 문서 템플릿이 들어 있다. 모델 입장에서는 “이 도메인의 지식”과 “이 데이터셋 작성자의 습관”을 분리해서 받지 않는다. 그냥 다음 토큰을 맞히기 위한 패턴으로 들어온다.

초보자가 가장 많이 놓치는 부분도 이것이다. 모델은 사람이 붙인 의미 단위로 배우지 않는다. “이 항목은 사실 지식이고, 이 항목은 문체고, 이 항목은 우연히 섞인 노이즈다” 같은 라벨이 내부에 자동으로 생기지 않는다. 손실 함수는 정답 토큰 확률만 본다. 그래서 도메인 데이터의 양식이 일정하면 모델은 그 양식까지 열심히 배운다. 데이터에 답변 앞마다 “물론입니다.”가 있으면 “물론입니다.”를 배운다. 데이터에 장황한 면책 문구가 있으면 장황함을 배운다.

파괴적 망각은 왜 생기는가

파괴적 망각은 신경망이 새 작업을 학습하면서 이전 작업의 성능을 잃는 현상이다. 오래된 문제다. McCloskey와 Cohen은 1989년에 연결주의 네트워크의 순차 학습에서 기존 지식이 급격히 무너지는 현상을 catastrophic interference로 정리했다. LLM fine-tune에서 보는 품질 저하도 같은 계열의 문제로 이해하는 편이 맞다.

모델 파라미터는 공유 자원이다. 새 데이터에 맞춰 파라미터를 움직이면, 그 파라미터를 함께 쓰던 기존 능력도 같이 바뀐다. 작은 MLP에서도 생기는 문제가 수십억 개 파라미터의 트랜스포머에서는 사라지지 않는다. 규모가 커지면 완충 능력이 생기지만, post-train이 잘 된 모델은 이미 여러 목적 사이에서 균형을 잡은 상태라 작은 업데이트도 눈에 띄는 행동 변화를 만든다.

EWC(Elastic Weight Consolidation)는 중요한 파라미터를 덜 움직이게 만들어 망각을 줄이려는 대표적인 방법이다. Kirkpatrick 등은 2017년 논문 Overcoming catastrophic forgetting in neural networks에서 이전 작업에 중요한 파라미터를 Fisher information으로 추정하고, 그 파라미터가 크게 변하지 않도록 제약을 걸었다. 아이디어는 좋다. 문제는 LLM의 실제 fine-tune 환경이 훨씬 지저분하다는 데 있다. 작업 경계가 명확하지 않고, “이전 작업”이 사실상 인터넷 전체와 instruction behavior 전체이며, 무엇을 보존해야 하는지도 단일 점수로 표현하기 어렵다.

LoRA도 이 문제를 완전히 없애지 않는다. LoRA는 기존 가중치를 고정하고 저랭크 adapter만 학습해 효율을 높인다. QLoRA는 양자화된 base model 위에서 adapter를 학습해 메모리 비용을 크게 줄였다. 둘 다 실무적으로 중요하다. 나도 full fine-tune보다 LoRA 계열을 먼저 선택하는 편이다. 되돌리기 쉽고, 실험 비용이 낮고, base model을 직접 망가뜨리지 않는다.

그래도 추론 시점에는 adapter가 base model의 출력 분포에 더해진다. adapter가 특정 토큰 방향으로 logit을 밀면, 최종 next token 분포는 바뀐다. base weight를 보존했다는 사실과 응답 품질이 보존된다는 사실은 다르다. adapter를 끄면 원래 모델로 돌아갈 수 있다는 운영상의 장점이 있을 뿐, adapter를 켠 상태에서의 분포 훼손은 여전히 평가해야 한다.

“도메인 지식”이라는 말이 너무 크다

도메인 특화라고 말할 때 서로 다른 목표가 한 단어에 섞인다. 어떤 사람은 회사 내부 약어를 알게 하고 싶어 한다. 어떤 사람은 특정 JSON 스키마로 답하게 하고 싶어 한다. 어떤 사람은 판례를 근거로 법률 질의에 답하게 만들고 싶어 한다. 어떤 사람은 의료 문진에서 금지 표현을 피하게 하고 싶어 한다. 이 목표들은 같은 fine-tune으로 묶을 일이 아니다.

내 기준에서는 다음처럼 나눠야 한다.

목표fine-tune 적합도더 나은 선택
답변 포맷 고정높음SFT, few-shot, constrained decoding
특정 말투 주입높음SFT, system prompt
도구 호출 패턴 학습높음SFT, synthetic trajectory
내부 문서 사실 질의낮음RAG, 검색, citation 기반 QA
자주 바뀌는 정책 반영낮음외부 지식베이스, rule layer
전문 추론 능력 강화애매함고품질 reasoning 데이터, 평가셋, 장기 실험

fine-tune이 잘하는 일은 행동 패턴을 바꾸는 쪽이다. 항상 JSON으로 답하게 만들기, 특정 tool call schema를 따르게 하기, “분석 후 최종 답변” 같은 응답 구조를 유지하게 하기, 짧은 고객 응대 톤을 익히게 하기. 이런 작업은 모델이 이미 가진 언어 능력 위에 반복 가능한 표면 패턴을 덧씌우는 일이어서 성공 가능성이 높다.

반대로 새로운 사실을 많이 넣는 작업은 불리하다. “2024년 7월에 우리 회사 요금제가 바뀌었다” 같은 사실은 검색으로 가져오는 편이 낫다. 모델 파라미터에 박아 넣으면 수정도 어렵고, 출처도 흐려지고, 비슷한 질문에서 환각 여부를 통제하기 힘들다. 무엇보다 그 사실을 넣기 위해 전체 분포를 흔드는 비용이 너무 크다. LLM을 지식 저장소로 쓰려는 순간 운영 난이도가 올라간다.

<think>...</think> 같은 패턴 주입은 가능한가

특정 reasoning 모델이 일관되게 <think>...</think> 블록을 만들거나, 답변 전에 내부 추론 형식을 따르는 현상은 fine-tune으로 패턴을 주입하기 좋은 예다. 이유는 간단하다. 이 작업은 새 사실을 외우는 것보다 훨씬 국소적이고 반복적이다.

데이터셋의 많은 샘플이 다음 구조를 가진다고 해 보자.

사용자: 문제 ...
모델: <think>
중간 추론 ...
</think>
정답 ...

모델은 “문제가 들어오면 <think>를 열고, 중간 과정을 쓰고, </think> 뒤에 답한다”는 강한 형식 패턴을 배운다. 이 패턴은 수많은 입력에서 동일하게 반복된다. 정답 지식이 샘플마다 다르더라도 wrapper 구조는 같다. 다음 토큰 예측 관점에서 <think> 토큰의 확률을 올리는 신호가 매우 일관적이다.

JSON 출력도 비슷하다. 모든 샘플이 {, "answer", "reason" 같은 구조를 반복하면 모델은 그 토큰 전이 패턴을 안정적으로 배운다. tool calling도 마찬가지다. 사용자의 요청을 보고 함수 이름을 고르고, arguments를 채우고, 특정 종료 토큰을 내는 패턴은 fine-tune으로 잘 잡힌다. 모델이 이미 언어와 추론의 바탕 능력을 갖고 있기 때문에, 우리가 넣는 것은 “어떤 형식으로 그 능력을 꺼낼지”에 가깝다.

도메인 사실 주입은 양상이 다르다. “A 약어는 B를 뜻한다”, “C 정책은 D 조건에서 예외다”, “E 제품은 F 리전에만 배포된다” 같은 항목은 서로 공유하는 표면 패턴이 약하다. 각각이 별도 사실이다. 분포 관점에서는 특정 문맥에서 특정 토큰을 올리는 미세한 조작이 많이 필요하다. 충분히 반복하면 외울 수는 있다. 그러나 그 외움은 일반화와 충돌한다. 비슷한 문맥에서 엉뚱한 사실을 끌고 오거나, 오래된 pre-training 지식과 새 fine-tune 지식이 섞인다.

그래서 “패턴 주입은 가능하고 지식 주입은 위험하다”는 구분이 실무에서 쓸모 있다. 이 문장을 너무 넓게 일반화하면 안 된다. 대규모 continued pre-training, 엄격한 데이터 정제, 충분한 compute, 넓은 평가를 갖추면 도메인 적응은 가능하다. 의료, 법률, 코드처럼 말뭉치 규모가 크고 문체가 안정된 분야에서는 domain-adaptive pretraining이 성과를 낸다. 다만 스타트업이나 제품팀이 흔히 말하는 “우리 문서 넣고 fine-tune”은 그 레벨의 작업이 아니다.

손실이 내려가도 모델이 좋아졌다는 뜻은 아니다

fine-tune 실험에서 train loss가 예쁘게 내려가면 마음이 놓인다. eval loss까지 내려가면 더 그렇다. 그런데 eval set이 같은 데이터 생성 방식에서 나온 경우, 모델은 그 생성 방식에 맞춰진다. 템플릿, 문체, 질문 길이, 답변 어휘가 비슷하면 loss는 잘 내려간다. 실제 사용자 입력은 다르게 온다.

이 간극을 보려면 평가셋을 최소한 둘로 나눠야 한다. 하나는 도메인 목표 평가다. 회사 약어를 맞히는지, 정해진 스키마를 지키는지, tool call 인자를 제대로 채우는지 본다. 다른 하나는 보존 평가다. base model이 원래 잘하던 일반 질의, 코딩, 요약, 다국어, 안전 거절, 긴 문맥 처리를 같이 본다. fine-tune 후 첫 번째 점수만 오르고 두 번째 점수가 내려가면 제품에서는 실패다.

나는 도메인 fine-tune을 볼 때 “성공 샘플”보다 “퇴행 샘플”을 먼저 본다. 잘 된 예시는 찾기 쉽다. 데이터셋에 가까운 질문을 던지면 거의 반드시 나온다. 반대로 퇴행은 사소하게 시작한다. 이전에는 “모른다”고 하던 질문에 자신 있게 답한다. 코드 블록을 닫지 않는다. 한국어 질문에 영어로 섞어 답한다. 프롬프트에서 “간단히”라고 했는데도 fine-tune 데이터의 장황한 형식을 따라간다. 이런 퇴행이 보이면 loss 그래프가 예뻐도 배포하면 안 된다.

간단한 보존 평가 테이블은 반드시 있어야 한다.

모델: base vs domain-lora-r16
샘플 수: 각 항목 100~300개

평가 항목
- 일반 지시 수행
- 한국어 질의응답
- 코드 생성
- 요약
- 거절해야 하는 질문
- 도메인 QA
- 출력 포맷 준수

기록할 값
- 정답률 또는 pass rate
- 형식 위반률
- hallucination 판정률
- 평균 응답 길이
- 사람이 본 퇴행 사례 20개

여기서 평균 응답 길이는 생각보다 중요하다. fine-tune 후 응답 길이가 30% 줄거나 2배로 늘면 모델의 행동 분포가 바뀐 것이다. 정답률 하나로 잡히지 않는 변화가 길이에 먼저 찍힌다. 형식 위반률도 마찬가지다. 도메인 QA가 5점 올랐는데 일반 지시 수행에서 JSON 깨짐이 늘었다면, 그 모델은 서비스의 다른 경로에서 장애를 만든다.

그래도 fine-tune이 필요한 순간

fine-tune을 버리자는 말은 실무적으로 틀렸다. 나는 반대로 fine-tune을 좋아한다. 다만 지식 주입 도구로 쓰는 순간 비용 대비 위험이 커진다고 본다.

좋은 fine-tune 목표는 모델의 행동을 좁고 명확하게 바꾼다. 예를 들면 다음과 같다.

  • tool call을 특정 스키마로 안정화한다.
  • 응답을 제품 톤에 맞춘다.
  • 특정 태스크의 입출력 형식을 반복 학습시킨다.
  • 긴 프롬프트에 매번 넣던 few-shot 예시를 모델 행동으로 압축한다.
  • 작은 모델이 큰 모델의 응답 스타일을 흉내 내게 만든다.

이 경우에도 데이터는 “많이”보다 “깨끗하게”가 먼저다. 나쁜 샘플 10만 개보다 좋은 샘플 2천 개가 낫다. 특히 instruction-response 데이터에서는 답변 품질보다 일관성이 더 중요할 때가 많다. 같은 입력 유형에 대해 어떤 길이, 어떤 포맷, 어떤 거절 방식, 어떤 도구 호출을 원하는지 흔들리면 모델도 흔들린다.

LoRA rank를 올리고 epoch을 늘리는 방식으로 해결하려는 유혹도 조심해야 한다. 학습이 안 되는 이유가 용량 부족일 때도 있지만, 목표가 잘못 정의된 경우가 더 많다. 사실 질의를 맞히고 싶다면 RAG를 붙여야 한다. 정책을 최신으로 유지하고 싶다면 검색 가능한 정책 저장소와 검증 로직을 둬야 한다. 모델이 특정 절차를 수행하게 하고 싶다면 절차 샘플을 만들고 fine-tune해야 한다. 셋을 한 데이터셋에 섞으면 어느 것도 안정적이지 않다.

“우리 데이터로 학습”이라는 문장의 위험

제품 회의에서 “우리 데이터로 학습시키면 되죠”라는 말이 나오면 먼저 물어야 한다. 무엇을 바꾸려는가. 사실 기억인가, 답변 형식인가, 도메인 용어 감각인가, 도구 사용인가, 금지 행동인가. 목표를 이렇게 쪼개면 fine-tune으로 할 일과 하지 말아야 할 일이 갈린다.

사실 기억은 검색과 컨텍스트 주입으로 처리한다. 답변 형식은 prompt, constrained decoding, SFT가 후보가 된다. 도구 사용은 trajectory 데이터로 학습할 수 있다. 금지 행동은 rule layer와 preference optimization을 같이 봐야 한다. 도메인 용어 감각은 충분한 말뭉치와 평가셋이 있을 때 continued pre-training을 검토한다. 이 구분을 하지 않으면 fine-tune은 만능 해결책처럼 보이다가, 배포 직전에 일반 성능 퇴행으로 발목을 잡는다.

LLM은 패턴 학습기다. 이 말은 모델을 깎아내리는 표현이 아니다. 오히려 LLM이 왜 그렇게 강력한지 설명하는 가장 정확한 문장에 가깝다. 언어, 코드, 추론, 대화 예절, 도구 사용이 모두 토큰 패턴으로 압축될 수 있었기 때문에 지금의 모델이 가능했다. 같은 이유로 아무 패턴이나 사후에 밀어 넣을 수 없다. 이미 만들어진 next token 분포는 수많은 능력이 겹쳐 있는 얇은 균형점이다.

내가 지금 fine-tune 설계를 한다면 첫 문서는 학습 스크립트가 아니라 실패 조건 목록이다. 어떤 일반 능력이 떨어지면 중단할지, 어떤 포맷 위반을 허용하지 않을지, 도메인 점수가 얼마나 올라야 손상을 감수할지 먼저 정한다. 그다음 데이터셋을 만든다. 그리고 base model, prompt-only, RAG, LoRA를 같은 평가표에서 비교한다.

도메인 fine-tune은 마지막에 놓는 카드에 가깝다. 먼저 검색으로 해결되는지 본다. 프롬프트로 충분한지 본다. 출력 제약으로 막을 수 있는지 본다. 그래도 반복되는 행동 패턴을 모델 내부로 넣어야 할 때 fine-tune을 꺼낸다. 그때도 목표는 “모델에게 새 세계를 가르친다”가 아니라 “이미 가진 능력이 특정 패턴으로 나오게 만든다”에 두는 편이 안전하다.

Tags
LLMFine-TuningCatastrophic ForgettingTrain & Tune