(*) 기존에 자바로하였으나.. 요즘은.. AI 학습에 관심이 생겨 파이썬으로 만들고 학습하면서
포스팅하였습니다.

LangChain 영화 추천 시스템 구축 이야기

개요

LangChain과 LLM(대형 언어 모델)을 활용하면 사용자 선호도에 최적화된 추천 시스템을 효율적으로 구축할 수 있습니다.

이 시스템은 RAG(Retrieval-Augmented Generation), 임베딩 기반 검색, LLM 프롬프트 엔지니어링, 벡터 데이터베이스 등 다양한 기술을 종합적으로 활용하여 개인화된 영화 추천 서비스를 구현합니다.

아키텍처 개요

핵심 구성 요소

1. 사용자 행동 데이터 수집

  • 클릭, 구매, 평점 등 사용자-아이템 상호작용 기록을 저장합니다.
  • 실시간 사용자 행동 패턴을 분석하여 선호도를 파악합니다.

2. 사용자 프로필 생성

  • LLM을 활용해 사용자 행동 이력으로부터 자연어 기반 프로필(선호 장르, 특정 키워드 등)을 추출합니다.
  • 동적으로 업데이트되는 개인화된 사용자 프로필을 생성합니다.

3. 후보 아이템 검색(Candidate Retrieval)

  • 임베딩 벡터 DB(예: Chroma, Milvus 등)에서 유사한 아이템을 빠르게 검색합니다.
  • 콘텐츠 기반 필터링과 협업 필터링을 결합한 하이브리드 검색을 수행합니다.

4. LLM 기반 랭킹 및 추천

  • 후보 아이템과 사용자 프로필을 프롬프트로 LLM에 입력하여 reasoning을 통해 최적의 추천 시스템을 생성합니다.
  • 추천 이유와 함께 개인화된 설명을 제공합니다.

5. 추천 결과 재순위 및 피드백 수집

  • 추천 결과를 사용자에게 제공하고, 실제 행동 피드백을 다시 데이터로 수집해 모델을 지속적으로 개선합니다.

핵심 설계 및 구현 방법

데이터 준비 및 임베딩

사용자-아이템 상호작용 데이터를 CSV, DB 등으로 준비

# 예시 아이템 데이터 (영화 제목 및 설명)
items = [
    {"id": 1, "title": "인셉션", "desc": "꿈을 조작하는 SF 스릴러"},
    {"id": 2, "title": "인터스텔라", "desc": "우주를 탐험하는 과학 드라마"},
    {"id": 3, "title": "인디스 밀라", "desc": "우주를 배경으로 한 가족과 희생"},
    # ... 더 많은 아이템
]

아이템 임베딩 생성 및 벡터 DB 저장

from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma

# 1. 아이템 데이터 전처리 (영화 제목 및 설명)
# 2. 임베딩 생성 및 벡터 DB 저장
embedding_model = OpenAIEmbeddings()
docs = [item["desc"] for item in items]
vector_db = Chroma.from_texts(docs, embedding_model, metadatas=items)

사용자 프로필 생성 (LLM 활용)

from langchain.chat_models import ChatOpenAI

# 사용자의 최근 시청 기록 예시
user_history = [
    "인셉션", "인터스텔라"
]

# LLM에게 선호 장르/키워드 요약 요청
llm = ChatOpenAI(model="gpt-4o")
prompt = f"""
나가 최근에 본 영화는 {', '.join(user_history)}입니다. 나가 좋아할 만한 장르니 키워드, 특질을 요약해줘.
"""

user_profile = llm.invoke(prompt)
print("사용자 프로필 요약:", user_profile)

후보 아이템 검색 (Retrieval)

# 사용자 프로필 임베딩과 아이템 벡터 간 유사도 검색
user_profile_embedding = embedding_model.embed_query(user_profile)
results = vector_db.similarity_search_by_vector(user_embedding, k=5)

