Here's a concise, professional technical briefing for the personalized-recommender-course repository, written in the style of a senior AI engineer consultant report.


The Problem

This repository delivers a hands-on course for building a real-time personalized recommender for H&M fashion articles. It spans feature engineering, two-tower neural network training, MLOps via Hopsworks, KServe deployment, and a Streamlit web interface. While the scope is broad and the educational value is clear, the codebase shows several structural and quality concerns that would need addressing before it could safely power a production system.

What This Does

The repository implements a 5-module FTI (Feature/Training/Inference) architecture using Hopsworks Feature Store, two-tower embedding models, and vector-based real-time inference. Core workflows are concentrated in recsys/training/two_tower.py (23 functions, 8 types), recsys/inference/llm_ranking_predictor.py (6 functions, 2 classes), and recsys/ui/recommenders.py (9 functions). Data flows through recsys/features/ for preprocessing, recsys/hopsworks_integration/ for store interaction, and recsys/ui/ for the Streamlit frontend. The system reads H&M raw data, computes features, trains user/item embeddings, registers models, and serves recommendations via a KServe-backed online pipeline.

How It Is Wired

Execution starts at streamlit_app.py:103 (main), which reaches 37 downstream functions. The internal call graph shows 137 resolved call edges. Key entry points and their callers:

  • get_feature_store – called from 4 places; participates in a circular import with recsys/hopsworks_integration/feature_store.py
  • predict – called from 4 places; invoked via llm_recommendations -> should_show_item x3
  • sample – called from 3 places; feeds compute_ranking_dataset
  • should_show_item – called from 3 places; called by llm_recommendations x3 and customer_recommendations x2
  • df_to_ds – called from 2 places; used by get_train_val_split
  • get_model – called from 2 places; feeds deploy -> get_model x2
  • track – called from 2 places; invoked by display_item x2 and display_llm_item x2

The most connected module is recsys/config (Ca=10, Ce=0, instability=0), followed by recsys/ui/recommenders (instability=0.8) and streamlit_app (instability=1, Ce=5). Two circular import cycles exist involving recsys/hopsworks_integration/__init__.py and recsys/hopsworks_integration/feature_store.py, which increases cognitive load when tracing dependencies.

The traced exit from the process goes through main -> customer_recommendations -> predict [model via self.llm.invoke], indicating the LLM-powered ranker makes an outbound model call. File I/O and network calls are limited but present: recsys/ui/utils.py opens files without a context manager, and several functions make network calls to Hopsworks.

How To Use It

Setup: This is a Python project. Install with pip install -e . or uv pip install -e . from the root, as pyproject.toml is present. No Dockerfile exists; local Python 3.x is the intended runtime.

Configuration: Environment variables and secrets are expected in .env.example. The .github/workflows/ml_pipelines.yaml workflow references secrets and has no permissions declaration and no timeout-minutes. The code-health audit confirms secret-shaped paths are present in assets/github_actions_secrets.png.

Running it: Start the Streamlit demo with streamlit run streamlit_app.py. The live demo is hosted at https://decodingml-hands-on-personalized-recommender.streamlit.app/ but runs in 0-cost mode, scaling to 0 instances during idle periods and requiring 1–2 minutes to warm on first interaction.

Real-World Use

This codebase is suited for learning, prototyping, and coursework. A practical scenario: a data science team clones the repo, populates the Hopsworks feature store with H&M interaction data, trains the two-tower model via the notebooks, and iterates on the LLM ranking logic in recsys/hopsworks_integration/llm_ranking_serving.py. The Streamlit app provides a quick UI for testing recommendations per user. Because no test suite exists, changes to feature engineering or model logic carry regression risk.

Code Health & Issues

The measured code health audit (5 findings, 0 critical) identifies:

  • [HIGH] No test suite; 32 source files have no corresponding test files. Any change ships with no signal that existing behavior holds.
  • [MEDIUM] Dependencies declared without a lockfile (pyproject.toml has no uv.lock or requirements.txt lock) – builds are non-reproducible across environments.
  • [MEDIUM] Broad exception handling in tools/clean_hopsworks_resources.py – bare except swallows errors indiscriminately.
  • [MEDIUM] Duplicate 6-line blocks across recsys/hopsworks_integration/llm_ranking_serving.py, ranking_serving.py, and two_tower_serving.py – 16 repeated blocks total.
  • [MEDIUM] Import cycle between recsys/hopsworks_integration/__init__.py and recsys/hopsworks_integration/feature_store.py.
  • [LOW] File opened without context manager in recsys/ui/utils.py – handle may leak on error.
  • [LOW] No Dependabot/Renovate configured; 2 manifest files exist but no update bot.
  • [LOW] No dependency vulnerability scan in CI; no dependency-review-action or osv-scanner gate.

Additional SDLC observations: no Dockerfile, no LICENSE committed (though one exists in the file structure), and GitHub Actions secrets are present in the repository tree.

The Bottom Line

This is a well-structured, educational repository that successfully walks through the lifecycle of building a real-time recommenderβ€”from feature engineering to KServe deployment. The FTI architecture is clear, the notebooks are practical, and the Streamlit demo provides immediate feedback. However, the absence of tests, a lockfile, and CI dependency scanning means it is not production-ready without remediation. Teams looking to learn the full stack of a modern recommender system will get significant value; teams needing battle-hardened reliability should budget time to add test coverage, lock dependencies, and break the import cycles before promoting any branch to production.


Report generated by static analysis pipeline. All counts, file paths, and code evidence are drawn from the repository structure and import graph as-is.