
요약
안녕하세요. 토스 Commerce Personalization Team에서 토스 쇼핑의 추천 시스템을 만들고 있는 ML Engineer 구국원입니다.
추천 시스템은 흔히 더 좋은 모델을 만드는 문제로 보입니다. 하지만 실제 서비스를 운영하다 보면 모델 바깥에도 성능을 좌우하는 중요한 결정이 많아요. 각 추천 모델에서 상품을 몇 개씩 가져올 것인지 정하는 TopK도 그중 하나입니다.
저희는 여러 리트리벌(Retrieval) 모델의 TopK를 경험적으로 정해 왔습니다. 새로운 리트리벌 모델이 생길 때마다 후보 수는 조금씩 늘었고, 어느새 랭커(Ranker)가 평가해야 할 상품과 광고 유효성 검사량도 함께 커졌어요. 그렇다고 모든 리트리벌 모델의 후보를 같은 비율로 줄이면 가치 있는 상품까지 잃을 수 있었습니다.
이 글에서는 이 문제를 조합 최적화 문제로 바꿔 풀고, 온라인 실험으로 검증한 과정을 소개할게요. 결론부터 말하면 전체 후보 수를 약 절반으로 줄이면서 User CVR(User Conversion Rate)은 7.55%, 사용자당 주문 수는 10.13% 높일 수 있었습니다.
TopK가 커질수록 추천이 좋아질까요?
토스 쇼핑의 추천 시스템은 크게 Retrieval, Ranking 단계로 이루어져 있어요.
- Retrieval은 수많은 상품 중 사용자가 좋아할 만한 후보를 빠르게 가져옵니다.
- Ranking은 가져온 후보마다 클릭이나 구매 가능성을 예측해 순서를 정합니다.
TopK의 K는 각 리트리벌 모델이 다음 단계로 넘기는 상품 수예요. 예를 들어 구매 이력을 보는 모델에서 500개, 최근 클릭을 보는 모델에서 200개를 가져오면 두 모델의 TopK 합은 700개가 됩니다.
후보가 많으면 좋은 상품을 놓칠 가능성은 줄어듭니다. 하지만 공짜는 아니에요. Ranking 단계가 평가할 상품이 많아지고, 광고 상품의 유효성을 확인하는 비용도 늘어납니다. 따라서 피드를 만드는 데 총 소요 시간이 증가하여 응답 시간이 길어질 수 있고, 점수가 낮은 후보가 뒤 단계까지 살아남을 가능성도 커져요.
당시 TopK는 주로 각 모델을 담당하는 ML Engineer의 경험에 따라 정했습니다. 개별 모델만 보면 합리적인 값이어도 여러 리트리벌 모델의 후보를 합치면 전체 후보 수가 계속 커지는 구조였어요. 더 어려운 점은 모든 리트리벌 모델이 같은 가치를 만들지 않는다는 것이었습니다. 어떤 모델은 상위 수백 개까지 구매 가능성이 높지만, 다른 모델은 상위 몇십 개 이후 가치가 빠르게 낮아졌어요.
그래서 질문을 바꿨습니다.
모든 리트리벌 모델의 TopK를 똑같이 줄이지 않고, 전체 후보 수라는 예산 안에서 가치가 높은 모델에 더 많은 TopK를 배정할 수 없을까?
TopK 배정을 배낭 문제로 바꿔보기
이 문제는 배낭 문제(Knapsack Problem)와 닮았습니다. 무게 제한이 있는 배낭에 물건을 담되, 물건 가치의 합을 가장 크게 만드는 조합을 찾는 문제예요.
추천 시스템에 대입하면 이렇게 볼 수 있습니다.
- 배낭의 용량: 전체 리트리벌 모델이 가져올 수 있는 상품 수
- 물건: 각 리트리벌 모델의 각 순위에 있는 상품
- 물건의 가치: 해당 상품의 예상 클릭·구매 가치
- 결정할 것: 각 모델에서 몇 위까지 가져올지, 즉 모델별 TopK
가치가 높은 물건부터 차례로 넣는 탐욕적 방법만으로는 전체 최적 조합을 놓칠 수 있어요. 10kg 배낭에 9kg짜리 100점 물건 하나를 넣는 것보다 5kg짜리 60점 물건 두 개를 넣는 편이 더 좋은 것과 같습니다.
저희는 이 조합을 찾기 위해 정수계획법(Integer Programming)을 사용했습니다. 정수계획법은 선택 여부처럼 정수로 표현되는 결정을, 반드시 지켜야 할 조건 안에서 최적화하는 방법이에요. 세 가지 요소만 기억하면 됩니다.
- 결정 변수: 어떤 리트리벌 모델의 몇 번째 상품까지 선택할 것인가
- 목적 함수: 선택한 상품의 예상 가치 합을 최대화한다
- 제약 조건: 전체 후보 수와 모델별 최소 수량 같은 운영 규칙을 지킨다
수식으로는 다음처럼 표현할 수 있습니다.

