본문으로 건너뛰기

추천 시스템에서 RAG·파인튜닝·LTR·Jev 선택 기준

·32 min read

자연어로 요구사항을 입력하면 적합한 항목을 추천해 주는 기능을 만든다고 가정했다. RAG를 붙이면 될지, 모델을 파인튜닝해야 할지, Learning to Rank나 Jev 같은 판단 모델은 어디에 들어가는지 따져 봐야 했다.

답을 찾으려고 검색, 판단, 정렬, 설명 생성을 나눠 봤다. 네 기술은 같은 자리를 놓고 다투는 대안이 아니었다. 필요한 역할에 맞게 결합할 수 있었다.

예로 든 서비스는 조건에 맞는 식당을 추천하는 가상의 서비스다. 등장하는 식당과 수치는 모두 설명을 위한 가정이고, 실제 가게나 서비스의 정보가 아니다. 구성에 대한 판단도 공개 자료를 바탕으로 한 설계 제안이다.

한 요청 안에 성격이 다른 조건이 섞여 있었다

사용자가 이렇게 요청한다고 가정했다.

“토요일 저녁에 어른 둘, 아이 둘이 갈 식당을 찾고 있어요. 대화하기 조용한 곳이면 좋겠고, 아이랑 가기 편했으면 해요. 예산은 1인 2만 원을 넘지 않았으면 하고, 차를 가져가서 주차는 꼭 돼야 해요.”

식당 데이터에는 가게 소개, 메뉴별 가격, 주차·유아의자 같은 시설 정보, 영업시간, 방문 리뷰, 정보 확인 시점이 등록돼 있다.

조건처리 방법이유
4명 기준 1인 2만 원 이하메뉴 가격 데이터를 이용한 코드 계산인원수, 아이 메뉴, 세트 구성 등을 일관되게 처리해야 한다
주차 가능시설 정보 데이터 조회주차 여부를 의미 유사도로 판단하면 안 된다
대화하기 조용함방문 리뷰 등 근거를 바탕으로 평가단일 필드로 표현하기 어려운 판단이다
아이랑 가기 편함유아의자·좌석 구성·리뷰를 함께 평가리뷰에 ‘아이’라는 단어가 있는지만으로는 판단하기 부족하다
추천 이유를 이해하기 쉽게 설명근거를 참조한 문장 생성 또는 템플릿순위와 설명은 별도의 출력이다

예산을 넘는 식당이 ‘분위기가 좋아 보인다’는 이유로 필수 조건을 통과하면 안 된다. 주차 정보가 확인되지 않은 곳을 주차 가능한 곳으로 간주해서도 안 된다. 그래서 필수 조건, 선호 조건, 정보 부족을 구분하는 설계를 가장 앞에 뒀다.

네 기술은 서로 다른 층위에 있었다

기술분류핵심 질문이 사례에서 맡는 역할
RAG검색과 생성을 결합하는 구성어떤 외부 정보를 근거로 답할까?최신 식당 정보를 찾아 추천 설명에 제공
파인튜닝사전학습 모델을 추가 학습하는 방법어떤 작업을 더 잘 수행하도록 바꿀까?요구사항 해석, 검색 표현, 적합도 판단 등을 개선
LTR순위를 학습하는 방법들의 집합어떤 후보를 위에 보여줄까?평가 사례를 이용해 후보의 상대적 순서를 학습
JevTypeSafe AI가 제공하는 판단 모델주어진 정보와 기준에 어떤 판단을 내릴까?선택, 기준별 점수, 참·거짓 확률을 반환

RAG 안에 파인튜닝한 모델을 넣을 수 있다. 신경망 랭커(후보 목록의 순서를 매기는 신경망 모델)를 순위 학습 목적에 맞춰 파인튜닝할 수도 있다. Jev의 평가 결과를 LTR의 입력으로 쓸 수도 있다. 네 항목은 서로 배타적인 선택지가 아니었다.

RAG는 최신 정보를 찾아 답변 근거로 쓰는 자리였다

RAG는 Retrieval-Augmented Generation의 약자다. 외부 정보를 검색해 생성 모델이 참고하도록 만드는 접근이다. 원 논문은 모델 파라미터에 담긴 지식과 외부 검색 정보를 결합하는 방법을 제시했다.

이 사례에 대입하면 사용자 요구에 관련된 식당 정보와 리뷰를 찾고, 그 내용을 바탕으로 추천과 설명을 생성하는 흐름이 된다.

