← 목록으로
추천 알고리즘 설계 2026.03.19 ✍️ 최하영

추천 시스템 상세 로직

Holliverse 추천 시스템은 고객 상태를 이해한 뒤 후보를 검색하고, 세그먼트와 페르소나에 맞는 설명까지 생성하는 운영형 RAG 추천 시스템으로 설계하고 구현했습니다.

추천 시스템 상세 로직

좋습니다. 아래는 이전에 정리한 추천 시스템 상세 로직 문서를 전부 “~했습니다”체로 통일해서 다시 정리한 버전입니다. 노션 문서에 바로 붙여 넣을 수 있도록 제목, 구조, 문체를 모두 맞췄습니다.


통신 추천 시스템 상세 로직 문서

1. 문서 목적

본 문서는 Holliverse의 LLM 기반 RAG 추천 시스템이 어떤 데이터와 규칙을 바탕으로 동작했는지, 그리고 실제 서비스 환경에서 어떻게 안정성과 추천 품질을 확보했는지를 발표, 문서화, 인수인계 관점에서 한눈에 이해할 수 있도록 정리했습니다.

이 추천 시스템은 단순히 인기 상품을 보여주는 것이 아니라, 고객의 현재 상태를 반영한 개인화 추천을 제공하는 것을 목표로 했습니다. 이를 위해 고객 컨텍스트, 상품 벡터 검색, 세그먼트 전략, 하드 필터, LLM 기반 추천 이유 생성, 캐시 및 fallback 전략까지 하나의 흐름으로 설계했습니다.


2. 추천 시스템 한 줄 정의

고객 컨텍스트를 바탕으로 후보 상품을 검색(Retrieval)하고, 세그먼트·페르소나를 반영한 LLM이 추천 이유를 생성(Generation)하는 RAG 기반 개인화 추천 시스템으로 설계했습니다.


3. 시스템 설계 목표

본 추천 시스템은 다음 네 가지 목표를 중심으로 설계했습니다.

3.1 고객 컨텍스트 기반 개인화

고객의 성향, 현재 상품, 최근 관심 태그, 상담 맥락, 이탈 위험도 등을 함께 반영하여 추천을 개인화했습니다.

3.2 모바일 편향 완화

벡터 검색을 사용할 경우 휴대폰 요금제에 후보가 과도하게 몰릴 수 있었기 때문에, 쿼리 단계, 검색 단계, 후처리 단계에서 다단계 제어를 적용하여 다양한 상품 유형이 추천 후보에 포함되도록 했습니다.

3.3 안전한 룰 기반 필터링

연령 태그나 특정 세그먼트의 가격 정책처럼 서비스 운영상 반드시 지켜야 하는 조건은 하드 룰로 적용하여 잘못된 추천을 원천 차단했습니다.

3.4 운영 가능성과 비용 최적화

LLM 호출이 항상 발생하지 않도록 최근 7일 추천 결과를 재사용했고, 컨텍스트 누락, 임베딩 실패, LLM 실패 상황에서도 fallback이 가능하도록 설계했습니다.


4. 전체 흐름 요약

추천 시스템의 전체 흐름은 아래와 같이 구성했습니다.

  1. memberId 로 추천 요청을 받았습니다.
  2. 최근 7일 이내 생성된 추천 결과가 있는지 먼저 확인했습니다.
  3. 캐시가 있으면 기존 추천 결과를 그대로 반환했습니다.
  4. 캐시가 없으면 member_llm_context 를 로딩했습니다.
  5. 고객 컨텍스트를 바탕으로 Retrieval 쿼리를 생성했습니다.
  6. 쿼리를 임베딩하고 pgvector 로 상품 후보를 검색했습니다.
  7. 연령 필터, 타입 분산, 세그먼트별 룰을 적용해 후보를 재정렬했습니다.
  8. 세그먼트/페르소나 프롬프트를 적용해 LLM이 추천 이유를 생성하도록 했습니다.
  9. 최종 추천 결과를 저장하고 응답했습니다.
  10. 실패 시에는 fallback 로직으로 기본 추천을 반환했습니다.

5. 핵심 데이터 구조

5.1 member_llm_context 테이블

이 테이블은 고객 한 명당 LLM이 이해해야 할 핵심 정보를 정규화해서 모아 둔 컨텍스트 테이블로 설계했습니다. 추천 시스템의 출발점이 되는 핵심 데이터였으며, Retrieval과 LLM 프롬프트 양쪽에서 모두 활용했습니다.

5.1.1 기본 정보

이 정보는 고객의 기본 상태와 가족 구조를 이해하는 데 사용했습니다.

5.1.2 세분화 / 페르소나

이 정보는 추천의 전략 방향과 설명 톤을 결정하는 데 활용했습니다.

5.1.3 현재 이용 / 관심 신호

이 정보는 고객이 현재 무엇을 사용하고 있고, 무엇에 관심을 보이고 있는지를 반영하는 데 사용했습니다.

