본문 바로가기
AI2026년 9월 1일16분 읽기

파인튜닝 vs RAG vs 프롬프트 엔지니어링 — 언제 무엇을 선택하나

YS
김영삼
조회 6
파인튜닝 vs RAG vs 프롬프트 엔지니어링 — 언제 무엇을 선택하나

지식을 주입할 땐 RAG, 형식과 말투를 고정할 땐 파인튜닝, 그 전에 항상 프롬프트 엔지니어링부터 — 이 순서를 지키면 열에 아홉은 파인튜닝까지 갈 필요가 없다.

셋은 경쟁 기술이 아니라 서로 다른 문제를 푸는 도구다. 최신성·출처가 필요하면 RAG, 출력 형태를 강제하고 싶으면 파인튜닝, 나머지 대부분은 프롬프트로 해결된다. 실무에서는 결국 이 셋을 섞어 쓰게 되는데, 순서를 거꾸로 밟으면 돈과 시간을 크게 버린다.

"우리도 파인튜닝 해야 하지 않나요?" 지난 2년간 이 질문을 수십 번 받았다. 그리고 그중 실제로 파인튜닝이 정답이었던 경우는 손에 꼽는다. 대부분은 프롬프트를 다시 짜거나 검색 파이프라인을 붙이면 끝날 문제였다. 그런데도 다들 파인튜닝부터 떠올린다 — 아마 제일 '있어 보여서'일 거다. 이 글에서는 세 접근법을 비용·데이터·최신성·정확도라는 네 축으로 갈라서 보고, 실제로 무엇을 언제 골라야 하는지 정리한다.

기준프롬프트 엔지니어링RAG파인튜닝
초기 착수 비용거의 0 (시간뿐)중 (인프라·임베딩)높음 (데이터·학습)
필요 데이터량예시 몇 개문서 코퍼스수백~수만 쌍
최신성 반영수동으로만실시간 (인덱스 갱신)느림 (재학습 필요)
출처·근거 제시어려움가능 (인용 반환)불가
출력 형식·톤 고정중간낮음강함
추론당 토큰 비용중~높음 (긴 프롬프트)높음 (문맥 주입)낮음 (짧은 프롬프트)
변경 반영 속도즉시빠름느림 (시간~일)

셋은 애초에 경쟁 관계가 아니다

결론부터. 프롬프트 엔지니어링은 모델에게 지시하는 방법이고, RAG는 모델에게 지식을 붙여주는 방법이며, 파인튜닝은 모델의 행동 자체를 바꾸는 방법이다. 푸는 문제가 다르다. "vs"로 묶어 놓으니 하나를 고르는 것처럼 보이지만, 현장에서는 거의 항상 프롬프트 위에 RAG를, 필요하면 그 위에 파인튜닝을 얹는다.

비유를 하자면 이렇다. 프롬프트 엔지니어링은 유능한 신입에게 업무 지시서를 잘 써 주는 것이다. RAG는 그 신입 책상에 사내 위키와 최신 매뉴얼을 올려 두고 "찾아보고 답해"라고 하는 것. 파인튜닝은 아예 그 신입을 몇 달간 교육시켜 우리 회사 방식이 몸에 배게 만드는 것이다. 지식이 자꾸 바뀌는데 교육부터 시키면? 배운 게 금방 옛날 정보가 된다. 이게 파인튜닝으로 지식을 주입하려다 실패하는 전형적 이유다.

프롬프트 엔지니어링 — 가장 먼저, 가장 싸게

무조건 여기서 시작해야 한다. 코드 배포도, 인프라도, 데이터셋도 필요 없이 텍스트만 고치면 되기 때문이다. 최신 모델들은 프롬프트에 예시 몇 개(few-shot)와 명확한 제약만 줘도 웬만한 태스크를 처리한다. 내 경험상 "파인튜닝이 필요할 것 같다"던 요구의 절반 이상이 시스템 프롬프트를 다시 쓰는 것으로 해결됐다.