메뉴 가격이 바뀌었을 때 모델을 다시 학습시키는 대신 원본 데이터와 검색 인덱스(검색을 빠르게 하려고 미리 만들어두는 색인)를 갱신할 수 있다. 다만 원본이 최신이라고 검색 결과까지 자동으로 최신이 되지는 않는다. 동기화, 캐시, 문서 버전 관리가 함께 필요하다.

RAG가 반드시 벡터 DB(텍스트를 숫자 벡터로 바꿔 저장하고 의미가 가까운 항목을 찾는 DB)를 뜻하지는 않는다. 구조화된 조건 조회, 키워드 검색, 의미 검색을 상황에 맞게 조합할 수 있다. 생성 없이 검색 결과를 정렬해 보여주기만 한다면, 그 기능은 검색·추천 파이프라인이라고 부르는 편이 정확하다.

이 가상 서비스에서는 가게 이름이나 ‘유아의자’ 같은 시설명에는 정확한 키워드가 중요하다. 반면 ‘아이랑 가기 편한 곳’ 같은 표현에는 의미 검색이 유용할 수 있다. 키워드 검색과 벡터 검색을 함께 쓰는 하이브리드 검색이 두 특성을 결합하는 방법이다. 실제로 나아지는지는 데이터를 놓고 검증할 문제로 남겼다.

RAG만으로 추천이 충분히 잘될 수도 있다. 하지만 검색된 문서가 사용자 요청과 비슷하다고 해서 그 식당이 적합하다는 보장은 없다. 검색 결과에 좋은 후보가 없으면 생성 모델은 그 후보를 근거 있게 추천할 수 없다. 후보가 있어도 평가 기준이 모호하면 순위가 흔들릴 수 있다.

파인튜닝은 어떤 능력을 고칠지부터 정해야 했다

사전학습된 모델(pretrained model)은 대량의 일반 데이터로 미리 학습을 마쳐 언어를 이해하고 만드는 기본 능력을 이미 갖춘 모델이다. GPT 같은 LLM이 여기에 해당한다. 모델을 처음부터 학습시키려면 막대한 데이터와 비용이 들어서, 보통은 이렇게 만들어진 모델을 가져와 출발점으로 쓴다.

파인튜닝은 이 사전학습된 모델을 특정 작업이나 도메인의 데이터로 추가 학습하는 방법이다. 추가 학습에는 입력과 그에 맞는 정답을 짝지은 데이터를 쓴다. 모델에 입력을 넣어 나온 답을 정답과 비교하고, 틀린 만큼 모델 안의 숫자(파라미터)를 조금씩 고치는 과정을 반복한다. 사전학습보다 훨씬 적은 데이터로, 이미 갖춘 능력을 해당 작업 쪽으로 다듬는 단계다. 모델 전체를 고치지 않고 작은 추가 부품(어댑터)만 붙여 학습하는 방식도 있는데, 이쪽이 메모리와 비용이 덜 든다.

그런데 ‘추천 시스템을 파인튜닝한다’는 말만으로는 설계를 시작할 수 없었다. 추천 파이프라인 안에는 학습시킬 수 있는 모델이 여럿이고, 어느 모델을 고치느냐에 따라 필요한 데이터도 기대하는 개선도 달라진다. 그래서 무엇을 학습할지부터 나눠 봤다.

표에 나오는 임베딩 모델은 텍스트를 의미가 담긴 숫자 벡터로 바꾸는 모델이다. 리랭커는 1차 검색으로 모은 후보를 요청과 함께 다시 보고 순서를 새로 매기는 모델이다.

학습 대상학습 사례의 예기대하는 개선
요구사항 해석 모델자연어 요청과 필수·선호 조건의 정답조건 추출 오류 감소
임베딩 모델요청에 맞는 식당, 헷갈리기 쉬운 식당적합한 후보를 검색에서 덜 놓침
리랭커동일 요청에서 더 적합한 후보에 대한 평가후보 순서 개선
설명 생성 모델근거 자료와 검수된 추천 설명필요한 항목을 일관된 형식으로 설명

첫 행인 요구사항 해석 모델을 예로 들면 이렇다. 가져다 쓰는 LLM은 한국어 문장 자체는 이미 잘 읽는다. 문제는 "차 가져가요"를 '주차 필수'로, "1인 2만 원은 안 넘었으면"을 '예산 상한'으로 뽑아내는 일이다. 여기서 자주 틀리면 실제 요청 문장과 정답 조건을 짝지은 데이터를 모아 추가 학습시킨다. 학습 데이터 한 건은 아래처럼 생겼다.

{
  "input": "토요일 저녁 4명이요. 차 가져가고, 1인 2만 원은 안 넘었으면 해요.",
  "output": { "인원": 4, "주차": "필수", "1인 예산 상한": 20000 }
}

