Python/FastAPI микросервис для семантического поиска квестов, рекомендаций квестов и рекомендаций пользователей в Become Overman.
Go Backend · API · Архитектура · Алгоритмы
BecomeOverman-RecommendationSystem — отдельный микросервис рекомендаций для проекта Become Overman.
Основной backend хранит пользователей, квесты, задачи, прогресс и игровую экономику. Этот сервис отвечает за ML-часть: переводит квесты и пользовательские профили в эмбеддинги, ищет семантически похожие квесты, строит персональные рекомендации и помогает находить пользователей с похожими интересами.
Проект связан с основным backend-репозиторием:
Полный текст дипломной работы доступен в backend-репозитории:
Поиск по квестам нельзя хорошо решить только через точное совпадение слов.
Например, запросы:
хочу стать более спортивным
бегать
физическая активность
прокачать здоровье
могут вести к похожим квестам, хотя формулировки разные. Поэтому сервис использует семантические эмбеддинги: он сравнивает не строки как набор токенов, а смысловые представления запросов, квестов и пользовательских профилей.
Такой подход лучше подходит под UX Become Overman: пользователь может описывать цель обычным языком, а система должна подобрать подходящие квесты.
- BM25 baseline для сравнения классического текстового поиска;
- semantic search на базе
sentence-transformers; - модель
paraphrase-multilingual-MiniLM-L12-v2; - FastAPI-сервис для интеграции с Go backend;
- загрузка модели при старте приложения;
- хранение эмбеддингов квестов и пользователей;
- SQLite-based storage для эмбеддингов;
- добавление квестов в индекс;
- добавление пользователей и построение user profile embedding;
- семантический поиск квестов по текстовому запросу;
- поиск похожих квестов;
- рекомендации квестов по истории пользователя;
- рекомендации пользователей по близости профилей;
- объяснения рекомендаций;
- синхронизация данных из PostgreSQL backend-сервиса;
- benchmark-эксперименты для сравнения подходов.
flowchart TD
A["Go Backend"] --> B["Recommendation API"]
B --> C["FastAPI routes"]
C --> D["SentenceTransformer model"]
C --> E["SQLite embedding storage"]
F["Quests"] --> G["Quest text: title + description + category"]
G --> H["Quest embeddings"]
H --> E
I["User quest history"] --> J["Mean pooling"]
J --> K["User profile embedding"]
K --> E
D --> L["Semantic quest search"]
D --> M["Similar quests"]
D --> N["Quest recommendations"]
D --> O["User recommendations"]
L --> P["Results with similarity_score"]
M --> P
N --> P
O --> P
В репозитории есть BM25-реализация для проверки классического текстового поиска:
title + description + category → tokenization → BM25Okapi → ranked results
BM25 хорошо работает, когда запрос и документ используют похожие слова. Но для Become Overman этого недостаточно: пользователь может описывать цель обычным языком, а не словами из названия квеста.
Основной подход — sentence-transformers:
query → embedding
quest title + description + category → embedding
cosine similarity → top-k quests
Модель:
paraphrase-multilingual-MiniLM-L12-v2
Она подходит для русскоязычных и смешанных запросов и позволяет находить квесты по смыслу, а не только по совпадению слов.
Для пользователя собирается список уже купленных или пройденных квестов. Их эмбеддинги усредняются:
user_profile_embedding = mean(user_quest_embeddings)
Затем сервис ищет квесты, близкие к этому профилю, исключая те, которые уже есть у пользователя.
Похожая логика используется для рекомендаций пользователей:
user profile embedding ↔ other user profile embeddings
Если профили близки, сервис возвращает потенциально похожих пользователей и объяснение причины рекомендации.
POST /api/quests/addДобавляет квесты в индекс и сохраняет их эмбеддинги.
POST /api/users/addСохраняет пользователей и строит profile embedding на основе их квестов.
POST /api/searchИщет квесты по текстовому запросу.
Пример сценария:
query: "хочу научиться концентрироваться"
→ похожие квесты про фокус, дисциплину и глубокую работу
POST /api/similarИщет квесты, похожие на выбранный квест.
POST /api/quests/recommendВозвращает персональные рекомендации на основе истории пользователя.
POST /api/users/recommendВозвращает пользователей с похожими профилями.
POST /sync-dbЗабирает квесты и пользовательские связи из PostgreSQL основного backend-сервиса, строит эмбеддинги и сохраняет их в локальное хранилище микросервиса.
| Область | Технологии |
|---|---|
| Язык | Python |
| API | FastAPI, Uvicorn |
| ML / NLP | sentence-transformers, PyTorch |
| Semantic model | paraphrase-multilingual-MiniLM-L12-v2 |
| Similarity | cosine similarity |
| Baseline search | BM25 |
| Storage | SQLite BLOB storage |
| Integration DB | PostgreSQL via psycopg2 |
| Data validation | Pydantic |
Основной backend вызывает recommendation service для трех задач:
- Search — пользователь ищет квесты естественным языком.
- Quest recommendations — пользователь получает персональные рекомендации.
- Friend recommendations — пользователь получает рекомендации похожих профилей.
Связанный репозиторий:
git clone https://github.com/Optoed/BecomeOverman-RecommendationSystem.git
cd BecomeOverman-RecommendationSystempython -m venv .venv
source .venv/bin/activate # Linux / macOS
# .venv\Scripts\activate # Windowspip install fastapi uvicorn sentence-transformers torch numpy pydantic psycopg2-binary tqdm rank-bm25Если в проект будет добавлен requirements.txt, лучше запускать так:
pip install -r requirements.txtuvicorn src.recommendation_bert_api.main:app --host 0.0.0.0 --port 8000 --reloadAPI будет доступен по адресу:
http://localhost:8000
В отличие от BM25, semantic search может находить релевантные квесты даже при разных формулировках.
Примеры запросов из тестового сценария:
дисциплина
бегать
утренние привычки
концентрация внимания
харизма и общение
контроль своих импульсов
хочу научиться находить друзей
стать более спортивным и активным
устал на работе — у меня выгорание
Такие запросы лучше подходят под реальный UX: пользователь описывает состояние или цель, а сервис подбирает подходящие квесты.
- добавить
requirements.txtи.env.example; - вынести PostgreSQL config из кода в переменные окружения;
- добавить Dockerfile и Docker Compose вместе с Go backend;
- унифицировать endpoint naming между сервисами;
- добавить полноценные benchmark-метрики: Precision@K, Recall@K, MRR, NDCG;
- добавить FAISS или pgvector для ускорения поиска на большом каталоге;
- добавить batch indexing и background jobs;
- покрыть API интеграционными тестами;
- добавить OpenAPI examples для запросов и ответов.
Проект выполнен в рамках дипломной работы студентом 4-ого курса СГУ КНиИТ Стеклянниковым Петром Сергеевичем.
MIT License.