Skip to main content
Glama

Two-Tower Recsys MCP — 신경망 기반 검색, MCP로 제공

Amazon의 2023년 리뷰 코퍼스로 학습된 딥러닝 투-타워 추천 모델을 MCP(Model Context Protocol) 도구 서버로 제공하고, Streamlit 채팅 프론트엔드를 통해 Gemini 에이전트가 사용자를 대신해 해당 도구를 호출할 수 있게 하는 프로젝트입니다.

이 README는 전체 파이프라인을 처음부터 끝까지 다룹니다: 모델이 무엇인지, 어떻게 학습되었는지, 실제 성능이 어떤지(추정이 아닌 측정), MCP 서버가 이를 어떻게 노출하는지, 그리고 프론트엔드를 실행하거나 배포하는 방법까지.


1. 이 프로젝트가 무엇인가

투-타워 모델은 대규모 산업용 추천 시스템 뒤에 있는 표준 아키텍처입니다(사용자와 아이템을 각각 별도의 "타워"로 임베딩하여 동일한 벡터 공간에 배치하고, 관련 쌍이 서로 가깝게 위치하도록 학습하는 이 패턴은 YouTube, Pinterest, Amazon 자체 검색 시스템에서도 사용되는 것과 동일한 형태입니다). 이 프로젝트는 이를 처음부터 구현하고, 실제 Amazon 상호작용 데이터로 학습한 뒤, 일반적인 REST API 대신 MCP를 통해 에이전트가 사용할 수 있도록 래핑합니다.

REST API 대신 MCP를 사용하는 이유? MCP는 Anthropic이 LLM 에이전트를 도구와 데이터에 연결하기 위해 도입한 프로토콜입니다. 학습된 모델을 (예를 들어 Flask 엔드포인트 대신) MCP 도구로 래핑하면, MCP 호환 에이전트 — Claude Desktop, 이 프로젝트 자체의 Streamlit+Gemini 프론트엔드, 또는 다른 MCP 클라이언트 — 가 recommend_for_user, similar_items 등을 직접 호출할 수 있으며, LLM이 자연어를 기반으로 언제 어떻게 호출할지 결정합니다.

Related MCP server: consulting-mcp-server

2. 아키텍처

  • 사용자 타워: 학습된 사용자 ID 임베딩(64차원) → 2계층 MLP → 64차원 출력.

  • 아이템 타워: 학습된 아이템 ID 임베딩(64차원)에 제품 제목의 고정된 all-MiniLM-L6-v2 문장 임베딩(384차원, 64차원으로 투영)을 연결 → 2계층 MLP → 64차원 출력. 고정된 텍스트 임베딩은 모델에 콜드 스타트 능력을 부여합니다 — 상호작용 기록이 전혀 없어도 제목만으로 아이템을 벡터 공간에 합리적으로 배치할 수 있습니다.

  • 두 타워 모두 L2 정규화된 벡터를 출력하며, 유사도는 내적(즉, 코사인 유사도)입니다.

  • 학습 손실: 배치 내 샘플링된 소프트맥스 — B개의 (사용자, 아이템) 양성 쌍 배치에서, 배치 내의 다른 모든 아이템이 각 사용자에게 음성으로 작용하며, 결과 B×B 유사도 행렬에 교차 엔트로피를 적용합니다. 이는 명시적 음성 샘플링 없이 검색 타워를 학습하는 표준적이고 계산 효율적인 방법입니다.

  • 서빙: 아이템 임베딩은 한 번 사전 계산되어 FAISS(IndexFlatIP)에 인덱싱되어 빠른 최근접 이웃 검색을 지원합니다. 원시(학습되지 않은) MiniLM 제목 임베딩으로 구축된 두 번째 FAISS 인덱스는 협업 신호와 독립적으로 작동하는 콜드 스타트 텍스트 검색을 가능하게 합니다.

        ┌────────────┐                          ┌────────────┐
        │  User ID   │                          │  Item ID   │
        └─────┬──────┘                          └─────┬──────┘
              │ embed(64)                              │ embed(64)
              ▼                                         ▼
        ┌────────────┐                    ┌──────────────────────────┐
        │  MLP (128) │                    │  Item title → MiniLM(384) │
        └─────┬──────┘                    └─────────────┬─────────────┘
              │                                          │ project(64)
              │                                          ▼
              │                                   concat(128) → MLP(128)
              ▼                                          ▼
        user vector (64, L2-norm)          item vector (64, L2-norm)
              └──────────────┬───────────────────────────┘
                              ▼
                    dot product = relevance score