이런 쌍을 충분히 모아 학습시키면 모델이 이 서비스의 요청 해석 방식을 익힌다. 모델을 새로 만드는 게 아니라, 이미 가진 언어 능력 위에 이 해석 방식만 더 가르친다.

메뉴 가격표나 식당 목록을 모델에 외우게 하는 건 이 사례의 우선 목표가 아니었다. 사실을 학습시킬 수는 있지만, 자주 바뀌는 값의 정확한 갱신과 출처 추적은 별개 문제다. 가격은 DB에서 읽고, 비교 방식이나 ‘가성비 좋은 곳’ 같은 표현 해석처럼 반복되는 작업의 오류를 학습 대상으로 삼는 편이 관리하기 쉽다고 판단했다.

파인튜닝이 잘못된 검색 결과나 부실한 원본 데이터를 자동으로 해결해 주지도 않는다. 그래서 학습 전에 프롬프트, 입력 데이터, 검색 품질부터 확인하고, 학습에 쓰지 않은 요청으로 개선 여부를 평가하기로 했다.

LTR은 좋은 순서가 무엇인지 데이터로 배우는 접근이다

Learning to Rank는 후보의 순위를 학습하는 접근들의 집합이다. 특정 LLM이나 단일 제품 이름이 아니다. XGBoost(결정 트리 여러 개를 차례로 더해 가며 학습하는 그래디언트 부스팅 라이브러리)의 랭킹 기능처럼 특징값을 입력받는 트리 기반 모델도 쓸 수 있다.

각 ‘사용자 요청–식당’ 쌍에 다음 정보를 만든다고 가정했다.

  • 요청과 가게 소개의 검색 점수
  • 요청한 시설(주차·유아의자)의 충족 여부
  • 인원수와 메뉴 가격으로 계산한 예상 비용
  • 리뷰로 평가한 소음 수준
  • 동일 요청에 대한 전문가 적합도 등급

여기서 적합도 등급은 정답에 해당하고, 나머지는 모델이 판단에 활용할 입력 특징이다. 가상의 평가 데이터를 표로 만들어 봤다.

요청 ID후보검색 점수시설 요구 충족률전문가 적합도 등급
Q1식당 A0.830.501
Q1식당 B0.761.003
Q1식당 C0.690.752

등급은 예시로 0~3을 썼다. 모델은 여러 요청 그룹의 데이터를 보고 어떤 입력 조합이 더 높은 적합도와 연결되는지 학습한다. 단순한 선형 가중치 조합을 넘어 비선형 관계도 학습할 수 있다.

LTR 접근은 보통 pointwise, pairwise, listwise로 나눠 설명한다. pointwise는 후보별 적합도를 예측하고, pairwise는 후보 쌍의 우열을 학습하고, listwise는 목록 수준의 순위 목적을 다룬다. 다만 실무에서는 알고리즘 이름보다 요청 단위의 데이터 구성과 평가 기준을 먼저 정하는 게 중요하다.

클릭을 곧바로 좋은 추천의 정답으로 쓰는 건 위험하다. 상단에 노출돼서 클릭됐거나, 이름이 익숙한 가게라 선택됐을 수 있다. 그래서 노출 위치, 표시된 후보, 모델 버전을 함께 기록하고, 클릭·전문가 평가·실제 방문 만족도는 서로 다른 신호로 나눠 둔다.

학습과 평가도 요청 단위로 나눠야 한다. 같은 요청의 후보 행을 무작위로 쪼개면 비슷한 맥락이 양쪽에 섞여 성능을 낙관적으로 보게 된다. 가게가 자주 바뀌는 지역이라면 과거 데이터로 학습하고 이후 시점의 요청으로 평가하는 방식도 필요하다.

Jev는 정해진 질문에 구조화된 판단을 돌려주는 모델이다

Jev는 TypeSafe AI의 판단 모델이다. 제공한 정보인 state와 질문을 받아 구조화된 답을 돌려준다. 공식 문서는 질문 유형을 Choice·Score·Noul로 나눠 안내한다.

유형의미식당 추천에서의 예
Choice주어진 선택지 중 하나를 선택가게 성격을 가족 외식·데이트·회식 등으로 분류
Score설명된 단계별 기준에 따라 평가리뷰에 근거해 소음 수준을 평가
Noul예/아니오 질문의 ‘예’ 확률을 반환아이와 가기 편하다는 근거가 리뷰에 있는지 판단

Jev는 자유로운 추천 설명문을 생성하는 모델이 아니다. 설명이 필요하면 원본 자료를 쓰는 템플릿이나 생성 모델을 따로 붙인다.