# Chroma, Milvus 등 벡터 DB에서 top-N 후보 아이템 추출
# RAG 프레임워크 외부 데이터와 연동 가능

LLM 기반 랭킹 및 추천

# 후보군과 사용자 프로필을 LLM에 프롬프트로 입력
candidate_titles = [r.metadata["title"] for r in results]
ranking_prompt = f"""
사용자 프로필: {user_profile}
후보 영화: {', '.join(candidate_titles)}
이 중에서 사용자가 가장 좋아할 만한 영화를 3개 추천하고, 그 이유를 각각 설명해줘.
"""

recommendations = llm.invoke(ranking_prompt)
print(recommendations)

통합 추천 함수 구현

코def recommend_movies(user_history, items, embedding_model, vector_db, llm):
    # 1. 사용자 프로필 생성
    prompt = f"나가 최근에 본 영화는 {', '.join(user_history)}입니다. 나가 좋아할 만한 장르니 키워드, 특질을 요약해줘."
    user_profile = llm.invoke(prompt)
    
    # 2. 후보 아이템 검색
    user_embedding = embedding_model.embed_query(user_profile)
    results = vector_db.similarity_search_by_vector(user_embedding, k=5)
    
    # 3. LLM 기반 랭킹 및 추천
    candidate_titles = [r.metadata["title"] for r in results]
    ranking_prompt = f"""
    사용자 프로필: {user_profile}
    후보 영화: {', '.join(candidate_titles)}
    이 중에서 사용자가 가장 좋아할 만한 영화를 3개 추천하고, 그 이유를 각각 설명해줘.
    """
    
    recommendations = llm.invoke(ranking_prompt)
    return recommendations

# 사용 예시
user_history = ["인셉션", "인터스텔라"]
recommendations = recommend_movies(user_history, items, embedding_model, vector_db, llm)
print(recommendations)

LangChain의 역할과 장점

주요 기능 및 이점

  • 모듈화: 데이터 수집, 임베딩, 검색, LLM 프롬프트 결과 생성 등각 단계를 체계적/에이전트로 분리해 관리.
  • 다양한 데이터 소스 통합: API, 외부DB, 문서 등 다양한 소스 연동이 용이.
  • 대화형 추천: 사용자의 자연어 질의에 맞춰 맞춤형 추천 및 설명 제공.
  • 확장성: LLM, 임베딩 모델, 벡터 DB 등 다양한 백엔드의 손쉬운 연동.

예시 워크플로우 (영화 추천 기준)

시나리오별 구현

1. 사용자가 "최근에 본 영화와 비슷한 코미디 영화 추천해줘"라고 요청

2. LangChain의 사용자 행동 아카이브 요청을 LLM에 전달, 선호 장르/키워드 추출

3. 벡터 DB에서 유사 모티브 검색 후보를 찾아 추출 구성

4. 후보군과 사용자 요청을 LLM 프롬프트에 일괄 추천 시스템 생성

5. 결과와 추천 이유를 사용자에게 자연어로 제공

실전 팁

성능 최적화 방안

LLM의 환독서에어 벡터 위해 후보 아이템 리스트를 명량히 제공
프롬프트 엔지니어링으로 추천 이유, 사용자 맞춤 설명 등 자연스러운 UX구현
피드백 루프를 통해 추천 품질 지속 개선

마무리

LangChain과 LLM, 벡터 DB, RAG 프레임워크를 결합하면 사용자 선호도 기반의 고도화된 추천 시스템을 빠르고 유연하게 구축할 수 있습니다.
특히 자연어 기반의 개인화된 추천 이유 제공과 실시간 대화형 인터페이스를 통해 기존 추천 시스템 대비 월등한 사용자 경험을 제공할 수 있습니다.

profile
꾸준히, 의미있는 사이드 프로젝트 경험과 문제해결 과정을 기록하기 위한 공간입니다.

0개의 댓글