3. 데이터셋

McAuley-Lab/Amazon-Reviews-2023 (UC San Diego McAuley Lab), Video_Games 카테고리 — 원시 리뷰 + 아이템 메타데이터, HuggingFace에서 직접 다운로드.

단계

개수

원시 리뷰

4,624,615

원시 사용자 / 아이템

2,766,656 / 137,249

5-코어 필터링 후 (사용자 및 아이템 ≥5 상호작용)

857,505 상호작용

사용자 / 아이템 (필터링 후)

98,906 / 26,354

학습 / 검증 / 테스트 상호작용

659,693 / 98,906 / 98,906

분할 프로토콜 — 사용자별 마지막 두 개 제외, 타임스탬프 기준 정렬: 각 사용자의 가장 최근 상호작용 → 테스트, 두 번째로 최근 → 검증, 나머지 → 학습. 이는 시간적 분할이므로, 모델은 학습에 사용된 데이터와 비교하여 진정한 미래 행동을 예측하는 것으로 평가되며, 무작위로 분리된 상호작용(학습에 미래 정보가 누출되어 수치가 부풀려질 수 있음)이 아닙니다.

4. 평가 (실제 측정된 수치)

평가는 전체 카탈로그 랭킹을 사용합니다 — 모든 후보가 26,354개 아이템 전체에 대해 점수가 매겨지며, 작은 샘플링된 음성 하위 집합이 아닙니다. 샘플링된 음성 평가(오래된 RecSys 논문에서 흔함, 예: 99개의 무작위 음성에 대해서만 랭킹)는 오프라인 지표를 상당히 부풀리는 것으로 알려져 있으므로, 이는 더 어렵고 정직한 프로토콜입니다. 각 사용자의 이미 본 아이템은 자신의 후보 랭킹에서 제외됩니다.

테스트 세트 — 98,906명의 사용자, 각 사용자의 보류된 최종 상호작용:

지표

Recall@10

1.40%

NDCG@10

0.70%

HitRate@10

1.40% (leave-one-out에서 Recall@10과 동일: 사용자당 정확히 하나의 관련 아이템)

맥락: 26,354개 아이템 카탈로그에서 k=10일 때 무작위 확률은 10/26,354 = 0.038%입니다. 학습된 모델은 전체 카탈로그 랭킹에서 무작위보다 약 37배 우수합니다.

검증 Recall@10은 학습 중(에폭 142/150) 2.43%로 정점에 달했습니다 — 테스트 수치가 더 낮은 이유는 테스트 상호작용이 각 사용자의 학습 기록에서 가장 먼 미래의 상호작용이기 때문이며, 이는 본질적으로 더 어려운 예측입니다. 이 차이는 시간적 분할의 예상된 동작이지 버그가 아닙니다. 테스트 수치(1.40%)가 어디서든 인용되어야 하는 값입니다 — 검증은 학습 중 최상의 체크포인트를 선택하는 데만 사용되었으므로, 이를 최종 결과로 보고하는 것은 체리 피킹의 한 형태가 됩니다.

전체 학습 곡선: models/train_history.csv. 원시 결과: models/test_results.json.

5. MCP 도구 (mcp_server.py)

도구

설명

recommend_for_user(user_id, k)

상위 k개 개인화 추천, 사용자가 이미 상호작용한 아이템 제외

similar_items(item_id, k)

학습된 아이템 타워 임베딩을 통한 아이템 간 유사도

search_items(query_text, k)

아이템 제목에 대한 콜드 스타트 의미 검색 (MiniLM만 사용 — 협업 모델이 약한 신호를 가진 아이템에 유용)

explain_recommendation(user_id, item_id)

유사도 점수와 대상과 가장 유사한 사용자의 과거 아이템, 해석 가능성 제공

6. 프론트엔드 (streamlit_app.py)