이 사례에서는 ‘이 식당이 좋은가?’처럼 뭉뚱그려 묻기보다 질문을 구체적으로 나누는 편이 낫다.

리뷰에 대화하기 시끄럽다는 언급이 반복되는가?

아이를 데려간 손님이 편했다는 후기가 있는가?

네 명이 한 테이블에 편하게 앉을 수 있다는 근거가 있는가?

점수 단계에는 ‘낮음·중간·높음’이 각각 무엇을 뜻하는지 정의해 둬야 한다. 자료가 없어서 판단할 수 없는 경우는 별도 값으로 뺀다. 초기에는 각 항목의 결과를 사람이 정한 가중치로 합칠 수 있다. TypeSafe도 이렇게 판단을 쪼개 코드에서 결합하는 패턴을 안내한다.

Jev는 후보 재정렬에도 쓸 수 있다. 공식 예제도 검색으로 후보를 줄이고, 요청과 후보를 함께 평가한 결과로 정렬한다. 다만 그 예제는 특정 데이터에서의 사용법을 보여줄 뿐이다. 한국어 식당 추천에서 다른 방식보다 낫다는 증거로 읽지는 않았다.

높은 적합도와 높은 확신도는 다른 값이다

모델은 어떤 식당이 부적합하다고 강하게 확신할 수도 있다. Choice와 Score의 confidence는 답변의 확률 분포를 하나의 숫자로 요약한 값이다. 요약하는 방법은 여러 가지이고, 이 값은 그중 하나로 계산한 결과다. Noul은 별도의 confidence 없이 확률을 돌려준다.

임계값(이 값 이상이면 결과를 믿고 쓰겠다고 정하는 기준선)은 적용 분야와 모델 성능에 따라 달라지므로, 자체 데이터로 검증하며 조정하기로 했다.

정확한 계산과 검증은 코드에 남겼다

Jev 1.13의 공식 제한 사항에는 수치 계산, 날짜 비교, 선택지 순서의 영향, 불필요하게 큰 입력, 입력에 포함된 유도성 지시문 등이 들어 있다. 그래서 가격 계산은 코드에서 처리하고, 평가에는 관련 자료만 넘기고, 선택지 순서를 바꿔도 답이 유지되는지 검증하기로 했다.

조합은 단계별로 늘려 가기로 했다

초기 구성은 검색과 평가 방식 하나로 잡았다

학습 데이터가 없는 초기 서비스라면 아래 구성이 실용적인 출발점이다. 필수 조건은 DB와 코드로 거르고, 남은 후보만 평가 모델에 넘기는 흐름이다.

Jev는 이 평가 단계의 후보 중 하나다. Jev, 일반 LLM의 구조화된 평가, 전용 리랭커를 같은 후보·정답 데이터로 비교한 뒤 고른다. 이 구성은 실험용 초안이지, 특정 모델이 가장 좋다는 벤치마크 결과가 아니다.

DB 필터 후 후보가 적다면 각 후보를 직접 평가할 수 있다. 후보가 많아질수록 별도 검색으로 평가 대상을 줄일 필요가 커진다. 검색을 생략할지는 전체 식당 수뿐 아니라 후보당 정보량, 요청량, 지연시간과 비용에 달려 있다.

LTR은 평가 이력이 쌓인 뒤의 선택지로 미뤘다

담당자 평가가 쌓였는데 사람이 정한 점수 공식으로는 반복되는 순위 오류를 고치기 어렵다면, 그때가 LTR을 비교해 볼 시점이다. Jev 없이 LTR만 넣은 구성은 이렇다.

이 구성에서 Jev는 필수가 아니다. 검색 점수, 시설 정보, 가격, 위치만으로 충분한 품질이 나온다면 Jev를 붙일 이유가 없다.

반대로 ‘소음 수준’처럼 리뷰를 읽어야 얻을 수 있는 평가가 쓸모 있다면, Jev가 그 특징을 만들고 LTR이 다른 정보와 함께 쓰게 할 수 있다.

이때 Jev의 출력을 정답처럼 다루지 않는다. Jev는 입력 특징을 제공하고, 학습의 기준은 실제 평가 데이터다. 항목별 점수와 가중치 합산의 기준이 달라지므로, 기존 수동 점수 공식과 LTR을 별도 실험군으로 비교하기로 했다.

파인튜닝 대상은 오류가 나는 위치로 좁혔다