핵심 기법은 몇 개 안 된다. 역할 부여, 출력 형식 명시(특히 JSON이면 스키마를 통째로 보여주기), few-shot 예시, 그리고 복잡한 추론엔 단계적 사고 유도. 아래는 분류 태스크를 프롬프트만으로 안정화시킨 예시다.

당신은 CS 티켓 분류기다. 아래 티켓을 정확히 하나의 카테고리로 분류한다.

카테고리: ["결제", "배송", "환불", "기술문의", "기타"]

규칙:
- 애매하면 본문의 '핵심 동사'를 기준으로 판단한다 (예: 돈을 돌려달라 → 환불)
- 여러 주제가 섞이면 고객이 '가장 원하는 행동'을 고른다
- 반드시 아래 JSON만 출력한다. 설명 금지.

출력 스키마:
{"category": "환불", "confidence": 0.0~1.0}

예시 1)
티켓: "결제는 됐는데 물건이 안 와요. 그냥 취소하고 돈 주세요"
출력: {"category": "환불", "confidence": 0.86}

티켓: "{{user_ticket}}"
참고 few-shot 예시는 많다고 좋은 게 아니다. 3~5개면 대부분 충분하고, 예시가 길어질수록 토큰값이 매 호출마다 나간다. 예시가 20개를 넘어가기 시작하면 그건 파인튜닝을 검토하라는 신호다.

한계도 분명하다. 프롬프트로는 모델이 학습 시점에 모르는 사내 지식(어제 올라온 정책 문서 같은 것)을 알게 할 수 없고, 매 호출마다 긴 지시문을 함께 보내야 하니 규모가 커지면 토큰 비용이 은근히 쌓인다. 여기서 막히면 다음 두 카드를 꺼낸다.

RAG — 최신성과 출처가 필요할 때

RAG(검색 증강 생성)는 질문이 들어오면 관련 문서를 먼저 찾아서 프롬프트에 끼워 넣고 답하게 하는 구조다. 모델을 건드리지 않고 지식만 갈아 끼운다. 그래서 최신성이 필요할 때, 그리고 "이 답 어디서 나왔어?"에 출처를 대야 할 때 사실상 유일한 실무적 정답이다.

동작은 두 단계다. (1) 문서를 청크로 잘라 임베딩해서 벡터 DB에 넣어 두는 인덱싱, (2) 질문이 오면 의미가 가까운 청크를 검색해 프롬프트에 붙이는 검색+생성. 문서가 바뀌면 해당 청크만 다시 인덱싱하면 되니, 지식이 자주 갱신되는 도메인에 특히 강하다.

# RAG 검색+생성 최소 구현 (개념 코드)
query = "환불 규정이 올해 바뀌었나요?"

# 1) 질문을 임베딩 → 벡터 DB에서 유사 청크 top-k 검색
q_vec = embed(query)
chunks = vector_db.search(q_vec, top_k=5)

# 2) 검색 결과를 문맥으로 주입 (출처 메타데이터 포함)
context = "\n\n".join(
    f"[출처: {c.source} p.{c.page}]\n{c.text}" for c in chunks
)

prompt = f"""아래 문맥만 근거로 답하라. 문맥에 없으면 '자료 없음'이라 답한다.
답변 끝에 사용한 출처를 반드시 표기한다.

[문맥]
{context}

[질문] {query}"""

answer = llm.generate(prompt)

RAG의 진짜 난이도는 LLM 쪽이 아니라 검색 품질에 있다. 이건 문서로 잘 안 나오는데, 실무에서 RAG가 헛소리를 하면 십중팔구 원인은 모델이 아니라 엉뚱한 청크를 물어온 검색 단계다. 청크를 너무 크게 자르면 노이즈가 섞이고, 너무 작게 자르면 문맥이 끊긴다. 나는 보통 300~800토큰 사이에서 문서 성격 보고 조절하고, 청크 간 겹침(overlap)을 조금 준다. 그리고 순수 벡터 검색만 믿지 말고 키워드 검색과 섞은 하이브리드 검색을 쓰면 재현율이 눈에 띄게 올라간다.