여기서 x_{i,k}는 리트리벌 모델 i의 k번째 상품을 선택하면 1, 아니면 0인 값입니다. w_{i,k}는 그 상품의 예상 가치예요. 실제 실험군을 만들 때는 노출 이후 구매 가능성을 나타내는 pICVR(=pCTR * pCVR)을 선택했습니다.
제약 조건도 함께 넣었습니다.
- 전체 TopK 합은 기존의 약 50%를 넘지 않습니다.
- 특정 리트리벌 모델의 후보가 완전히 사라지지 않도록 최소 후보 수를 보장합니다.
- 한 모델에서 100번째 상품을 선택하려면 1번째부터 99번째 상품도 선택해야 합니다.
세 번째 조건이 필요한 이유는 TopK가 ‘몇 위까지 가져올 것인가’를 뜻하기 때문이에요. 100번째 상품만 고르고 그보다 높은 순위의 상품을 버릴 수는 없습니다.
실제 로그로 모델별 가치 곡선 만들기
최적화에 넣을 가치는 추측으로 정하지 않았습니다. 실제 추천 로그를 바탕으로 다음 과정을 거쳤어요.
- 사용자, 피드, 리트리벌 모델별 실제 로그를 가져옵니다.
- 각 상품에 Ranking 단계에서 사용하는 랭커로부터 pCTR, pCVR을 배치로 계산합니다.
- 리트리벌 모델과 순위별로 예측값의 평균을 집계했습니다.
- 각 리트리벌 모델에서 후보를 한 개 더 가져올 때 얻는 기대 가치가 얼마나 되는지 비교했습니다.