반복되는 문제우선 확인할 부분학습이 필요할 때의 후보
적합한 식당이 검색 후보에 없다데이터 누락, 필터, 검색어, 검색 방식임베딩 모델 학습
좋은 후보는 있지만 순서가 부정확하다평가 기준, 입력 특징, 정답 일관성LTR 또는 리랭커 파인튜닝
필수 조건을 잘못 해석한다요구사항 스키마, 추출 프롬프트조건 추출 모델 파인튜닝
순위는 적절하지만 설명이 부정확하다근거 전달, 생성 지침, 사실 검증설명 생성 모델 파인튜닝

순위 오류가 있는데 설명 생성 모델부터 학습시키면 엉뚱한 곳을 고치게 된다. 고칠 부분을 좁히면 필요한 학습 데이터도 분명해진다.

도입 여부는 같은 후보로 비교 실험해 정하기로 했다

비교 실험의 재료는 실제 사용 맥락을 대표하는 요청과 전문가 평가다. 간단한 요청뿐 아니라 필수 조건이 많은 요청, 정보가 부족한 요청, 조건을 다 맞추는 식당이 없는 요청도 평가 세트에 들어가야 한다.

실험군구성확인할 질문
A필터 + 검색 + 단순 정렬기본 검색만으로 어느 정도 해결되는가?
B같은 후보 + 일반 LLM 평가자연어 판단을 추가하면 품질이 좋아지는가?
C같은 후보 + Jev 평가B와 비교해 품질·비용·시간이 어떤가?
D같은 후보 + LTR학습 데이터가 있을 때 순위가 개선되는가?
E같은 후보 + Jev 특징 + LTRJev 특징의 추가 효과가 있는가?

랭킹 비교에서는 후보 목록을 같게 유지해야 순위 결정 방식의 차이가 보인다. 전체 파이프라인도 따로 평가해서, 검색에서 빠진 후보 때문에 생기는 손실을 확인한다. 설명 생성은 같은 최종 후보와 근거를 주고 따로 평가할 수 있다.

추천 품질은 지표 하나로 보지 않았다.

  • 후보 Recall@K: 평가된 적합 후보 중 얼마나 후보 목록에 포함됐는가. 정답 후보가 불완전하면 지표의 범위도 제한된다.
  • NDCG@K: 높은 적합도 등급의 후보가 상단에 배치되는가. NDCG(Normalized Discounted Cumulative Gain)는 등급이 높은 후보가 위에 있을수록 점수를 더 주는 순위 지표다.
  • 필수 조건 위반율: 확인된 예산·주차 같은 필수 조건을 어긴 추천이 있는가.
  • 판단 보류 품질: 근거가 부족하거나 적합한 식당이 없을 때 억지 추천을 피하는가.
  • 설명 근거 일치율: 설명의 사실 주장이 제공된 자료에 의해 뒷받침되는가.
  • 운영 비용과 지연시간: 평가 호출, 검색, 설명 생성을 포함한 전체 비용과 p50·p95 응답시간(전체 요청의 50%·95%가 이 시간 안에 끝나는 값)은 어떤가.

LTR이 생겼다고 Jev를 유지할 필요는 없다. Jev 특징을 뺀 실험과 비교해 품질 차이가 없으면 호출을 줄일 수 있다. 파인튜닝도 학습에 쓰지 않은 요청에서 유의미한 개선이 확인될 때만 채택한다.

상황마다 출발점이 달랐다

현재 상황시작하기 좋은 선택
최신 정보 기반의 설명이 필요하다검색 + 생성(RAG)
추천 목록만 필요하고 후보가 적다DB 필터 + 직접 평가·정렬
학습 데이터 없이 의미적 적합성을 평가하고 싶다Jev·일반 LLM·리랭커 비교
일관된 전문가 평가가 충분히 쌓였다검색 + LTR 비교 실험
Jev의 의미 판단과 정형 정보를 함께 활용하고 싶다Jev 결과를 LTR 입력 특징으로 사용
특정 해석·검색·판단 오류가 반복된다해당 모델에 대한 파인튜닝 검토

좋은 초기 설계는 모든 기술을 넣은 설계가 아니다. 필수 조건은 정확하게 검증하고, 검색은 좋은 후보를 확보하고, 평가는 선호 조건의 차이를 드러내야 한다. 설명이 필요하면 확인된 근거로 쓴다.

이 가상의 서비스라면 검색과 하나의 평가 방식으로 시작하겠다. 운영 과정에서 요청, 노출된 후보, 원본 버전, 평가 결과를 기록하고, 이후 LTR이나 파인튜닝을 적용할 때 같은 문제를 더 잘 해결하는지 비교하겠다. 기술을 추가하는 기준은 기능의 개수가 아니라 검증된 품질 개선과 운영 비용이다.