주의 "문맥에 없으면 자료 없음이라 답하라"는 지시를 프롬프트에 안 넣으면, 검색이 실패했을 때 모델이 아는 척 지어낸다. RAG를 붙였다고 환각이 자동으로 사라지지 않는다 — 오히려 그럴듯한 출처까지 붙여서 더 위험하게 틀린다.

파인튜닝 — 형식·톤·도메인 말투를 고정할 때

파인튜닝은 모델 가중치를 우리 데이터로 추가 학습시켜 행동 자체를 바꾸는 것이다. 잘못 알려진 게 하나 있는데, 파인튜닝은 지식을 넣는 도구가 아니라 패턴을 새기는 도구다. 특정 출력 형식을 매번 정확히 뽑아야 할 때, 특유의 말투나 브랜드 보이스를 일관되게 유지할 때, 프롬프트로는 안 되는 미묘한 분류 경계를 학습시킬 때 빛난다.

학습 데이터는 보통 입력-정답 쌍의 JSONL 형태로 준비한다. 품질이 전부다. 지저분한 데이터 만 개보다 깔끔하게 정제한 수백~수천 개가 낫다는 걸 매번 체감한다.

{"messages": [{"role": "system", "content": "너는 우리 회사 톤의 상담원이다"}, {"role": "user", "content": "배송 언제 와요?"}, {"role": "assistant", "content": "고객님, 주문번호 알려주시면 바로 확인해 드릴게요 :)"}]}
{"messages": [{"role": "system", "content": "너는 우리 회사 톤의 상담원이다"}, {"role": "user", "content": "환불하고 싶어요"}, {"role": "assistant", "content": "불편을 드려 죄송해요. 환불은 3영업일 내 처리되며, 절차 안내드릴게요."}]}

전체 가중치를 다 학습시키는 방식은 비싸고 무거워서, 요즘은 LoRA 같은 파라미터 효율 기법(PEFT)으로 일부만 학습시키는 게 표준이다. 비용과 시간이 훨씬 적게 든다. 그래도 파인튜닝의 진짜 비용은 GPU가 아니라 데이터를 만들고 유지하는 사람의 시간이다. 그리고 결정적 단점 하나 — 파인튜닝한 모델은 지식이 학습 시점에 고정된다. 정책이 바뀌면 데이터 고치고 다시 돌려야 한다. 그래서 자주 바뀌는 정보엔 절대 파인튜닝을 쓰면 안 된다.

비용·데이터·최신성·정확도 트레이드오프 한눈에

네 축으로 정리하면 선택이 훨씬 명확해진다. 아래 표는 "이 축이 가장 중요하면 무엇을 봐야 하나"를 정리한 것이다.

가장 중요한 것1순위 선택이유
빨리·싸게 검증프롬프트배포·데이터 없이 즉시 반복
정보 최신성RAG인덱스만 갱신하면 반영
출처·근거 추적RAG검색된 문서를 인용 가능
출력 형식·톤 일관성파인튜닝패턴이 가중치에 각인
추론당 비용 절감파인튜닝프롬프트를 짧게 유지
도메인 사실 정확도RAG (+파인튜닝)근거 주입이 환각을 줄임

정확도 항목만 좀 더 짚자. "파인튜닝하면 정확해진다"는 오해가 많다. 사실 관계의 정확도, 즉 틀린 사실을 안 말하게 하는 데는 RAG가 훨씬 효과적이다. 파인튜닝이 올려주는 건 형식의 정확도(원하는 JSON 구조를 꼬박꼬박 지키는 것, 분류 경계를 정확히 긋는 것)에 가깝다. 이 둘을 구분 못 하면 엉뚱한 도구를 고르게 된다.

의사결정 플로우 — 실제로 이렇게 고른다