pICVR(Predicted ICVR)은 노출 후 구매까지 이어질 확률을 뜻합니다. 즉, 각 모델별 후보 상품이 창출할 것으로 기대되는 비즈니스 가치를 추정한 값이에요.
시뮬레이션 결과는 모델마다 달랐습니다. 기존 TopK를 그대로 유지하는 편이 좋은 리트리벌 모델도 있었고, 25%나 10% 수준까지 줄여도 전체 목적 함수에 미치는 영향이 작은 모델도 있었어요. 모든 리트리벌 모델의 TopK를 50%씩 줄이는 방식보다, 모델별 가치 곡선에 따라 다르게 배분해야 한다는 뜻이었습니다.
온라인에서 네 가지 방법 비교하기
오프라인 시뮬레이션이 좋아도 실제 사용자의 행동이 같으리라는 보장은 없습니다. 그래서 홈 피드에서 여러 실험군을 동시에 비교했어요.
실험군방법확인하려는 것비교군기존 TopK현재 성과의 기준일괄 1/2 축소모든 리트리벌 모델의 TopK를 일괄적으로 1/2로 줄이기단순 축소의 효과일괄 1/4 축소모든 리트리벌 모델의 TopK를 일괄적으로 1/4로 줄이기더 공격적인 축소의 효과정수계획법TopK 합을 약 절반으로 제한하고 pICVR 합이 커지도록 모델별로 다르게 배정가치 기반 배분의 효과Maximum CoverageTopK 합을 약 절반으로 제한하고 더 넓은 상품 커버리지를 만들도록 배정다양성 중심 배분의 효과실험은 7일 동안 진행했고 위너를 고르는 규칙도 결과를 보기 전에 정했습니다.
- 목표 지표: User CVR(User Conversion Rate, 노출된 사용자 중 구매한 사용자의 비율), Order PU(Order Per User, 사용자 한 명당 주문 수)
- 보조 지표: ICVR(Impression-CVR, 구매 수/노출 수), CVR(Conversion Rate, 구매 수/클릭 수), CTR(Click Through Rate, 클릭 수/노출 수), GPU(GMV Per User, 사용자 한 명당 GMV)
- 가드레일 지표: RPU(Revenue Per User, 사용자 한 명당 매출)
가장 높은 숫자보다 균형 잡힌 결과를 선택했어요
정수계획법 실험군은 비교군보다 전체 후보를 약 절반만 사용하면서 다음과 같은 변화를 보였습니다. 아래 수치는 모두 비교군 대비 상대 변화율입니다.
지표변화User CVR+7.552%Order PU+10.133%ICVR+9.286%CVR+13.496%GPU+11.218%RPU+0.832%CTR-3.710%User CVR, Order PU의 p-value는 0.0001보다 작았습니다. p-value는 ‘실제로 차이가 없다고 가정했을 때, 우연히 이 정도 이상의 차이를 관측할 가능성’을 가늠하는 값이에요. 값이 작을수록 단순한 우연만으로 설명하기 어렵다는 뜻입니다.
흥미로운 점은 목표 지표가 가장 높았던 실험군이 따로 있었다는 것입니다. TopK를 1/4로 줄인 실험군은 User CVR이 8.89%, Order PU가 10.52% 증가했습니다. 하지만 RPU는 3.98%, AOV(Average Order Value)는 5.73% 감소했어요. 주문 수는 늘었지만 낮은 가격대의 상품에 구매가 치우쳤을 가능성이 있었습니다.
Maximum Coverage 실험군은 RPU가 2.05% 증가해 수익성 방어에는 더 유리했습니다. 반면 User CVR과 Order PU의 개선 폭은 정수계획법 실험군보다 작았습니다.
저희는 목표 지표, 수익성, 전환 효율을 함께 비교해 정수계획법 실험군을 최종 위너로 선택했습니다. 한 지표의 최고점을 고르는 대신, 제품이 만들고 싶은 전체 효용을 기준으로 결정한 셈이에요.
후보를 줄이는 데에도 비용이 있었습니다
좋은 결과만 있었던 것은 아닙니다. 정수계획법 실험군의 CTR은 3.71% 감소했고, 사용자당 고유 노출 상품 수도 22.07% 줄었습니다.
CTR이 낮아진 동시에 CVR이 높아졌다는 것은 어떻게 봐야 할까요? 후보를 줄이면서 클릭 기회 자체는 감소했지만, 남은 클릭이 구매로 이어지는 효율은 높아졌다고 해석할 수 있습니다. ‘많이 보여주기’보다 ‘구매 가능성이 높은 후보를 남기기’에 가까운 변화예요. 다만 이 결과만으로 인과관계를 단정할 수는 없습니다.
고유 노출 상품 수의 감소는 더 분명한 과제였습니다. 목적 함수가 예측 구매 가치에 집중하면 자주 좋은 점수를 받는 상품이 반복해서 선택될 수 있어요. 전환 효율을 높이는 것과 새로운 상품을 발견하게 하는 것은 서로 충돌할 수 있습니다.
그래서 후속 실험에서는 TopK를 유지한 채 Gumbel Weighted Sampling을 적용했습니다. 목표 지표를 유의하게 떨어뜨리지 않으면서 피드 중복도를 평균 11.25% 낮추고, 노출 상품 다양성을 4.61% 높였습니다. RPU도 2.30% 증가했습니다. 첫 실험에서 드러난 비용을 다음 실험의 목표로 바꾼 결과였어요.
Next Step: 사용자마다 다른 TopK
이번 프로젝트로 경험에 의존하던 TopK를 데이터 기반의 최적화 문제로 바꿀 수 있었습니다. 하지만 현재 방식은 여전히 모든 사용자에게 같은 모델별 TopK를 적용하는 Global K입니다.
사용자마다 필요한 후보의 구성은 다를 수 있어요. 구매와 클릭 이력이 충분한 사용자는 개인화 모델의 후보를 더 많이 활용할 수 있습니다. 반대로 이력이 거의 없는 사용자는 인기 상품 모델이나 탐색형 리트리벌 모델이 더 중요할 수 있어요. 최근 행동의 유무나 관심사의 선명도에 따라서도 적절한 배분은 달라질 겁니다.
앞으로는 다음 두 방향을 검토하고 있습니다.
- 동적으로 갱신되는 Global K: 최근 로그와 모델 성능을 반영해 모델별 TopK를 주기적으로 다시 계산합니다.
- 개인화된 TopK: 사용자의 이력량, 최근성, 상태에 따라 같은 전체 예산 안에서도 모델별 TopK를 다르게 배정합니다.
개인화된 TopK는 후보를 더 많이 가져오는 방식이 아닙니다. 사용자에게 필요한 리트리벌 모델에 후보 예산을 더 정확하게 쓰는 방식에 가까워요. 다만 예측 오차가 배정 결과로 이어질 수 있고, 신규 리트리벌 모델은 로그가 부족하다는 문제가 있습니다. 신규 리트리벌 모델을 실제 노출 없이 평가할 수 있는 Shadow Logging과, 다양성·중복도 지표를 함께 관리하는 체계가 필요한 이유입니다.
마치며
추천 시스템의 성능은 모델의 정확도만으로 결정되지 않습니다. 어떤 후보를 몇 개 가져오고, 어떤 지표를 최적화하며, 무엇을 안전장치로 둘지 같은 운영 결정도 사용자 경험과 비즈니스 성과를 크게 바꿉니다.
이번 프로젝트에서 얻은 가장 큰 교훈은 세 가지였습니다.
- 경험적으로 정하던 설정값도 목적 함수와 제약 조건을 정의하면 최적화 문제로 바꿀 수 있습니다.
- 오프라인 예측값은 출발점일 뿐이며, 실제 사용자의 행동은 온라인 실험으로 확인해야 합니다.
- 위너는 가장 높은 숫자를 만든 안이 아니라, 목표 지표와 가드레일, 장기적인 사용자 경험을 함께 만족한 안이어야 합니다.
후보를 절반으로 줄이는 일은 단순한 비용 절감이 아니었습니다. 어떤 후보가 정말 가치 있는지 다시 정의하고, 추천 시스템이 쓰는 한정된 예산을 더 잘 배분하는 일이었어요. 이제는 이 배분을 사용자마다 다르게 만드는 다음 문제를 풀어보려 합니다.