two-tower-recsys-mcp
Two-Tower Recsys MCP — нейросетевой поиск, доступный через MCP
Глубокая модель рекомендаций с двумя башнями, обученная на собственном корпусе отзывов Amazon 2023 года, развернутая как сервер инструментов MCP (Model Context Protocol), с чат-интерфейсом на Streamlit, который позволяет агенту Gemini вызывать эти инструменты от вашего имени.
Этот README описывает весь конвейер от начала до конца: что представляет собой модель, как она обучалась, насколько хорошо она реально работает (измерено, а не оценено), как MCP-сервер ее предоставляет и как запустить или развернуть фронтенд.
1. Что это такое
Модели с двумя башнями — стандартная архитектура для крупномасштабных промышленных рекомендательных систем (этот паттерн — отдельные «башни», которые встраивают пользователя и товар в одно и то же векторное пространство, обучаясь так, чтобы релевантные пары оказывались близко друг к другу, — используется в продакшене YouTube, Pinterest и собственных системах поиска Amazon). Этот проект реализует такую модель с нуля, обучает ее на реальных данных взаимодействий Amazon и оборачивает для использования агентами через MCP вместо типичного REST API.
Почему MCP вместо REST API? MCP — это протокол, который Anthropic представила для подключения LLM-агентов к инструментам и данным. Обертывание обученной модели в виде MCP-инструментов (а не, скажем, конечной точки Flask) означает, что любой MCP-совместимый агент — Claude Desktop, собственный фронтенд этого проекта на Streamlit+Gemini или любой другой MCP-клиент — может напрямую вызывать recommend_for_user, similar_items и т.д., при этом LLM сама решает, когда и как их вызывать, на основе естественного языка.
Related MCP server: Modular RAG MCP Server
2. Архитектура
Башня пользователя: изученное встраивание ID пользователя (64-мерное) → 2-слойный MLP → 64-мерный выход.
Башня товара: изученное встраивание ID товара (64-мерное), объединенное с замороженным встраиванием предложения
all-MiniLM-L6-v2из названия товара (384-мерное, проецируемое в 64-мерное) → 2-слойный MLP → 64-мерный выход. Замороженное текстовое встраивание дает модели возможность холодного старта — она может разумно разместить товар в векторном пространстве даже без истории взаимодействий, только на основе его названия.Обе башни выдают L2-нормализованные векторы; сходство — это скалярное произведение (эквивалентно косинусному сходству).
Функция потерь при обучении: внутрипакетный семплированный softmax — для пакета из B положительных пар (пользователь, товар) каждый другой товар в пакете выступает отрицательным для каждого пользователя, и применяется кросс-энтропия к полученной матрице сходства B×B. Это стандартный, вычислительно эффективный способ обучения башен поиска без явного отрицательного сэмплирования.
Сервинг: встраивания товаров предвычисляются один раз и индексируются в FAISS (
IndexFlatIP) для быстрого поиска ближайших соседей. Второй индекс FAISS, построенный на сырых (необученных) встраиваниях MiniLM из названий, обеспечивает текстовый поиск с холодным стартом, который работает независимо от обученного коллаборативного сигнала.
┌────────────┐ ┌────────────┐
│ 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 score3. Набор данных
McAuley-Lab/Amazon-Reviews-2023 (лаборатория McAuley, UCSD), категория Video_Games — сырые отзывы + метаданные товаров, загруженные напрямую с HuggingFace.
Шаг | Количество |
Сырые отзывы | 4 624 615 |
Сырые пользователи / товары | 2 766 656 / 137 249 |
После 5-core фильтрации (пользователи и товары с ≥5 взаимодействиями) | 857 505 взаимодействий |
Пользователи / товары (после фильтрации) | 98 906 / 26 354 |
Взаимодействия Train / Valid / Test | 659 693 / 98 906 / 98 906 |
Протокол разбиения — leave-last-two-out для каждого пользователя, отсортировано по времени: самое последнее взаимодействие каждого пользователя → тест, второе с конца → валидация, остальные → обучение. Это временное разбиение, поэтому модель оценивается на предсказании действительно будущего поведения относительно того, на чем она обучалась, а не на случайно удержанных взаимодействиях (что привело бы к утечке будущей информации в обучение и завышению показателей).
4. Оценка (реальные, измеренные числа)
Оценка использует ранжирование по полному каталогу — каждый кандидат оценивается по всем 26 354 товарам, а не по небольшой выборке отрицательных примеров. Оценка с семплированными отрицательными примерами (распространенная в старых статьях по RecSys, например, ранжирование только по 99 случайным отрицательным) известна тем, что существенно завышает офлайн-метрики, поэтому здесь используется более сложный и честный протокол. Уже просмотренные пользователем товары исключаются из его собственного ранжирования кандидатов.
Тестовый набор — 98 906 пользователей, у каждого удержанное финальное взаимодействие:
Метрика | Значение |
Recall@10 | 1.40% |
NDCG@10 | 0.70% |
HitRate@10 | 1.40% (идентично Recall@10 при leave-one-out: ровно один релевантный товар на пользователя) |
Для контекста: случайный шанс в каталоге из 26 354 товаров при k=10 составляет 10/26 354 = 0.038%. Обученная модель примерно в 37 раз лучше случайной при ранжировании по полному каталогу.
Валидационный Recall@10 достиг пика 2.43% (эпоха 142/150) во время обучения — тестовое число ниже, потому что тестовое взаимодействие — это самое дальнее взаимодействие каждого пользователя в будущее относительно его обучающей истории, что по своей сути является более сложным предсказанием. Этот разрыв — ожидаемое поведение для временного разбиения, а не ошибка. Тестовое число (1.40%) — это то, которое следует цитировать где угодно — валидация использовалась только для выбора лучшей контрольной точки во время обучения, поэтому сообщение о ней как о финальном результате было бы формой подбора результатов.
Полная кривая обучения: models/train_history.csv. Сырые результаты: models/test_results.json.
5. MCP-инструменты (mcp_server.py)
Инструмент | Описание |
| Топ-k персонализированных рекомендаций, исключает товары, с которыми пользователь уже взаимодействовал |
| Сходство товар-товар через обученные встраивания башни товаров |
| Семантический поиск с холодным стартом по названиям товаров (только MiniLM — работает для товаров, по которым у коллаборативной модели слабый сигнал) |
| Оценка сходства плюс прошлые товары пользователя, наиболее похожие на целевой, для интерпретируемости |
6. Фронтенд (streamlit_app.py)
Чат-интерфейс в том же стиле, что и weather-mcp-server: он запускает 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
faiss и torch конфликтуют из-за инициализации OpenMP runtime на macOS, что вызывает segfault при вызовах поиска FAISS, если torch/numpy не импортированы до faiss, с установленными KMP_DUPLICATE_LIB_OK=TRUE и OMP_NUM_THREADS=1. Оба уже обработаны внутри mcp_server.py и src/build_index.py.
8. Развертывание на Streamlit Community Cloud
Запушьте этот репозиторий на GitHub (публичный или приватный — Community Cloud может развернуть оба для личного аккаунта).
Перейдите на share.streamlit.io, нажмите New app и укажите этот репозиторий с
streamlit_app.pyв качестве точки входа.В Settings → Secrets приложения добавьте:
GEMINI_API_KEY = "your_gemini_api_key_here"Это тот же механизм, что и
.streamlit/secrets.tomlлокально — ключ хранится только в хранилище секретов Streamlit, никогда в репозитории или истории git, и приложение читает его автоматически, так что посетителям никогда не нужно вводить ключ.Разверните. Первый запуск будет медленным (~1-2 мин), пока загружается модель MiniLM и индексы FAISS; последующие загрузки быстрые.
Примечание о размере репозитория: models/ (~110 МБ: обученная контрольная точка + индексы FAISS) включен в коммит, чтобы развернутому приложению не нужно было переобучаться при каждом холодном старте. data/raw/ (~2.9 ГБ сырых загрузок с HuggingFace) находится в .gitignore и нужен только если вы хотите воспроизвести обучение с нуля.
9. Технологический стек
Python, PyTorch, FAISS, Sentence-Transformers (MiniLM), FastMCP, MCP Python SDK, Google Gemini API, Streamlit, pandas, HuggingFace datasets/huggingface_hub.
This server cannot be deployed
Maintenance
Related MCP Connectors
Cloud or self-hosted knowledge for AI agents: hybrid search, reranking, GraphRAG, scoped MCP tools.
Real-time Amazon, WIPO & PACER data for AI agents — 19 tools via the MCP protocol.
- WauldoOAuthcom.wauldo
Stateless agentic tools over MCP: concept extraction, long-context, knowledge graph, planning.
- geoOAuthco.thinair
Geocoding, routing, isochrones, traffic, weather, and place search for AI agents. 19 MCP tools.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceProvides RAG-based knowledge retrieval and document management as MCP tools, supporting hybrid search, reranking, and retrieval process visualization.-
- AlicenseNot gradedqualityCmaintenanceA modular RAG framework exposing knowledge retrieval tools via MCP, enabling AI assistants to perform hybrid search, reranking, and multimodal document queries with full observability and evaluation.MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to perform retrieval-augmented generation with hybrid search, reranking, multi-modal image processing, and RAG evaluation through standardized MCP tools.MIT
- AlicenseNot gradedqualityBmaintenanceEnables agents to turn documents into vectors, perform approximate nearest neighbor search with HNSW, and filter by metadata via MCP tools for RAG workflows.MIT