내가 새 LLM 기능을 설계할 때 머릿속으로 돌리는 순서는 거의 고정돼 있다. 위에서 아래로 내려가되, 웬만하면 위에서 멈추는 게 이긴다.

1. 프롬프트만으로 목표 품질이 나오나?
   └ YES → 끝. (여기서 끝나는 경우가 제일 많다)
   └ NO ↓

2. 부족한 게 '지식/사실/최신성'인가?
   └ YES → RAG를 붙인다.
   └ NO ↓  (부족한 게 형식·톤·행동 패턴이면)

3. 원하는 입출력 예시를 최소 수백 개 모을 수 있나?
   └ NO  → 프롬프트 few-shot 강화 + 더 큰 모델 검토
   └ YES → 파인튜닝.

4. 지식도 필요하고 형식도 고정해야 하나?
   └ YES → RAG + 파인튜닝 하이브리드
  1. 먼저 프롬프트로 끝까지 밀어본다. 여기서 되면 다른 건 다 오버엔지니어링이다.
  2. 모델이 몰라서 틀리면(사내 정보, 최신 정보) → RAG.
  3. 모델이 알면서도 형식·말투를 못 맞추면 → 데이터 모아서 파인튜닝.
  4. 둘 다면 하이브리드. 순서는 항상 위에서 아래로.

하이브리드 — 실무는 대부분 조합이다

규모가 커진 제품은 셋 중 하나만 쓰는 경우가 오히려 드물다. 가장 흔한 조합은 RAG로 지식을 대고, 파인튜닝으로 답변 형식과 톤을 잡는 구성이다. 예를 들어 사내 고객지원 봇이라면, 최신 정책은 RAG로 실시간 반영하고, "우리 회사 상담 말투로 짧게 요점부터"라는 스타일은 파인튜닝으로 고정한다. 지식은 계속 바뀌지만 말투는 안 바뀌니, 각각 잘하는 도구에 맡기는 셈이다.

여기에 프롬프트 엔지니어링은 항상 깔려 있다. 파인튜닝된 모델이든 RAG든, 결국 시스템 프롬프트로 가드레일과 출력 규칙을 잡아 준다. 그러니까 정확히 말하면 하이브리드는 "프롬프트(기본) + RAG(지식) + 파인튜닝(형식)"의 3층 구조인 셈이다. 개인적으로는 파인튜닝은 최대한 미루는 편이다. 한 번 파인튜닝 파이프라인을 운영에 넣으면, 모델 버전 올릴 때마다 데이터 다시 돌리고 평가하는 유지보수가 계속 따라붙기 때문이다.

참고 하이브리드로 갈 땐 평가 세트를 먼저 만들어라. 뭘 바꿨을 때 좋아졌는지 나빠졌는지 숫자로 안 보이면, RAG 튜닝과 파인튜닝을 동시에 만지다가 원인을 영영 못 찾는다. 나는 대표 질문 50~100개에 기대 답을 붙인 평가셋부터 만들고 시작한다.

내가 실제로 데인 실패 사례

이론보다 실패가 기억에 남는다. 세 가지만 공유한다.

1) 지식을 파인튜닝으로 넣으려던 삽질. 초창기에 제품 매뉴얼 수천 페이지를 파인튜닝으로 "외우게" 하려 했다. 결과는 최악이었다. 모델은 그럴듯한 문장은 잘 만들었지만 세부 스펙을 자꾸 틀렸고(환각), 매뉴얼이 개정될 때마다 다시 학습시켜야 했다. RAG로 갈아엎으니 정확도도 오르고 갱신도 문서만 바꾸면 끝이었다. 교훈: 사실은 파인튜닝 말고 RAG로.

2) RAG를 붙였는데 환각이 더 늘어난 건. 검색 품질이 나쁜 상태에서 top-k만 잔뜩 키웠더니, 관련 없는 청크가 문맥에 섞여 들어가 모델이 그걸 근거로 엉뚱한 답을 확신 있게 냈다. "문맥에 없으면 모른다고 답하라"는 지시도 빠져 있었다. 청크 전략을 손보고 하이브리드 검색으로 바꾸고, 근거 없으면 회피하도록 프롬프트를 고치고 나서야 잡혔다.

