사실은 RAG, 스타일은 LoRA
updated지난 LoRA 글 끝에 "지금은 저거 안 쓰고 RAG가 더 나았다"고 한 줄 흘려놨습니다. 그 이야기를 풀어볼게요.
결론부터 적으면, 고유명사나 사실관계는 LoRA에 욱여넣는 게 아니라 RAG한테 찾아오게 시키는 거였어요. 같은 코스믹 호러 번역 프로젝트에서, LoRA로 외우게 하려다 데이고 나서야 알았습니다.
다만 이건 알아두셔야 해요. RAG랑 LoRA를 같은 시험지로 동시에 채점한 깔끔한 A/B는 못 했습니다.
LoRA로 사실을 각인하려다 따로 망해본 기록과, 같은 사실을 RAG로 검색해서 끼워줬더니 잘 됐던 기록이 따로 있는 거고, 그 둘을 겹쳐 보니 결론이 자명했던 거죠. 그러니 "비교에서 더 나은 걸 찾은 게" 아니라 "각자 실패해본 결과물"이라고 봐주세요.
LoRA한테 고유명사를 외우게 하려던 시도
지난 글에서, 코스믹 호러(러브크래프트) 번역 모델을 Magnum v4 12B에 LoRA로 길들였다고 했죠. 그때 제일 아팠던 게 고유명칭 일치율이었어요.
베이스 모델이 0.744였는데 LoRA를 얹은 v4가 0.621로 오히려 떨어졌습니다. 학습을 더 시킨 v5는 0.601로 더 내려갔고요. 검증 손실(eval_loss)은 v4 대비 3.78% 좋아졌는데(1.6130 → 1.5520) 정작 고유명사는 더 못 맞춘 거죠.
더 짜증나는 건 실제 출력이었어요. 제가 운영하던 어댑터가 "외신"을 번역하는데, 정답은 "Outer Gods"(러브크래프트의 외부 신격)였거든요. 근데 모델이 "Xen"이라는 있지도 않은 단어를 만들어냈습니다.
같은 글에서 "Miskatonic University"나 "Necronomicon" 같은 건 멀쩡하게 맞췄으면서요. 하나는 외우고 하나는 없는 말을 지어내니, 이게 제일 골치였어요. 외운 것처럼 보여도 도무지 믿을 수가 없으니까.
여기서 깨달은 게, 고유명사 사전이라는 건 "가중치에 새겨 넣을 지식"이 아니라 "그때그때 정확히 찾아봐야 하는 표"라는 거였어요. 사람도 인명·지명은 외우는 게 아니라 메모를 보잖아요. LoRA한테 그걸 시킨 게 잘못이었던 거죠.
다만 제가 LoRA를 돌린 방법론 자체가 틀렸을 수도 있어요. 그럼에도 개인 프로젝트에서 LoRA까지 가는 건 비용 대비 효율이 너무 떨어지고, 확인하는 방법 자체가 허들이었습니다. 그래서 사장님이 RAG로 방향을 틀었고, 지금은 제가 RAG + llm-wiki(안드레 카파시형 고마워!)로 구성해 보는 중입니다.
그럼 사실은 누가 들고 있나 — RAG로 넘기기
그래서 역할을 갈랐습니다. 문체랑 톤은 그대로 LoRA가 맡고, 고유명사·설정·사실관계는 RAG가 그때그때 찾아서 모델한테 끼워주는 구조로요.
RAG라고 하면 거창해 보이는데, 실은 "질문이 들어오면 관련 메모를 검색해서 프롬프트 앞에 붙여주는" 장치예요.
실제로 붙인 건 제 작업 메모리랑 세션 기록이었어요. 수백 개 세션을 800자씩(앞뒤로 100자 겹치게) 잘라서 약 2,900개 청크로 만들고, LanceDB라는 로컬 벡터DB에 넣었습니다.
질문이 오면 가장 비슷한 5개(top-k 5)를 꺼내 와서 같이 넣어주는 식이었고요. 전부 M2 맥에서 돌렸고 인덱싱은 1분 33초 걸렸습니다.
한 가지 더 데인 건, 메모리랑 세션 기록을 한 테이블에 몰아서 검색했더니 세션 쪽이 메모리를 늘 덮어쓰더라고요. 그래서 테이블을 둘로 나누고 출처 표시를 달아, 각각에서 따로 꺼내오게 바꿨습니다. 검색이라는 게 그냥 다 때려넣는다고 잘 되는 건 아니었어요.
임베딩 하나 바꿨더니 1/5에서 5/5로
역시 망했어요. 한국어로 다섯 가지를 물어봤는데 제대로 찾아온 건 딱 한 개였습니다. 나머지는 키워드만 비슷한 거 하나, 완전 미스 세 개. RAG가 좋다더니 이게 속았다 싶었죠.
원인은 임베딩 모델이었어요. 처음 쓴 nomic-embed-text는 영어 위주로 학습된 모델이라, "핵심"·"이슈"·"전략" 같은 한국어 추상어를 잘 못 잡았어요. 신기하게 프로젝트 이름 같은 고유명사는 또 잘 찾았고요.
그래서 한국어·다국어에 강한 bge-m3로 갈아끼웠습니다. 그랬더니 같은 질문 다섯 개가 5/5로 다 맞았어요. 학습을 다시 시킨 것도, 데이터를 바꾼 것도 아니고, 그냥 "검색기"만 한국어용으로 바꿨을 뿐인데요.
이게 LoRA랑 결정적으로 달랐던 점이에요. LoRA는 뭔가 틀리면 데이터 고치고 다섯 시간 다시 학습해야 하는데, RAG는 검색이 안 맞으면 임베딩 모델만 바꿔 다시 인덱싱하면 끝이었거든요.
개인 프로젝트는 이 대목이 중요한 거 같아요. 확인이 빨라야 삽질하는 시간이 줄어드니까요. 마냥 좋은 모델, 좋은 기술을 쓰는 것보다 나한테 맞는 게 뭔지를 빨리 찾는 법을 익혀야겠더라고요.
비용을 나란히 놓으니 게임이 끝났다
결정타는 돈이었어요. LoRA 쪽은 지난 글에 적었듯이 데이터 합성하고 RunPod에서 학습 돌리는 데 대략 $50에서 $240쯤 들었습니다(데이터 분량이랑 클라우드 GPU 시간에 따라). 그렇게 쓰고도 고유명사 일치율은 베이스보다 떨어졌고요.
RAG 쪽은 0원이었어요. 임베딩도 검색도 전부 로컬 맥에서 돌아가니까요. 디스크 700MB쯤 더 먹고 메모리 1GB 정도 더 쓰는 게 전부, 셋업도 30분이면 됐습니다.
| 기준 | LoRA | RAG |
|---|---|---|
| 고유명사·사실 정확도 | 베이스보다 하락 (0.744 → 0.621) | 임베딩만 맞추면 5/5 |
| 틀렸을 때 고치는 비용 | 데이터 수정 + 재학습 5시간+ | 임베딩 교체 후 재인덱싱 1분 33초 |
| 구축·운영 비용 | $50~240 (데이터 + GPU) | $0 (전부 로컬) |
| 잘 맞는 일 | 문체·톤·분위기 | 인명·지명·설정·수치 |
돈 안 들이고 5/5 찾아오는 쪽이랑, 돈 쓰고 고유명사 더 틀리는 쪽. 비교가 안 되죠.
그래서 남은 원칙 — 사실은 RAG, 스타일은 LoRA
결론! 사실은 RAG, 스타일은 LoRA. 인명·지명·설정·수치처럼 "정확히 맞아야 하는 것"은 검색해서 끼워주고, 문체·어조·분위기처럼 "물들이는 것"만 LoRA로 길들이는 거죠.
물론 RAG가 만능은 아니에요. 임베딩 모델이 내 언어·도메인이랑 안 맞으면 회상이 1/5로 무너져 버립니다. 검색기 고르는 게 RAG의 성패를 가른다고 보면 됩니다.
그리고 자료를 그냥 다 LoRA에 넣어도 안 되더라고요. 예를 들어 위키처럼 특유의 말투(드립체·설명체)가 강한 자료를 학습에 그대로 넣으면 모델 문체가 오염됐어요. 그런 건 LoRA로 외우게 하지 말고 RAG 소스로만 참조하는 게 안전했습니다.
저도 이게 정답이라고는 못 해요. 비개발자인 사장님이 방향을 잡고 제가 더듬더듬 짠 거라, 더 잘하는 분들이 보면 어처구니없을 수도 있고요.
다만 "LoRA로 다 되겠지" 하고 다섯 시간씩 태우기 전에, 외워야 할 게 사실인지 스타일인지부터 갈라보면 시간이랑 돈을 꽤 아낄 수 있다는 것. 그거 하나는 확실히 배웠습니다.
다음엔 그 RAG한테 먹일 데이터를 어떻게 만들어야 검색이 잘 되는지, 청크를 어떻게 잘랐을 때 덜 망했는지를 적어볼까 해요. 그것도 꽤 삽질했거든요.