5.1.4 이용 패턴 / 이탈 위험

이 정보는 추천의 방향성을 바꾸는 핵심 신호로 사용했습니다. 예를 들어 churn 위험 고객에게는 방어적 추천이, upsell 고객에게는 확장형 추천이 필요하다고 판단했습니다.


5.2 product 테이블

이 테이블은 추천 후보가 되는 상품 마스터와 임베딩 정보를 포함하도록 설계했습니다.

5.2.1 기본 정보

5.2.2 벡터 검색 관련

embedding_vector 는 OpenAI 임베딩을 사용해 생성했으며, pgvector 기반 유사도 검색에 사용했습니다.


6. 추천 파이프라인 상세

6.1 API 입력

추천 요청은 POST /api/v1/recommendations 로 받도록 구현했습니다. 요청 바디는 다음과 같았습니다.

{
  "memberId": 123
}

FastAPI 엔트리 포인트는 app/realtime/api/v1/recommendation.py 로 구성했습니다.


6.2 캐시 확인

추천 생성 전에 먼저 최근 7일 내 생성된 추천 결과가 있는지 확인하도록 설계했습니다.

목적

처리 방식

설계 의도

추천은 고객 맥락이 자주 바뀌는 정보이지만, 매 요청마다 LLM을 호출하는 것은 비용과 지연 측면에서 비효율적이라고 판단했습니다. 따라서 “최근 7일 내 추천 결과가 있으면 reuse” 하는 캐시 전략을 적용했습니다.


6.3 컨텍스트 로딩

캐시가 없으면 member_llm_context 를 조회했습니다.

분기

컨텍스트가 있는 경우에는 단순 인기 기반이 아니라, 고객 상태를 반영한 개인화 경로로 추천을 진행했습니다.


6.4 Retrieval 쿼리 텍스트 생성

Retrieval 쿼리 생성의 목적은 고객이 실제로 관심 가질 만한 상품 유형이 벡터 검색 후보에 고르게 포함되도록 하는 것이었습니다.

기본적으로 다음 세 가지 입력 신호를 사용했습니다.

6.4.1 current_product_types

현재 사용 중인 타입에는 가장 강한 기본 가중치를 부여했습니다.

6.4.2 product_type_clicks

최근 클릭이 많은 타입은 현재 관심도가 높다고 보고 추가 가중치를 부여했습니다.

6.4.3 recent_viewed_tags_top_3

최근 본 태그를 상품 타입과 매핑하여, 해당 타입 가중치를 강화했습니다.

6.4.4 타입 라벨 변환

내부 enum 타입은 사람이 이해할 수 있는 텍스트로 변환해 사용했습니다.

예를 들어,

6.4.5 쿼리 텍스트 설계 의도

모바일 상품만 과도하게 검색되지 않도록, 쿼리 마지막에 다음과 같은 문장을 추가했습니다.

“특히 휴대폰 요금제, 인터넷 상품, IPTV 상품 중에서 고객에게 어울리는 다양한 상품 유형을 함께 고려해 주세요.”

즉, 쿼리 생성 단계부터 검색 편향을 줄이기 위한 힌트를 주는 구조로 설계했습니다.


6.5 임베딩 및 벡터 검색

생성된 Retrieval 쿼리는 OpenAI 임베딩으로 변환했고, pgvector 기반 유사도 검색으로 최대 50개의 후보를 탐색했습니다.

6.5.1 검색 후보 수

6.5.2 타입 가중치 적용

compute_product_type_weights(ctx) 함수는 고객 상태를 바탕으로 타입별 boost 점수를 계산하도록 구현했습니다.

가중치 입력 신호는 다음 세 가지였습니다.

6.5.3 세그먼트별 차등 가중치

SEGMENT_WEIGHT_CONFIG 를 통해 세그먼트마다 current, click, tag 비중을 다르게 적용했습니다.

예를 들어,

즉, 현재 사용 타입 > 클릭 수 > 최근 태그를 기본 축으로 보되, 세그먼트에 따라 비율이 달라지도록 설계했습니다.


7. 후보 후처리 로직

Retrieval 결과는 바로 LLM에 전달하지 않고, 후보 재정렬 및 필터링을 거쳤습니다.

7.1 데이터 사용 패턴 기반 재정렬

data_usage_pattern 값을 활용하여 일부 상품의 우선순위를 조정했습니다.

예를 들어,

이 단계는 고객의 실제 사용량 대비 더 적절한 상품이 상위로 오도록 조정하는 역할을 했습니다.


7.2 연령 태그 하드 필터

상품의 tags 에 연령 관련 태그가 있는 경우, 고객 연령대와 완전히 맞지 않으면 추천 후보에서 제외했습니다.

예를 들어,

등의 태그를 하드 필터 대상으로 처리했습니다.

설계 원칙

이 필터는 하드 룰로 적용했습니다. 추천 후보 수가 줄어들더라도 절대 완화하지 않았습니다.

목적