3) 프롬프트로 될 걸 파인튜닝한 낭비. 팀에서 분류기를 파인튜닝하겠다고 몇 주를 잡았는데, 막상 예시 5개짜리 few-shot 프롬프트가 파인튜닝 모델과 거의 동급 성능을 냈다. 데이터 라벨링에 쓴 시간이 통째로 날아갔다. 그 뒤로는 뭘 하든 프롬프트 베이스라인부터 세우고 시작한다. 파인튜닝은 그 베이스라인을 확실히 이길 때만 한다.

자주 묻는 질문

RAG와 파인튜닝 중 뭘 먼저 시도해야 하나요?

프롬프트 엔지니어링 다음으로는 거의 항상 RAG가 먼저다. RAG는 모델을 안 건드리고 지식만 붙이므로 착수가 빠르고, 대부분의 "모델이 우리 걸 모른다" 문제를 해결한다. 파인튜닝은 RAG로도 형식·톤이 안 잡힐 때 마지막에 검토한다.

파인튜닝하면 환각(할루시네이션)이 줄어드나요?

사실 관계 환각을 줄이는 데는 파인튜닝보다 RAG가 훨씬 효과적이다. 파인튜닝은 없는 지식을 채워 넣기보다 형식과 말투 패턴을 각인시키는 도구라, 오히려 학습 데이터에 없던 걸 자신 있게 지어내게 만들 수도 있다. 환각이 문제라면 근거를 주입하는 RAG를 먼저 보라.

RAG와 파인튜닝을 같이 써도 되나요?

된다. 오히려 규모 있는 제품에선 흔한 조합이다. RAG로 최신 지식을 실시간 반영하고, 파인튜닝으로 출력 형식과 브랜드 톤을 고정하면 각 기법의 약점을 서로 메운다. 단, 평가셋을 먼저 만들어 두 가지를 따로 검증할 수 있어야 원인 파악이 된다.

파인튜닝에는 데이터가 얼마나 필요한가요?

태스크마다 다르지만, 형식·톤 학습 같은 경우 잘 정제된 수백~수천 개 쌍으로도 효과를 본다. 양보다 품질이 중요하다. 지저분한 데이터 수만 개보다 깨끗한 수백 개가 낫다. 만약 좋은 예시를 수백 개도 못 모으겠다면, 아직 파인튜닝 타이밍이 아니라는 뜻이다.

비용을 줄이려면 어떤 선택이 유리한가요?

단기·소규모라면 프롬프트가 가장 싸다(초기 비용 0). 하지만 호출량이 아주 많고 프롬프트가 길다면, 파인튜닝으로 프롬프트를 짧게 줄여 추론당 토큰 비용을 낮추는 쪽이 장기적으로 이득일 수 있다. 즉 트래픽 규모와 프롬프트 길이를 함께 봐야 한다.

자주 바뀌는 정보에 파인튜닝을 쓰면 안 되는 이유는?

파인튜닝된 지식은 학습 시점에 고정되기 때문이다. 가격, 정책, 재고처럼 수시로 바뀌는 값을 파인튜닝에 넣으면 개정될 때마다 데이터를 고쳐 재학습해야 하고, 그 사이엔 옛 정보로 답한다. 이런 데이터는 RAG로 인덱스만 갱신하는 게 정답이다.

소규모 팀이라면 어디까지 하는 게 현실적인가요?

대부분의 소규모 팀은 프롬프트 엔지니어링 + RAG 조합에서 멈추는 게 현실적이고 충분하다. 파인튜닝은 데이터 구축과 유지보수 인력이 계속 드는 작업이라, 그 비용을 감당할 명확한 이유(형식 강제, 대규모 추론 비용 절감 등)가 생기기 전엔 미루는 편을 권한다.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록