
1995년 스타일로 문서를 작성하도록 LLM 미세 조정하기
요약
90년대 기술 문서 스타일을 재현하기 위해 Microsoft의 오래된 매뉴얼 데이터를 활용하여 LLM을 미세 조정하는 과정을 다룹니다. Bitsavers에서 데이터를 수집하고, OCR 텍스트 정제 및 합성 지시문 생성을 통해 학습 데이터셋을 구축하는 실무적인 방법론을 제시합니다.
핵심 포인트
- Bitsavers를 활용한 고전 기술 문서 데이터 확보
- gemma-4-26b를 이용한 데이터 정제 및 품질 관리
- 합성 지시문(Synthetic Instruction)을 통한 학습 데이터 생성
- 로컬 우선(Local-first) 모델 구축을 위한 미세 조정 전략
1995년 스타일로 문서를 작성하도록 LLM 미세 조정하기
나의 2030년 예측에서 나는 기술 작가(tech writers)들이 강력한 하드웨어에서 로컬로 실행되는 특화된 LLM(Large Language Models)을 사용하게 될 것이라고 썼다. 엔지니어링 전문가들 사이에서 이러한 "로컬 우선(local first)"으로의 움직임에 대한 징후가 보이긴 하지만, 연결된 프런티어 모델(frontier models)들이 훨씬 더 강력하기 때문에 아직 그 단계에 도달하지는 못했다. 그렇다고 해서 우리가 실험을 할 수 없다는 뜻은 아니다. 그것이 바로 내가 지난주에 한 일로, 80년대와 90년대의 소프트웨어 기술 작가처럼 글을 쓰도록 지시 모델(instruct model)을 미세 조정(fine-tune)하려고 시도한 것이다.
연구를 위한 오래된 기술 문서 지식 소환하기
90년대 기술 작가처럼 글을 쓰는 개인용 로컬 모델을 훈련시키려면 방대한 양의 텍스트 소스가 필요하다. 예를 들어, 만약 내가 나 자신처럼 글을 쓰도록 모델을 미세 조정하고 싶다면, 이 블로그는 이 포스트 시점에서 겨우 10만 단어 정도밖에 되지 않으므로 충분하지 않을 것이다. 철저한 훈련을 위해서는 더 많은 샘플이 필요하며, 그러한 샘플은 구하기 쉽지 않을 뿐만 아니라 제작하기도 간단하지 않다. 유일하게 빠른 방법은 기존의 코퍼스(corpus)를 사용하는 것이다. 어디서 구할 수 있을까?
Bitsavers를 소개한다. 이곳은 오래된 컴퓨터 매뉴얼과 브로셔를 수집하고 스캔하는 웹사이트다. 이곳은 컴퓨터 역사와 고대 기술 문서의 믿을 수 없을 정도로 가치 있는 저장소이며, 곳곳에서 미러(mirrors) 사이트를 이용할 수 있다. 나는 90년대 Microsoft 매뉴얼을 좋아하기 때문에, Microsoft 컬렉션을 훈련 자료의 소스로 선택했다. 이 컬렉션은 1977년에서 2005년 사이에 출판된 절판된 문서들을 포함하고 있으며, 오래된 시스템과 SDK(Software Development Kits)를 다루는 3,700만 단어 이상의 분량을 담고 있다.

