<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kubeflow on lo0 — Tech Blog</title><link>https://blog.lo0.es/en/tags/kubeflow/</link><description>Recent content in Kubeflow on lo0 — Tech Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 31 Aug 2026 09:30:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/en/tags/kubeflow/index.xml" rel="self" type="application/rss+xml"/><item><title>Kubeflow in depth: which pieces are worth it in an on-premise LLM platform and which ones you already have</title><link>https://blog.lo0.es/en/posts/kubeflow-pieces-worth-it-on-premise-llm-platform/</link><pubDate>Mon, 31 Aug 2026 09:30:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/kubeflow-pieces-worth-it-on-premise-llm-platform/</guid><description>&lt;blockquote>
&lt;p>Second post in the platform and self-service run, after &lt;a href="https://blog.lo0.es/en/posts/backstage-self-service-portal-llm-platform/">Backstage&lt;/a> and before &lt;a href="https://blog.lo0.es/en/posts/knative-scale-to-zero-llm-inference/">Knative&lt;/a>. The question here is not what Kubeflow is, but which parts of Kubeflow still make sense once you have built half a platform on your own.&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Kubeflow graduated in the CNCF on 17 August 2026, and that headline hides the important one: it is no longer a monolithic platform, it is an umbrella of independent subprojects, each with its own repository, its own version and its own life. That changes how you have to evaluate it entirely. The 2020 question, should I install Kubeflow?, has become the 2026 one, which piece of Kubeflow do I install, and at what cost?&lt;/p>
&lt;p>For a platform that already has RKE2, vLLM, &lt;a href="https://blog.lo0.es/en/posts/kserve-open-inference-protocol-control-plane/">KServe&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/gitops-inference-stack-flux/">Flux&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/volcano-kueue-gang-scheduling-gpu-quotas-kubernetes/">Volcano or Kueue&lt;/a>, the honest answer is that Kubeflow as a whole &lt;strong>duplicates&lt;/strong> almost everything you already have. KServe no longer lives under Kubeflow: it left, and since November 2025 it has been a CNCF project in its own right, so anyone serving models with KServe does not need Kubeflow to serve. The Trainer leans on Volcano and Kueue, it does not replace them. And the full manifest drags in Istio, Dex and cert-manager as hard dependencies that clash with what you already operate. The only thing that may be worth installing on its own is Pipelines, as an orchestrator for data and training flows, and perhaps the Trainer for its fine-tuning templates. The rest you either already have, or do not need.&lt;/p>
&lt;h2 id="the-analogy-the-hypermarket-and-the-specialist-shop">The analogy: the hypermarket and the specialist shop&lt;/h2>
&lt;p>Kubeflow was born as a hypermarket: a single building with everything an ML team might need, from notebooks to the inference server, taking in pipelines and hyperparameter tuning along the way. It made sense in 2019, when assembling each piece separately was a project in itself and there were no standards.&lt;/p>
&lt;p>By 2026 the hypermarket has been converted into a street of specialist shops. The butcher&amp;rsquo;s counter, KServe, went independent, opened its own premises and is doing better alone. The fishmonger&amp;rsquo;s, the Trainer, now depends on the central market next door, Volcano and Kueue, instead of having its own cold store. And the shared building still demands that you put in its wiring, its plumbing and its security system (Istio, cert-manager, Dex) even though you already have your own.&lt;/p>
&lt;p>Anyone arriving today with a half-full fridge, which is the case for anyone with a platform already running, does not need the whole hypermarket. They need to know which shop to walk into for what they are missing, and to avoid buying twice what they already have at home.&lt;/p>
&lt;h2 id="what-kubeflow-is-in-2026">What Kubeflow is in 2026&lt;/h2>
&lt;p>Kubeflow was created by Google in 2017 and graduated in the CNCF on 17 August 2026, reaching the top level alongside Kubernetes or Prometheus. The graduation figures are serious: more than 6,600 contributors from over a thousand organisations, and adopters such as Bloomberg, NVIDIA, Red Hat or Spotify.&lt;/p>
&lt;p>The structural change is the one that matters for the decision. The full distribution, the &lt;em>Kubeflow Community Distribution&lt;/em>, is numbered by year and month (the current one is 26.03, from March 2026, on a six-monthly cadence), but &lt;strong>each component is by now a subproject with its own repository and its own cycle&lt;/strong>, usable independently. The distribution only packages them together. That means &amp;ldquo;installing Kubeflow&amp;rdquo; is no longer an atomic decision: it is a shopping list.&lt;/p>
&lt;h2 id="component-by-component">Component by component&lt;/h2>
&lt;h3 id="kubeflow-pipelines-the-piece-you-may-actually-want">Kubeflow Pipelines: the piece you may actually want&lt;/h3>
&lt;p>Pipelines orchestrates containerised ML workflows. They are written in Python with its SDK, which compiles to an intermediate YAML representation so they are portable, and underneath they run on &lt;strong>Argo Workflows&lt;/strong>. It is the piece most likely to add value to an existing platform: a flow of &amp;ldquo;ingest, embeddings, fine-tuning, evaluation, deployment&amp;rdquo; is exactly what you need to operate RAG and adapters repeatably.&lt;/p>
&lt;p>The small print has two parts. The first is that if you already use plain Argo Workflows, Pipelines adds a layer of SDK, interface and metadata &lt;strong>on top of the same engine&lt;/strong>: it does not bring a new scheduler, it brings the typed component model and the runs interface. The second is that its metadata and lineage system, MLMD, is &lt;strong>being removed&lt;/strong> from Pipelines itself, so it is not wise to build the platform&amp;rsquo;s traceability on that particular piece.&lt;/p>
&lt;h3 id="kubeflow-trainer-it-leans-on-your-scheduler-it-does-not-replace-it">Kubeflow Trainer: it leans on your scheduler, it does not replace it&lt;/h3>
&lt;p>The old Training Operator, the one with &lt;code>PyTorchJob&lt;/code> and &lt;code>TFJob&lt;/code>, has been rewritten as &lt;strong>Kubeflow Trainer&lt;/strong>, with a single &lt;code>TrainJob&lt;/code> API that unifies all frameworks. Version 2.2 positions itself explicitly for distributed training and &lt;strong>LLM fine-tuning&lt;/strong>, with support for PyTorch, DeepSpeed, HuggingFace and company.&lt;/p>
&lt;p>A common expectation needs correcting here. The Trainer &lt;strong>does not replace Volcano or Kueue&lt;/strong>: it leans on them. The &lt;code>TrainJob&lt;/code> carries a &lt;code>podGroupPolicy&lt;/code> field that automatically creates the Volcano &lt;code>PodGroup&lt;/code> objects for &lt;em>gang scheduling&lt;/em>, and it integrates with Kueue&amp;rsquo;s queues. If you already built that scheduler, as we saw in its post, the Trainer adds the &lt;code>TrainJob&lt;/code> abstraction and some fine-tuning templates on top of what you already have, not a new scheduling layer. It may be worth it for the templates; not for the scheduler.&lt;/p>
&lt;h3 id="katib-only-half-relevant">Katib: only half relevant&lt;/h3>
&lt;p>Katib does Kubernetes-native AutoML: hyperparameter optimisation with algorithms such as Bayesian optimisation, TPE or Hyperband, plus architecture search. In the LLM era it has repositioned itself, with official documentation for tuning fine-tuning hyperparameters and even for tuning RAG pipelines.&lt;/p>
&lt;p>The practical reading is lukewarm. Architecture search is irrelevant for anyone doing LoRA and RAG. Hyperparameter optimisation can be useful for learning-rate or LoRA-rank sweeps, but it competes with doing it from the SDK of the &lt;a href="https://blog.lo0.es/en/posts/qlora-runbook-dataset-to-served-adapter/">QLoRA runbook&lt;/a> itself or with Ray Tune, and it rarely justifies dragging in Katib for that alone.&lt;/p>
&lt;h3 id="kserve-the-piece-that-is-no-longer-in-kubeflow">KServe: the piece that is no longer in Kubeflow&lt;/h3>
&lt;p>This is the fact that settles half the evaluation. &lt;strong>KServe left Kubeflow.&lt;/strong> It was born inside the project in 2019, was donated to the Linux Foundation in 2022, was renamed from KFServing to KServe and graduated from Kubeflow that same year, and since November 2025 it has been a &lt;strong>CNCF incubating project in its own right&lt;/strong>. In the 2026 taxonomy it appears as an ecosystem project, external, not as a core component.&lt;/p>
&lt;p>The consequence is direct: &lt;strong>anyone already serving with KServe does not need Kubeflow to serve&lt;/strong>. And KServe is exactly where the LLM action is: its 0.15 release strengthened the vLLM backend and introduced an &lt;code>LLMInferenceService&lt;/code> resource with disaggregated serving, prefix caching, per-variant autoscaling and OpenAI-compatible APIs. If your serving layer is vLLM on KServe, you already have that layer complete and Kubeflow adds nothing to it.&lt;/p>
&lt;h3 id="model-registry-notebooks-and-the-rest">Model Registry, Notebooks and the rest&lt;/h3>
&lt;p>The &lt;strong>Model Registry&lt;/strong>, now reorganised under the name Kubeflow Hub, is an index of models, versions and metadata. It stores pointers and states, not the bytes. Against MLflow, it lacks the experiment and metric tracking that is MLflow&amp;rsquo;s strength, to the point that the guides recommend combining them rather than substituting one for the other; and against an OCI registry, it does not package the binary, which still lives wherever you put it. It is still a young component, below version 1.0.&lt;/p>
&lt;p>The &lt;strong>Notebooks&lt;/strong> live in two versions, the stable 1 and a 2 redesigned on CRDs that is still in alpha. The &lt;strong>Spark Operator&lt;/strong> remains in the core; &lt;strong>Feast&lt;/strong>, by contrast, has left the core and is now an ecosystem project, a nuance worth being clear about before counting on it.&lt;/p>
&lt;h3 id="multi-tenancy-powerful-and-tied-to-istio">Multi-tenancy: powerful and tied to Istio&lt;/h3>
&lt;p>Isolation between teams is done with &lt;strong>Profiles&lt;/strong>, a CRD that wraps a namespace and gives it RoleBindings, ServiceAccounts and Istio authorisation policies that validate an identity header derived from OIDC. It is a complete model, but it has an Achilles heel: &lt;strong>it depends entirely on the Istio sidecar and on that header&lt;/strong>. If traffic bypasses the mesh or someone forges the header, isolation breaks, and all multi-tenant security ends up coupled to Istio, which clashes head-on if you already operate another mesh or no &lt;em>service mesh&lt;/em> at all.&lt;/p>
&lt;h2 id="the-cost-of-installing-the-whole-thing">The cost of installing the whole thing&lt;/h2>
&lt;p>Here is the main reason not to install the full distribution on top of an existing platform. The 26.03 manifest drags in as &lt;strong>hard dependencies&lt;/strong>: Istio, cert-manager, Dex for OIDC, OAuth2-Proxy, and Knative Serving and Eventing for KServe. It recommends 16 GB of RAM and 8 vCPU as a minimum, and the aggregate of all components comes to around 4.4 CPU cores and 12 GB of memory for the control plane alone.&lt;/p>
&lt;p>The project itself acknowledges the problem. There is an open thread in its repository, bluntly titled &amp;ldquo;community feedback on Kubeflow&amp;rsquo;s complexity&amp;rdquo;, where it is admitted that Kubeflow practically forces a dedicated cluster because of the assumptions it makes about what is installed, that Istio and Dex should be swappable and not fixed dependencies, and that a lighter Helm that installs only what is needed is missing. For anyone already operating cert-manager, an ingress and GitOps with Flux, the full manifest does not coexist: it duplicates and tramples the base infrastructure.&lt;/p>
&lt;h2 id="kubeflow-against-the-alternatives">Kubeflow against the alternatives&lt;/h2>
&lt;p>The field is wide and almost all the comparative literature is written by vendors with a product of their own, so it has to be read with tweezers. With that caution:&lt;/p>
&lt;p>&lt;strong>Plain Argo Workflows&lt;/strong> is the engine Pipelines uses underneath; if all you need is container graphs, Pipelines is overhead. &lt;strong>MLflow&lt;/strong> is strong in experiment tracking and lightweight registry, installs in minutes, and does not orchestrate distributed training: it is complementary, and in fact we use it in the post on &lt;a href="https://blog.lo0.es/en/posts/prompt-versioning-contract-five-word-change/">prompt versioning&lt;/a>. &lt;strong>Flyte&lt;/strong> is a typed orchestrator that many perceive as lighter to operate than full Kubeflow. And &lt;strong>Ray on Kubernetes&lt;/strong> is the most serious competitor for LLM workloads, because with a single runtime it covers training, serving and tuning, overlapping at once with the Trainer, Katib and KServe.&lt;/p>
&lt;p>Where Kubeflow wins is in breadth and in governance: a CNCF-graduated umbrella with adoption by large companies. Where it loses is in operational weight, in hard dependencies, and in the fact that its best pieces are already independent projects that do not require the rest.&lt;/p>
&lt;h2 id="the-real-fit-with-llm-workloads">The real fit with LLM workloads&lt;/h2>
&lt;p>The project has moved towards GenAI, and that has to be acknowledged: there is an SDK with LLM fine-tuning templates, the Trainer adds support for reinforcement post-training methods, and new agent-oriented pieces have appeared. It is not empty marketing, there is real work there.&lt;/p>
&lt;p>But the question for a specific platform is not whether Kubeflow does LLM: it is which part I have not already duplicated. On a stack of RKE2, vLLM, KServe, Flux and Volcano or Kueue, the balance looks like this:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Component&lt;/th>
&lt;th>Does it add anything new to your stack?&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>KServe&lt;/td>
&lt;td>No: you already have it, and it is no longer Kubeflow&amp;rsquo;s&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Trainer&lt;/td>
&lt;td>Only the fine-tuning templates; you already have the scheduler&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Katib&lt;/td>
&lt;td>Marginal: LoRA HP sweeps, little more&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Pipelines&lt;/td>
&lt;td>Possibly yes, as a flow orchestrator, but it runs on Argo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Model Registry&lt;/td>
&lt;td>Optional: competes with MLflow and with your OCI registry&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Notebooks&lt;/td>
&lt;td>Depends on what you use for notebooks today&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Multi-tenancy&lt;/td>
&lt;td>No, if you already isolate by namespace without tying everything to Istio&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="operational-traps-and-honest-scepticism">Operational traps and honest scepticism&lt;/h2>
&lt;p>&lt;strong>Do not install the full manifest on a platform that already works.&lt;/strong> You are going to duplicate Istio, cert-manager and the rest, and fight a dependency war with no prize at the end. If something in Kubeflow interests you, install it as a standalone subproject.&lt;/p>
&lt;p>&lt;strong>KServe is not Kubeflow.&lt;/strong> It is the most common category error of 2026. If someone justifies building all of Kubeflow &amp;ldquo;to serve models&amp;rdquo;, you already know they have not checked that KServe left long ago and lives on its own.&lt;/p>
&lt;p>&lt;strong>The Trainer does not save you the scheduler.&lt;/strong> It needs Volcano or Kueue underneath. If you expected it to solve GPU &lt;em>gang scheduling&lt;/em> by itself, it does not.&lt;/p>
&lt;p>&lt;strong>Multi-tenancy ties you to Istio.&lt;/strong> Before adopting Profiles, ask yourself whether you want security between teams to depend on one specific mesh. If you already isolate well by namespace and RBAC, you may not need that layer.&lt;/p>
&lt;p>&lt;strong>MLMD is on its way out.&lt;/strong> Do not build your pipelines&amp;rsquo; traceability on the metadata system the project itself is retiring.&lt;/p>
&lt;h2 id="for-an-inference-factory">For an inference factory&lt;/h2>
&lt;p>The conclusion is comfortable to apply. Kubeflow in 2026 is not a yes-or-no decision, it is a menu you order from à la carte. On a platform that already serves with KServe, schedules with Volcano and deploys with Flux, the menu shrinks a great deal.&lt;/p>
&lt;p>If you need to orchestrate data and training flows repeatably, and you do not want to build plain Argo Workflows with its ergonomics, &lt;strong>Pipelines&lt;/strong> is the piece worth evaluating, installed standalone. If you do distributed fine-tuning frequently and want a uniform abstraction on top of your scheduler, the &lt;strong>Trainer&lt;/strong> may save you some templates, knowing that it leans on the Volcano you already have. Everything else you either have, or a specialist piece covers better.&lt;/p>
&lt;p>The expensive mistake would be installing the whole hypermarket to buy bread. Kubeflow stopped being that; treat it as what it is, a street of shops, and walk only into the one you are missing. The next piece in this run, &lt;a href="https://blog.lo0.es/en/posts/knative-scale-to-zero-llm-inference/">Knative&lt;/a>, is precisely one of those specialist shops, the one that decides whether switching off the GPU when nobody is using it pays off or costs you dear.&lt;/p>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/kserve-open-inference-protocol-control-plane/">KServe and the Open Inference Protocol&lt;/a> — the piece that left Kubeflow and holds up your serving.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/volcano-kueue-gang-scheduling-gpu-quotas-kubernetes/">Volcano and Kueue: gang scheduling and GPU quotas&lt;/a> — the scheduler the Trainer leans on.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/qlora-runbook-dataset-to-served-adapter/">QLoRA runbook: from dataset to served adapter&lt;/a> — the fine-tuning that Pipelines and Trainer orchestrate.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/en/posts/backstage-self-service-portal-llm-platform/">Backstage as a self-service portal&lt;/a> — the shop window that shows all this to the teams.&lt;/li>
&lt;/ul>
&lt;h2 id="sources">Sources&lt;/h2>
&lt;ul>
&lt;li>CNCF, &lt;em>CNCF announces Kubeflow&amp;rsquo;s graduation&lt;/em> — &lt;a href="https://www.cncf.io/announcements/2026/08/17/cncf-announces-kubeflows-graduation-solidifying-the-standard-for-cloud-native-ai-operations/">https://www.cncf.io/announcements/2026/08/17/cncf-announces-kubeflows-graduation-solidifying-the-standard-for-cloud-native-ai-operations/&lt;/a>&lt;/li>
&lt;li>CNCF, &lt;em>Kubeflow unveils new cloud native innovations to supercharge AI&lt;/em> — &lt;a href="https://www.cncf.io/blog/2026/07/28/kubeflow-unveils-new-cloud-native-innovations-to-supercharge-ai/">https://www.cncf.io/blog/2026/07/28/kubeflow-unveils-new-cloud-native-innovations-to-supercharge-ai/&lt;/a>&lt;/li>
&lt;li>CNCF, &lt;em>KServe becomes a CNCF incubating project&lt;/em> — &lt;a href="https://www.cncf.io/blog/2025/11/11/kserve-becomes-a-cncf-incubating-project/">https://www.cncf.io/blog/2025/11/11/kserve-becomes-a-cncf-incubating-project/&lt;/a>&lt;/li>
&lt;li>Kubeflow Docs, &lt;em>Introduction / components&lt;/em> — &lt;a href="https://www.kubeflow.org/docs/started/introduction/">https://www.kubeflow.org/docs/started/introduction/&lt;/a>&lt;/li>
&lt;li>Kubeflow Docs, &lt;em>Pipelines overview&lt;/em> — &lt;a href="https://www.kubeflow.org/docs/components/pipelines/overview/">https://www.kubeflow.org/docs/components/pipelines/overview/&lt;/a>&lt;/li>
&lt;li>Kubeflow Trainer Docs, &lt;em>Volcano gang scheduling and Kueue&lt;/em> — &lt;a href="https://trainer.kubeflow.org/en/latest/operator-guides/job-scheduling/volcano.html">https://trainer.kubeflow.org/en/latest/operator-guides/job-scheduling/volcano.html&lt;/a>&lt;/li>
&lt;li>Kubeflow Docs, &lt;em>Migrating to Kubeflow Trainer v2&lt;/em> — &lt;a href="https://www.kubeflow.org/docs/components/trainer/operator-guides/migration/">https://www.kubeflow.org/docs/components/trainer/operator-guides/migration/&lt;/a>&lt;/li>
&lt;li>Kubeflow Docs, &lt;em>Katib overview&lt;/em> — &lt;a href="https://www.kubeflow.org/docs/components/katib/overview/">https://www.kubeflow.org/docs/components/katib/overview/&lt;/a>&lt;/li>
&lt;li>Kubeflow Docs, &lt;em>Hyperparameter optimization for LLM fine-tuning&lt;/em> — &lt;a href="https://www.kubeflow.org/docs/components/katib/user-guides/llm-hp-optimization/">https://www.kubeflow.org/docs/components/katib/user-guides/llm-hp-optimization/&lt;/a>&lt;/li>
&lt;li>Kubeflow Docs, &lt;em>Model Registry overview&lt;/em> — &lt;a href="https://www.kubeflow.org/docs/components/model-registry/overview/">https://www.kubeflow.org/docs/components/model-registry/overview/&lt;/a>&lt;/li>
&lt;li>Kubeflow Docs, &lt;em>Multi-tenancy design&lt;/em> — &lt;a href="https://www.kubeflow.org/docs/concepts/multi-tenancy/design/">https://www.kubeflow.org/docs/concepts/multi-tenancy/design/&lt;/a>&lt;/li>
&lt;li>GitHub, &lt;em>kubeflow/manifests (dependencias y recursos)&lt;/em> — &lt;a href="https://github.com/kubeflow/manifests">https://github.com/kubeflow/manifests&lt;/a>&lt;/li>
&lt;li>GitHub, &lt;em>kubeflow/manifests #2451: community feedback on complexity&lt;/em> — &lt;a href="https://github.com/kubeflow/manifests/issues/2451">https://github.com/kubeflow/manifests/issues/2451&lt;/a>&lt;/li>
&lt;li>InfoQ, &lt;em>Kubeflow expands AI capabilities as CNCF graduation nears&lt;/em> — &lt;a href="https://www.infoq.com/news/2026/08/kubeflow/">https://www.infoq.com/news/2026/08/kubeflow/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>The OSS catalogue for LLMOps in six stages: tool by tool, what each one does and when to choose it</title><link>https://blog.lo0.es/en/posts/oss-catalogue-llmops-six-stages-tool-by-tool/</link><pubDate>Sat, 23 May 2026 07:30:00 +0200</pubDate><guid>https://blog.lo0.es/en/posts/oss-catalogue-llmops-six-stages-tool-by-tool/</guid><description>&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>For each of the six LLMOps stages (Data, Tune, Eval, Deploy, Observe, Retrain) and the two cross-cutting components (prompt + data versioning), the open source ecosystem has canonical pieces that this blog has been citing again and again. This post gathers them in one place with &lt;strong>cards of roughly 150 words per core tool&lt;/strong>: what it does, how it differs from the alternatives inside the same bucket, its &lt;strong>licence and governance model&lt;/strong>, and a typical gotcha that you only learn in production. Plus more alternatives as bullets, a &lt;strong>decision matrix per stage&lt;/strong> according to the case (small / large corpus, single tenant / multi-tenant…), a &lt;strong>diagram&lt;/strong> of the connected OSS stack and a &lt;strong>master table&lt;/strong> of licences / EE offerings. The intention: that the reader closes the post knowing what is available, which company maintains it, what gap each piece fills, and when to choose it. This is not opinion: it is a curated catalogue.&lt;/p>
&lt;h2 id="you-are-here-every-stage-but-by-oss-column">You are here: every stage, but by OSS column&lt;/h2>
&lt;p>This post shares a map with the two previous ones in the series, the six stages and the two cross-cutting pieces are all active, but it zooms in on the &lt;strong>open source column&lt;/strong>.&lt;/p>
&lt;div class="diagram" style="max-width:820px;margin:1rem auto;">
&lt;svg viewBox="0 0 820 220" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="OSS catalogue by LLMOps pipeline stage">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#ff8a4c;stroke-width:2}.cross{fill:#ffe9d6;stroke:#c66;stroke-width:1.4;rx:6}.lbl{font:600 12px sans-serif;fill:#222}.sm{font:11px sans-serif;fill:#333}.tiny{font:10px sans-serif;fill:#444}.oss{fill:#dfe9f5;stroke:#356}&lt;/style>
&lt;text x="410" y="20" text-anchor="middle" class="lbl">OSS catalogue: the consultant's toolbox by stage&lt;/text>
&lt;rect x="20" y="38" width="120" height="32" class="box active"/>&lt;text x="80" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="150" y="38" width="120" height="32" class="box active"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="38" width="120" height="32" class="box active"/>&lt;text x="340" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="410" y="38" width="120" height="32" class="box active"/>&lt;text x="470" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="540" y="38" width="120" height="32" class="box active"/>&lt;text x="600" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="670" y="38" width="120" height="32" class="box active"/>&lt;text x="730" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;rect x="20" y="88" width="120" height="78" class="box oss"/>
&lt;text x="80" y="103" text-anchor="middle" class="tiny">DVC · lakeFS&lt;/text>
&lt;text x="80" y="117" text-anchor="middle" class="tiny">MinIO · Ceph&lt;/text>
&lt;text x="80" y="131" text-anchor="middle" class="tiny">Qdrant · pgvector&lt;/text>
&lt;text x="80" y="145" text-anchor="middle" class="tiny">Kafka · Flink&lt;/text>
&lt;text x="80" y="159" text-anchor="middle" class="tiny">Debezium · Karapace&lt;/text>
&lt;rect x="150" y="88" width="120" height="78" class="box oss"/>
&lt;text x="210" y="103" text-anchor="middle" class="tiny">HF Transformers&lt;/text>
&lt;text x="210" y="117" text-anchor="middle" class="tiny">PEFT · bitsandbytes&lt;/text>
&lt;text x="210" y="131" text-anchor="middle" class="tiny">DeepSpeed · FSDP&lt;/text>
&lt;text x="210" y="145" text-anchor="middle" class="tiny">Axolotl · LLaMA-Factory&lt;/text>
&lt;text x="210" y="159" text-anchor="middle" class="tiny">Ray Train · MLflow&lt;/text>
&lt;rect x="280" y="88" width="120" height="78" class="box oss"/>
&lt;text x="340" y="103" text-anchor="middle" class="tiny">DeepEval · RAGAS&lt;/text>
&lt;text x="340" y="117" text-anchor="middle" class="tiny">Promptfoo&lt;/text>
&lt;text x="340" y="131" text-anchor="middle" class="tiny">lm-eval-harness&lt;/text>
&lt;text x="340" y="145" text-anchor="middle" class="tiny">NeMo Guardrails&lt;/text>
&lt;text x="340" y="159" text-anchor="middle" class="tiny">Presidio · LlamaGuard&lt;/text>
&lt;rect x="410" y="88" width="120" height="78" class="box oss"/>
&lt;text x="470" y="103" text-anchor="middle" class="tiny">vLLM · TGI · SGLang&lt;/text>
&lt;text x="470" y="117" text-anchor="middle" class="tiny">TensorRT-LLM&lt;/text>
&lt;text x="470" y="131" text-anchor="middle" class="tiny">llama.cpp · Triton&lt;/text>
&lt;text x="470" y="145" text-anchor="middle" class="tiny">KServe · KubeRay&lt;/text>
&lt;text x="470" y="159" text-anchor="middle" class="tiny">Envoy AI · LiteLLM&lt;/text>
&lt;rect x="540" y="88" width="120" height="78" class="box oss"/>
&lt;text x="600" y="103" text-anchor="middle" class="tiny">OpenTelemetry&lt;/text>
&lt;text x="600" y="117" text-anchor="middle" class="tiny">Tempo · Jaeger&lt;/text>
&lt;text x="600" y="131" text-anchor="middle" class="tiny">Prometheus · Loki&lt;/text>
&lt;text x="600" y="145" text-anchor="middle" class="tiny">Langfuse · Phoenix&lt;/text>
&lt;text x="600" y="159" text-anchor="middle" class="tiny">Tetragon · Evidently&lt;/text>
&lt;rect x="670" y="88" width="120" height="78" class="box oss"/>
&lt;text x="730" y="103" text-anchor="middle" class="tiny">Airflow · Prefect&lt;/text>
&lt;text x="730" y="117" text-anchor="middle" class="tiny">Dagster · Argo&lt;/text>
&lt;text x="730" y="131" text-anchor="middle" class="tiny">Kubeflow Pipelines&lt;/text>
&lt;text x="730" y="145" text-anchor="middle" class="tiny">Feast&lt;/text>
&lt;text x="730" y="159" text-anchor="middle" class="tiny">Argilla · Label Studio&lt;/text>
&lt;rect x="20" y="180" width="380" height="22" class="cross"/>
&lt;text x="210" y="195" text-anchor="middle" class="sm">Prompt versioning: Langfuse Prompts · MLflow Prompt Registry&lt;/text>
&lt;rect x="410" y="180" width="380" height="22" class="cross"/>
&lt;text x="600" y="195" text-anchor="middle" class="sm">Data versioning: DVC · lakeFS · OpenLineage · DataHub&lt;/text>
&lt;/svg>
&lt;/div>
&lt;h2 id="the-analogy-the-electricians-toolbox">The analogy: the electrician&amp;rsquo;s toolbox&lt;/h2>
&lt;p>A professional electrician arrives at an installation with a box organised into compartments. Nothing is improvised: for every type of cable there is a specific wire stripper, for every screw a screwdriver of the exact gauge, for every measurement a multimeter and a clamp meter, for every connection the right terminal block or connector. The difference between a professional electrician and a handyman is not that one knows more theory, the handyman has often read the manuals, it is that &lt;strong>the right tool is within arm&amp;rsquo;s reach and he knows when to use each one&lt;/strong>. The day the specific stripper is missing, improvising with a box cutter breaks the insulation, leaves a badly terminated cable, and the panel comes back under warranty two months later.&lt;/p>
&lt;p>The OSS LLMOps stack works the same way. For every canonical problem, versioning a dataset, indexing a corpus for retrieval, serving tokens with dynamic batching, propagating &lt;code>trace_id&lt;/code> end-to-end, managing prompts with a &lt;code>production&lt;/code> label, orchestrating retraining pipelines, there is a canonical piece of the open source ecosystem that solves it, maintained by a serious community or foundation, with a clear licence and a well documented gotcha. The consultant who knows which tool to use for each job builds a robust system in weeks; the one who improvises with &amp;ldquo;whatever the team already knows&amp;rdquo; pays later in operations, usually once the system is carrying real load and any replacement is expensive.&lt;/p>
&lt;p>This post opens the toolbox and shows each card. It is not a user manual, that is what the deep-dive posts linked at the end are for; it is the &lt;strong>curated catalogue&lt;/strong>.&lt;/p>
&lt;h2 id="diagram-of-the-connected-reference-oss-stack">Diagram of the connected reference OSS stack&lt;/h2>
&lt;p>The catalogue makes sense once you see how the pieces connect into a single coherent architecture, the one this blog has been describing throughout the series. The boxes do not float; they talk to each other over stable contracts (HTTP, gRPC, OTel, Kafka, S3/MinIO API).&lt;/p>
&lt;div class="diagram" style="max-width:820px;margin:1rem auto;">
&lt;svg viewBox="0 0 820 460" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="reference OSS LLMOps stack with connected boxes">
&lt;style>.b{stroke:#333;stroke-width:1.4;rx:6;fill:#eef2f7}.serv{fill:#ff8a4c;stroke:#a44}.data{fill:#dfe9f5;stroke:#356}.obs{fill:#d8eecf;stroke:#373}.ctrl{fill:#f5e3d8;stroke:#763}.bg{fill:#fafafa;stroke:#ccc;rx:8}.lbl{font:600 12px sans-serif;fill:#222}.sm{font:11px sans-serif;fill:#222}.tiny{font:600 10px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#a)}.otel{stroke:#1a73e8;stroke-width:1.4;fill:none;stroke-dasharray:3 2;marker-end:url(#ab)}&lt;/style>
&lt;defs>&lt;marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#666"/>&lt;/marker>&lt;marker id="ab" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="#1a73e8"/>&lt;/marker>&lt;/defs>
&lt;text x="410" y="20" text-anchor="middle" class="lbl">Connected OSS LLMOps stack: serving, data, observability and control plane&lt;/text>
&lt;rect x="20" y="40" width="780" height="80" class="b bg"/>
&lt;text x="30" y="58" class="tiny">SERVING PLANE&lt;/text>
&lt;rect x="40" y="68" width="120" height="40" class="b serv"/>&lt;text x="100" y="93" text-anchor="middle" class="sm">Envoy AI Gateway&lt;/text>
&lt;rect x="180" y="68" width="120" height="40" class="b serv"/>&lt;text x="240" y="93" text-anchor="middle" class="sm">vLLM (LoRA hot-swap)&lt;/text>
&lt;rect x="320" y="68" width="120" height="40" class="b serv"/>&lt;text x="380" y="93" text-anchor="middle" class="sm">KServe / Operator&lt;/text>
&lt;rect x="460" y="68" width="120" height="40" class="b serv"/>&lt;text x="520" y="93" text-anchor="middle" class="sm">Triton (multi-model)&lt;/text>
&lt;rect x="600" y="68" width="180" height="40" class="b serv"/>&lt;text x="690" y="93" text-anchor="middle" class="sm">Kubernetes (RKE2 + Cilium)&lt;/text>
&lt;path class="arr" d="M160,88 L180,88"/>&lt;path class="arr" d="M300,88 L320,88"/>
&lt;rect x="20" y="140" width="380" height="170" class="b bg"/>
&lt;text x="30" y="158" class="tiny">DATA PLANE&lt;/text>
&lt;rect x="40" y="168" width="160" height="36" class="b data"/>&lt;text x="120" y="190" text-anchor="middle" class="sm">PostgreSQL + pgvector&lt;/text>
&lt;rect x="220" y="168" width="160" height="36" class="b data"/>&lt;text x="300" y="190" text-anchor="middle" class="sm">Qdrant (RAG)&lt;/text>
&lt;rect x="40" y="214" width="160" height="36" class="b data"/>&lt;text x="120" y="236" text-anchor="middle" class="sm">MinIO / Ceph (S3)&lt;/text>
&lt;rect x="220" y="214" width="160" height="36" class="b data"/>&lt;text x="300" y="236" text-anchor="middle" class="sm">Kafka + Debezium&lt;/text>
&lt;rect x="40" y="260" width="160" height="36" class="b data"/>&lt;text x="120" y="282" text-anchor="middle" class="sm">DVC + lakeFS&lt;/text>
&lt;rect x="220" y="260" width="160" height="36" class="b data"/>&lt;text x="300" y="282" text-anchor="middle" class="sm">Flink / Spark&lt;/text>
&lt;path class="arr" d="M380,186 L460,186 L460,88 L460,108"/>
&lt;rect x="420" y="140" width="380" height="170" class="b bg"/>
&lt;text x="430" y="158" class="tiny">OBSERVABILITY PLANE&lt;/text>
&lt;rect x="440" y="168" width="160" height="36" class="b obs"/>&lt;text x="520" y="190" text-anchor="middle" class="sm">OTel Collector&lt;/text>
&lt;rect x="620" y="168" width="160" height="36" class="b obs"/>&lt;text x="700" y="190" text-anchor="middle" class="sm">Langfuse&lt;/text>
&lt;rect x="440" y="214" width="160" height="36" class="b obs"/>&lt;text x="520" y="236" text-anchor="middle" class="sm">Tempo (traces)&lt;/text>
&lt;rect x="620" y="214" width="160" height="36" class="b obs"/>&lt;text x="700" y="236" text-anchor="middle" class="sm">Phoenix Arize OSS&lt;/text>
&lt;rect x="440" y="260" width="160" height="36" class="b obs"/>&lt;text x="520" y="282" text-anchor="middle" class="sm">Prometheus + Grafana&lt;/text>
&lt;rect x="620" y="260" width="160" height="36" class="b obs"/>&lt;text x="700" y="282" text-anchor="middle" class="sm">Loki + Tetragon&lt;/text>
&lt;path class="otel" d="M240,108 L240,130 L460,130 L460,168"/>
&lt;text x="350" y="146" class="tiny" fill="#1a73e8">OTel spans (gen_ai.*)&lt;/text>
&lt;rect x="20" y="330" width="780" height="110" class="b bg"/>
&lt;text x="30" y="348" class="tiny">CONTROL PLANE (Tune + Eval + Retrain + Prompt versioning)&lt;/text>
&lt;rect x="40" y="358" width="140" height="36" class="b ctrl"/>&lt;text x="110" y="380" text-anchor="middle" class="sm">Axolotl + PEFT&lt;/text>
&lt;rect x="200" y="358" width="140" height="36" class="b ctrl"/>&lt;text x="270" y="380" text-anchor="middle" class="sm">MLflow Tracking&lt;/text>
&lt;rect x="360" y="358" width="140" height="36" class="b ctrl"/>&lt;text x="430" y="380" text-anchor="middle" class="sm">Promptfoo + RAGAS&lt;/text>
&lt;rect x="520" y="358" width="140" height="36" class="b ctrl"/>&lt;text x="590" y="380" text-anchor="middle" class="sm">Argo / Kubeflow Pipelines&lt;/text>
&lt;rect x="680" y="358" width="100" height="36" class="b ctrl"/>&lt;text x="730" y="380" text-anchor="middle" class="sm">Argilla&lt;/text>
&lt;rect x="40" y="402" width="140" height="30" class="b ctrl"/>&lt;text x="110" y="420" text-anchor="middle" class="sm">Langfuse Prompts&lt;/text>
&lt;rect x="200" y="402" width="140" height="30" class="b ctrl"/>&lt;text x="270" y="420" text-anchor="middle" class="sm">Feast&lt;/text>
&lt;rect x="360" y="402" width="140" height="30" class="b ctrl"/>&lt;text x="430" y="420" text-anchor="middle" class="sm">NeMo Guardrails&lt;/text>
&lt;rect x="520" y="402" width="140" height="30" class="b ctrl"/>&lt;text x="590" y="420" text-anchor="middle" class="sm">OpenLineage + DataHub&lt;/text>
&lt;rect x="680" y="402" width="100" height="30" class="b ctrl"/>&lt;text x="730" y="420" text-anchor="middle" class="sm">Presidio&lt;/text>
&lt;path class="arr" d="M110,358 L110,300 L110,300"/>&lt;path class="arr" d="M110,300 L110,260 L120,260"/>
&lt;/svg>
&lt;/div>
&lt;p>Solid arrows mark data / control flow; the dashed blue ones are OTel traces. The K8s plane holds everything up. The control plane at the bottom is where the retraining pipelines, the evals in CI, the versioned prompts and the lineage live. The data plane on the left feeds both the serving side (RAG, configs) and the control plane (datasets, lineage). The observability plane receives from serving and from everything else.&lt;/p>
&lt;p>Now we go stage by stage. Each one opens with a context paragraph, then cards for the core tools (about 150 words each), bullets with relevant alternatives, and a specific decision matrix at the end.&lt;/p>
&lt;h2 id="stage-1--data--cross-cutting-data-versioning">Stage 1 — Data + cross-cutting Data versioning&lt;/h2>
&lt;p>The Data stage solves three distinct problems that beginners confuse: &lt;strong>versioning&lt;/strong> datasets (so that &lt;code>(dataset_id, version, hash)&lt;/code> exists and propagates), &lt;strong>storing and serving&lt;/strong> the operational corpus (object store + vector index + structured text), and &lt;strong>moving it&lt;/strong> between systems with CDC and stable schemas. Covered in detail in the posts on &lt;a href="https://blog.lo0.es/en/posts/data-versioning-llmops-dvc-lakefs-reproducible-golden-dataset/">data versioning with DVC and lakeFS&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/postgresql-qdrant-rag-ingestion-postman-syncing-two-worlds/">PostgreSQL + Qdrant in ingestion&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/rag-on-kafka-reference-architecture-streaming-datalakes/">RAG over Kafka&lt;/a>.&lt;/p>
&lt;h3 id="dvc-data-version-control">DVC (Data Version Control)&lt;/h3>
&lt;p>DVC puts datasets under version control with the same discipline that git applies to code. The &lt;code>.dvc&lt;/code> pointers live in git (plain text, about 200 bytes per dataset), the bulk content lives in a remote object store (S3, MinIO, Azure Blob, GCS). Each &lt;code>dvc add&lt;/code> computes a SHA-256 hash of the dataset, uploads it to the remote and stores the pointer. The key line: the &lt;code>dataset_hash&lt;/code> becomes the luggage tag that travels to the trainer, to experiment tracking and to lineage. The same dataset retrained twice produces the same hash, and therefore reproducible experiments. DVC integrates with MLflow and W&amp;amp;B as an input artefact. &lt;strong>Gotcha:&lt;/strong> it works well for datasets that change by replacement (I swap &lt;code>train.jsonl&lt;/code> for a new version) and worse for datasets with thousands of small files that change individually. For that case, combine it with lakeFS. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Iterative.ai&lt;/strong> since 2017. There is DVC Studio (managed) and &lt;code>dvc data&lt;/code> (pure CLI) on different planes.&lt;/p>
&lt;h3 id="lakefs">lakeFS&lt;/h3>
&lt;p>lakeFS brings git semantics (branch, commit, merge, rollback) to an entire S3/MinIO/ADLS bucket. Where DVC versions individual files as pointers in git, lakeFS versions &lt;strong>the whole bucket&lt;/strong>: you can branch the corpus, ingest new data into the branch, validate that it passes checks (recall@10 over golden queries for embeddings, completeness for a tabular corpus), and only then merge into &lt;code>main&lt;/code>. It is the piece that makes continuous RAG safe: the production corpus is always on &lt;code>main&lt;/code>, updates are tested on branches. It offers hooks (pre-merge, pre-commit) that fire automatic validations, and time-travel to reproduce the state of the bucket at a past date. &lt;strong>Gotcha:&lt;/strong> the manifest overhead on huge buckets (hundreds of millions of objects) deserves sizing; lakeFS keeps metadata in its own Postgres, not in the bucket. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Treeverse&lt;/strong> since 2020. Managed offering: &lt;strong>lakeFS Cloud&lt;/strong>.&lt;/p>
&lt;h3 id="minio">MinIO&lt;/h3>
&lt;p>MinIO is the S3-compatible object store that fills the &amp;ldquo;S3 on-premise&amp;rdquo; gap without surprises. API identical to S3 (the AWS SDKs work by pointing them at a different endpoint), its own CLI client (&lt;code>mc&lt;/code>), erasure-coded mode for fault tolerance, bucket-to-bucket replication, encryption at rest. It is the base on which the other data plane components are built: DVC remote, lakeFS underlying storage, Postgres snapshots, MLflow artefacts, eval datasets, saved models, distributed KV cache fabric. In small deployments it runs single-node multi-disk; in serious ones, distributed clusters. &lt;strong>Gotcha:&lt;/strong> the licence changed to &lt;strong>AGPLv3&lt;/strong> in 2021 (it was Apache 2.0 before), which means distributing software connected to MinIO obliges you to open the code that connects to it. For internal on-premise use this is not a problem; for a vendor packaging MinIO inside a commercial product, it is. Maintained by &lt;strong>MinIO Inc.&lt;/strong> with a SUBNET enterprise offering and a community fork called &lt;strong>AIStor&lt;/strong> launched in 2025.&lt;/p>
&lt;h3 id="qdrant">Qdrant&lt;/h3>
&lt;p>Qdrant is the OSS vector database most aligned with this blog&amp;rsquo;s &amp;ldquo;RAG corpus per tenant with strict ACLs&amp;rdquo; pattern. Written in Rust, it exposes a REST + gRPC API, indexes with HNSW + scalar/binary quantisation to cut memory, supports efficient payload filtering (it is not post-filtering: it integrates the filter into the HNSW search), and allows collections isolated per tenant. For the &lt;a href="https://blog.lo0.es/en/posts/anatomy-llm-request-production-tour-six-stages/">multi-tenant chatbot&lt;/a> scenario, Qdrant is where the &lt;code>tenant_&amp;lt;id&amp;gt;_kb_v3&lt;/code> collections with strict ACL live. It scales well horizontally (sharding by payload) and vertically (millions of chunks on a node with 64GB RAM). &lt;strong>Gotcha:&lt;/strong> binary quantisation is aggressive, it cuts VRAM by 32× but degrades recall by 10-20 %; enabling it without re-tuning the threshold breaks retrieval silently. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Qdrant Solutions GmbH&lt;/strong> (Germany). There is Qdrant Cloud (managed) and EU-only support for ENS cases.&lt;/p>
&lt;h3 id="postgresql--pgvector">PostgreSQL + pgvector&lt;/h3>
&lt;p>Postgres 18 with the &lt;code>pgvector&lt;/code> extension is the stack&amp;rsquo;s &amp;ldquo;hidden vector database&amp;rdquo;: when the corpus is small (under a million embeddings) and Postgres is already in production for operational data, running a separate Qdrant is expensive operations. pgvector adds a &lt;code>vector(dim)&lt;/code> type, HNSW and IVF indexes, and the operators &lt;code>&amp;lt;-&amp;gt;&lt;/code>, &lt;code>&amp;lt;#&amp;gt;&lt;/code>, &lt;code>&amp;lt;=&amp;gt;&lt;/code> for cosine, L2 and dot product. Combined with &lt;code>tsvector&lt;/code> (Postgres full-text search) it allows &lt;strong>hybrid search&lt;/strong>, dense + sparse, in a single SQL query. Version 0.8 (2025) introduced halfvec and bit support to reduce size by 4×-8×. &lt;strong>Gotcha:&lt;/strong> HNSW in pgvector consumes a fair amount of RAM to build the index (roughly 2× the size of the embeddings) and blocks inserts during the build; in production you build on a secondary, promote it, and discard the primary. Licence &lt;strong>PostgreSQL License&lt;/strong> (permissive BSD-style) for both the core and pgvector. Maintained by the &lt;strong>PostgreSQL Development Group&lt;/strong> plus pgvector by &lt;strong>Andrew Kane&lt;/strong> + Crunchy Data + Neon.&lt;/p>
&lt;h3 id="apache-kafka--debezium">Apache Kafka + Debezium&lt;/h3>
&lt;p>Kafka is the event bus where &amp;ldquo;everything that happens in the company is a stream&amp;rdquo; becomes real. For LLMOps in production it serves two functions: &lt;strong>CDC from source systems&lt;/strong> (Debezium captures changes in Postgres / MySQL / MongoDB and publishes them as topics) and &lt;strong>LLM event buffer&lt;/strong> (every request, every piece of feedback, every eval result ends up in a topic with the &lt;code>trace_id&lt;/code> propagated). As the &lt;a href="https://blog.lo0.es/en/posts/rag-on-kafka-reference-architecture-streaming-datalakes/">post on RAG over Kafka&lt;/a> explains, the RAG corpus is kept fresh by capturing changes from the CMS / source system as CDC, running the embedding in Flink streaming, and ingesting into Qdrant continuously. &lt;strong>Gotcha:&lt;/strong> a badly sized Kafka with long retention plus multi-client topics turns into a fast disk sink; measuring throughput per topic and key cardinality before production is mandatory. Kafka licence &lt;strong>Apache 2.0&lt;/strong> (&lt;strong>ASF&lt;/strong> project); Debezium &lt;strong>Apache 2.0&lt;/strong> (project incubated by &lt;strong>Red Hat&lt;/strong>). Kafka-compatible drop-in alternative: &lt;strong>Redpanda&lt;/strong> (BSL, restricted commercial use).&lt;/p>
&lt;h3 id="apache-flink-brief-mention">Apache Flink (brief mention)&lt;/h3>
&lt;p>Flink processes streams with sub-second latency and exactly-once semantics. On the LLM plane it is used to: run embeddings in streaming (over CDC topics), aggregate online metrics, materialise features for retraining. Licence Apache 2.0, ASF. Common alternative: &lt;strong>Spark Structured Streaming&lt;/strong> (also ASF, micro-batch latency).&lt;/p>
&lt;p>&lt;strong>More options for Data&lt;/strong>, mentioned on the blog:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Ceph&lt;/strong> — object store for large clusters with geo-distributed replication. LGPL/Apache licence, &lt;strong>Red Hat / IBM&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Milvus&lt;/strong> — C++ vector database, an alternative to Qdrant; better for corpora of billions. Apache 2.0, &lt;strong>Zilliz&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Karapace&lt;/strong> — Confluent-compatible OSS Schema Registry. Apache 2.0, &lt;strong>Aiven&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>DataHub / Apache Atlas / OpenMetadata&lt;/strong> — catalogue + lineage. Apache 2.0, &lt;strong>Acryl Data / ASF / Collate&lt;/strong> respectively.&lt;/li>
&lt;li>&lt;strong>OpenLineage&lt;/strong> — cross-system lineage event standard. Apache 2.0, &lt;strong>Linux Foundation AI&amp;amp;Data&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Decision matrix — Data:&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>If your case is&lt;/th>
&lt;th>Choose&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Corpus &amp;lt; 1M embeddings, you already have Postgres&lt;/td>
&lt;td>&lt;strong>pgvector&lt;/strong> (one component fewer)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Corpus 1M-100M, multi-tenant with ACL&lt;/td>
&lt;td>&lt;strong>Qdrant&lt;/strong> (integrated filtering, ACLs per collection)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Corpus &amp;gt; 100M, aggressive sharding&lt;/td>
&lt;td>&lt;strong>Milvus&lt;/strong> (scales linearly better into the billions)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Training datasets + experiment tracking&lt;/td>
&lt;td>&lt;strong>DVC&lt;/strong> over MinIO + MLflow integration&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>RAG corpus with controlled releases&lt;/td>
&lt;td>&lt;strong>lakeFS&lt;/strong> over MinIO + pre-merge hooks&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>You want both&lt;/td>
&lt;td>&lt;strong>DVC + lakeFS&lt;/strong> as complements (the blog&amp;rsquo;s recommendation)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="stage-2--tune">Stage 2 — Tune&lt;/h2>
&lt;p>The Tune stage produces a new &lt;code>model_id, model_version&lt;/code>, typically a LoRA adapter over a stable base, with lineage back to the dataset and experiment tracking to reproduce it. Detail in the &lt;a href="https://blog.lo0.es/en/posts/continuous-fine-tuning-production-real-traffic-deployed-adapter/">post on continuous fine-tuning&lt;/a>.&lt;/p>
&lt;h3 id="huggingface-transformers--peft">HuggingFace Transformers + PEFT&lt;/h3>
&lt;p>&lt;code>transformers&lt;/code> is the canonical library for loading and training models of the decoder-only family (Llama, Mistral, Qwen, Gemma…) and encoder-decoder. &lt;code>peft&lt;/code> (Parameter-Efficient Fine-Tuning) is the complement that adds declarative support for LoRA, QLoRA, IA3 and assorted adapters. Together they form the &lt;strong>mandatory core&lt;/strong> of the OSS Tune stack: any higher-level framework (Axolotl, LLaMA-Factory) uses them underneath. PEFT allows you to train an adapter of about 280 MB (order of magnitude) instead of a full model of about 140 GB, with a functionally equivalent result on most style / domain adjustment tasks. &lt;strong>Gotcha:&lt;/strong> PEFT with a badly configured &lt;code>target_modules&lt;/code> trains an adapter that covers only Q and V of the attention, leaving out key, output proj and MLP. The result looks trained but performs poorly; adding &lt;code>target_modules=[&amp;quot;all-linear&amp;quot;]&lt;/code> fixes it (at the cost of a larger adapter). Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Hugging Face SAS&lt;/strong> (a French company); open governance model with active external maintainers.&lt;/p>
&lt;h3 id="bitsandbytes">bitsandbytes&lt;/h3>
&lt;p>bitsandbytes implements weight quantisation to 8-bit and 4-bit with NF4 for models loaded with &lt;code>transformers&lt;/code>. It reduces the 140 GB of Llama 3 70B FP16 to about 40 GB in NF4, allowing QLoRA training on a single H100 80GB. The trick is that the weights stay quantised in memory while the sensitive computations (attention, gradient updates in the adapter) are done in FP16/BF16 with on-the-fly dequantisation. Ideal for fine-tuning on limited hardware and for serving with vLLM when you want to cut VRAM. &lt;strong>Gotcha:&lt;/strong> NF4 quantisation is lossy; on small models (&amp;lt; 7B) the quality degradation is noticeable. For production serving of models under 7B, INT8 is preferred (more memory, less loss) or FP8 if the hardware supports it (the H100 does). Licence &lt;strong>MIT&lt;/strong>, maintained by &lt;strong>Tim Dettmers&lt;/strong> (originally at U. Washington, now with support from Anthropic and HuggingFace).&lt;/p>
&lt;h3 id="mlflow-tracking">MLflow Tracking&lt;/h3>
&lt;p>MLflow is the reference OSS experiment tracking tool: each trainer run records parameters (lr, batch size, epochs, target_modules), metrics (loss curves, eval scores), artefacts (model, tokeniser, configs) and, crucially, &lt;strong>input artefacts&lt;/strong> (dataset_id, dataset_hash, parent_run). The model registry associates each &lt;code>model_version&lt;/code> with a reproducible &lt;code>run_id&lt;/code>. The line of continuity between Tune and Deploy passes through here: the deployment reads the model to serve from the registry, with its lineage made explicit. MLflow 2.x integrates &lt;strong>MLflow Prompts&lt;/strong> (prompt registry) and &lt;strong>MLflow Tracing&lt;/strong> (OTel-compatible spans), cutting the number of components needed. &lt;strong>Gotcha:&lt;/strong> the default backend store is SQLite, which works for personal experiments and breaks on a shared cluster. In production: Postgres as the backend store + MinIO/S3 as the artefact store. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>LF AI &amp;amp; Data&lt;/strong> (donated by Databricks in 2020).&lt;/p>
&lt;h3 id="axolotl">Axolotl&lt;/h3>
&lt;p>Axolotl wraps &lt;code>transformers + PEFT + bitsandbytes + DeepSpeed + FSDP&lt;/code> in a declarative YAML configuration: instead of writing a script of about 300 lines to configure a fine-tuning run, you define a &lt;code>config.yml&lt;/code> with base model, dataset path, LoRA config and training hyperparameters, and run it in one line. It supports Llama, Mistral, Qwen, Gemma, Phi… loads. It keeps compatibility with the HuggingFace Hub to download models and datasets, and with MLflow / W&amp;amp;B for tracking. It is the convenience framework this blog cites when it talks about &amp;ldquo;productive fine-tuning without reinventing the wheel&amp;rdquo;. &lt;strong>Gotcha:&lt;/strong> the pace of change in the community is fast; a &lt;code>config.yml&lt;/code> that worked six months ago can break with a current version because of internal refactors. Pinning the exact Axolotl version in the environment mitigates this. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by the &lt;strong>OpenAccess AI Collective&lt;/strong> (community-driven). A very similar alternative, more widely used in China: &lt;strong>LLaMA-Factory&lt;/strong> (Apache 2.0, Beihang U.).&lt;/p>
&lt;h3 id="ray-train">Ray Train&lt;/h3>
&lt;p>Ray Train scales fine-tuning to multiple nodes by distributing workers across a Ray cluster. While DeepSpeed and FSDP are &lt;strong>intra-job parallelism&lt;/strong> (several GPUs collaborating on one job), Ray Train is the &lt;strong>orchestration plane&lt;/strong> that builds the cluster, launches workers, manages checkpoints, recovers from node failures, and integrates with Slurm or Kubernetes. For training runs beyond 8 GPUs on changing clusters, Ray Train avoids the operational burden of &amp;ldquo;manually launching N torchrun processes with NCCL&amp;rdquo;. It combines with MLflow for tracking. &lt;strong>Gotcha:&lt;/strong> the Ray learning curve is real; for a single node with 4-8 GPUs, &lt;code>torchrun&lt;/code> or Hugging Face Accelerate are simpler. Ray Train shines when there are N changing nodes. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Anyscale Inc.&lt;/strong> (commercial backer) + community. A more K8s-native alternative: &lt;strong>Kubeflow Training Operator&lt;/strong> (Apache 2.0, LF AI &amp;amp; Data).&lt;/p>
&lt;p>&lt;strong>More options for Tune:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>DeepSpeed&lt;/strong> — ZeRO parallelism in 3 stages, mixed precision, CPU/NVMe offload. MIT, &lt;strong>Microsoft&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>FSDP&lt;/strong> (Fully Sharded Data Parallel) — native PyTorch parallelism, an alternative to DeepSpeed. BSD, &lt;strong>Meta&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>LLaMA-Factory&lt;/strong> — equivalent to Axolotl with a focus on the Llama family. Apache 2.0, &lt;strong>Beihang University&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Decision matrix — Tune:&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>If your case is&lt;/th>
&lt;th>Choose&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Fine-tune on 1 GPU with 24GB (RTX 4090)&lt;/td>
&lt;td>&lt;strong>QLoRA with bitsandbytes NF4&lt;/strong> + Axolotl&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Fine-tune on 1 H100 80GB, models &amp;lt; 13B&lt;/td>
&lt;td>&lt;strong>LoRA bf16&lt;/strong> + Axolotl&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Fine-tune on 4-8 GPUs, single node&lt;/td>
&lt;td>&lt;strong>transformers + PEFT + Accelerate&lt;/strong> + MLflow&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Multi-node fine-tune on a K8s cluster&lt;/td>
&lt;td>&lt;strong>Kubeflow Training Operator&lt;/strong> or &lt;strong>Ray Train&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reproducible tracking is mandatory&lt;/td>
&lt;td>&lt;strong>MLflow + DVC input artefact&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>You want the minimum viable&lt;/td>
&lt;td>&lt;strong>Axolotl + MLflow&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="stage-3--eval--guardrails">Stage 3 — Eval + Guardrails&lt;/h2>
&lt;p>Eval validates candidates pre and post promotion against a golden set with operational metrics; Guardrails runs safety online. Detailed in the posts on &lt;a href="https://blog.lo0.es/en/posts/evals-llm-layer-after-tracing/">evals&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/llm-guardrails-safety-four-lines-of-defence/">guardrails&lt;/a>.&lt;/p>
&lt;h3 id="deepeval">DeepEval&lt;/h3>
&lt;p>DeepEval is the &amp;ldquo;pytest-style&amp;rdquo; OSS eval suite: you define tests with assertions over faithfulness, answer relevancy, contextual precision, hallucination rate, summarisation quality… and run them in CI. Each metric is an evaluator: some rule-based, others LLM-as-judge with auditable prompts. The philosophy is &amp;ldquo;evals as unit tests&amp;rdquo;: parameterisable by dataset, failable in CI, integrable with GitHub Actions. &lt;strong>Gotcha:&lt;/strong> LLM-as-judge metrics vary between judge model versions, so if the judge moves up a version, the thresholds lose their earlier statistical meaning. Explicit pinning of the judge model in config plus periodic threshold recalibration is mandatory discipline. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Confident AI&lt;/strong> (a company); parallel commercial SaaS offering. Comparable: &lt;strong>TruLens&lt;/strong> (MIT, &lt;strong>TruEra&lt;/strong>) and &lt;strong>G-Eval&lt;/strong> (academic).&lt;/p>
&lt;h3 id="ragas-rag-assessment">RAGAS (RAG Assessment)&lt;/h3>
&lt;p>RAGAS specialises in evaluating RAG pipelines. It defines four canonical metrics: &lt;strong>faithfulness&lt;/strong> (the answer is supported by the retrieved chunks), &lt;strong>answer relevancy&lt;/strong> (the answer addresses the query), &lt;strong>context precision&lt;/strong> (the retrieved chunks are relevant), &lt;strong>context recall&lt;/strong> (all the relevant chunks were retrieved). Each metric is computed with LLM-as-judge over a dataset of (query, context, expected answer). For a RAG system, RAGAS is the evaluator that measures whether retrieval is aligned with generation. It integrates with Langfuse and MLflow to store results. &lt;strong>Gotcha:&lt;/strong> RAGAS works well with golden sets of under 1000 examples; over huge golden sets the cost of the LLM judge per evaluation explodes, and the practice is to sample. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Exploding Gradients&lt;/strong> (the authors&amp;rsquo; company).&lt;/p>
&lt;h3 id="promptfoo">Promptfoo&lt;/h3>
&lt;p>Promptfoo is the declarative, CI-oriented evaluator: in &lt;code>promptfooconfig.yaml&lt;/code> you define a set of prompts and a set of assertions (contains text X, does not contain Y, faithfulness &amp;gt; 0.8, judge approves…), point at a provider (OpenAI compatible, vLLM, Ollama…), and &lt;code>promptfoo eval&lt;/code> runs the matrix of prompts × providers × assertions, returns a diff against the baseline and fails CI if anything regresses. It is the most &amp;ldquo;DevOps-friendly&amp;rdquo; piece of the evals ecosystem: it integrates trivially with GitHub Actions, GitLab CI or Jenkins. &lt;strong>Gotcha:&lt;/strong> assertion thresholds have to be calibrated with real data; starting at a default &lt;code>&amp;gt; 0.5&lt;/code> produces false positives that erode the team&amp;rsquo;s trust. Calibrate after the first week. Licence &lt;strong>MIT&lt;/strong>, maintained by &lt;strong>Promptfoo, Inc.&lt;/strong> (a company); a commercial Promptfoo Cloud SaaS offering exists but the OSS version is complete.&lt;/p>
&lt;h3 id="nemo-guardrails">NeMo Guardrails&lt;/h3>
&lt;p>NeMo Guardrails is NVIDIA&amp;rsquo;s framework for defining and enforcing policies in LLM systems through a DSL called &lt;strong>Colang&lt;/strong>. It lets you express rules such as &amp;ldquo;if the user asks about topic X, answer with template Y&amp;rdquo; or &amp;ldquo;if the model tries to do Z, block it&amp;rdquo; in a conversational-script syntax rather than in Python. It runs as middleware between the app and the model: input rails (validate what comes in), output rails (validate what goes out), dialog rails (control the flow). Designed for complex multi-turn systems where the policies are nontrivial. &lt;strong>Gotcha:&lt;/strong> Colang adds latency per turn (roughly 50-200 ms depending on the policy graph); for high-throughput conversational chat, dialog rails are disabled and only input + output remain. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>NVIDIA&lt;/strong>.&lt;/p>
&lt;h3 id="microsoft-presidio">Microsoft Presidio&lt;/h3>
&lt;p>Presidio is the most mature OSS PII (Personally Identifiable Information) detector in the ecosystem. It detects DNI, NIE, IBAN, phone numbers, emails, physical addresses, credit card numbers, personal names, dates of birth… with recognisers based on regex + NER (spaCy) + custom validators. It supports &lt;strong>redaction&lt;/strong> (replace with placeholders), &lt;strong>masking&lt;/strong> (asterisks) or &lt;strong>deterministic anonymisation&lt;/strong> (repeatable hash). For ENS/NIS2 scenarios, it is the piece placed in front (on input) and behind (on output) the LLM to guarantee that no PII is processed or emitted. &lt;strong>Gotcha:&lt;/strong> the built-in recognisers cover English well and the rest badly; for Spanish, Catalan and Basque you have to add custom recognisers, which is disciplined work but doable. Licence &lt;strong>MIT&lt;/strong>, maintained by &lt;strong>Microsoft&lt;/strong>.&lt;/p>
&lt;p>&lt;strong>More options for Eval:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Phoenix Arize OSS&lt;/strong> — combines tracing + evals, an alternative to Langfuse Evals. ELv2, &lt;strong>Arize AI&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>lm-eval-harness&lt;/strong> — academic suite with standard benchmarks (MMLU, HellaSwag…). MIT, &lt;strong>EleutherAI&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>HELM&lt;/strong> — holistic academic evals. Apache 2.0, &lt;strong>Stanford CRFM&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Guardrails AI&lt;/strong> — a pythonic alternative to NeMo Guardrails. Apache 2.0, &lt;strong>Guardrails AI Inc.&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>LlamaGuard / PromptGuard / ShieldGemma&lt;/strong> — safety models, not frameworks. Open weights, Meta / Google.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Decision matrix — Eval + Guardrails:&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>If your case is&lt;/th>
&lt;th>Choose&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Eval in CI, &amp;ldquo;pytest for LLMs&amp;rdquo; style&lt;/td>
&lt;td>&lt;strong>Promptfoo + GitHub Actions&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Eval specific to a RAG pipeline&lt;/td>
&lt;td>&lt;strong>RAGAS + Langfuse datasets&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>General eval with custom metrics&lt;/td>
&lt;td>&lt;strong>DeepEval + MLflow dataset&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Dialog policy with declarative rules&lt;/td>
&lt;td>&lt;strong>NeMo Guardrails (Colang)&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>PII redaction in/out only&lt;/td>
&lt;td>&lt;strong>Presidio&lt;/strong> (you do not need NeMo)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Open safety model in Spanish&lt;/td>
&lt;td>&lt;strong>LlamaGuard 3&lt;/strong> or &lt;strong>ShieldGemma&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="stage-4--deploy">Stage 4 — Deploy&lt;/h2>
&lt;p>Deploy serves tokens to the user with predictable throughput and latency, adapter hot-swap and multi-tenancy where it applies. Covered in the posts on &lt;a href="https://blog.lo0.es/en/posts/vllm-kubernetes-llm-inference-that-scales/">vLLM on K8s&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/llm-inference-operators-kubernetes/">LLM operators&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/gpu-cluster-as-multi-tenant-platform/">multi-tenant cluster&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/kv-cache-working-memory-llm-inference/">KV cache&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/pagedattention-vllm-block-manager/">PagedAttention&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/disaggregated-serving-prefill-decode-specialised-pods/">disaggregated serving&lt;/a>.&lt;/p>
&lt;h3 id="vllm">vLLM&lt;/h3>
&lt;p>vLLM is &lt;strong>the&lt;/strong> reference OSS inference engine. It implements &lt;strong>PagedAttention&lt;/strong> (KV cache paging in the style of virtual memory, avoiding fragmentation), &lt;strong>continuous batching&lt;/strong> (requests join the batch as they arrive, rather than waiting for the next batch), &lt;strong>prefix caching&lt;/strong> (common prefixes, system prompts, do not recompute the KV cache), &lt;strong>LoRA hot-swap&lt;/strong> (&lt;code>--enable-lora&lt;/code> allows loading and unloading adapters without restarting the engine), an &lt;strong>OpenAI-compatible&lt;/strong> API, and &lt;strong>disaggregated prefill/decode&lt;/strong> support since 2025. It covers almost everything from Llama 3 / Mistral / Qwen / DeepSeek. &lt;strong>Gotcha:&lt;/strong> maximum throughput is only reached with &lt;code>--max-num-seqs&lt;/code> and &lt;code>--gpu-memory-utilization&lt;/code> tuned for the specific model and hardware; the defaults are conservative. The initial tuning session pays off: 2-3× throughput. Licence &lt;strong>Apache 2.0&lt;/strong>, originated at UC Berkeley, today maintained by the &lt;strong>vLLM Project / LF AI &amp;amp; Data&lt;/strong> plus a broad community (Red Hat, NVIDIA, AWS, IBM contribute). Serious alternatives in the same bucket: &lt;strong>TGI&lt;/strong> (Apache 2.0, &lt;strong>Hugging Face&lt;/strong>), &lt;strong>SGLang&lt;/strong> (Apache 2.0, &lt;strong>LMSys&lt;/strong>), &lt;strong>TensorRT-LLM&lt;/strong> (Apache 2.0, &lt;strong>NVIDIA&lt;/strong>, requires conversion).&lt;/p>
&lt;h3 id="kserve">KServe&lt;/h3>
&lt;p>KServe is the Kubernetes operator for serving ML models, LLMs included, in a declarative pattern: you define an &lt;code>InferenceService&lt;/code> YAML with the model and predictor (which can be vLLM, TGI, Triton, or a custom container) and KServe handles scheduling onto GPU nodes, autoscaling (scale-to-zero included), traffic splitting for canary, and model registry integration. It is the layer that standardises &amp;ldquo;how a model is deployed on K8s&amp;rdquo; across multiple engines, instead of inventing engine-specific YAML. It supports multi-model with &lt;strong>Inference Graphs&lt;/strong> (chaining preprocessor → model → postprocessor) and integrates with KEDA/Karpenter for GPU pool autoscaling. &lt;strong>Gotcha:&lt;/strong> scale-to-zero on GPU works badly in practice because the warm-up (loading weights into VRAM) takes tens of seconds; &lt;code>minReplicas: 1&lt;/code> is better. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Kubeflow / LF AI &amp;amp; Data&lt;/strong>. Alternatives: &lt;strong>KubeRay&lt;/strong> (Apache 2.0, &lt;strong>Anyscale&lt;/strong>), &lt;strong>llm-d&lt;/strong> (Apache 2.0, &lt;strong>CNCF&lt;/strong>), &lt;strong>KAITO&lt;/strong> (MIT, &lt;strong>Microsoft Azure&lt;/strong>).&lt;/p>
&lt;h3 id="triton-inference-server">Triton Inference Server&lt;/h3>
&lt;p>Triton serves heterogeneous models on a single backend: LLMs (via the vLLM or TensorRT-LLM backend), traditional models (ONNX, TorchScript, TensorFlow), custom models. For systems that mix LLM inference with traditional classifiers, embedding encoders, reranking models, OCR and so on, Triton avoids having N different engines in N pods. It supports ensemble models (chaining models in a single request), dynamic batching, model versioning, model warmup. &lt;strong>Gotcha:&lt;/strong> Triton is flexible but heavy to operate; for systems serving only LLMs, vLLM directly is simpler and more optimised. Triton shines when there is real heterogeneity. Licence &lt;strong>BSD-3-Clause&lt;/strong>, maintained by &lt;strong>NVIDIA&lt;/strong>.&lt;/p>
&lt;h3 id="envoy-ai-gateway">Envoy AI Gateway&lt;/h3>
&lt;p>Envoy AI Gateway is the CNCF ecosystem&amp;rsquo;s &amp;ldquo;LLM-aware API gateway&amp;rdquo;. Built on Envoy Proxy, it adds knowledge of the OpenAI-compatible APIs (chat completions, embeddings, etc.), routing across multiple backends (local vLLM + OpenAI + Anthropic + Bedrock), &lt;strong>token-based rate limiting&lt;/strong> (limits by tokens per minute, not by requests), intelligent retries, fallback between providers, and built-in OTel observability. It is the piece that makes &amp;ldquo;AI Gateway&amp;rdquo; real as an architectural category. &lt;strong>Gotcha:&lt;/strong> integration with authentication (OIDC, JWT) is flexible but requires detailed Envoy configuration; an &amp;ldquo;out of the box&amp;rdquo; AI Gateway with no configuration produces an Envoy that passes everything through. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>CNCF&lt;/strong> since the initial donation from Tetrate. Alternatives: &lt;strong>LiteLLM Proxy&lt;/strong> (MIT, &lt;strong>BerriAI&lt;/strong>), &lt;strong>Portkey&lt;/strong> (MIT, &lt;strong>Portkey AI&lt;/strong>), &lt;strong>Kong AI Gateway&lt;/strong> (Apache 2.0 base + EE, &lt;strong>Kong Inc.&lt;/strong>).&lt;/p>
&lt;h3 id="llamacpp">llama.cpp&lt;/h3>
&lt;p>llama.cpp serves LLMs on CPUs (and Apple Silicon, GPUs via Vulkan/Metal/CUDA) with very aggressive quantisation (GGUF format, down to 2-bit). It is the canonical option for inference on hardware without a dedicated GPU: edge devices, workstations, development machines. It covers everything from small models (Phi-3, Gemma 2B) to Llama 70B on hardware with enough RAM. &lt;strong>Gotcha:&lt;/strong> latency on CPU is orders of magnitude worse than on a dedicated GPU, so it is useful for offline evals, drift checks and local development, not for production serving under real load. Licence &lt;strong>MIT&lt;/strong>, maintained by &lt;strong>Georgi Gerganov&lt;/strong> + community.&lt;/p>
&lt;p>&lt;strong>More options for Deploy:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>TensorRT-LLM&lt;/strong> — maximum optimisation on NVIDIA Hopper/Ada. Apache 2.0, NVIDIA.&lt;/li>
&lt;li>&lt;strong>SGLang&lt;/strong> — good for workloads with structured generation and JSON. Apache 2.0, LMSys.&lt;/li>
&lt;li>&lt;strong>TGI&lt;/strong> — a mature alternative, focused on the HuggingFace ecosystem. Apache 2.0, HuggingFace.&lt;/li>
&lt;li>&lt;strong>NVIDIA Dynamo&lt;/strong> — multi-node disaggregated serving. Apache 2.0, NVIDIA.&lt;/li>
&lt;li>&lt;strong>llm-d&lt;/strong> — K8s operator specific to LLMs. Apache 2.0, CNCF.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Decision matrix — Deploy:&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>If your case is&lt;/th>
&lt;th>Choose&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Production serving on NVIDIA H100/A100&lt;/td>
&lt;td>&lt;strong>vLLM&lt;/strong> (the safe default)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Absolute throughput squeezing on Hopper&lt;/td>
&lt;td>&lt;strong>TensorRT-LLM&lt;/strong> + vLLM plugin or standalone&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Edge / local dev without GPU&lt;/td>
&lt;td>&lt;strong>llama.cpp&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Multi-model (LLM + classifiers + encoders)&lt;/td>
&lt;td>&lt;strong>Triton&lt;/strong> with the vLLM backend&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Declarative K8s with autoscaling&lt;/td>
&lt;td>&lt;strong>KServe&lt;/strong> + vLLM as predictor&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>AI Gateway with token rate limiting&lt;/td>
&lt;td>&lt;strong>Envoy AI Gateway&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Multi-node disaggregated GPU cluster&lt;/td>
&lt;td>&lt;strong>NVIDIA Dynamo&lt;/strong> over vLLM&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="stage-5--observe">Stage 5 — Observe&lt;/h2>
&lt;p>Observe propagates &lt;code>trace_id&lt;/code> end-to-end, emits runtime metrics, runs an LLM judge over sampling and detects drift. Detailed in &lt;a href="https://blog.lo0.es/en/posts/agentsight-llm-tracing-ebpf-zero-instrumentation/">tracing with AgentSight&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/mcp-deep-observability-opentelemetry/">MCP observability with OTel&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/ebpf-local-inference-statistical-drift-detection/">eBPF + drift&lt;/a>.&lt;/p>
&lt;h3 id="opentelemetry-collector">OpenTelemetry Collector&lt;/h3>
&lt;p>The OTel Collector is the agent that receives traces, metrics and logs in OTel format (or in any other via receivers), processes them (filters, sampling, attribute enrichment, PII redaction), and routes them to one or several backends (Tempo, Jaeger, Prometheus, Loki, Langfuse…). It is &lt;strong>the piece that decouples the apps from the observability backend&lt;/strong>: moving from Tempo to Jaeger means changing the Collector&amp;rsquo;s exporter, not the app. For LLMOps it matters especially because the &lt;strong>OTel GenAI semantic conventions&lt;/strong> spec defines the attributes &lt;code>gen_ai.request.model&lt;/code>, &lt;code>gen_ai.prompt.version&lt;/code>, &lt;code>gen_ai.response.tokens&lt;/code> and so on, which stitch the &lt;code>trace_id&lt;/code> to the system&amp;rsquo;s lineage. &lt;strong>Gotcha:&lt;/strong> the Collector configuration tends to grow; without discipline and periodic review it ends up as an 800-line YAML that nobody understands. Modularising with &lt;code>extensions&lt;/code> helps. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by the &lt;strong>CNCF / OpenTelemetry Project&lt;/strong>.&lt;/p>
&lt;h3 id="tempo-traces--jaeger">Tempo (traces) + Jaeger&lt;/h3>
&lt;p>Grafana Tempo is the distributed trace backend optimised for cost: it uses an object store (S3/MinIO) instead of Elasticsearch, deduplicates by &lt;code>trace_id&lt;/code>, and integrates natively with Grafana for visualisation. For LLMOps, where a real request generates 10-30 spans (gateway, prompt pull, RAG retrieval, prefill, decode N times, scoring), Tempo copes with high volumes at a reasonable cost. &lt;strong>Jaeger&lt;/strong> is the more established CNCF alternative, better for cases under 100k traces per day, worse for native object store. &lt;strong>Gotcha:&lt;/strong> Tempo has no traditional indexing; searches like &amp;ldquo;traces that took more than 5s and touched tenant X&amp;rdquo; require &lt;strong>TraceQL&lt;/strong> + Grafana and are not as fast as Jaeger with Elasticsearch. For immediate ad-hoc diagnosis it is worth keeping a parallel Jaeger with aggressive sampling. Licences &lt;strong>AGPL 3.0&lt;/strong> (Tempo) and &lt;strong>Apache 2.0&lt;/strong> (Jaeger), maintained by &lt;strong>Grafana Labs&lt;/strong> and &lt;strong>CNCF&lt;/strong> respectively.&lt;/p>
&lt;h3 id="prometheus--grafana">Prometheus + Grafana&lt;/h3>
&lt;p>Prometheus is the time-series metrics foundation of the ecosystem. Pull model (it scrapes &lt;code>/metrics&lt;/code> endpoints), PromQL for queries, exporters for everything (Postgres, Kafka, NVIDIA GPU via &lt;code>dcgm-exporter&lt;/code>, vLLM natively). Grafana visualises Prometheus + Tempo + Loki on a single plane. For LLMOps, the critical metrics are &lt;code>gpu_utilization&lt;/code>, &lt;code>kv_cache_usage_pct&lt;/code>, &lt;code>tokens_per_second&lt;/code>, &lt;code>prefill_latency_p95&lt;/code>, &lt;code>decode_latency_p95&lt;/code>, &lt;code>queue_depth&lt;/code>, aggregated by tenant. &lt;strong>Gotcha:&lt;/strong> Prometheus is very good up to about 1M active series; above that it is worth moving to &lt;strong>Thanos&lt;/strong> or &lt;strong>Mimir&lt;/strong> for long retention and horizontal scalability. For the blog&amp;rsquo;s typical LLM cluster (4-8 H100), Prometheus alone is enough. Licences &lt;strong>Apache 2.0&lt;/strong> (Prometheus, &lt;strong>CNCF&lt;/strong>) and &lt;strong>AGPL 3.0&lt;/strong> (Grafana 10+, &lt;strong>Grafana Labs&lt;/strong>).&lt;/p>
&lt;h3 id="langfuse">Langfuse&lt;/h3>
&lt;p>Langfuse is the LLM-specific OSS observability + prompt management tool. It captures spans with LLM semantic conventions (input, output, model, tokens, latency, score, user_id, session_id), visualises them as &lt;strong>conversational traces&lt;/strong> (not just span trees), manages &lt;strong>prompts versioned with a &lt;code>production&lt;/code> label&lt;/strong> and allows &lt;strong>curated datasets + evals&lt;/strong> from the same UI. For serious LLMOps, Langfuse fills the gap that neither Tempo nor Jaeger covers: a tracing UI designed to be LLM-first. &lt;strong>Gotcha:&lt;/strong> Langfuse maintains its own store (Postgres + ClickHouse for high volume); on large clusters the operational side of ClickHouse deserves attention. To get started, Postgres alone copes. Licence &lt;strong>MIT&lt;/strong> for the OSS core, &lt;strong>EE Enterprise Edition&lt;/strong> with additional features (SSO, audit logs, advanced RBAC). Maintained by &lt;strong>Langfuse GmbH&lt;/strong> (Berlin, German). There is Langfuse Cloud (SaaS).&lt;/p>
&lt;h3 id="phoenix-arize-oss">Phoenix Arize OSS&lt;/h3>
&lt;p>Phoenix is Arize AI&amp;rsquo;s OSS for LLM observability + evals, an alternative to Langfuse with a different emphasis: more oriented to evaluation and visual debugging (embedding drift, cluster analysis), less to prompt management. A good pairing with Langfuse when you want a dual approach: Langfuse for &amp;ldquo;production conversational traces&amp;rdquo;, Phoenix for &amp;ldquo;exploratory investigation of model behaviour&amp;rdquo;. &lt;strong>Gotcha:&lt;/strong> Phoenix duplicates functionality with Langfuse and with MLflow; having all three in production multiplies the operational burden. Pick one as the main tool and the others as complements. Licence &lt;strong>Elastic License 2.0&lt;/strong> (not strictly OSI), maintained by &lt;strong>Arize AI&lt;/strong>.&lt;/p>
&lt;h3 id="cilium-tetragon--hubble">Cilium Tetragon + Hubble&lt;/h3>
&lt;p>Tetragon (eBPF runtime security observer) and Hubble (eBPF network observer) are the low-level pieces that give real runtime visibility into the cluster: which processes run in which pods, what syscalls they make, what network connections they open, in real time. For ENS/NIS2 environments that demand &amp;ldquo;prove what ran in production&amp;rdquo;, Tetragon is the irrefutable audit layer: every process execution with its parent, its capabilities, its K8s context. Hubble visualises network flows by pod, namespace, service. &lt;strong>Gotcha:&lt;/strong> the volume of events generated is high; without kernel-side filtering (which Tetragon supports with &lt;code>TracingPolicy&lt;/code>), it saturates the observability plane fast. Discipline in policies. Licence &lt;strong>Apache 2.0&lt;/strong> for both, maintained by &lt;strong>Cilium / CNCF / Isovalent&lt;/strong>.&lt;/p>
&lt;h3 id="evidently-ai">Evidently AI&lt;/h3>
&lt;p>Evidently is the OSS library for &lt;strong>drift detection&lt;/strong>: it compares input and output distributions between two time windows (training vs production, current week vs previous week), applies statistical tests (KS, PSI, Wasserstein, chi-square) and generates HTML reports. For LLMOps it detects when the distribution of prompts changes (new topics, new lengths, new languages) or when the model starts answering shorter / longer / differently. &lt;strong>Gotcha:&lt;/strong> Evidently is oriented to tabular data and embeddings; for raw text it is best combined with an encoder embedder that produces vectors before applying the tests. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Evidently AI&lt;/strong> (a company). Alternatives: &lt;strong>NannyML&lt;/strong> (Apache 2.0, &lt;strong>NannyML BV&lt;/strong>), &lt;strong>Alibi Detect&lt;/strong> (Apache 2.0, &lt;strong>Seldon&lt;/strong>).&lt;/p>
&lt;p>&lt;strong>More options for Observe:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Loki&lt;/strong> — Prometheus-style logs backend for Grafana. AGPL 3.0, Grafana Labs.&lt;/li>
&lt;li>&lt;strong>Pixie&lt;/strong> — auto-instrumented eBPF observability. Apache 2.0, CNCF.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Decision matrix — Observe:&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>If your case is&lt;/th>
&lt;th>Choose&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Minimum viable stack&lt;/td>
&lt;td>&lt;strong>OTel Collector + Tempo + Prometheus + Grafana + Langfuse&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Traces with strong ad-hoc search&lt;/td>
&lt;td>Add &lt;strong>Jaeger&lt;/strong> with aggressive sampling&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ENS / NIS2 compliance runtime audit&lt;/td>
&lt;td>&lt;strong>Tetragon + Hubble&lt;/strong> + mandated retention&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Exploratory investigation of the model&lt;/td>
&lt;td>&lt;strong>Phoenix Arize OSS&lt;/strong> alongside Langfuse&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Statistical drift detection&lt;/td>
&lt;td>&lt;strong>Evidently&lt;/strong> over embeddings + inputs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Cluster beyond 1M Prometheus series&lt;/td>
&lt;td>&lt;strong>Mimir&lt;/strong> (Grafana Labs) or &lt;strong>Thanos&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="stage-6--retrain--cross-cutting-pieces">Stage 6 — Retrain + cross-cutting pieces&lt;/h2>
&lt;p>Retrain closes the loop feedback → triage → enriched dataset → new adapter. Prompt versioning and data versioning stitch lineage across stages. Detailed in &lt;a href="https://blog.lo0.es/en/posts/retrain-closing-the-loop-feedback-dataset-adapter/">retrain&lt;/a>, &lt;a href="https://blog.lo0.es/en/posts/prompt-versioning-contract-five-word-change/">prompt versioning&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/data-versioning-llmops-dvc-lakefs-reproducible-golden-dataset/">data versioning&lt;/a>.&lt;/p>
&lt;h3 id="apache-airflow">Apache Airflow&lt;/h3>
&lt;p>Airflow is the most established OSS DAG scheduler. You define workflows as Python code (DAGs), each DAG with tasks (operators) that run according to declared dependencies plus a cron schedule. For retraining: a weekly DAG that extracts feedback from Postgres, triages it with an LLM-as-classifier, enriches the enriched dataset in DVC, launches the fine-tuning job on Kubernetes, runs evals against the golden set, and promotes if it passes the gates. There is a huge ecosystem of operators for everything (S3, Postgres, Kafka, Slack, K8s, Spark…). &lt;strong>Gotcha:&lt;/strong> Airflow 2.x improved a great deal over the chaos of 1.x, but the scheduler is still a component that deserves operational attention (Postgres backend, executor pool, sidecar workers); for simple pipelines it is over-engineering. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by the &lt;strong>ASF&lt;/strong>.&lt;/p>
&lt;h3 id="argo-workflows">Argo Workflows&lt;/h3>
&lt;p>Argo Workflows is the K8s-native equivalent of Airflow: each step is a container, the DAGs are defined as K8s YAML, the executor is Kubernetes itself. For environments where &lt;strong>everything is K8s&lt;/strong>, Argo fits without an extra component to maintain. Long tasks (a six-hour fine-tuning run) execute as Pods that survive control plane failures. It integrates trivially with Kubeflow Pipelines (which is built on top). &lt;strong>Gotcha:&lt;/strong> Argo&amp;rsquo;s YAML syntax is verbose; for complex DAGs, Argo feels less productive than Airflow in Python. Solutions: &lt;strong>Hera&lt;/strong> (Python DSL for Argo, a &lt;strong>DataBricks contribution&lt;/strong>) or &lt;strong>Argo + custom CRDs&lt;/strong>. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>CNCF&lt;/strong>.&lt;/p>
&lt;h3 id="kubeflow-pipelines">Kubeflow Pipelines&lt;/h3>
&lt;p>Kubeflow Pipelines is the layer above Argo Workflows oriented specifically to ML: artefact tracking, experiment tracking, reusable pipeline templates, versioned components. Built on Argo, it adds the ML conceptual model (input artefact, output artefact, metrics) that raw Argo does not have. For cyclical retraining on a K8s cluster, it is the most &amp;ldquo;ML-ready&amp;rdquo; option in the OSS ecosystem. &lt;strong>Gotcha:&lt;/strong> Kubeflow as a full suite is heavy (10+ components); many organisations install only Pipelines + Training Operator + Katib and skip Notebook Server / legacy KFServing. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>CNCF / LF AI &amp;amp; Data&lt;/strong>.&lt;/p>
&lt;h3 id="feast">Feast&lt;/h3>
&lt;p>Feast is the most widely used OSS feature store. It defines &lt;strong>feature views&lt;/strong> over batch sources (BigQuery, Postgres, Parquet) and online sources (Redis, DynamoDB, Postgres with an extension), exposes a consistent API for read-during-training and read-during-inference (point-in-time correctness), and guarantees that the features of the model in production are the same ones it was trained with. For LLMOps where the model needs consistent user / session / context features (latest plan, tenure as a customer, recent tickets), Feast provides the discipline. &lt;strong>Gotcha:&lt;/strong> for many pure LLM systems (a RAG chatbot with no complex features), Feast is over-engineering, Postgres is enough. When there are real features (recommendation, scoring, ranking), Feast shines. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>LF AI &amp;amp; Data&lt;/strong>.&lt;/p>
&lt;h3 id="argilla">Argilla&lt;/h3>
&lt;p>Argilla is the OSS annotation + HiL (human-in-the-loop) platform most aligned with modern LLMOps. It creates annotation projects with templates (classification, ranking, span annotation, RLHF preference, free-form text), connects to HuggingFace datasets, and integrates with Langfuse to import traces from production as cases to annotate. It supports multiple annotators with reconciliation, kappa scoring and quality control. To enrich retrain datasets with cases from the &amp;ldquo;blunt tone&amp;rdquo; cluster of the &lt;a href="https://blog.lo0.es/en/posts/retrain-closing-the-loop-feedback-dataset-adapter/">Retrain post&lt;/a>, Argilla is the front end. &lt;strong>Gotcha:&lt;/strong> Argilla requires Elasticsearch for production performance; for small experiments SQLite is enough. Licence &lt;strong>Apache 2.0&lt;/strong>, maintained by &lt;strong>Argilla, Inc.&lt;/strong> (acquired by &lt;strong>Hugging Face&lt;/strong> in 2024). Alternative: &lt;strong>Label Studio&lt;/strong> (Apache 2.0, &lt;strong>HumanSignal&lt;/strong>), more generalist, less LLM-first.&lt;/p>
&lt;h3 id="langfuse-prompts--mlflow-prompt-registry">Langfuse Prompts + MLflow Prompt Registry&lt;/h3>
&lt;p>Langfuse Prompts manages prompts as versioned entities with labels (production, staging, experiment). The client reads the active prompt from Langfuse on the request path (with a local cache of a few seconds) and propagates &lt;code>prompt_id, prompt_version&lt;/code> to the OTel span, exactly as the &lt;a href="https://blog.lo0.es/en/posts/anatomy-llm-request-production-tour-six-stages/">forensic post&lt;/a> does. MLflow Prompt Registry does the same with a slightly different conceptual model (no labels-as-pointers; it uses stages, like the Models registry). Both are valid; the choice depends on which tracking tool is already in place. &lt;strong>Gotcha (Langfuse):&lt;/strong> labels are mutable, so changing &lt;code>production&lt;/code> points at another version with no explicit audit; prompts are better deployed via PR against the configs repo, not manually in the UI. Licences and governance covered above.&lt;/p>
&lt;p>&lt;strong>More options for Retrain + cross-cutting pieces:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Prefect&lt;/strong> — &amp;ldquo;modern&amp;rdquo; Python DAGs, an alternative to Airflow. Apache 2.0, &lt;strong>Prefect Tech&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Dagster&lt;/strong> — DAGs with a strong focus on data assets. Apache 2.0, &lt;strong>Dagster Labs&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>Label Studio&lt;/strong> — generalist annotation. Apache 2.0, &lt;strong>HumanSignal&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>OpenLineage&lt;/strong> — cross-system lineage event standard. Apache 2.0, &lt;strong>LF AI &amp;amp; Data&lt;/strong>.&lt;/li>
&lt;li>&lt;strong>DataHub / Apache Atlas / OpenMetadata&lt;/strong> — catalogue + lineage with a UI. Apache 2.0.&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Decision matrix — Retrain + cross-cutting pieces:&lt;/strong>&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>If your case is&lt;/th>
&lt;th>Choose&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Simple pipelines with a catalogue of operators&lt;/td>
&lt;td>&lt;strong>Airflow&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Everything is K8s, minimal components&lt;/td>
&lt;td>&lt;strong>Argo Workflows&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ML pipelines with artefact tracking&lt;/td>
&lt;td>&lt;strong>Kubeflow Pipelines&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>HiL annotation for LLM retraining&lt;/td>
&lt;td>&lt;strong>Argilla&lt;/strong> + Langfuse integration&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Features shared between training and inference&lt;/td>
&lt;td>&lt;strong>Feast&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>No complex features, only prompts + LLM&lt;/td>
&lt;td>Skip Feast&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Lightweight prompt registry&lt;/td>
&lt;td>&lt;strong>Langfuse Prompts&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>MLflow is already centralised&lt;/td>
&lt;td>&lt;strong>MLflow Prompt Registry&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="master-table-licence-governance-and-enterprise-offering">Master table: licence, governance and enterprise offering&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Tool&lt;/th>
&lt;th>Licence&lt;/th>
&lt;th>Governance / maintainer&lt;/th>
&lt;th>Commercial EE / SaaS&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>DVC&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Iterative.ai&lt;/td>
&lt;td>DVC Studio&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>lakeFS&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Treeverse&lt;/td>
&lt;td>lakeFS Cloud&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>MinIO&lt;/strong>&lt;/td>
&lt;td>AGPL v3&lt;/td>
&lt;td>MinIO Inc.&lt;/td>
&lt;td>SUBNET / AIStor&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Qdrant&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Qdrant GmbH&lt;/td>
&lt;td>Qdrant Cloud&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>pgvector&lt;/strong>&lt;/td>
&lt;td>PostgreSQL License&lt;/td>
&lt;td>Andrew Kane + community&lt;/td>
&lt;td>— (built-in Postgres clouds)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>PostgreSQL&lt;/strong>&lt;/td>
&lt;td>PostgreSQL License&lt;/td>
&lt;td>PostgreSQL Global Dev Group&lt;/td>
&lt;td>several managed (Crunchy, Neon, Aiven, EDB)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Apache Kafka&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>ASF&lt;/td>
&lt;td>Confluent Cloud&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Debezium&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Red Hat / ASF&lt;/td>
&lt;td>Debezium Server / Confluent Connectors&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Apache Flink&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>ASF&lt;/td>
&lt;td>Ververica Platform, Aiven&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>HF Transformers&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Hugging Face SAS&lt;/td>
&lt;td>HF Inference Endpoints / Enterprise Hub&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>PEFT&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Hugging Face SAS&lt;/td>
&lt;td>— (part of the HF offering)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>bitsandbytes&lt;/strong>&lt;/td>
&lt;td>MIT&lt;/td>
&lt;td>Tim Dettmers + community&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>MLflow&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>LF AI &amp;amp; Data&lt;/td>
&lt;td>Databricks MLflow&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Axolotl&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>OpenAccess AI Collective&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Ray (Train)&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Anyscale + community&lt;/td>
&lt;td>Anyscale Platform&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>DeepSpeed&lt;/strong>&lt;/td>
&lt;td>MIT&lt;/td>
&lt;td>Microsoft&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>DeepEval&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Confident AI&lt;/td>
&lt;td>Confident AI SaaS&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>RAGAS&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Exploding Gradients&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Promptfoo&lt;/strong>&lt;/td>
&lt;td>MIT&lt;/td>
&lt;td>Promptfoo, Inc.&lt;/td>
&lt;td>Promptfoo Cloud&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>NeMo Guardrails&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>NVIDIA&lt;/td>
&lt;td>NeMo Microservices&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Presidio&lt;/strong>&lt;/td>
&lt;td>MIT&lt;/td>
&lt;td>Microsoft&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Phoenix (Arize)&lt;/strong>&lt;/td>
&lt;td>Elastic v2&lt;/td>
&lt;td>Arize AI&lt;/td>
&lt;td>Arize Platform&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>vLLM&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>vLLM Project / LF AI &amp;amp; Data&lt;/td>
&lt;td>several (Red Hat, AWS, IBM, NVIDIA)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>TGI&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Hugging Face SAS&lt;/td>
&lt;td>HF Inference Endpoints&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>SGLang&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>LMSys + community&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>TensorRT-LLM&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>NVIDIA&lt;/td>
&lt;td>NVIDIA AI Enterprise&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>llama.cpp&lt;/strong>&lt;/td>
&lt;td>MIT&lt;/td>
&lt;td>Georgi Gerganov + community&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Triton Inference Server&lt;/strong>&lt;/td>
&lt;td>BSD-3&lt;/td>
&lt;td>NVIDIA&lt;/td>
&lt;td>NVIDIA AI Enterprise&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>KServe&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>LF AI &amp;amp; Data (Kubeflow)&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Envoy AI Gateway&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>CNCF / Tetrate&lt;/td>
&lt;td>Tetrate Service Bridge&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>LiteLLM&lt;/strong>&lt;/td>
&lt;td>MIT&lt;/td>
&lt;td>BerriAI&lt;/td>
&lt;td>LiteLLM Cloud&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>OpenTelemetry&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>CNCF&lt;/td>
&lt;td>several vendors (Honeycomb, Datadog, Grafana)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Tempo&lt;/strong>&lt;/td>
&lt;td>AGPL 3.0&lt;/td>
&lt;td>Grafana Labs&lt;/td>
&lt;td>Grafana Cloud Tempo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Jaeger&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>CNCF&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Prometheus&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>CNCF&lt;/td>
&lt;td>Grafana Cloud, AMP, GCP Managed Prom, Azure&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Grafana&lt;/strong>&lt;/td>
&lt;td>AGPL 3.0&lt;/td>
&lt;td>Grafana Labs&lt;/td>
&lt;td>Grafana Cloud, Grafana Enterprise&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Loki&lt;/strong>&lt;/td>
&lt;td>AGPL 3.0&lt;/td>
&lt;td>Grafana Labs&lt;/td>
&lt;td>Grafana Cloud Loki&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Langfuse&lt;/strong>&lt;/td>
&lt;td>MIT (core) / EE&lt;/td>
&lt;td>Langfuse GmbH&lt;/td>
&lt;td>Langfuse Cloud&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Tetragon&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Cilium / CNCF / Isovalent&lt;/td>
&lt;td>Isovalent Enterprise&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Hubble&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Cilium / CNCF&lt;/td>
&lt;td>Isovalent Enterprise&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Evidently AI&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Evidently AI&lt;/td>
&lt;td>Evidently Cloud&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Apache Airflow&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>ASF&lt;/td>
&lt;td>Astronomer, MWAA, Cloud Composer&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Argo Workflows&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>CNCF&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Kubeflow Pipelines&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>CNCF / LF AI &amp;amp; Data&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Feast&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>LF AI &amp;amp; Data&lt;/td>
&lt;td>Tecton (commercial)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Argilla&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Hugging Face&lt;/td>
&lt;td>HF Hub features&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>OpenLineage&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>LF AI &amp;amp; Data&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>DataHub&lt;/strong>&lt;/td>
&lt;td>Apache 2.0&lt;/td>
&lt;td>Acryl Data&lt;/td>
&lt;td>Acryl Cloud&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>The pattern to watch for when reading the table:&lt;/strong> &lt;strong>AGPL 3.0&lt;/strong> and &lt;strong>Elastic v2&lt;/strong> are the ones that add the most friction in companies with strict licensing policies (legal asks for a specific review). The &lt;strong>Apache 2.0&lt;/strong> ones pass compliance without argument. Those with an &amp;ldquo;EE Enterprise&amp;rdquo; tier or equivalent hide a decision: the OSS version is functionally complete for production, but team features (SSO, audit, advanced RBAC) live in the commercial version. For ENS customers under a HIGH declaration, the EE features (SSO with corporate SAML/OIDC, immutable audit logs) are usually mandatory, so it is worth knowing the price beforehand.&lt;/p>
&lt;h2 id="when-to-move-from-the-minimum-stack-to-the-full-stack">When to move from the &amp;ldquo;minimum stack&amp;rdquo; to the &amp;ldquo;full stack&amp;rdquo;&lt;/h2>
&lt;p>The whole catalogue can be intimidating. But you do not build all of it on day one. There is a reasonable order that this blog has been validating in posts throughout the series. The &lt;strong>minimum viable stack&lt;/strong> that serves an LLM API with acceptable discipline:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Serving&lt;/strong>: vLLM on Kubernetes plus an Envoy AI Gateway in front.&lt;/li>
&lt;li>&lt;strong>Data&lt;/strong>: Postgres + pgvector (no Qdrant), MinIO for object store, no Kafka.&lt;/li>
&lt;li>&lt;strong>Tune&lt;/strong>: Axolotl + MLflow, no Ray Train.&lt;/li>
&lt;li>&lt;strong>Eval&lt;/strong>: Promptfoo in CI, no RAGAS and no judge in production.&lt;/li>
&lt;li>&lt;strong>Observe&lt;/strong>: OTel Collector + Prometheus + Grafana + Langfuse, no Phoenix and no Tetragon.&lt;/li>
&lt;li>&lt;strong>Retrain&lt;/strong>: feedback in Postgres + crontab scripts, no Airflow.&lt;/li>
&lt;li>&lt;strong>Versioning&lt;/strong>: prompts in Langfuse + datasets in DVC over MinIO, no lakeFS.&lt;/li>
&lt;/ul>
&lt;p>That is &lt;strong>about 8-10 components&lt;/strong> and it serves a reasonable LLM system for a single tenant with moderate traffic. As the system grows, there are identifiable moments where adding each piece pays off:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Trigger&lt;/th>
&lt;th>Component to add&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Multi-tenant with isolated corpora&lt;/td>
&lt;td>&lt;strong>Qdrant&lt;/strong> (collections per tenant, ACL)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>The corpus is refreshed often and periodically breaks&lt;/td>
&lt;td>&lt;strong>lakeFS&lt;/strong> (branches with pre-merge hooks)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>The embedding pipeline needs streaming&lt;/td>
&lt;td>&lt;strong>Kafka + Debezium + Flink&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Retraining moves from monthly to weekly&lt;/td>
&lt;td>&lt;strong>Airflow&lt;/strong> or &lt;strong>Argo Workflows&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Shared features appear (customer profile, scoring)&lt;/td>
&lt;td>&lt;strong>Feast&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Annotation outgrows informal capacity&lt;/td>
&lt;td>&lt;strong>Argilla&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>RAG eval needs specific metrics&lt;/td>
&lt;td>&lt;strong>RAGAS&lt;/strong> + Langfuse datasets&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ENS compliance demands runtime audit&lt;/td>
&lt;td>&lt;strong>Tetragon + Hubble&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Drift is invisible and shows up late&lt;/td>
&lt;td>&lt;strong>Evidently&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A single stack stops covering multi-model&lt;/td>
&lt;td>&lt;strong>Triton&lt;/strong> or &lt;strong>KServe&lt;/strong> with several predictors&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Multiple simultaneous multi-tenant adapters&lt;/td>
&lt;td>&lt;strong>vLLM Production Stack&lt;/strong> + a dedicated Operator&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Each jump adds 1-2 components and is worth the cost only when the trigger is clear. Adding Kafka &amp;ldquo;just in case&amp;rdquo; when the corpus is updated once a month is net negative work.&lt;/p>
&lt;h2 id="what-we-have-not-covered-yet">What we have not covered (yet)&lt;/h2>
&lt;p>Some pieces still deserve a post of their own:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Schema Registry&lt;/strong> for LLM data and prompts (Confluent OSS, Karapace, JSON Schema Registry).&lt;/li>
&lt;li>&lt;strong>Catalogue + lineage&lt;/strong> in depth: DataHub vs Atlas vs OpenMetadata + OpenLineage taken seriously.&lt;/li>
&lt;li>&lt;strong>Federated learning&lt;/strong> over OSS (Flower, FedML) for scenarios where the data is not centralised.&lt;/li>
&lt;li>&lt;strong>OSS MCP Servers&lt;/strong> and their place in the stack as a tools / actions layer.&lt;/li>
&lt;li>&lt;strong>&amp;ldquo;Agentic&amp;rdquo; evals&lt;/strong> specific to multi-step systems with tool use.&lt;/li>
&lt;li>&lt;strong>Upgrade best practices&lt;/strong> for each component (vLLM every 6 weeks, Kafka major every 18 months, etc.).&lt;/li>
&lt;/ul>
&lt;h2 id="see-also">See also&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/anatomy-llm-request-production-tour-six-stages/">Anatomy of an LLM request in production&lt;/a> — the forensic piece that follows one request through the six stages; this catalogue is the list of tools that appeared along that route.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/parallel-catalogue-llmops-stages-open-source-hyperscalers/">The parallel catalogue: OSS vs hyperscalers&lt;/a> — the horizontal cut that shows, for each stage, what each OSS tool does and what its equivalent is on AWS, GCP and Azure.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/six-stage-llmops-pipeline-architecture-and-deep-dive/">The six-stage LLMOps pipeline&lt;/a> — the master map of the pipeline to which this catalogue puts concrete OSS names.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/mlops-for-llms-landscape-2026/">MLOps specific to LLMs in 2026&lt;/a> — general context on LLMOps.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/data-versioning-llmops-dvc-lakefs-reproducible-golden-dataset/">Data versioning with DVC and lakeFS&lt;/a> — the deep-dive on the two OSS protagonists of the Data stage + cross-cutting piece.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/prompt-versioning-contract-five-word-change/">Prompt versioning with Langfuse and MLflow&lt;/a> — the deep-dive on the Prompt cross-cutting piece.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/continuous-fine-tuning-production-real-traffic-deployed-adapter/">Continuous fine-tuning in production&lt;/a> — the Tune stage in real operations.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/evals-llm-layer-after-tracing/">Evals: the layer after tracing&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/llm-guardrails-safety-four-lines-of-defence/">Guardrails and safety in LLMs&lt;/a> — the deep-dives on Eval + safety.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/llm-guard-anatomy-scanners-langfuse-vllm-litellm/">LLM Guard: the sworn translator with a notebook of equivalences&lt;/a> — a specific zoom on the Protect AI tool with its Anonymize + Vault + Deanonymize pattern, the 36 composable scanners and the four deployment modes (lib, FastAPI API, OTel sidecar, AI Gateway plugin).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/kv-cache-working-memory-llm-inference/">KV cache&lt;/a> · &lt;a href="https://blog.lo0.es/en/posts/pagedattention-vllm-block-manager/">PagedAttention&lt;/a> · &lt;a href="https://blog.lo0.es/en/posts/disaggregated-serving-prefill-decode-specialised-pods/">Disaggregated serving&lt;/a> · &lt;a href="https://blog.lo0.es/en/posts/vllm-kubernetes-llm-inference-that-scales/">vLLM on K8s&lt;/a> · &lt;a href="https://blog.lo0.es/en/posts/llm-inference-operators-kubernetes/">LLM K8s operators&lt;/a> · &lt;a href="https://blog.lo0.es/en/posts/gpu-cluster-as-multi-tenant-platform/">Multi-tenant GPU cluster&lt;/a> — Deploy in all its layers.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/agentsight-llm-tracing-ebpf-zero-instrumentation/">AgentSight LLM tracing&lt;/a> · &lt;a href="https://blog.lo0.es/en/posts/mcp-deep-observability-opentelemetry/">MCP observability with OTel&lt;/a> · &lt;a href="https://blog.lo0.es/en/posts/ebpf-local-inference-statistical-drift-detection/">eBPF + drift&lt;/a> — Observe from its three angles.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/retrain-closing-the-loop-feedback-dataset-adapter/">Retrain: closing the loop&lt;/a> — the Retrain stage in detail.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/langfuse-inside-sorting-centre-bottleneck/">Langfuse from the inside: v3 architecture and the 10 backend knobs&lt;/a> — the operational deep-dive on the star observability tool of this catalogue: a six-service architecture, asynchronous ingestion and self-hosted tuning on the example cluster.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/isolating-ai-agents-workstation-to-cluster/">Isolating AI agents: overview&lt;/a> and &lt;a href="https://blog.lo0.es/en/posts/runbook-caging-ai-agent-bubblewrap-tetragon/">runbook&lt;/a> — the runtime security layer for agents that execute code: bubblewrap/ai-jail on the client and Tetragon (eBPF) on the cluster, with its Kata &lt;code>RuntimeClass&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/kserve-open-inference-protocol-control-plane/">Model chain of trust (1/4): KServe and the Open Inference Protocol&lt;/a> — the deep-dive on the control plane of the Deploy stage: InferenceService, ServingRuntime and the API contract that this catalogue only enumerates.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;a href="https://blog.lo0.es/en/posts/model-chain-of-trust-where-the-bytes-live-registry-oci-artefacts/">Model chain of trust (2/4): registry, OCI artefacts and distribution&lt;/a> — the missing piece between Tune and Deploy: where the weights live (OCI artefacts with ORAS, Harbor, MLflow) and how they reach the GPU node.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="references">References&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://docs.vllm.ai/">vLLM&lt;/a> · &lt;a href="https://github.com/vllm-project/production-stack">vLLM Production Stack&lt;/a> · &lt;a href="https://huggingface.co/docs/text-generation-inference/">TGI&lt;/a> · &lt;a href="https://docs.sglang.ai/">SGLang&lt;/a> · &lt;a href="https://nvidia.github.io/TensorRT-LLM/">TensorRT-LLM&lt;/a> · &lt;a href="https://github.com/ggerganov/llama.cpp">llama.cpp&lt;/a> — OSS inference engines.&lt;/li>
&lt;li>&lt;a href="https://docs.nvidia.com/deeplearning/triton-inference-server/">Triton Inference Server&lt;/a> · &lt;a href="https://kserve.github.io/website/">KServe&lt;/a> · &lt;a href="https://aigateway.envoyproxy.io/">Envoy AI Gateway&lt;/a> · &lt;a href="https://docs.litellm.ai/">LiteLLM&lt;/a> — orchestration and AI gateway.&lt;/li>
&lt;li>&lt;a href="https://qdrant.tech/documentation/">Qdrant&lt;/a> · &lt;a href="https://github.com/pgvector/pgvector">pgvector&lt;/a> · &lt;a href="https://milvus.io/docs">Milvus&lt;/a> — vector databases.&lt;/li>
&lt;li>&lt;a href="https://dvc.org/doc">DVC&lt;/a> · &lt;a href="https://docs.lakefs.io/">lakeFS&lt;/a> · &lt;a href="https://min.io/docs/">MinIO&lt;/a> — versioning and object store.&lt;/li>
&lt;li>&lt;a href="https://kafka.apache.org/documentation/">Apache Kafka&lt;/a> · &lt;a href="https://debezium.io/documentation/">Debezium&lt;/a> · &lt;a href="https://flink.apache.org/">Apache Flink&lt;/a> — streams and CDC.&lt;/li>
&lt;li>&lt;a href="https://huggingface.co/docs/transformers">Hugging Face Transformers&lt;/a> · &lt;a href="https://huggingface.co/docs/peft">PEFT&lt;/a> · &lt;a href="https://huggingface.co/docs/bitsandbytes">bitsandbytes&lt;/a> · &lt;a href="https://docs.axolotl.ai/">Axolotl&lt;/a> — fine-tuning.&lt;/li>
&lt;li>&lt;a href="https://mlflow.org/docs/">MLflow&lt;/a> · &lt;a href="https://docs.ray.io/en/latest/train/">Ray Train&lt;/a> · &lt;a href="https://www.kubeflow.org/docs/components/trainer/">Kubeflow Training Operator&lt;/a> — training orchestration.&lt;/li>
&lt;li>&lt;a href="https://docs.confident-ai.com/">DeepEval&lt;/a> · &lt;a href="https://docs.ragas.io/">RAGAS&lt;/a> · &lt;a href="https://promptfoo.dev/docs/">Promptfoo&lt;/a> · &lt;a href="https://docs.nvidia.com/nemo/guardrails/">NeMo Guardrails&lt;/a> · &lt;a href="https://microsoft.github.io/presidio/">Presidio&lt;/a> — evals and guardrails.&lt;/li>
&lt;li>&lt;a href="https://opentelemetry.io/docs/">OpenTelemetry&lt;/a> · &lt;a href="https://opentelemetry.io/docs/specs/semconv/gen-ai/">OTel GenAI semconv&lt;/a> · &lt;a href="https://grafana.com/docs/tempo/">Tempo&lt;/a> · &lt;a href="https://prometheus.io/docs/">Prometheus&lt;/a> · &lt;a href="https://grafana.com/docs/">Grafana&lt;/a> · &lt;a href="https://grafana.com/docs/loki/">Loki&lt;/a> — observability foundation.&lt;/li>
&lt;li>&lt;a href="https://langfuse.com/docs">Langfuse&lt;/a> · &lt;a href="https://docs.arize.com/phoenix">Phoenix Arize&lt;/a> · &lt;a href="https://docs.evidentlyai.com/">Evidently AI&lt;/a> — LLM observability and drift.&lt;/li>
&lt;li>&lt;a href="https://docs.cilium.io/">Cilium&lt;/a> · &lt;a href="https://tetragon.io/">Tetragon&lt;/a> · &lt;a href="https://docs.cilium.io/en/stable/observability/hubble/">Hubble&lt;/a> — eBPF runtime.&lt;/li>
&lt;li>&lt;a href="https://airflow.apache.org/docs/">Apache Airflow&lt;/a> · &lt;a href="https://argo-workflows.readthedocs.io/">Argo Workflows&lt;/a> · &lt;a href="https://www.kubeflow.org/docs/components/pipelines/">Kubeflow Pipelines&lt;/a> · &lt;a href="https://docs.feast.dev/">Feast&lt;/a> · &lt;a href="https://docs.argilla.io/">Argilla&lt;/a> — orchestration + retrain + annotation.&lt;/li>
&lt;/ul></description></item></channel></rss>