weather-mcp-server와 같은 스타일의 채팅 UI: MCP 서버를 stdio를 통해 하위 프로세스로 실행하고, 도구 스키마를 가져와 Gemini 함수 호출 선언으로 변환한 뒤 에이전트 루프를 실행합니다 — Gemini는 사용자 메시지에 따라 4개 도구 중 어떤 것을 호출할지(또는 호출하지 않을지) 결정하고, 도구는 실제 학습된 모델에 대해 실행되며, 결과는 최종 자연어 응답을 위해 다시 전달됩니다. 사이드바에는 각 도구의 설명과 학습된 카탈로그의 실제 ID를 사용한 원클릭 예제, 그리고 모델의 평가 통계가 있는 확장 패널이 표시됩니다.

7. 로컬 실행

uv venv --python 3.11 .venv
uv pip install -p .venv/bin/python -r requirements.txt

# one-time: reproduce the trained model from scratch
.venv/bin/python src/data_prep.py                  # downloads + filters the dataset
.venv/bin/python src/precompute_text_embeddings.py
.venv/bin/python src/train.py                       # ~150 epochs, ~40s/epoch on an M2 CPU
.venv/bin/python src/evaluate.py                    # writes models/test_results.json
.venv/bin/python src/build_index.py                 # builds FAISS indices for serving

# run the MCP server standalone (stdio transport)
.venv/bin/python mcp_server.py

# or run the chat frontend (spawns the MCP server itself)
cp .streamlit/secrets.toml.example .streamlit/secrets.toml   # then fill in your key
.venv/bin/streamlit run streamlit_app.py

.streamlit/secrets.toml(또는 GEMINI_API_KEY 환경 변수)이 설정되지 않은 경우, 앱은 런타임에 사이드바에서 키를 요청하는 것으로 대체됩니다.

macOS 참고 사항

faisstorch는 macOS에서 OpenMP 런타임 초기화에 충돌하여, torch/numpyfaiss 이전에 KMP_DUPLICATE_LIB_OK=TRUEOMP_NUM_THREADS=1로 임포트되지 않으면 FAISS 검색 호출이 세그폴트됩니다. 둘 다 mcp_server.pysrc/build_index.py 내에서 이미 처리되어 있습니다.

8. Streamlit Community Cloud에 배포

  1. 이 저장소를 GitHub에 푸시합니다(공개 또는 비공개 — Community Cloud는 개인 계정의 경우 둘 다 배포할 수 있습니다).

  2. share.streamlit.io로 이동하여 New app을 클릭하고, 이 저장소를 streamlit_app.py를 진입점으로 지정합니다.

  3. 앱의 Settings → Secrets에서 다음을 추가합니다:

    GEMINI_API_KEY = "your_gemini_api_key_here"

    이는 로컬에서 .streamlit/secrets.toml이 사용하는 것과 동일한 메커니즘입니다 — 키는 Streamlit의 시크릿 저장소에만 존재하며, 저장소나 git 기록에는 절대 포함되지 않습니다. 앱이 자동으로 읽으므로 방문자가 키를 입력할 필요가 없습니다.

  4. 배포합니다. 첫 부팅은 MiniLM 모델을 다운로드하고 FAISS 인덱스를 로드하는 동안 느릴 수 있습니다(~1-2분). 이후 로드는 빠릅니다.

저장소 크기 참고 사항: models/(~110MB: 학습된 체크포인트 + FAISS 인덱스)는 배포된 앱이 콜드 스타트마다 재학습할 필요가 없도록 커밋되어 있습니다. data/raw/(~2.9GB의 원시 HuggingFace 다운로드)는 gitignore되어 있으며, 처음부터 학습을 재현하려는 경우에만 필요합니다.

9. 기술 스택

Python, PyTorch, FAISS, Sentence-Transformers (MiniLM), FastMCP, MCP Python SDK, Google Gemini API, Streamlit, pandas, HuggingFace datasets/huggingface_hub.

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    A pluggable, observable modular RAG service framework that exposes tool interfaces via the MCP protocol, enabling AI assistants like Copilot and Claude to directly invoke knowledge retrieval and reasoning capabilities.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Exposes RAG and document intelligence pipelines as 8 composable tools for MCP-compatible clients, enabling querying, indexing, classifying, extracting, and assessing documents.
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides RAG-based knowledge retrieval and document management as MCP tools, supporting hybrid search, reranking, and retrieval process visualization.
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to query documents in a Bedrock Knowledge Base through the MCP protocol, with tools for semantic search and agentic retrieval.
    MIT

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shreyaschhabra/two-tower-recsys-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server