나는 OCR(광학 문자 인식)된 텍스트 파일들을 다운로드했고, 오래된 Python 스크립트를 사용하여 아티팩트(artifacts)와 불필요한 요소(색인 및 프런트매터(frontmatter) 등)를 제거하여 콘텐츠를 정제했다. 그런 다음 OpenRouter를 통해 저렴하고 빠른 모델인 gemma-4-26b를 사용하여 각 단락의 이해 가능성을 바탕으로 "유지(keep)" 또는 "삭제(drop)"로 분류했다. 이 두 번째 단계에는 약 8달러의 비용이 들었다. 이러한 2단계 정제 과정을 거쳤음에도 불구하고, 훈련 데이터에는 나중에야 발견하게 된 노이즈가 남아 있었지만, 나의 테스트에는 대체로 괜찮았다.
나는 정제된 텍스트를 문단 및 섹션 경계에 따라 훈련 예시(training examples)로 나누었으며, 제목에서 끊고 코드 블록은 통째로 유지했습니다. 각 청크(chunk)는 Claude의 조언에 따라 약 512 토큰(tokens)으로 제한했습니다. 각 청크는 템플릿에서 추출한 합성 지시문(synthetic instruction)과 쌍을 이루었습니다. 결과적으로 JSONL 형식(한 줄당 하나의 JSON 객체)으로 된 192,456개의 예시를 얻었습니다. 더 나은 지시문과 질문을 만들기 위해 작은 모델을 사용할 수도 있었겠지만, 나는 성격이 급한 사람입니다.
처음부터 학습시키는 것의 대안으로서의 미세 조정 (Fine-tuning)
이상적인 세상이라면, 나만의 LLM인 Fabrice를 만드는 데 태워버릴 수 있는 수백만 달러가 굴러다니고 있을 것입니다. 하지만 나는 부유한 상태와는 거리가 멀기 때문에(그렇지 않았다면 이 글을 쓰고 있지도 않았을 것입니다), Fabrice의 대안은 미세 조정(fine-tuning)입니다. 미세 조정은 생성되는 각 토큰이 훈련 자료에 의해 조건화되도록 모델의 "가중치(weights)"를 미세하게 조정하는 과정을 포함합니다. 나는 미세 조정을 마치 예인선(tugs)을 사용하여 거대한 빙하의 궤적을 아주 약간 조종하는 것에 비유하곤 합니다. 의도한 효과를 얻기 위해 아주 조금만 움직이는 것이죠.
왜 RAG(retrieval-augmented generation, 검색 증강 생성)가 아니라 미세 조정일까요? 왜냐하면 이번 실험에서 나의 관심사는 RAG가 탁월한 성능을 보이는 사실 검색(retrieving facts) 시나리오보다는, LLM이 문맥에 대한 지식과 상관없이 특정 스타일로 행동하고 글을 쓰도록 만드는 데 있었기 때문입니다. 전체 학습(full training)과 비교했을 때, 미세 조정은 방대한 양의 데이터를 필요로 하지 않으므로 비용이 더 저렴합니다. 또한, 그냥 해보고 싶었습니다. 기술로서 미세 조정을 시도해 보고 그것이 얼마나 실현 가능한지 보고 싶었습니다.
상당히 오래된 그래픽 카드를 가진 내 컴퓨터에서 모델을 미세 조정하느라 며칠 또는 몇 주를 허비하는 것을 피하기 위해, 나는 Runpod에 의존했습니다. Runpod은 AI 개발자를 위한 온라인 서비스로, (비교적) 저렴한 가격에 사전 구성된 GPU와 도구를 갖춘 온디맨드 포드(on-demand pods)를 제공합니다. 예를 들어, 시간당 6달러 미만으로 Nvidia B200(192gb 메모리)이라는 괴물 같은 카드를 임대할 수 있습니다. 이 서비스는 설정 가능한 자동 충전 및 비용 제어 메커니즘을 갖춘 편리한 API를 제공합니다.