성인에게 키즈 요금제나 병사 전용 상품이 노출되는 것처럼 명백히 잘못된 추천을 원천 차단하기 위해서였습니다.


7.3 타입 분산 및 TOP-K 보장

벡터 검색 결과가 한 상품 타입에 과도하게 몰리는 문제를 막기 위해 타입 분산 로직을 적용했습니다.

규칙

처리 방식

  1. 연령 필터를 통과한 후보에 대해 타입별 최대 2개씩 1차 후보를 구성했습니다.
  2. 상위 3개가 확보되면 그대로 사용했습니다.
  3. 3개보다 적으면 타입 분산 규칙은 일부 완화하되, 연령 필터는 유지한 채 추가 후보를 채워 넣었습니다.

목적


8. 세그먼트 전략

추천은 모든 고객에게 동일한 방식으로 동작하지 않도록 설계했습니다. 고객 세그먼트에 따라 무엇을 성공으로 볼지 자체가 다르다고 판단했기 때문입니다.

8.1 CHURN_RISK

목표

이탈 방지, 불만 완화, 부담 감소를 목표로 했습니다.

전략

가격 상한 룰

고객이 현재 사용 중인 타입별 최고 가격을 기준으로, 같은 타입 추천 상품이 현 최고가 × CHURN_MAX_PRICE_RATIO 를 초과하면 제거했습니다.

즉,

“지금보다 너무 비싼 상품은 이탈 위험 고객에게 보여주지 않는다”

는 원칙을 적용했습니다.

한 줄 요약

비싼 업셀보다, 이탈을 막는 현실적 대안을 제안했습니다.


8.2 UPSELL

목표

혜택 확장, ARPU 상승, 사용 경험 업그레이드를 목표로 했습니다.

전략

한 줄 요약

지출 대비 체감가치가 커지는 업그레이드 제안을 목표로 했습니다.


8.3 NORMAL

목표

균형 최적화, 만족도 유지, 가성비 중심 구성을 목표로 했습니다.

전략

한 줄 요약

무리 없는 개인화 최적안을 제안했습니다.


8.4 공통 규칙 vs 차별 포인트

공통 규칙

차별 포인트

정리하면,

을 목표로 운영했습니다.


9. LLM 추천 단계

9.1 LLM 입력 구조

LLM에는 두 종류의 정보를 함께 전달했습니다.

고객 컨텍스트

후보 상품 리스트

즉, LLM은 “아무 상품이나 추천하는 역할”이 아니라, 이미 정제된 후보 상품 중 어떤 것을 어떤 이유로 추천할지 설명하는 역할을 맡도록 했습니다.


9.2 프롬프트 설계

추천 시스템에서 LLM은 자유 생성기가 아니라, 톤과 구조가 강하게 통제된 생성기로 사용했습니다.

9.2.1 세그먼트 프롬프트

세그먼트별 system prompt는 다음과 같이 차이를 두었습니다.

공통 규칙


9.2.2 페르소나 스타일 프롬프트

세그먼트가 “무엇을 추천할지”를 정했다면, 페르소나는 “어떻게 말할지”를 정하도록 설계했습니다.

예를 들어,

즉, 세그먼트와 페르소나 2축으로 LLM reason의 방향과 말투를 동시에 제어했습니다.


9.3 LLM 출력 처리

LLM은 반드시 JSON으로 응답하도록 했습니다.

예시는 다음과 같았습니다.

{
  "products": [
    { "productId": 1, "reason": "..." }
  ]
}

후처리 규칙


10. Fallback 전략

10.1 컨텍스트 없음

member_llm_context 가 없는 경우에는,

10.2 임베딩 / OpenAI 실패

10.3 조건 미충족

연령 필터 등으로 추천 가능한 상품이 없으면,

설계 의도

실제 서비스에서는 “추천이 실패해서 아무 응답도 못 주는 것”이 가장 위험하다고 판단했습니다. 따라서 항상 동작하는 경로를 확보하는 것이 중요하다고 보았습니다.


11. 응답 구조

루트 응답

상품 항목

응답은 외부 API 기준으로 일관된 JSON 스키마를 유지하도록 설계했습니다.


12. 평가 구조

추천 품질은 오프라인 스크립트로 평가했습니다.

입력

지표

목적

즉, 추천 시스템은 단순히 “LLM을 붙였다”에서 끝난 것이 아니라, 오프라인 평가와 튜닝이 가능한 구조로 설계했습니다.


13. 핵심 설계 포인트 요약

13.1 모바일 편향 완화

단일 단계가 아닌 다단계 제어를 사용했습니다.

13.2 안전한 룰 기반 필터

13.3 LLM 통제형 사용

13.4 운영성과 비용 최적화


14. 한 줄 정리

Holliverse 추천 시스템은 고객 상태를 이해한 뒤 후보를 검색하고, 세그먼트와 페르소나에 맞는 설명까지 생성하는 운영형 RAG 추천 시스템으로 설계하고 구현했습니다.


#고객 컨텍스트 #LLM #RAG #pgvector