MLOps and LLMOps: LLM apps

Sefism.

Chapter 01

From notebook to package

The shape of the whole lifecycle, the tools that fill each step, and how to turn notebook code into a tested, locked, containerised Python project that anyone can run.

The MLOps lifecycle

Also called ML lifecycle, MLOps loop, LLMOps

What
The loop a production model lives in: data is collected and validated, a model is trained and evaluated, approved and deployed, served to users, monitored, and retrained when it decays. LLMOps is the same loop where prompts, eval sets and model versions are the moving parts.
Why
Every tool and practice in this sheet exists to make one arrow in the loop repeatable. Knowing the loop tells you which gap is hurting your project right now.
Code
data -> validate -> train -> evaluate -> register
  ^                                          |
  |                                          v
retrain <- monitor <- serve <- deploy <- approve

Watch out

Treating deployment as the finish line: most of a model's cost and risk comes after it goes live.

Tool map per stage

Also called MLOps stack, MLOps tools

What
A reference of common open source tools for each step of the lifecycle. Pick one per row and learn it well; they are largely interchangeable once you understand the job each row does.
Why
Job adverts list tools, but the skill is the job behind them. A map keeps you from learning three orchestrators and no monitoring.
Code
Package      uv, pytest, Docker
Version      Git, DVC
Track        MLflow tracking and model registry
Orchestrate  Prefect, Airflow, Dagster
Serve        FastAPI, BentoML, vLLM
CI/CD        GitHub Actions, promptfoo
Monitor      Prometheus, Grafana, Evidently
Trace, eval  Langfuse, Arize Phoenix, MLflow

Watch out

Adopting a whole platform before you have one model in production that needs it.

Project layout and pyproject.toml

Also called src layout, pyproject, Python package

What
A repository where notebook code becomes importable modules under src/<package>/, with dependencies, entry points and tool settings declared in one pyproject.toml file. Notebooks stay for exploration and import from the package.
Why
Code in a package can be tested, reused by the training job and the API, and installed the same way on a laptop, in CI and in a container.
Example
src/churn/data.py loads and splits data, src/churn/features.py builds features, src/churn/train.py is the entry point, and tests/ mirrors them.

Watch out

Copying cells from a notebook into the serving code, so training and serving drift apart without anyone noticing.

Dependencies and lockfiles

Also called uv, uv.lock, pinned dependencies, virtual environment

What
A lockfile records the exact version of every package, including indirect ones, that your project resolved to. uv, a fast Python package and project manager, writes uv.lock and recreates the same environment anywhere with one command.
Why
A model trained with one version of a library can behave differently or fail to load with another. Locked environments make training runs and deployments repeatable.
Shell
uv init churn-model --package
cd churn-model
uv add scikit-learn pandas mlflow
uv add --dev pytest ruff
uv run pytest
git add pyproject.toml uv.lock

Watch out

Running pip install by hand on the server, so production has versions nobody wrote down.

Config and secrets

Also called environment variables, params.yaml, 12-factor config

What
Settings that change between runs or environments, such as paths, hyperparameters, model names and API keys, kept out of the code: parameters in a versioned config file, secrets in environment variables or a secrets manager.
Why
The same code can then train on a sample in CI and on full data in production, and no key ever lands in Git or a notebook output.

Watch out

Leaving an API key in a notebook cell that is later committed or shared.

An LLM client module

Also called model wrapper, LLM config, prompt version

What
One module that every feature calls instead of the provider SDK directly. It holds the model name, prompt version, timeouts and retries as config, so they can be changed, logged and tested in one place.
Why
When a model is deprecated, a price changes or a prompt regresses, you change one file and every call site follows, and every trace records exactly which version answered.
Python
from dataclasses import dataclass
from openai import OpenAI
@dataclass(frozen=True)
class LLMConfig:
    model: str
    prompt_version: str
    timeout_s: float = 30.0
def complete(cfg: LLMConfig, messages: list[dict]) -> str:
    client = OpenAI(timeout=cfg.timeout_s, max_retries=2)
    r = client.chat.completions.create(
        model=cfg.model, messages=messages, temperature=0)
    return r.choices[0].message.content

Watch out

Hard-coding model names and prompts in a dozen files, so nobody knows which version a user saw.

Tests for ML code

Also called pytest, unit tests, smoke test

What
Fast tests with pytest for the deterministic parts: feature functions, data loading, schemas and output shapes, plus a smoke test that trains on a tiny sample and checks predictions have the right type and range.
Why
Most production ML failures are ordinary bugs in data and feature code, not in the maths. Tests catch them before a long training run or a deploy.

Watch out

Testing that accuracy equals an exact number, which fails on every harmless change; test ranges and invariants instead.

Container image

Also called Dockerfile, Docker, image

What
A packaged file system with your code, a Python runtime and locked dependencies, built from a Dockerfile, that runs the same way on a laptop, in CI and in the cloud.
Why
Training jobs and model APIs both ship as images. It removes "works on my machine" and is what orchestrators and serving platforms expect.
Dockerfile
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev --no-install-project
COPY src ./src
RUN uv sync --frozen --no-dev
CMD ["uv", "run", "python", "-m", "churn.serve"]

Watch out

Copying the whole repository, including data and secrets, into the image.

01 · From notebook to package1 / 11