신비로운 전문 용어들로 가득한 세계로의 진입
모델을 미세 조정(Fine-tuning)하기로 결정한 후, 저는 가장 합리적인 방법이 무엇인지 Claude와 상담했습니다. 우리는 QLoRA (Quantized Low-Rank Adaptation)로 결론을 내렸습니다. 이는 LLM의 각 가중치(Weight)를 변경하는 대신, 가중치를 "동결(Freezing)"하고 그 위에 어댑터(Adapter)를 얹는 방식으로 미세 조정을 수행합니다. 이 어댑터는 모델의 동작을 재구성하는 작은 파일입니다 (말하자면 마스크와 비슷합니다).
QLoRA의 Q는 결과물이 양자화(Quantized)되었음을 의미하며, 즉 압축되어 메모리 요구 사항을 줄여준다는 뜻입니다.
제 말을 잘 따라오고 계신가요? 좋습니다. 만약 이 내용이 난해하다고 느껴진다면, 실제로 그렇기 때문입니다.
요즘 집에서 LLM으로 무언가를 한다는 것은 타협의 연속입니다. 시간이나 돈을 희생하거나, 아니면 야심 찬 목표를 억제해야 합니다. 저는 주말이 채 지나기 전에 의미 있는 결과물을 얻기 위해 균형을 맞추려 노력했습니다. 저는 Llama 3.1 8B Instruct와 Qwen 2.5 7B Instruct 두 가지 모델에 대해 미세 조정을 시도하기로 했습니다. 이 정도 크기(약 8B)라면 Macbook Air에서도 원활하게 실행됩니다. 또한 Llama 베이스 모델(질문에 답하도록 훈련되지 않은 모델)도 테스트했습니다.
저는 여러 가지 다른 조건 하에서 미세 조정을 테스트했습니다. 훈련 자료의 양(데이터셋의 일부 vs 전체 코퍼스), 에포크(Epochs, 훈련 횟수)의 수, 그리고 랭크(Rank)와 같은 구조적 파라미터(Parameters)를 변화시켰습니다. 저는 이 모든 것에 대해 피상적인 지식만 가지고 있지만, 제 에이전트가 올바른 선택을 할 것이라고 믿었고, 기쁜 마음으로 매 단계마다 질문을 던졌습니다. 예를 들어, 어떤 경우에는 3 에포크가 "과적합(Overfitting)"을 초래할 수 있는데, LLM의 세계에서는 이것이 과도한 훈련으로 번역됩니다. 즐거운 시간이 되겠군요.
| 실행 (Run) | 베이스 (Base) | 데이터 (Data) | 에포크 (Epochs) | 랭크 (Rank) |
|---|---|---|---|---|
| Llama instruct-40k | Llama 3.1 8B Instruct | 40k | 1 | 16 |
| ... |
어댑터(Adapters)는 미세 조정(Fine-tuning)을 수행한 대상 모델에만 적용할 수 있습니다. 각 어댑터를 훈련한 후, 저는 이를 노트북으로 내보내어 GGUF LoRA 파일로 변환 및 양자화(Quantized)하였고, 벤치마킹(Benchmarking) 목적으로 제 노트북에서 실행할 수 있도록 로컬 Ollama 모델로 등록했습니다. 로컬 변환 방식은 더 빠르고 GPU가 필요하지 않지만, 추론(Inference) 속도는 완전히 병합된(Fully merged) 모델보다 다소 느립니다. 이번 테스트에서는 속도가 그리 중요하지 않았습니다.
휴식 시간을 포함하여 모든 조건에 대한 어댑터 훈련에는 아마도 하루 전체가 소요되었으며, 총 비용은 50달러였습니다. 그 과정에서 어댑터 두 개를 잃었습니다. Runpod은 예산에 매우 엄격하여 잔액이 0이 되면 즉시 포드(Pod)를 삭제합니다 (네, 교훈을 얻었습니다). Claude가 각 실행을 설정하고 Runpod의 API를 후속 처리하는 역할을 맡았습니다. Claude Code의 /goal 명령어는 각 단계를 반복하는 데 매우 유용했습니다 (돌이켜보면, YOLO 모드로 실행했을 것입니다).
이 표는 제가 비교한 모든 모델과 그 조건들을 보여줍니다:
| 이름 | 설명 |
|---|---|
llama3.1:8b | 수정되지 않은 Llama 베이스라인 |
qwen2.5:7b | 수정되지 않은 Qwen 베이스라인 |
msft-base-40k | Llama 베이스(비-instruct) + 40k (대조군) |
msft-instruct-40k | Llama instruct + 40k, 1 에포크, 랭크 16 |
msft-qwen-40k | Qwen + 40k, 3 에포크, 랭크 16 |
msft-qwen-192k | Qwen + 192k, 1 에포크, 랭크 16 |
msft-qwen-r8 | Qwen + 40k, 1 에포크, 랭크 8 |
msft-qwen-r16 | Qwen + 40k, 1 에포크, 랭크 16 |
미세 조정 후 스타일 전이가 일어났는가?
저는 각 모델에 동일한 프롬프트(Prompts)를 적용했습니다:
- C 언어의 필수 함수인
malloc()에 대해 문서화할 것. 훈련 자료에 포함되어 있을 법한 내용입니다. - 가상의
ConnectWifi()Win32 API 함수에 대해 문서화할 것. 훈련 자료에 존재하지 않는 내용입니다. - REST API가 무엇인지 1990년대 Microsoft 스타일로 설명할 것 (시대착오적인 테스트입니다).
malloc() 테스트의 경우, 수정되지 않은 모델들은 README 스타일의 현대적인 Markdown 문서를 생성한 반면, 미세 조정(Fine-tuned)된 모델들은 Synopsis 블록, Return Value 섹션 등을 포함하여 당대의 시대상에 맞는 구조를 사용했습니다. 가상의 ConnectWifi() 함수에 대해서는 오직 3 epochs 모델만이 허구를 유지하며 마치 실제인 것처럼 문서화한 반면, 다른 모델들은 내부 지식을 고수하고 학습에 저항하며 제4의 벽을 깨뜨렸습니다.
REST API 연습 또한 매우 흥미로웠습니다. Llama Instruct 40k는 실패하여 무미건조한 마케팅 산문을 생성했습니다. Claude는 이를 Llama가 친근하고 접근하기 쉽게 만들기 위해 거치는 강력한 인간 피드백 기반 강화학습 (RLHF) 때문이라고 분석했습니다. Qwen 미세 조정 모델들은 훨씬 더 잘 격식을 유지하며, HTTP 메서드 이름을 동사로 사용하고 공식적인 헤딩을 사용하여 시대적 구조를 갖춘 문서를 생성했습니다. Qwen 192k가 가장 강력했는데, 마치 Windows 2000 Resource Kit의 한 장(Chapter)처럼 시작되었습니다.

