LLM & AI Agent 추천 시스템 프로젝트에서
도메인 특화 응답 품질을 개선하기 위해
Google Colab 무료 환경(T4 GPU)에서 QLoRA 파인튜닝을 직접 진행
기존 프로젝트는 사용자 질문 → 분류 → ChromaDB 검색 → LLM 답변 생성 순서로 동작
LLM의 도메인 특화 어휘 학습 및 모델명과 추천이유로 이루어진 구조화된 답변 생성 품질 향상을 위한 파인튜닝 진행
베이스 모델 (4-bit NF4 양자화)
↓
LoRA 어댑터 부착 (rank=16, Attention + FFN 전체)
↓
학습 가능 파라미터: 전체의 약 1%
↓
SFTTrainer 학습 (3 에포크)
↓
어댑터만 저장 (~수십 MB)
Train Loss는 5.08 → 1.22로 꾸준히 감소 (감소율 76%). Eval Loss와 비슷한 추세로, 과적합 징후 없이 학습되었음을 확인.
파인튜닝 전은 장황하게 답변하는 반면, 파인튜닝 후는 핵심 도구명과 선택 근거만 간결하게 제시한다.
답변 포맷이 최적화되고, 필요한 토큰 수도 크게 줄었다.
1from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
2from peft import PeftModel
3import torch
4
5MODEL_ID = "google/gemma-3-4b-it"
6ADAPTER_ID = "wooyeolj/gemma-3-4b-airecommender"
7
8bnb_config = BitsAndBytesConfig(
9 load_in_4bit=True,
10 bnb_4bit_quant_type="nf4",
11 bnb_4bit_use_double_quant=True,
12 bnb_4bit_compute_dtype=torch.bfloat16,
13)
14
15# 1. 베이스 모델 로드
16base_model = AutoModelForCausalLM.from_pretrained(
17 MODEL_ID,
18 quantization_config=bnb_config,
19 device_map="auto",
20 torch_dtype=torch.bfloat16,
21)
22tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
23
24# 2. HuggingFace Hub에서 어댑터 로드
25model = PeftModel.from_pretrained(base_model, ADAPTER_ID)
26
27# 3. 추론
28SYSTEM_PROMPT = (
29 "당신은 AI 도구 전문 추천 어시스턴트입니다.\n"
30 "사용자의 질문의 목적을 LLM 모델 추천, AI 에이전트 프레임워크 추천, AI 도구 선택과 무관한 일반적인 질문으로 구분하고,\n"
31 "질문의 목적에 맞게 명확하게 답변합니다."
32)
33
34def generate_response(question, max_new_tokens=250):
35 prompt = (
36 f"<start_of_turn>user\n"
37 f"{SYSTEM_PROMPT}\n\n{question}"
38 f"<end_of_turn>\n"
39 f"<start_of_turn>model\n"
40 )
41 inputs = tokenizer(prompt, return_tensors="pt",
42 truncation=True, max_length=512).to(model.device)
43 with torch.no_grad():
44 outputs = model.generate(
45 **inputs,
46 max_new_tokens=max_new_tokens,
47 do_sample=False,
48 repetition_penalty=1.2,
49 pad_token_id=tokenizer.eos_token_id,
50 eos_token_id=tokenizer.eos_token_id,
51 )
52 generated = outputs[0][inputs["input_ids"].shape[-1]:]
53 return tokenizer.decode(generated, skip_special_tokens=True).strip()
54
55print(generate_response("그림 잘 그리는 무료 AI 모델 추천해줘"))