다시 한번 말씀드리겠습니다. 1990년대 문서로 학습되고 2000년대 개념으로 테스트된 7B 모델이, 실제 당시의 자료로 착각할 수 있을 만큼 설득력 있는 장(Chapter)의 도입부를 만들어냈습니다. 스타일이 전이(Style transferred)된 것입니다. 놀랍습니다. 반면에, 질문에 답하도록 학습된 것이 아니라 텍스트를 자동 완성하도록 학습된 베이스 모델(Base model)은 처참하게 실패하며, 수백 줄의 쓰레기 같은 원시 코퍼스(Raw corpus)를 거의 무작위로 쏟아냈습니다. 베이스 모델은 "이 질문에 답하라" 또는 "이것을 완성하라"라는 개념 자체가 없습니다.
| 모델 | malloc() | ConnectWifi() | REST API |
|---|---|---|---|
llama3.1:8b | |||
| 현대적인 스타일, 마크다운 헤더 (markdown headers) | 평이한 영어, Win32 어휘 없음 | 현대적이고 친근함, 비유 사용 | |
qwen2.5:7b | |||
| 현대적인 스타일, 좋은 구조 | 올바른 형식, 프레임 파괴 (breaks frame) | 현대적인 에세이, 스스로를 “1990년대 스타일”이라고 명명 | |
msft-instruct-40k | |||
| 간결함, 마침표 사용, 정확한 어휘 | SAL 주석 (annotations), ERROR_SUCCESS | 실패: 마케팅 산문 스타일 | |
msft-qwen-40k | |||
| 매뉴얼 페이지 (man-page) 구조, ENOMEM | 허구에 몰입하여 상수를 발명함 | 일관성 유지 (Holds register) | |
msft-qwen-192k | |||
| 전체 매뉴얼 페이지 (man-page), See Also, 예시 | 프레임 파괴 (주의 사항 포함) | 가장 강력함: 장(chapter) 스타일, HATEOAS | |
msft-base-40k | |||
| 프롬프트를 완전히 무시함 | 프롬프트를 완전히 무시함 | 프롬프트를 완전히 무시함 |
저는 Qwen 모델들 사이에서 1 에포크 (epoch)를 적용하고, 랭크 (rank)를 8에서 16 사이로 변화시키며 랭크의 효과를 비교하는 것으로 실험을 마쳤습니다. 제가 제대로 이해했다면, 랭크 8은 각 어댑터 행렬 (adapter matrix)이 오직 8개의 독립적인 패턴만을 설명할 수 있음을 의미합니다. 이는 조절할 수 있는 다이얼이 8개뿐인 것과 같습니다. 다이얼이 이렇게 적으면 어댑터가 너무 영리해질 수 없습니다. 즉, 훈련 데이터에서 가장 강력하고 반복되는 패턴에 완전히 몰입해야만 합니다. 이론적으로 랭크 16은 더 표현력이 풍부하고 미묘합니다.
| 모델 | malloc() | ConnectWifi() | REST API |
|---|---|---|---|
qwen2.5:7b 베이스라인 (baseline) | |||
| 현대적인 설명 방식 | 올바른 형식, 프레임 파괴 (breaks frame) | 긴 현대적 에세이, 스스로를 명명함 | |
msft-qwen-r8 (40k, 1ep, rank 8) | |||
| 간결함, 정확한 어휘, 최소한의 구조 | 모든 모델 중 최고: 전체 교차 참조 (cross-refs), 플랫폼 요구 사항, 워크플로우 | 장(chapter) 스타일, “이 섹션에서” | |
msft-qwen-r16 (40k, 1ep, rank 16) | |||
| 개요 + 오류 + 예시 | 최소한의 내용, 프레임 파괴 없음 | ⚠️ SOAP 환각 (hallucination) | |
msft-qwen-40k (40k, 3ep, rank 16) | |||
| 구문 + 설명 + ENOMEM | 주의 사항과 함께 프레임 파괴 | 깔끔하게 일관성 유지 (Holds register) | |
msft-qwen-192k (192k, 1ep, rank 16) | |||
| 전체 매뉴얼 페이지 (man-page) + See Also + 예시 | 주의 사항과 함께 프레임 파괴 | REST에서 최고: 장(chapter) 개요, HATEOAS |
순위 비교(rank comparison) 결과에 따르면, 자유도(degrees of freedom)가 더 적은 작은 어댑터(adapter)가 더 큰 어댑터보다 허구에 더 쉽게 빠져드는 것으로 나타났습니다. 즉, 순위(rank) 16인 어댑터는 코퍼스(corpus)로부터 더 쉽게 "탈출"할 수 있습니다. 또한, 적당한 순위인 16과 단 1 에포크(epoch)만을 결합했을 때 환각(hallucination)이 더 빈번하게 발생하는 것으로 밝혀졌습니다. 이는 어댑터가 관련 개념을 탐색할 만큼의 표현력(expressive)은 갖추고 있지만, 프롬프트(prompt)가 전달하고자 하는 바에 고정될 만큼 충분히 강화(reinforced)되지 않았기 때문입니다. 순위와 에포크는 마치 사운드 믹서를 사용하는 것처럼 서로 상호작용하는 것으로 보입니다. 흥미롭게도, 어댑터가 저렴할수록 모사(impersonation)는 더 정직해집니다.
미세 조정된 모델은 설득력 있는 모사자가 되지만, 대체재는 아닙니다
미세 조정(fine-tuned)된 모델들은 90년대 후반 Microsoft 기술 작가들을 훌륭하게 모사했습니다. 코퍼스는 모델에 일부 지식뿐만 아니라 스타일과 목소리를 각인시켰으며, 동시에 새로운 개념을 설명하는 모델 본연의 능력은 대부분 유지했습니다. 이는 스타일 검토나 사내 스타일 가이드를 따르는 새 문서 초안 작성과 같은 작업을 목표로 하는 효과적인 소형 모델을 제작할 수 있는 비교적 저렴한 프로세스입니다.
하지만 그 단계에 도달하는 과정이 간단하지는 않습니다. 모델을 미세 조정하는 것은 비용이 저렴하지만, 제작하기 쉽지 않은 상당한 양의 고품질 학습 데이터(training data)를 필요로 합니다. 데이터를 확보하더라도, 적절하고 추가 학습을 수용할 능력이 있는 기반 모델(underlying model)을 선택해야 합니다. 게다가 사용할 수 있는 여러 매개변수(parameter)들로 인해, 미세 조정된 모델을 최적의 지점(sweet spot)에 도달하게 만드는 작업은 시간이 많이 소요되는 과제가 됩니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN AI Posts의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기