<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Llmops on lo0 — Blog Técnico</title><link>https://blog.lo0.es/tags/llmops/</link><description>Recent content in Llmops on lo0 — Blog Técnico</description><generator>Hugo -- gohugo.io</generator><language>es</language><lastBuildDate>Thu, 21 May 2026 07:15:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/tags/llmops/index.xml" rel="self" type="application/rss+xml"/><item><title>El cluster GPU como plataforma: cómo convertir un cluster compartido en un servicio multi-tenant que tus equipos puedan consumir</title><link>https://blog.lo0.es/posts/cluster-h100-plataforma-multi-tenant/</link><pubDate>Thu, 21 May 2026 07:15:00 +0200</pubDate><guid>https://blog.lo0.es/posts/cluster-h100-plataforma-multi-tenant/</guid><description>&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Tener un cluster de GPUs caro y muchas cargas distintas que lo quieren usar no es un problema de &lt;strong>infraestructura&lt;/strong>: es un problema de &lt;strong>producto interno&lt;/strong>. Lo que separa &amp;ldquo;tenemos un cluster&amp;rdquo; de &amp;ldquo;tenemos una plataforma de inferencia&amp;rdquo; son cuatro capas que el mercado ha consolidado en 2026: una &lt;strong>capa de gateway&lt;/strong> que centraliza autenticación, routing y políticas (LiteLLM, Portkey, Kong AI Gateway); un &lt;strong>modelo de aislamiento GPU&lt;/strong> apropiado al perfil de los tenants (MIG hardware-isolation para multi-tenant no confiable, MPS para procesos del mismo equipo, time-slicing solo para dev); un &lt;strong>sistema de quotas y rate limiting&lt;/strong> con presupuestos por tenant/equipo/proyecto (LiteLLM lo hace en su core a nivel team/user/api-key con 429s descriptivos); y un &lt;strong>plano de observabilidad multi-tenant&lt;/strong> que permite cost attribution real (showback como paso intermedio, chargeback como destino), tracing por tenant y dashboards diferenciados. Aplicado a un cluster GPU mid-scale típico (un nodo con 4-8 H100 SXM y NVLink, un punto habitual para empezar en producción), esto se traduce en decisiones concretas: con ~640 GB de VRAM agregada en 8 GPUs y dos modelos típicos en producción (un modelo grande de 70B+ con tensor parallel y un modelo mediano replicado), el cluster sirve entre &lt;strong>decenas y bajos centenares de sesiones simultáneas&lt;/strong> según mix; el aislamiento GPU se suele resolver con &lt;strong>MIG en cargas inferiores y dedicación per-model&lt;/strong> en cargas grandes; y la métrica de éxito de la plataforma es la &lt;strong>utilización efectiva&lt;/strong>, que en producción típica está en &lt;strong>30-40%&lt;/strong> y el objetivo razonable de optimización es subirla a 60-70% sin degradar SLA.&lt;/p>
&lt;blockquote>
&lt;p>Este es el &lt;strong>quinto post de la serie MLOps para LLMs&lt;/strong>. Es el más operacionalmente orientado y atraviesa varias etapas del pipeline (Deploy + Observe + transversales). El &amp;ldquo;estás aquí&amp;rdquo; señala las dos etapas activas porque la noción de plataforma multi-tenant no vive en una sola.&lt;/p>
&lt;/blockquote>
&lt;h2 id="estás-aquí-deploy--observe-cluster-como-producto">Estás aquí: Deploy + Observe (cluster como producto)&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 90" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="estás aquí: Deploy + Observe">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#7adb7a;stroke-width:3}.active2{fill:#c47aff;stroke-width:3}.idle{fill:#f4f4f4}.lbl{font:600 12px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#mt1)}.cyc{stroke:#888;stroke-width:1.2;fill:none;stroke-dasharray:4 2;marker-end:url(#mt1)}&lt;/style>
&lt;defs>&lt;marker id="mt1" 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;/defs>
&lt;text x="390" y="20" text-anchor="middle" class="lbl">Estás aquí: DEPLOY + OBSERVE · el cluster como plataforma con tenants&lt;/text>
&lt;rect x="30" y="35" width="110" height="35" class="box idle"/>&lt;text x="85" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="155" y="35" width="110" height="35" class="box idle"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="35" width="110" height="35" class="box idle"/>&lt;text x="335" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="405" y="35" width="110" height="35" class="box active"/>&lt;text x="460" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="530" y="35" width="110" height="35" class="box active2"/>&lt;text x="585" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="655" y="35" width="110" height="35" class="box idle"/>&lt;text x="710" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;path class="arr" d="M140,52 L155,52"/>&lt;path class="arr" d="M265,52 L280,52"/>&lt;path class="arr" d="M390,52 L405,52"/>&lt;path class="arr" d="M515,52 L530,52"/>&lt;path class="arr" d="M640,52 L655,52"/>
&lt;path class="cyc" d="M710,72 L710,82 L85,82 L85,72"/>
&lt;/svg>
&lt;/div>
&lt;h2 id="la-pregunta-que-cambia-el-marco">La pregunta que cambia el marco&lt;/h2>
&lt;p>Cuando un equipo de plataforma adquiere hardware GPU caro y empieza a montar inferencia, la primera versión casi siempre es &lt;strong>mononosa&lt;/strong>: un modelo, un cliente, una latencia objetivo. Funciona. Cuando llega el segundo equipo pidiendo el mismo recurso, &lt;strong>la mononosa se vuelve política interna&lt;/strong>: ¿cuántas réplicas le damos? ¿Qué hacemos si chocan los SLA? ¿Quién paga los tokens del experimento del equipo B? Y cuando llega el tercero, lo que era un proyecto de SRE pasa a ser un proyecto de &lt;strong>producto interno&lt;/strong>.&lt;/p>
&lt;p>La distinción no es técnica, es de marco. &lt;strong>Un cluster es infra&lt;/strong>. &lt;strong>Una plataforma es un servicio con clientes, contratos y métricas de éxito&lt;/strong>. El cambio de marco implica:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Clientes identificables&lt;/strong> (tenants), no usuarios anónimos.&lt;/li>
&lt;li>&lt;strong>Contratos&lt;/strong> (latency SLA, throughput garantizado, modelos disponibles), no &amp;ldquo;lo que dé tiempo&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>Métricas de éxito&lt;/strong> que no son técnicas sino de producto: adopción, satisfaction, cost per query por tenant, tiempo del primer &amp;ldquo;hello world&amp;rdquo;.&lt;/li>
&lt;/ul>
&lt;p>Este post recorre cómo se opera ese cambio de marco. Lo aterriza sobre un &lt;strong>cluster mid-scale (4-8 H100 SXM con NVLink en un solo nodo)&lt;/strong>, configuración habitual cuando se empieza con inferencia LLM seria; pero los principios se generalizan a cualquier topología, desde un nodo único con dos GPUs hasta clusters multi-nodo con InfiniBand.&lt;/p>
&lt;h2 id="las-cuatro-capas-de-una-plataforma-de-inferencia-multi-tenant">Las cuatro capas de una plataforma de inferencia multi-tenant&lt;/h2>
&lt;p>La arquitectura canónica que se ha establecido en 2026 tiene &lt;strong>cuatro capas&lt;/strong> que cualquier plataforma multi-tenant seria implementa, en orden de afuera hacia adentro:&lt;/p>
&lt;div class="diagram" style="max-width:780px;margin:1.5rem auto;">
&lt;svg viewBox="0 0 780 410" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Cuatro capas plataforma multi-tenant">
&lt;style>.title{font:700 13px sans-serif;fill:#222}.lbl{font:600 12px sans-serif;fill:#222}.sm{font:11px sans-serif;fill:#555}.tiny{font:10px sans-serif;fill:#666}.layer{stroke:#444;stroke-width:1.5;rx:6}.gw{fill:#ffe9d6}.pol{fill:#d6eaff}.iso{fill:#d9f5d6}.obs{fill:#e9d6f5}.cluster{stroke:#666;stroke-dasharray:4 2;fill:none}.tenant{stroke:#888;stroke-width:1.4;fill:#fffce6;rx:4}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#pm1)}&lt;/style>
&lt;defs>&lt;marker id="pm1" 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;/defs>
&lt;text x="390" y="22" text-anchor="middle" class="title">Las cuatro capas de la plataforma multi-tenant&lt;/text>
&lt;rect x="40" y="50" width="100" height="40" class="tenant"/>&lt;text x="90" y="68" text-anchor="middle" class="sm">Tenant A&lt;/text>&lt;text x="90" y="82" text-anchor="middle" class="tiny">soporte chat&lt;/text>
&lt;rect x="160" y="50" width="100" height="40" class="tenant"/>&lt;text x="210" y="68" text-anchor="middle" class="sm">Tenant B&lt;/text>&lt;text x="210" y="82" text-anchor="middle" class="tiny">RAG legal&lt;/text>
&lt;rect x="280" y="50" width="100" height="40" class="tenant"/>&lt;text x="330" y="68" text-anchor="middle" class="sm">Tenant C&lt;/text>&lt;text x="330" y="82" text-anchor="middle" class="tiny">agente code&lt;/text>
&lt;rect x="400" y="50" width="100" height="40" class="tenant"/>&lt;text x="450" y="68" text-anchor="middle" class="sm">Tenant D&lt;/text>&lt;text x="450" y="82" text-anchor="middle" class="tiny">data extr.&lt;/text>
&lt;rect x="520" y="50" width="100" height="40" class="tenant"/>&lt;text x="570" y="68" text-anchor="middle" class="sm">Tenant E&lt;/text>&lt;text x="570" y="82" text-anchor="middle" class="tiny">batch ETL&lt;/text>
&lt;rect x="640" y="50" width="100" height="40" class="tenant"/>&lt;text x="690" y="68" text-anchor="middle" class="sm">notebooks&lt;/text>&lt;text x="690" y="82" text-anchor="middle" class="tiny">research&lt;/text>
&lt;rect x="40" y="120" width="700" height="60" class="layer gw"/>
&lt;text x="390" y="144" text-anchor="middle" class="lbl">Capa 1 · AI Gateway&lt;/text>
&lt;text x="55" y="166" class="sm">Auth (OIDC/API keys) · Routing por modelo · Failover · Caching · Logging · OTel emission · Rate limiting&lt;/text>
&lt;rect x="40" y="195" width="700" height="60" class="layer pol"/>
&lt;text x="390" y="219" text-anchor="middle" class="lbl">Capa 2 · Policy &amp;amp; Quota Plane&lt;/text>
&lt;text x="55" y="241" class="sm">Quotas RPS/TPM por tenant · Budgets mensuales · Whitelist modelos · Priority classes · Admission control&lt;/text>
&lt;rect x="40" y="270" width="700" height="60" class="layer iso"/>
&lt;text x="390" y="294" text-anchor="middle" class="lbl">Capa 3 · Isolation Plane&lt;/text>
&lt;text x="55" y="316" class="sm">MIG / MPS / time-slicing · Namespaces K8s · NetworkPolicies · ResourceQuotas · Priority + preemption&lt;/text>
&lt;rect x="40" y="345" width="700" height="55" class="layer obs"/>
&lt;text x="390" y="369" text-anchor="middle" class="lbl">Capa 4 · Observability Plane (multi-tenant)&lt;/text>
&lt;text x="55" y="391" class="sm">Traces con tenant_id · Métricas labeled · Cost attribution · Dashboards por tenant · Audit logs&lt;/text>
&lt;path class="arr" d="M90,90 L390,120"/>
&lt;path class="arr" d="M450,90 L390,120"/>
&lt;path class="arr" d="M690,90 L390,120"/>
&lt;/svg>
&lt;/div>
&lt;p>Cada capa resuelve un problema concreto. Vamos a una por una.&lt;/p>
&lt;h2 id="capa-1--ai-gateway-la-puerta-de-entrada-única">Capa 1 — AI Gateway: la puerta de entrada única&lt;/h2>
&lt;p>El &lt;strong>AI Gateway&lt;/strong> es el componente que tus tenants ven. Es una API HTTP/gRPC compatible con OpenAI (típicamente &lt;code>/v1/chat/completions&lt;/code>, &lt;code>/v1/embeddings&lt;/code>, &lt;code>/v1/models&lt;/code>) que &lt;strong>centraliza&lt;/strong> todo lo que pasa antes de tocar los backends de inferencia.&lt;/p>
&lt;h3 id="por-qué-centralizar">Por qué centralizar&lt;/h3>
&lt;p>Sin gateway, los tenants se conectan directamente a vLLM o al modelo que sea. Cada cambio (rotar un endpoint, añadir un modelo, cambiar credenciales, aplicar política) requiere notificar a todos los tenants. Cada tenant tiene su propia lógica de retry, su propio logging, su propio modelo de auth. Es inoperable a partir del tercer cliente.&lt;/p>
&lt;p>Con gateway, &lt;strong>el cambio se hace en un sitio&lt;/strong>. Los tenants tienen una URL estable y unas credenciales; el resto es problema del gateway.&lt;/p>
&lt;h3 id="las-tres-opciones-dominantes-2026">Las tres opciones dominantes 2026&lt;/h3>
&lt;p>&lt;strong>&lt;a href="https://docs.litellm.ai/">LiteLLM&lt;/a>&lt;/strong> es la opción &lt;strong>OSS más popular&lt;/strong>, Python-first, modelo de despliegue como proxy. Soporta &lt;strong>100+ proveedores&lt;/strong> (OpenAI, Anthropic, Bedrock, vLLM self-hosted, Ollama, etc.) detrás de una API OpenAI-compatible unificada. &lt;strong>Hierarchy nativa multi-tenant&lt;/strong> con Organizations → Teams → Users → API Keys, cada nivel con budget independiente. Versión Apache 2.0 cubre lo básico; &lt;strong>RBAC, SSO, audit logs y team-level enforcement requieren versión Enterprise paga&lt;/strong>. Despliegue en K8s con Helm chart oficial.&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://portkey.ai/">Portkey&lt;/a>&lt;/strong> es la opción &lt;strong>comercial / SaaS&lt;/strong> más madura. Single control plane que enforces budgets, quotas, permissions, compliance. &lt;strong>Real-time spending tracking&lt;/strong> con alerting. RBAC, audit, workspaces, SSO incluidos. Trade-off: dependencia de un servicio externo y modelo de pricing por requests.&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://konghq.com/blog/enterprise/llm-cost-management-ai-showback-and-chargeback">Kong AI Gateway&lt;/a>&lt;/strong> es la opción para organizaciones &lt;strong>que ya tienen Kong como API gateway&lt;/strong>. Plug-in AI sobre el gateway Kong existente, integra con su modelo de plugins, consumers y rate-limits. Si tu equipo de plataforma ya opera Kong, es la fricción más baja.&lt;/p>
&lt;h3 id="cuándo-elegir-cada-uno">Cuándo elegir cada uno&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Situación&lt;/th>
&lt;th>Gateway&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>OSS puro, self-host, equipo Python-first&lt;/td>
&lt;td>&lt;strong>LiteLLM&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Necesitas RBAC, SSO, audit log out-of-the-box, presupuesto disponible&lt;/td>
&lt;td>&lt;strong>Portkey&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Ya operas Kong como API gateway corporativo&lt;/td>
&lt;td>&lt;strong>Kong AI Gateway&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Greenfield enterprise con compliance estricto&lt;/td>
&lt;td>Portkey (probablemente)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Empresa media OSS-first sin compliance regulado&lt;/td>
&lt;td>LiteLLM (típicamente)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="lo-que-el-gateway-tiene-que-hacer-mínimo">Lo que el gateway tiene que hacer mínimo&lt;/h3>
&lt;p>Independientemente de la opción, lo que cualquier deployment serio debe enforcer:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Auth y identidad&lt;/strong>: cada request lleva una API key resoluble a un tenant + usuario + equipo.&lt;/li>
&lt;li>&lt;strong>Routing por modelo&lt;/strong>: el tenant pide &lt;code>model: &amp;quot;gpt-4o&amp;quot;&lt;/code>; el gateway decide si va a OpenAI, a Azure OpenAI, a tu vLLM con Qwen3 32B (fallback más barato), según política.&lt;/li>
&lt;li>&lt;strong>Rate limiting&lt;/strong>: RPS por tenant, TPM (tokens por minuto), concurrency limits.&lt;/li>
&lt;li>&lt;strong>Caching de respuestas idénticas&lt;/strong>: 5-30% de las queries de RAG son repetidas; cachear ahorra latencia y coste.&lt;/li>
&lt;li>&lt;strong>OTel emission&lt;/strong>: cada llamada produce un span con &lt;code>gen_ai.*&lt;/code> semantic conventions y &lt;code>tenant_id&lt;/code> como atributo. Cubierto en &lt;a href="https://blog.lo0.es/posts/evals-llm-la-capa-despues-de-tracing/">post de Evals&lt;/a> y &lt;a href="https://blog.lo0.es/posts/mcp-observability-otel/">MCP observability&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Failover&lt;/strong>: si vLLM se cae, el gateway redirige a OpenAI API. Si OpenAI rate-limita, el gateway tira a Anthropic. Política configurable.&lt;/li>
&lt;/ul>
&lt;h3 id="ejemplo-de-configuración-litellm-multi-tenant">Ejemplo de configuración LiteLLM multi-tenant&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># litellm-config.yaml — ejemplo simplificado&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">model_list&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">model_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">llama-3-70b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">litellm_params&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">model&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">openai/llama-3-70b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">api_base&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">http://vllm-llama3-70b.inference/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">api_key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">os.environ/VLLM_API_KEY&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">model_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">qwen3-32b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">litellm_params&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">model&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">openai/qwen3-32b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">api_base&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">http://vllm-qwen3-32b.inference/v1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">api_key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">os.environ/VLLM_API_KEY&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">model_name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">gpt-4o&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">litellm_params&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">model&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">openai/gpt-4o&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">api_key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">os.environ/OPENAI_API_KEY&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">router_settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">routing_strategy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">usage-based-routing-v2&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">fallbacks&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">llama-3-70b&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="l">qwen3-32b, gpt-4o] &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># si vLLM cae, fallback al externo&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">general_settings&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">master_key&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">os.environ/LITELLM_MASTER_KEY&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">database_url&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">os.environ/DATABASE_URL &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># Postgres para budgets/keys&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># Hierarchy: Organizations → Teams → Users → API Keys&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c"># Se crean vía API, no en YAML estático&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Crear un team con presupuesto:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">curl -X POST http://litellm/team/new &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -H &lt;span class="s2">&amp;#34;Authorization: Bearer &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nv">LITELLM_MASTER_KEY&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="s1">&amp;#39;{
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;team_alias&amp;#34;: &amp;#34;soporte-chat&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;max_budget&amp;#34;: 500, # 500 USD/mes
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;budget_duration&amp;#34;: &amp;#34;30d&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;tpm_limit&amp;#34;: 100000, # 100K tokens/min
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;rpm_limit&amp;#34;: 1000, # 1000 requests/min
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;models&amp;#34;: [&amp;#34;llama-3-70b&amp;#34;, &amp;#34;qwen3-32b&amp;#34;] # acceso a estos
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> }&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Y la API key del team:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">curl -X POST http://litellm/key/generate &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -H &lt;span class="s2">&amp;#34;Authorization: Bearer &lt;/span>&lt;span class="si">${&lt;/span>&lt;span class="nv">LITELLM_MASTER_KEY&lt;/span>&lt;span class="si">}&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> -d &lt;span class="s1">&amp;#39;{
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;team_id&amp;#34;: &amp;#34;&amp;lt;team-id&amp;gt;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;duration&amp;#34;: &amp;#34;30d&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> &amp;#34;metadata&amp;#34;: {&amp;#34;environment&amp;#34;: &amp;#34;production&amp;#34;, &amp;#34;app&amp;#34;: &amp;#34;support-bot&amp;#34;}
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="s1"> }&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Esa API key es lo que el tenant usa. Cada request que pase con ella consumirá del budget del team. Cuando se agote, LiteLLM devuelve &lt;strong>HTTP 429&lt;/strong> con descripción.&lt;/p>
&lt;h2 id="capa-2--policy--quota-plane-qué-puede-hacer-cada-tenant">Capa 2 — Policy &amp;amp; Quota Plane: qué puede hacer cada tenant&lt;/h2>
&lt;p>El gateway es donde se enforza. La política es &lt;strong>lo que se enforza&lt;/strong>. Cinco ejes de política multi-tenant:&lt;/p>
&lt;h3 id="quotas-técnicas">Quotas técnicas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>TPM&lt;/strong> (tokens por minuto): el límite duro de consumo. Para un Llama 3 70B en TP=5, ~3000 tokens/s salidos sostenidos = 180K TPM agregados. Si tienes 10 tenants, asignar 18K cada uno como techo.&lt;/li>
&lt;li>&lt;strong>RPS / RPM&lt;/strong>: control de carga, no de consumo. Una sesión de 4K tokens cuenta como una request; un batch de 100 mini-completions también. Útil contra abuso.&lt;/li>
&lt;li>&lt;strong>Concurrency&lt;/strong>: cuántas requests simultáneas activas por tenant. Importante para SLA de latencia: 100 RPS con concurrency=50 se traducen en 2 segundos por request.&lt;/li>
&lt;/ul>
&lt;h3 id="budgets-económicos">Budgets económicos&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Mensual por tenant&lt;/strong>: hard cap en USD.&lt;/li>
&lt;li>&lt;strong>Diario y por hora&lt;/strong>: soft caps para evitar runaway en un solo día.&lt;/li>
&lt;li>&lt;strong>Por proyecto / API key&lt;/strong>: granularidad fina dentro de un mismo tenant.&lt;/li>
&lt;/ul>
&lt;p>LiteLLM tiene un campo &lt;code>max_budget&lt;/code> en cada nivel de la jerarquía (organization, team, user, api key). Los presupuestos se heredan/restringen hacia abajo.&lt;/p>
&lt;h3 id="whitelist-y-blacklist-de-modelos">Whitelist y blacklist de modelos&lt;/h3>
&lt;p>Tenants con cargas críticas → solo modelos estables (&lt;code>llama-3-70b&lt;/code>, &lt;code>gpt-4o&lt;/code>). Tenants de investigación → acceso también a modelos experimentales.&lt;/p>
&lt;h3 id="priority-classes">Priority classes&lt;/h3>
&lt;p>No todos los requests son iguales. Tres clases típicas:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Guaranteed&lt;/strong>: cargas con SLA, latencia respetada incluso bajo presión.&lt;/li>
&lt;li>&lt;strong>Best-effort&lt;/strong>: cargas normales sin SLA estricto.&lt;/li>
&lt;li>&lt;strong>Spot&lt;/strong>: batches que pueden esperar, evictable si llega un guaranteed.&lt;/li>
&lt;/ul>
&lt;p>El &lt;a href="https://arxiv.org/abs/2603.00356">paper Token Management in Multi-Tenant AI Inference Platforms&lt;/a> (2026) formaliza esto con un &lt;strong>modelo de token pools por priority class&lt;/strong> que se ha empezado a adoptar en producción. Mantiene &lt;strong>P99 latency garantizada&lt;/strong> para guaranteed workloads incluso bajo overload, throttling selectivo sobre spot.&lt;/p>
&lt;h3 id="admission-control">Admission control&lt;/h3>
&lt;p>Antes de aceptar una request: ¿hay capacidad? Si no, devolver 429 inmediatamente en vez de encolar y degradar a todos. Es la disciplina operacional más infravalorada — un cluster con admission control bien hecho tiene &lt;strong>latencia predecible&lt;/strong>; sin él, &lt;strong>catastrophic degradation&lt;/strong> cuando llega el pico.&lt;/p>
&lt;h3 id="el-patrón-típico-en-2026">El patrón típico en 2026&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Política conceptual para un tenant &amp;#34;soporte-chat&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">tenant&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">soporte-chat&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">quotas&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">tpm&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">50000&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">rpm&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">500&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">max_concurrency&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">30&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">budget&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">monthly_usd&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">800&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">alert_thresholds&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="m">0.5&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.8&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">0.95&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># avisa cuando llegues&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">models_allowed&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">llama-3-70b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">qwen3-32b&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">priority&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">guaranteed&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">fallback_on_overload&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">qwen3-32b &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># si guaranteed se llena, fallback&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">gpt-4o-mini &lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c"># último recurso, modelo externo&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="capa-3--isolation-plane-aislar-las-cargas-físicamente">Capa 3 — Isolation Plane: aislar las cargas físicamente&lt;/h2>
&lt;p>Esta es la capa más densa técnicamente. Tienes un nodo con varias GPUs H100 SXM interconectadas por NVLink. ¿Cómo las particionas entre tenants?&lt;/p>
&lt;h3 id="tres-mecanismos-nvidia-para-compartir-gpu">Tres mecanismos NVIDIA para compartir GPU&lt;/h3>
&lt;p>&lt;strong>MIG (Multi-Instance GPU)&lt;/strong> es el aislamiento más fuerte. Particiona la GPU en hasta &lt;strong>7 instancias&lt;/strong> con &lt;strong>memoria HBM separada físicamente&lt;/strong> y &lt;strong>compute units (SMs) dedicados&lt;/strong>. Los tenants en MIG diferentes no pueden tocarse: una carga no consume memoria que otra necesita, una no degrada el throughput de otra. &lt;strong>Aislamiento hardware&lt;/strong>. Disponible en A100, H100, B100, B200.&lt;/p>
&lt;p>&lt;strong>MPS (Multi-Process Service)&lt;/strong> es soft. Múltiples procesos comparten la GPU concurrentemente, NVIDIA reparte SMs según uso. Buen rendimiento si todos los procesos son tuyos y confías en ellos. Peor para multi-tenant entre clientes que no se conocen porque un proceso ruidoso puede degradar a los otros.&lt;/p>
&lt;p>&lt;strong>Time-slicing&lt;/strong> es lo más simple: la GPU se asigna alternadamente, slot por slot, a procesos distintos. Latencia mucho peor (waits entre slots); no se recomienda para cargas de producción con SLA.&lt;/p>
&lt;h3 id="la-elección-para-multi-tenant-2026">La elección para multi-tenant 2026&lt;/h3>
&lt;p>Según el survey de adopción enterprise: &lt;strong>80% usa MIG para multi-tenant no confiable&lt;/strong> (clientes distintos que no se conocen) y &lt;strong>MPS para entornos confiados&lt;/strong> (procesos del mismo equipo) donde quieres maximizar throughput. Time-slicing solo se usa en dev/staging para que cada developer toque GPU sin coste de exclusividad.&lt;/p>
&lt;p>Limitación importante de MIG: &lt;strong>aísla compute y memoria HBM&lt;/strong>, pero &lt;strong>el camino PCIe sigue siendo compartido&lt;/strong>. Para cargas PCIe-bound (mucho tráfico host↔device), tenants en MIG distintos pueden seguir afectándose. Para inferencia LLM, el path principal es HBM, así que esto rara vez es problema. Pero conviene saberlo.&lt;/p>
&lt;h3 id="las-particiones-mig-en-h100">Las particiones MIG en H100&lt;/h3>
&lt;p>Una H100 (80GB HBM3) se puede particionar en perfiles fijos:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Perfil&lt;/th>
&lt;th>SM&lt;/th>
&lt;th>Memoria&lt;/th>
&lt;th>Instancias máx por GPU&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1g.10gb&lt;/td>
&lt;td>14&lt;/td>
&lt;td>10 GB&lt;/td>
&lt;td>7&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1g.20gb&lt;/td>
&lt;td>14&lt;/td>
&lt;td>20 GB&lt;/td>
&lt;td>4&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2g.20gb&lt;/td>
&lt;td>28&lt;/td>
&lt;td>20 GB&lt;/td>
&lt;td>3&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3g.40gb&lt;/td>
&lt;td>42&lt;/td>
&lt;td>40 GB&lt;/td>
&lt;td>2&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>7g.80gb&lt;/td>
&lt;td>98&lt;/td>
&lt;td>80 GB&lt;/td>
&lt;td>1 (toda la GPU)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Para un cluster mid-scale con NVLink, &lt;strong>MIG tiene un problema fundamental&lt;/strong>: cuando particionas con MIG, &lt;strong>se desactiva el NVLink entre GPUs&lt;/strong>. Una H100 en MIG &lt;strong>no&lt;/strong> participa en tensor parallel multi-GPU. Si vas a servir un modelo grande con tensor parallel (Llama 3 70B con TP=4 o TP=8, por ejemplo), esas GPUs deben estar enteras, sin MIG.&lt;/p>
&lt;p>Esto define la decisión arquitectónica. Hay dos enfoques principales:&lt;/p>
&lt;h3 id="enfoque-a--modelo-grande-compartido-con-quotas-en-gateway">Enfoque A — Modelo grande compartido con quotas en gateway&lt;/h3>
&lt;p>Todas las GPUs del nodo sirven &lt;strong>un único modelo grande con tensor parallel&lt;/strong> que abarca el nodo entero. Todos los tenants comparten esa instancia. El aislamiento se hace en la capa de gateway (quotas, rate limiting) y la capa de policy (priority classes). El kernel del cluster es una sola instancia vLLM enorme con &lt;code>--max-num-seqs=128&lt;/code> o similar; vLLM internamente reparte tiempo de GPU entre las requests activas con continuous batching.&lt;/p>
&lt;p>&lt;strong>Ventajas&lt;/strong>: aprovechas todas las GPUs al máximo, NVLink activo, mejor utilización del KV cache.
&lt;strong>Desventajas&lt;/strong>: aislamiento blando — un tenant que satura no degrada a otros directamente (vLLM bachea), pero sí compite por slots del batch. Necesitas priority classes serias.&lt;/p>
&lt;h3 id="enfoque-b--dedicar-gpus-por-modelo--tenant">Enfoque B — Dedicar GPUs por modelo / tenant&lt;/h3>
&lt;p>Divides las GPUs en pools dedicados a modelos distintos. Ejemplos en un nodo de 8 GPUs:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>4 GPUs&lt;/strong>: modelo grande de 70B con TP=4.&lt;/li>
&lt;li>&lt;strong>2 GPUs&lt;/strong>: modelo mediano de 32B replicado (2 instancias independientes) para tenants con SLA estricto.&lt;/li>
&lt;li>&lt;strong>2 GPUs&lt;/strong>: cargas misceláneas (modelos más pequeños, experimentación).&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Ventajas&lt;/strong>: aislamiento físico entre modelos / tenants críticos.
&lt;strong>Desventajas&lt;/strong>: peor utilización agregada; algunas GPUs idle mientras otras saturan.&lt;/p>
&lt;h3 id="enfoque-c-avanzado--mig-en-algunas-gpus--dedicar-el-resto">Enfoque C (avanzado) — MIG en algunas GPUs + dedicar el resto&lt;/h3>
&lt;p>Si tienes cargas pequeñas (modelos de 4B, 7B), puedes hacer MIG en 1-2 GPUs para servirlas y dedicar las restantes a tensor parallel del modelo grande. Combina aislamiento fuerte para cargas chicas con aprovechamiento del NVLink para el modelo grande.&lt;/p>
&lt;h3 id="la-elección-operativa-empieza-por-a-sube-a-c-si-hace-falta">La elección operativa: empieza por A, sube a C si hace falta&lt;/h3>
&lt;p>En la mayoría de despliegues, el Enfoque A (modelo grande compartido + quotas) es el punto de partida correcto. La utilización es mejor, la operación es más simple, y los aislamientos blandos del gateway funcionan para cargas razonables.&lt;/p>
&lt;p>Cuando hay un tenant con SLA estricto que no tolera competir con otros, mueves a Enfoque B para ese tenant en particular (dedicar GPUs a una instancia del modelo solo para él), manteniendo el resto del cluster compartido.&lt;/p>
&lt;p>Enfoque C es para cuando tienes 10+ tenants con perfiles muy heterogéneos.&lt;/p>
&lt;h3 id="aislamiento-a-nivel-kubernetes">Aislamiento a nivel Kubernetes&lt;/h3>
&lt;p>Independiente del aislamiento GPU, en K8s se aplica aislamiento de pod:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Namespaces por tenant&lt;/strong>: &lt;code>tenant-soporte&lt;/code>, &lt;code>tenant-legal&lt;/code>, etc.&lt;/li>
&lt;li>&lt;strong>ResourceQuotas y LimitRanges&lt;/strong>: límites de CPU/memoria por namespace.&lt;/li>
&lt;li>&lt;strong>NetworkPolicies&lt;/strong>: tenant A no puede hablar con namespaces de tenant B.&lt;/li>
&lt;li>&lt;strong>PriorityClasses K8s&lt;/strong>: clases con valor numérico que define preemption order si llega un pod más crítico.&lt;/li>
&lt;li>&lt;strong>PodDisruptionBudgets&lt;/strong>: cuántos pods de cada deployment pueden caer simultáneamente.&lt;/li>
&lt;/ul>
&lt;h2 id="capa-4--observability-plane-ver-lo-que-pasa-por-tenant">Capa 4 — Observability Plane: ver lo que pasa por tenant&lt;/h2>
&lt;p>La cuarta capa: &lt;strong>observabilidad con dimensión tenant&lt;/strong>. Sin esto, no puedes hacer cost attribution, no puedes debugear incidentes de un solo tenant, no puedes mostrar dashboards a stakeholders.&lt;/p>
&lt;h3 id="las-cuatro-propiedades-obligatorias">Las cuatro propiedades obligatorias&lt;/h3>
&lt;p>&lt;strong>1. tenant_id en todos los spans&lt;/strong>. El AI gateway resuelve la API key y atribuye un &lt;code>tenant_id&lt;/code>. Ese ID &lt;strong>se propaga&lt;/strong> vía &lt;code>params._meta&lt;/code> o headers OTel a todos los componentes downstream (vLLM, retrieval, MCP servers, tools). Cualquier span en cualquier sistema lleva ese label. Es lo que permite reconstruir traces tenant-específicos.&lt;/p>
&lt;p>&lt;strong>2. Métricas labeled por tenant&lt;/strong>. &lt;code>gen_ai.usage.input_tokens{tenant=&amp;quot;soporte-chat&amp;quot;}&lt;/code> o equivalentes. Prometheus, Grafana, agrupable por tenant.&lt;/p>
&lt;p>&lt;strong>3. Cost attribution real&lt;/strong>. La suma de tokens × cost/token por tenant da el coste. Para vLLM self-hosted, el coste es por hora de GPU + parte proporcional de tokens (puedes calcular un cost-per-1k-tokens equivalente).&lt;/p>
&lt;p>&lt;strong>4. Audit log inmutable&lt;/strong>. Cada API key usada, cada modelo invocado, cada cambio de quota, cada budget exceeded. Para compliance.&lt;/p>
&lt;h3 id="showback-vs-chargeback">Showback vs chargeback&lt;/h3>
&lt;p>Distinción importante de FinOps que ha ganado claridad en 2026:&lt;/p>
&lt;p>&lt;strong>Showback&lt;/strong>: visibilidad sin consecuencia. &amp;ldquo;Equipo de soporte, has consumido $623 este mes en LLM&amp;rdquo;. Información, no factura. Permite detectar abusos sin penalizar antes de que el equipo entienda.&lt;/p>
&lt;p>&lt;strong>Chargeback&lt;/strong>: el coste se imputa al presupuesto del equipo. Cuando se acaba, se acaba. Cambia comportamiento.&lt;/p>
&lt;p>La práctica que funciona: &lt;strong>6-18 meses en showback&lt;/strong> mientras se calibran tags, se identifican misattributions, se forma a los equipos. &lt;strong>Después chargeback&lt;/strong> cuando los números son creíbles. Lanzar chargeback el día 1 cuando los costs aún están sucios crea pelea política inmediata; lanzar showback prepara terreno para que el chargeback aterrice ordenadamente.&lt;/p>
&lt;p>&lt;a href="https://spendark.com/blog/kubernetes-cost-allocation/">Solo 14% de organizaciones tienen chargeback activo&lt;/a> según un survey reciente, lo que indica que esto sigue siendo mayoritariamente showback en producción real.&lt;/p>
&lt;h3 id="herramientas">Herramientas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://www.kubecost.com/">Kubecost&lt;/a>&lt;/strong>: cost allocation por namespace, deployment, pod en Kubernetes. Para el coste de la GPU compartida, allocate proporcionalmente a tokens consumidos por tenant.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://www.finout.io/">Finout&lt;/a>&lt;/strong>: FinOps platform que combina cloud bills + LLM API costs en una vista unificada con tagging virtual.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://langfuse.com/">Langfuse&lt;/a>&lt;/strong>: ya cubierto. Cost tracking por trace, agrupable por usuario o session metadata.&lt;/li>
&lt;li>&lt;strong>LiteLLM tracking nativo&lt;/strong>: el master DB de LiteLLM mantiene running spend por team, user, API key, accesible vía API o UI.&lt;/li>
&lt;/ul>
&lt;h3 id="dashboard-mínimo-multi-tenant">Dashboard mínimo multi-tenant&lt;/h3>
&lt;p>Cualquier plataforma debería tener:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Resumen por tenant&lt;/strong>: spend mensual, RPS actual, TPM consumido, % budget gastado, sesiones activas.&lt;/li>
&lt;li>&lt;strong>Top usuarios&lt;/strong> dentro de cada tenant (para detección de abuso interno).&lt;/li>
&lt;li>&lt;strong>Latencia p95 por tenant&lt;/strong>: SLA tracking.&lt;/li>
&lt;li>&lt;strong>Errores 429 / 503&lt;/strong>: cuántas requests están siendo rate-limitadas o rechazadas por overload.&lt;/li>
&lt;li>&lt;strong>Cost trend&lt;/strong>: trayectoria mensual con proyección.&lt;/li>
&lt;li>&lt;strong>Drift por tenant&lt;/strong> (de la serie post-tracing): si un tenant empieza a tener peores resultados, alerta.&lt;/li>
&lt;/ol>
&lt;h2 id="dimensionado-en-clusters-gpu-mid-scale-decisiones-concretas">Dimensionado en clusters GPU mid-scale: decisiones concretas&lt;/h2>
&lt;p>Bajemos a hardware. Tomamos como referencia un nodo con &lt;strong>N H100 SXM (entre 4 y 8) con NVLink/NVSwitch&lt;/strong>, 80 GB HBM3 cada una. Eso da entre &lt;strong>320 GB y 640 GB de VRAM agregada&lt;/strong>. Conectividad inter-GPU 900 GB/s (NVLink 4) o 600 GB/s (NVLink 3) según generación. Ancho de banda HBM por GPU 3.35 TB/s.&lt;/p>
&lt;h3 id="decisiones-por-defecto">Decisiones por defecto&lt;/h3>
&lt;p>Empezar con &lt;strong>Enfoque A&lt;/strong>: todas las GPUs del nodo sirviendo &lt;strong>un único modelo grande de 70B en BF16 con tensor parallel = N&lt;/strong>. Capacidad real esperada (calculada para un nodo HGX estándar de 8 GPUs como ejemplo; escala aproximadamente lineal con N):&lt;/p>
&lt;ul>
&lt;li>VRAM modelo (70B BF16): ~140 GB (≈ 17.5 GB/GPU en TP=8).&lt;/li>
&lt;li>VRAM overhead vLLM + activations: ~10 GB/GPU.&lt;/li>
&lt;li>VRAM libre para KV cache: ~52 GB/GPU. En un nodo de 8 GPUs son &lt;strong>~416 GB agregados&lt;/strong>; en uno de 4 son ~210 GB.&lt;/li>
&lt;li>Con &lt;code>--kv-cache-dtype=fp8&lt;/code> y un modelo 70B GQA: ~320 KB/token.&lt;/li>
&lt;li>Capacidad agregada de cache (nodo de 8 GPUs): &lt;strong>~1.3M tokens&lt;/strong> repartibles entre sesiones simultáneas.&lt;/li>
&lt;/ul>
&lt;p>Esto se traduce en throughput y concurrencia (cifras orientativas para un nodo de 8 GPUs):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:right">Sesiones simultáneas&lt;/th>
&lt;th style="text-align:right">Contexto medio por sesión&lt;/th>
&lt;th style="text-align:right">Throughput agregado (tokens/s)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:right">32&lt;/td>
&lt;td style="text-align:right">16K&lt;/td>
&lt;td style="text-align:right">~5000&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:right">64&lt;/td>
&lt;td style="text-align:right">8K&lt;/td>
&lt;td style="text-align:right">~8000&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:right">128&lt;/td>
&lt;td style="text-align:right">4K&lt;/td>
&lt;td style="text-align:right">~12000&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Latencias típicas: &lt;strong>TTFT ~150ms&lt;/strong> a tráfico bajo, &lt;strong>TPOT ~15-20 ms/tok&lt;/strong>. Con concurrencia alta, TTFT sube hasta ~500ms si el queue está saturado.&lt;/p>
&lt;h3 id="esquema-de-tenants-ejemplo">Esquema de tenants ejemplo&lt;/h3>
&lt;p>Cluster con 4 tenants y un pool de research:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Tenant&lt;/th>
&lt;th style="text-align:right">TPM cap&lt;/th>
&lt;th style="text-align:right">RPM cap&lt;/th>
&lt;th style="text-align:right">Concurrency&lt;/th>
&lt;th style="text-align:right">Budget&lt;/th>
&lt;th>Priority&lt;/th>
&lt;th>Modelos&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Soporte chat&lt;/td>
&lt;td style="text-align:right">80K&lt;/td>
&lt;td style="text-align:right">800&lt;/td>
&lt;td style="text-align:right">50&lt;/td>
&lt;td style="text-align:right">1500 USD/mes&lt;/td>
&lt;td>Guaranteed&lt;/td>
&lt;td>llama-3-70b, qwen3-32b&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Legal RAG&lt;/td>
&lt;td style="text-align:right">30K&lt;/td>
&lt;td style="text-align:right">200&lt;/td>
&lt;td style="text-align:right">15&lt;/td>
&lt;td style="text-align:right">600 USD/mes&lt;/td>
&lt;td>Guaranteed&lt;/td>
&lt;td>llama-3-70b&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Agente code&lt;/td>
&lt;td style="text-align:right">50K&lt;/td>
&lt;td style="text-align:right">300&lt;/td>
&lt;td style="text-align:right">25&lt;/td>
&lt;td style="text-align:right">1200 USD/mes&lt;/td>
&lt;td>Best-effort&lt;/td>
&lt;td>llama-3-70b, qwen-coder&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Data extr. batch&lt;/td>
&lt;td style="text-align:right">40K&lt;/td>
&lt;td style="text-align:right">1000&lt;/td>
&lt;td style="text-align:right">40&lt;/td>
&lt;td style="text-align:right">400 USD/mes&lt;/td>
&lt;td>Spot&lt;/td>
&lt;td>llama-3-70b, qwen3-32b&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Research / notebooks&lt;/td>
&lt;td style="text-align:right">10K&lt;/td>
&lt;td style="text-align:right">100&lt;/td>
&lt;td style="text-align:right">5&lt;/td>
&lt;td style="text-align:right">200 USD/mes&lt;/td>
&lt;td>Spot&lt;/td>
&lt;td>todos&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Suma TPM: 210K. Capacidad agregada del cluster: ~180K TPM sostenidos. &lt;strong>Está overcommit del ~15%&lt;/strong>, asumiendo que no todos los tenants llegan al techo simultáneamente. Es lo normal y deseable; si todos lo hacen al mismo tiempo, las priority classes degradan ordenadamente.&lt;/p>
&lt;h3 id="cuándo-añadir-hardware">Cuándo añadir hardware&lt;/h3>
&lt;p>Señales que indican que el nodo se ha quedado pequeño:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>TTFT p95 sostenida &amp;gt; 500 ms&lt;/strong> durante horas de pico → el queue se está acumulando.&lt;/li>
&lt;li>&lt;strong>&lt;code>vllm:num_requests_waiting&lt;/code> constantemente &amp;gt; 20&lt;/strong> → admission control empezando a rechazar.&lt;/li>
&lt;li>&lt;strong>Utilización GPU sostenida &amp;gt; 80% en horas críticas&lt;/strong> sin caer abajo en horas valle → no hay margen.&lt;/li>
&lt;li>&lt;strong>Tasa de 429 sobre los tenants guaranteed &amp;gt; 1%&lt;/strong> → la plataforma rompe SLA en producción.&lt;/li>
&lt;/ul>
&lt;p>Cuando varios de estos se cumplan, el siguiente paso natural es añadir otro nodo HGX con NVLink interno y montar &lt;strong>una segunda instancia vLLM&lt;/strong> del mismo modelo. El gateway hace load balancing entre las dos instancias. Throughput agregado se duplica; latencia se mantiene.&lt;/p>
&lt;h2 id="trampas-operativas-comunes">Trampas operativas comunes&lt;/h2>
&lt;h3 id="gateway-sin-auth-backdoor-al-cluster">Gateway sin auth: backdoor al cluster&lt;/h3>
&lt;p>Tu vLLM está en un Service ClusterIP, la app principal habla con él. Algún tenant directo descubre el endpoint y le pega directamente sin pasar por el gateway. Quotas y costs se evaden silenciosamente. &lt;strong>NetworkPolicy estricta&lt;/strong>: solo el gateway puede hablar con los Service vLLM; el resto del cluster no.&lt;/p>
&lt;h3 id="mig-y-nvlink-incompatibles">MIG y NVLink incompatibles&lt;/h3>
&lt;p>Activas MIG en una GPU pensando que tendrás aislamiento + multi-GPU; descubres que MIG desactiva NVLink. Cualquier modelo grande con TP queda inservible. &lt;strong>Decide MIG vs NVLink globalmente por cluster&lt;/strong>, no por GPU individual.&lt;/p>
&lt;h3 id="quotas-pegadas-al-techo-del-cluster">Quotas pegadas al techo del cluster&lt;/h3>
&lt;p>Sumas los TPM de todos los tenants y dan exactamente la capacidad del cluster. Cuando dos tenants pico simultáneamente, ambos esperan o uno rechaza. &lt;strong>Overcommit 10-20%&lt;/strong> es saludable (asume que no todos pican a la vez); más es peligroso.&lt;/p>
&lt;h3 id="sin-observabilidad-multi-tenant-desde-el-día-1">Sin observabilidad multi-tenant desde el día 1&lt;/h3>
&lt;p>Lanzas con quotas y aislamiento pero sin tenant_id en spans. A los 3 meses, tu CFO pregunta &amp;ldquo;¿cuánto cuesta el agente de soporte vs el de legal?&amp;rdquo; y no puedes responder. &lt;strong>OTel con tenant_id obligatorio desde la primera versión&lt;/strong>, aunque no haya dashboards aún; tener los datos vale más que tener dashboards perfectos sin datos.&lt;/p>
&lt;h3 id="showback-que-nunca-llega-a-chargeback">Showback que nunca llega a chargeback&lt;/h3>
&lt;p>Llevas 18 meses en showback, los equipos saben los números, nadie cambia comportamiento. Sin la presión del chargeback real, el incentivo se diluye. &lt;strong>Calendario explícito&lt;/strong> para la transición a chargeback, con dueño y deadline.&lt;/p>
&lt;h3 id="modelos-no-whitelisteados-consumiendo-presupuesto">Modelos no whitelisteados consumiendo presupuesto&lt;/h3>
&lt;p>Un equipo descubre que LiteLLM tiene &lt;code>gpt-4o&lt;/code> configurado. Lo usa sin permiso. El budget se quema en API externa cuando la idea era usar el self-hosted barato. &lt;strong>Whitelist explícita por team de modelos accesibles&lt;/strong>.&lt;/p>
&lt;h3 id="priority-classes-mal-calibradas">Priority classes mal calibradas&lt;/h3>
&lt;p>Todo el mundo se declara &amp;ldquo;guaranteed&amp;rdquo;. En el primer pico, no queda nada por degradar y todo sufre. &lt;strong>Priority classes solo para casos críticos&lt;/strong> con justificación. La mayoría debería ser best-effort.&lt;/p>
&lt;h3 id="sin-failover-desde-el-gateway">Sin failover desde el gateway&lt;/h3>
&lt;p>Tu vLLM se cae. El gateway no tiene fallback configurado y devuelve 503 a todos los tenants. &lt;strong>Fallback configurado&lt;/strong> a otro modelo, idealmente externo (OpenAI) para cargas guaranteed, aunque pague más por hora — la disponibilidad vale más que el coste por hora.&lt;/p>
&lt;h2 id="roadmap-operativo-de-arranque">Roadmap operativo de arranque&lt;/h2>
&lt;p>Si parte de cero con un nodo GPU vacío, el orden mínimo es el siguiente. Cada hito es un día de trabajo con margen, no apretado:&lt;/p>
&lt;p>&lt;strong>Día 1-2 — Infra base K8s&lt;/strong>. NVIDIA GPU Operator + nvidia-device-plugin + dcgm-exporter + NetworkPolicies cluster-default. Validación: un pod básico con &lt;code>nvidia.com/gpu: 1&lt;/code> se schedulea.&lt;/p>
&lt;p>&lt;strong>Día 3 — vLLM con un modelo grande y tensor parallel del nodo entero&lt;/strong>. Helm chart de vLLM Production Stack (o vLLM bare manifests). Pesos del modelo en PVC compartido (CephFS o NFS). Validación: una petición &lt;code>curl&lt;/code> contra el Service interno responde.&lt;/p>
&lt;p>&lt;strong>Día 4 — AI Gateway: LiteLLM&lt;/strong>. Helm chart, Postgres para budgets, master key, primer model_list pointing a vLLM. Validación: una petición OpenAI-compatible vía LiteLLM responde con el mismo contenido que el vLLM directo.&lt;/p>
&lt;p>&lt;strong>Día 5 — Multi-tenancy básica&lt;/strong>. Crear teams, API keys, budget, model whitelist. Probar con dos teams. Validación: el segundo team usando el modelo que no tiene whitelisteado recibe 403.&lt;/p>
&lt;p>&lt;strong>Día 6 — Observabilidad mínima&lt;/strong>. Prometheus + Grafana scraping vLLM y LiteLLM. Dashboard con TTFT, TPOT, throughput, num_requests_waiting, budget_consumed_per_team. Validación: visible en Grafana con datos reales.&lt;/p>
&lt;p>&lt;strong>Día 7-8 — Cliente piloto&lt;/strong>. Un tenant real (idealmente uno interno controlado) empieza a usar. Mide latencias reales, descubre los primeros incidentes operativos.&lt;/p>
&lt;p>&lt;strong>Día 9-10 — Tuning&lt;/strong>. Ajustar &lt;code>--max-num-seqs&lt;/code>, &lt;code>--gpu-memory-utilization&lt;/code>, priority classes, quotas según lo aprendido del piloto.&lt;/p>
&lt;p>&lt;strong>Día 11-14 — Onboarding del segundo tenant + iteración&lt;/strong>. Repeat. Cada nuevo tenant onboarded revela nuevos casos.&lt;/p>
&lt;p>A las dos semanas tienes una plataforma operacional con dos tenants reales y datos para decidir si está lista para más. La línea de avance de aquí en adelante es &lt;strong>horizontal&lt;/strong> (más tenants) hasta saturar; a partir de ahí, &lt;strong>vertical&lt;/strong> (más hardware).&lt;/p>
&lt;h2 id="lo-que-no-hemos-cubierto-próximos-posts">Lo que no hemos cubierto (próximos posts)&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Fine-tuning continuo en producción&lt;/strong> (post 6, decidido): LoRA/QLoRA/DPO, dataset curation, eval gates, A/B versioning con tráfico real entre versiones del modelo.&lt;/li>
&lt;li>&lt;strong>Constitutional AI y alignment runtime&lt;/strong>: opción que sigue en la mesa.&lt;/li>
&lt;li>&lt;strong>Edge LLMs&lt;/strong>: cuando un cluster H100 es demasiado caro para una carga concreta, modelos distillados corriendo en NPUs o GPUs consumer.&lt;/li>
&lt;li>&lt;strong>GPU networking deep dive&lt;/strong>: NCCL, InfiniBand, GPUDirect, RDMA. Para clusters multi-nodo con tensor parallel cross-host.&lt;/li>
&lt;/ul>
&lt;h2 id="referencias">Referencias&lt;/h2>
&lt;p>Multi-tenancy y aislamiento GPU:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.linuxoperatingsystem.net/multitenant-gpu-infrastructure-4-powerful-design-rules/">Multitenant GPU Infrastructure: 4 Powerful Design Rules&lt;/a> — survey de patrones enterprise.&lt;/li>
&lt;li>&lt;a href="https://www.spheron.network/blog/run-multiple-llms-one-gpu-mig-time-slicing-guide/">Run Multiple LLMs on One GPU: MIG, Time-Slicing, and MPS Guide (Spheron)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://sagar-parmar.medium.com/a-practical-guide-to-gpu-partitioning-with-mig-on-on-prem-servers-and-kubernetes-797ccea7e1c7">A Practical Guide to GPU Partitioning with MIG (Medium)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.suse.com/c/kubecon-eu-2026-nvidia-mig-suse-virtualization/">GPU Partitioning for AI Workloads: NVIDIA MIG with SUSE Virtualization (KubeCon EU 2026)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://arxiv.org/abs/2508.20274">Predictable LLM Serving on GPU Clusters (arxiv 2508.20274)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://arxiv.org/abs/2603.00356">Token Management in Multi-Tenant AI Inference Platforms (arxiv 2603.00356)&lt;/a> — paper de priority + admission control.&lt;/li>
&lt;/ul>
&lt;p>AI Gateways:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://docs.litellm.ai/docs/proxy/multi_tenant_architecture">LiteLLM — Multi-Tenant Architecture&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://docs.litellm.ai/docs/proxy/users">LiteLLM — Budgets and Rate Limits&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://portkey.ai/">Portkey AI Gateway&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://konghq.com/blog/enterprise/llm-cost-management-ai-showback-and-chargeback">Kong AI Gateway — LLM Cost Management&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.spheron.network/blog/ai-gateway-litellm-portkey-kong-gpu-cloud/">AI Gateway Setup 2026: LiteLLM, Portkey, Kong (Spheron)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://techsy.io/en/blog/best-llm-gateway-tools">Stop Juggling LLM APIs: 8 Gateways Ranked 2026 (TECHSY)&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>FinOps multi-tenant:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.digiusher.com/blog/the-death-of-cost-allocation-why-chargeback-models-are-failing-in-the-kubernetes-and-ai-era/">The Death of Chargeback in the Kubernetes and AI Era (DigiUsher)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://medium.com/@nicholasthoni/how-to-actually-track-kubernetes-costs-in-2026-a-practical-guide-to-showback-chargeback-and-the-6a4c23f9cf51">How to Actually Track Kubernetes Costs in 2026 (Medium)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://konghq.com/blog/enterprise/llm-cost-management-ai-showback-and-chargeback">LLM Cost Management: AI Showback and Chargeback (Kong)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.kubecost.com/">Kubecost — cost allocation&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.finout.io/">Finout — FinOps + AI costs&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Cross-references:&lt;/p>
&lt;ul>
&lt;li>Posts previos serie 4: &lt;a href="https://blog.lo0.es/posts/mlops-llms-panorama-2026/">Panorama MLOps LLMs&lt;/a>, &lt;a href="https://blog.lo0.es/posts/rag-kafka-datalake-arquitectura/">RAG sobre Kafka&lt;/a>, &lt;a href="https://blog.lo0.es/posts/pipeline-llmops-seis-etapas/">Pipeline de 6 etapas&lt;/a>, &lt;a href="https://blog.lo0.es/posts/postgresql-qdrant-ingestion-microservicios/">PostgreSQL + Qdrant&lt;/a>.&lt;/li>
&lt;li>Posts relevantes de la serie inferencia: &lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">vLLM en Kubernetes&lt;/a> — el escenario de nodo HGX multi-GPU que aquí desarrollamos. &lt;a href="https://blog.lo0.es/posts/operators-llm-kubernetes/">Operators LLM K8s&lt;/a> — vLLM Production Stack y OME que el gateway puede dirigir.&lt;/li>
&lt;li>Observabilidad: &lt;a href="https://blog.lo0.es/posts/evals-llm-la-capa-despues-de-tracing/">Evals&lt;/a>, &lt;a href="https://blog.lo0.es/posts/mcp-observability-otel/">MCP observability&lt;/a>, &lt;a href="https://blog.lo0.es/posts/ebpf-on-device-inference-drift/">eBPF + drift&lt;/a>.&lt;/li>
&lt;/ul></description></item><item><title>El pipeline LLMOps de seis etapas: arquitectura global y deep dive en cada componente</title><link>https://blog.lo0.es/posts/pipeline-llmops-seis-etapas/</link><pubDate>Thu, 21 May 2026 06:30:00 +0200</pubDate><guid>https://blog.lo0.es/posts/pipeline-llmops-seis-etapas/</guid><description>&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Los dos primeros posts de la serie establecieron el &lt;a href="https://blog.lo0.es/posts/mlops-llms-panorama-2026/">panorama LLMOps&lt;/a> y bajaron al detalle del &lt;a href="https://blog.lo0.es/posts/rag-kafka-datalake-arquitectura/">pipeline de datos con Kafka&lt;/a>. Este post hace el zoom intermedio: dibuja &lt;strong>el mapa completo del sistema&lt;/strong> —una arquitectura global de un LLMOps moderno con todas las piezas que el campo ha estabilizado en 2026— y entra en profundidad en cada una de las &lt;strong>seis etapas canónicas del pipeline&lt;/strong>: &lt;strong>Data&lt;/strong>, &lt;strong>Tune&lt;/strong>, &lt;strong>Eval&lt;/strong>, &lt;strong>Deploy&lt;/strong>, &lt;strong>Observe&lt;/strong>, &lt;strong>Retrain&lt;/strong>. Para cada etapa damos las &lt;strong>sub-tareas operativas&lt;/strong>, las &lt;strong>herramientas dominantes&lt;/strong>, las &lt;strong>decisiones de diseño&lt;/strong> que aparecen siempre, y las &lt;strong>trampas específicas&lt;/strong> que se ven repetidamente en producción. Y, lo más importante operativamente: cada etapa lleva un &lt;strong>mini-mapa &amp;ldquo;estás aquí&amp;rdquo;&lt;/strong> sobre el ciclo, que se reutilizará en cualquier post posterior de la serie para situar al lector. La idea: que cualquiera leyendo un post sobre fine-tuning, sobre prompt versioning, sobre eval gates o sobre drift detection, pueda mirar el mini-mapa y saber inmediatamente en qué pieza del sistema más grande está pensando ese día.&lt;/p>
&lt;blockquote>
&lt;p>Este es el &lt;strong>tercer post de la serie MLOps específico para LLMs&lt;/strong>. Anteriores: &lt;a href="https://blog.lo0.es/posts/mlops-llms-panorama-2026/">Panorama 2026&lt;/a> y &lt;a href="https://blog.lo0.es/posts/rag-kafka-datalake-arquitectura/">RAG sobre Kafka&lt;/a>. Aquí pasamos de &amp;ldquo;el qué&amp;rdquo; y &amp;ldquo;una pieza&amp;rdquo; a &lt;strong>el mapa entero&lt;/strong>, con detalle por etapa.&lt;/p>
&lt;/blockquote>
&lt;h2 id="la-arquitectura-global-el-mapa-maestro">La arquitectura global: el mapa maestro&lt;/h2>
&lt;p>Antes de bajar a cada etapa, fijemos el mapa entero. Lo que sigue es el dibujo de referencia de un sistema LLMOps de producción en 2026, con todos los componentes que el campo ha estabilizado en su lugar:&lt;/p>
&lt;div class="diagram" style="max-width:780px;margin:1.5rem auto;">
&lt;svg viewBox="0 0 780 580" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Arquitectura global LLMOps 2026">
&lt;style>.title{font:700 14px sans-serif;fill:#222}.stage-title{font:700 13px sans-serif;fill:#222}.lbl{font:11px sans-serif;fill:#333}.sm{font:10px sans-serif;fill:#555}.tiny{font:9px sans-serif;fill:#666}.stage{stroke:#444;stroke-width:1.5;rx:8}.data{fill:#ffe9d6}.tune{fill:#ffd6d6}.eval{fill:#d6eaff}.deploy{fill:#d9f5d6}.obs{fill:#e9d6f5}.retrain{fill:#fff5b0}.cross{fill:#f0f0f0;stroke:#888;stroke-dasharray:4 2;rx:6}.arr{stroke:#444;stroke-width:1.6;fill:none;marker-end:url(#ar)}.cycle{stroke:#888;stroke-width:1.4;fill:none;marker-end:url(#ar);stroke-dasharray:6 3}&lt;/style>
&lt;defs>&lt;marker id="ar" 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="#444"/>&lt;/marker>&lt;/defs>
&lt;text x="390" y="22" text-anchor="middle" class="title">Arquitectura global LLMOps 2026 — las seis etapas y los componentes transversales&lt;/text>
&lt;rect x="20" y="50" width="240" height="170" class="stage data"/>
&lt;text x="140" y="72" text-anchor="middle" class="stage-title">1 · DATA&lt;/text>
&lt;text x="35" y="92" class="sm">• Origenes: OLTP, APIs, logs, scraping&lt;/text>
&lt;text x="35" y="108" class="sm">• CDC: Debezium, Flink CDC&lt;/text>
&lt;text x="35" y="124" class="sm">• Transport: Kafka + Schema Registry&lt;/text>
&lt;text x="35" y="140" class="sm">• Stream proc: Flink SQL, RisingWave&lt;/text>
&lt;text x="35" y="156" class="sm">• Versioning: DVC + lakeFS&lt;/text>
&lt;text x="35" y="172" class="sm">• Tableflow → Iceberg/Delta&lt;/text>
&lt;text x="35" y="188" class="sm">• Vector stores: Milvus, Qdrant,&lt;/text>
&lt;text x="35" y="202" class="sm"> Weaviate, pgvector, LanceDB&lt;/text>
&lt;rect x="280" y="50" width="240" height="170" class="stage tune"/>
&lt;text x="400" y="72" text-anchor="middle" class="stage-title">2 · TUNE&lt;/text>
&lt;text x="295" y="92" class="sm">• Modalidades: fine-tune / RAG /&lt;/text>
&lt;text x="295" y="106" class="sm"> agent training&lt;/text>
&lt;text x="295" y="124" class="sm">• Frameworks: PEFT, Axolotl, TRL,&lt;/text>
&lt;text x="295" y="138" class="sm"> Unsloth, llama-factory&lt;/text>
&lt;text x="295" y="156" class="sm">• Técnicas: LoRA, QLoRA, DPO, RLHF&lt;/text>
&lt;text x="295" y="172" class="sm">• Clusters: H100/B200 + NVLink&lt;/text>
&lt;text x="295" y="188" class="sm">• Experiment tracking: MLflow, W&amp;amp;B&lt;/text>
&lt;text x="295" y="202" class="sm">• Adapter registry: HF Hub privado&lt;/text>
&lt;rect x="540" y="50" width="220" height="170" class="stage eval"/>
&lt;text x="650" y="72" text-anchor="middle" class="stage-title">3 · EVAL&lt;/text>
&lt;text x="555" y="92" class="sm">• CI frameworks: DeepEval,&lt;/text>
&lt;text x="555" y="106" class="sm"> Promptfoo, Ragas, OpenAI Evals&lt;/text>
&lt;text x="555" y="124" class="sm">• Platforms: Langfuse, LangSmith,&lt;/text>
&lt;text x="555" y="138" class="sm"> Phoenix, Braintrust&lt;/text>
&lt;text x="555" y="156" class="sm">• Judge LLM (G-Eval, Prometheus)&lt;/text>
&lt;text x="555" y="172" class="sm">• Golden dataset versionado&lt;/text>
&lt;text x="555" y="188" class="sm">• Eval gates en CI/CD&lt;/text>
&lt;text x="555" y="202" class="sm">• Calibración 85-90% vs humano&lt;/text>
&lt;rect x="20" y="245" width="240" height="170" class="stage deploy"/>
&lt;text x="140" y="267" text-anchor="middle" class="stage-title">4 · DEPLOY&lt;/text>
&lt;text x="35" y="287" class="sm">• Model registry: MLflow, OME&lt;/text>
&lt;text x="35" y="303" class="sm">• Serving: vLLM, SGLang, TRT-LLM&lt;/text>
&lt;text x="35" y="319" class="sm">• Operators K8s: vLLM Prod Stack,&lt;/text>
&lt;text x="35" y="333" class="sm"> KServe, OME, NVIDIA Dynamo, llm-d&lt;/text>
&lt;text x="35" y="349" class="sm">• Gateway / router: LiteLLM&lt;/text>
&lt;text x="35" y="365" class="sm">• Estrategias: canary, blue-green,&lt;/text>
&lt;text x="35" y="379" class="sm"> shadow, A/B versioning&lt;/text>
&lt;text x="35" y="395" class="sm">• Autoscaling: KEDA + métricas LLM&lt;/text>
&lt;rect x="280" y="245" width="240" height="170" class="stage obs"/>
&lt;text x="400" y="267" text-anchor="middle" class="stage-title">5 · OBSERVE&lt;/text>
&lt;text x="295" y="287" class="sm">• Tracing: OpenLLMetry, Langfuse,&lt;/text>
&lt;text x="295" y="301" class="sm"> Phoenix, LangSmith&lt;/text>
&lt;text x="295" y="319" class="sm">• Métricas: Prometheus, Grafana&lt;/text>
&lt;text x="295" y="335" class="sm">• Guardrails: NeMo, Llama Guard 4,&lt;/text>
&lt;text x="295" y="349" class="sm"> LLM Guard, Lakera&lt;/text>
&lt;text x="295" y="367" class="sm">• eBPF: Hubble, Tetragon, AgentSight&lt;/text>
&lt;text x="295" y="383" class="sm">• MCP observability (OTel GenAI)&lt;/text>
&lt;text x="295" y="399" class="sm">• Drift: Evidently, NannyML, WhyLabs&lt;/text>
&lt;rect x="540" y="245" width="220" height="170" class="stage retrain"/>
&lt;text x="650" y="267" text-anchor="middle" class="stage-title">6 · RETRAIN&lt;/text>
&lt;text x="555" y="287" class="sm">• Feedback explícito (thumbs)&lt;/text>
&lt;text x="555" y="303" class="sm">• Feedback implícito (latencia,&lt;/text>
&lt;text x="555" y="317" class="sm"> abandonment, retries)&lt;/text>
&lt;text x="555" y="335" class="sm">• Triaging de incidentes&lt;/text>
&lt;text x="555" y="351" class="sm">• Dataset enrichment con casos&lt;/text>
&lt;text x="555" y="365" class="sm"> donde el modelo falló&lt;/text>
&lt;text x="555" y="383" class="sm">• Cadence: trimestral o&lt;/text>
&lt;text x="555" y="397" class="sm"> incident-driven&lt;/text>
&lt;rect x="100" y="440" width="580" height="120" class="cross"/>
&lt;text x="390" y="462" text-anchor="middle" class="stage-title">Componentes transversales (atraviesan todas las etapas)&lt;/text>
&lt;text x="115" y="482" class="sm">• OpenTelemetry Collector (gen_ai.* y mcp.* semantic conventions)&lt;/text>
&lt;text x="115" y="498" class="sm">• Prompt versioning: Langfuse / MLflow Prompts (versionado v1/v2/v3 + labels + cache)&lt;/text>
&lt;text x="115" y="514" class="sm">• MCP servers + MCP Gateway (Traefik Hub, MintMCP) — interfaz herramientas-modelo&lt;/text>
&lt;text x="115" y="530" class="sm">• Model gateway: LiteLLM (100+ providers unificados como una API OpenAI-compatible)&lt;/text>
&lt;text x="115" y="546" class="sm">• Schema Registry (Avro/Protobuf/JSON Schema) compartido entre data y serving&lt;/text>
&lt;path class="arr" d="M260,135 L280,135"/>
&lt;path class="arr" d="M520,135 L540,135"/>
&lt;path class="arr" d="M650,220 L650,245"/>
&lt;path class="arr" d="M540,330 L520,330"/>
&lt;path class="arr" d="M280,330 L260,330"/>
&lt;path class="arr" d="M140,415 L140,440"/>
&lt;path class="arr" d="M400,415 L400,440"/>
&lt;path class="arr" d="M650,415 L650,440"/>
&lt;path class="cycle" d="M650,330 C780,330 780,135 760,135 L760,135"/>
&lt;text x="745" y="245" class="sm" text-anchor="middle">ciclo&lt;/text>
&lt;/svg>
&lt;/div>
&lt;p>Lo que ves: las &lt;strong>seis cajas grandes&lt;/strong> son las etapas; las &lt;strong>flechas continuas&lt;/strong> son el flujo del pipeline; la &lt;strong>flecha discontinua&lt;/strong> que va de &lt;strong>Retrain&lt;/strong> a &lt;strong>Data&lt;/strong> es el ciclo de feedback que convierte LLMOps en un proceso vivo, no en un proyecto que termina. La banda gris al pie son &lt;strong>componentes transversales&lt;/strong> —observabilidad, prompt versioning, MCP, gateway, schema— que atraviesan todas las etapas y se conectan a cada una.&lt;/p>
&lt;p>Tres lecturas rápidas del mapa:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Horizontal arriba&lt;/strong>: el camino feliz, &lt;strong>data → tune → eval&lt;/strong>. Lo que pasa cuando preparas el modelo.&lt;/li>
&lt;li>&lt;strong>Horizontal abajo&lt;/strong>: el camino de servicio, &lt;strong>deploy → observe → retrain&lt;/strong>. Lo que pasa cuando el modelo está vivo.&lt;/li>
&lt;li>&lt;strong>Vertical&lt;/strong>: la conexión entre los dos pisos. Eval gateway alimenta Deploy; Observe alimenta Retrain; Retrain devuelve a Data.&lt;/li>
&lt;/ul>
&lt;p>Cada etapa de aquí en adelante incluirá un &lt;strong>mini-mapa de navegación&lt;/strong> (&amp;ldquo;estás aquí&amp;rdquo;) para situarte en el ciclo completo. Vamos a cada una.&lt;/p>
&lt;h2 id="etapa-1--data-ingestión-transporte-versionado-indexación">Etapa 1 — Data: ingestión, transporte, versionado, indexación&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 90" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="estás aquí: Data">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#ff8a4c;stroke-width:3}.idle{fill:#f4f4f4}.lbl{font:600 12px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#mn)}.cyc{stroke:#888;stroke-width:1.2;fill:none;stroke-dasharray:4 2;marker-end:url(#mn)}&lt;/style>
&lt;defs>&lt;marker id="mn" 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;/defs>
&lt;text x="390" y="20" text-anchor="middle" class="lbl">Estás aquí: DATA · ingestión → transporte → versionado → indexación&lt;/text>
&lt;rect x="30" y="35" width="110" height="35" class="box active"/>&lt;text x="85" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="155" y="35" width="110" height="35" class="box idle"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="35" width="110" height="35" class="box idle"/>&lt;text x="335" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="405" y="35" width="110" height="35" class="box idle"/>&lt;text x="460" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="530" y="35" width="110" height="35" class="box idle"/>&lt;text x="585" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="655" y="35" width="110" height="35" class="box idle"/>&lt;text x="710" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;path class="arr" d="M140,52 L155,52"/>&lt;path class="arr" d="M265,52 L280,52"/>&lt;path class="arr" d="M390,52 L405,52"/>&lt;path class="arr" d="M515,52 L530,52"/>&lt;path class="arr" d="M640,52 L655,52"/>
&lt;path class="cyc" d="M710,72 L710,82 L85,82 L85,72"/>
&lt;/svg>
&lt;/div>
&lt;h3 id="sub-tareas-operativas">Sub-tareas operativas&lt;/h3>
&lt;p>La etapa Data es la más infravalorada y la que más bloquea proyectos. Sus sub-tareas:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Ingestión&lt;/strong> desde origenes heterogéneos: bases de datos OLTP (Postgres, MySQL), APIs externas, file shares, scraping, sistemas SaaS, logs de aplicaciones, mensajería interna.&lt;/li>
&lt;li>&lt;strong>Captura de cambios&lt;/strong> (CDC) en streaming si el dato es dinámico. Debezium sobre Kafka, Flink CDC, alternativas modernas como RisingWave que lee WAL directamente.&lt;/li>
&lt;li>&lt;strong>Transformación&lt;/strong> (cleansing, dedup, normalización, sanitization de PII).&lt;/li>
&lt;li>&lt;strong>Schema management&lt;/strong>: registro de esquemas, evolución compatible, compatibilidad backward/forward.&lt;/li>
&lt;li>&lt;strong>Versionado&lt;/strong> de datasets de training y golden datasets: DVC + lakeFS (unificadas en noviembre 2025).&lt;/li>
&lt;li>&lt;strong>Indexación&lt;/strong> para RAG: chunking, embeddings, escritura a vector stores. Cubierto en profundidad en el &lt;a href="https://blog.lo0.es/posts/rag-kafka-datalake-arquitectura/">post de Kafka&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Materialización&lt;/strong> a tablas analíticas: Tableflow → Iceberg/Delta, para consumo de BI y queries de baja latencia.&lt;/li>
&lt;/ul>
&lt;h3 id="herramientas-dominantes">Herramientas dominantes&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Sub-tarea&lt;/th>
&lt;th>Herramientas 2026&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>CDC&lt;/td>
&lt;td>Debezium, Flink CDC, RisingWave&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Transport&lt;/td>
&lt;td>Kafka (Confluent Cloud, Redpanda, Apache puro)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Schema Registry&lt;/td>
&lt;td>Confluent Schema Registry, Apicurio&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Stream processing&lt;/td>
&lt;td>Apache Flink, RisingWave, Kafka Streams&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Versionado de datos&lt;/td>
&lt;td>DVC + lakeFS&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Vector stores&lt;/td>
&lt;td>Milvus, Qdrant, Weaviate, pgvector, LanceDB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Tablas materializadas&lt;/td>
&lt;td>Tableflow → Iceberg/Delta&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ETL/ELT batch (cuando aplica)&lt;/td>
&lt;td>dbt + Snowflake/Databricks&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="decisiones-de-diseño">Decisiones de diseño&lt;/h3>
&lt;p>Las tres decisiones que aparecen siempre:&lt;/p>
&lt;p>&lt;strong>Batch vs streaming&lt;/strong>: cuanto más dinámico sea el dato, más streaming. Para corpus estáticos (manuales que nunca cambian) batch nocturno basta; para datos transaccionales que el agente necesita ver minuto a minuto, streaming desde el día 1.&lt;/p>
&lt;p>&lt;strong>Embedding model&lt;/strong>: cambiar el modelo de embeddings invalida todos los vectores indexados. Decisión arquitectónica: pinning del modelo + plan explícito de migración (dual-index pattern visto en el post de Kafka).&lt;/p>
&lt;p>&lt;strong>Vector store&lt;/strong>: pgvector si ya tienes Postgres operado y eres &amp;lt;10M vectores; Qdrant si quieres simplicidad mid-scale; Milvus si necesitas billones; Weaviate si valoras hybrid search nativo.&lt;/p>
&lt;h3 id="trampas">Trampas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Hardcodear conexiones a la fuente&lt;/strong> (sin abstracción): cuando la base de datos cambia (versión, host, esquema), rompes todo el pipeline. &lt;strong>Adapter layer&lt;/strong> desde el día 1.&lt;/li>
&lt;li>&lt;strong>Sin schema registry&lt;/strong>: los topics empiezan a romperse silenciosamente.&lt;/li>
&lt;li>&lt;strong>Reindexación full cuando algo cambia&lt;/strong>: cuesta horas o días. Diseñar &lt;strong>dual-index pattern&lt;/strong> desde el principio.&lt;/li>
&lt;li>&lt;strong>PII no sanitizada&lt;/strong>: el RAG está sirviendo datos sensibles sin querer. Anonymización en el pipeline, no en el consumo.&lt;/li>
&lt;/ul>
&lt;h2 id="etapa-2--tune-preparar-el-modelo-para-tu-caso">Etapa 2 — Tune: preparar el modelo para tu caso&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 90" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="estás aquí: Tune">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#ff7777;stroke-width:3}.idle{fill:#f4f4f4}.lbl{font:600 12px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#mn2)}.cyc{stroke:#888;stroke-width:1.2;fill:none;stroke-dasharray:4 2;marker-end:url(#mn2)}&lt;/style>
&lt;defs>&lt;marker id="mn2" 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;/defs>
&lt;text x="390" y="20" text-anchor="middle" class="lbl">Estás aquí: TUNE · fine-tuning / RAG-as-tuning / agent training&lt;/text>
&lt;rect x="30" y="35" width="110" height="35" class="box idle"/>&lt;text x="85" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="155" y="35" width="110" height="35" class="box active"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="35" width="110" height="35" class="box idle"/>&lt;text x="335" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="405" y="35" width="110" height="35" class="box idle"/>&lt;text x="460" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="530" y="35" width="110" height="35" class="box idle"/>&lt;text x="585" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="655" y="35" width="110" height="35" class="box idle"/>&lt;text x="710" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;path class="arr" d="M140,52 L155,52"/>&lt;path class="arr" d="M265,52 L280,52"/>&lt;path class="arr" d="M390,52 L405,52"/>&lt;path class="arr" d="M515,52 L530,52"/>&lt;path class="arr" d="M640,52 L655,52"/>
&lt;path class="cyc" d="M710,72 L710,82 L85,82 L85,72"/>
&lt;/svg>
&lt;/div>
&lt;h3 id="sub-tareas-operativas-1">Sub-tareas operativas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Selección de modelo base&lt;/strong>: Llama, Qwen, Mistral, Gemma, DeepSeek según licencia, tamaño, calidad en tu dominio.&lt;/li>
&lt;li>&lt;strong>Preparación del dataset&lt;/strong>: split train/val/test, formato (chat templates, JSONL), augmentación si aplica.&lt;/li>
&lt;li>&lt;strong>Configuración del adapter&lt;/strong>: LoRA rank, target modules, alpha; QLoRA si quieres entrenar en una GPU consumer; full fine-tune solo si tienes presupuesto.&lt;/li>
&lt;li>&lt;strong>Training loop&lt;/strong>: HuggingFace Transformers + PEFT + TRL como stack canónico; Axolotl o llama-factory como wrappers convenience; Unsloth si quieres 2-4× más velocidad en GPUs consumer.&lt;/li>
&lt;li>&lt;strong>Hyperparameter sweep&lt;/strong>: W&amp;amp;B Sweeps, Optuna, Ray Tune.&lt;/li>
&lt;li>&lt;strong>Checkpointing y resumability&lt;/strong>: save cada N pasos, resume desde fallo.&lt;/li>
&lt;li>&lt;strong>Promotion&lt;/strong>: el adapter promueve al registry tras pasar la siguiente etapa (Eval).&lt;/li>
&lt;/ul>
&lt;h3 id="las-tres-modalidades-de-tune">Las tres modalidades de Tune&lt;/h3>
&lt;p>Detalle del cuadro que vimos en el &lt;a href="https://blog.lo0.es/posts/mlops-llms-panorama-2026/">panorama&lt;/a>:&lt;/p>
&lt;p>&lt;strong>Fine-tuning supervisado (SFT)&lt;/strong> con LoRA/QLoRA. Recoges pares (prompt, ideal-response), aplicas SFT con cross-entropy loss. Lo más simple. La regla del pulgar: &lt;strong>300-3 000 ejemplos&lt;/strong> bien curados suelen ser más útiles que 50 000 ruidosos.&lt;/p>
&lt;p>&lt;strong>DPO (Direct Preference Optimization)&lt;/strong> y &lt;strong>RLAIF&lt;/strong>. En vez de &amp;ldquo;ideal-response&amp;rdquo;, recoges pares &lt;strong>(prompt, respuesta_buena, respuesta_mala)&lt;/strong> y entrenas al modelo a preferir la buena. Más estable que RLHF clásico, mismo objetivo. Es lo que la mayoría de equipos usa cuando van más allá de SFT.&lt;/p>
&lt;p>&lt;strong>Agent training&lt;/strong> (RFT / Reinforcement Fine-Tuning, RLHF puro). Para casos donde el modelo necesita aprender &lt;strong>trayectorias multistep&lt;/strong>: cuándo elegir tool A vs B, cuándo pedir confirmación, cómo descomponer una tarea grande. Mucho más caro y complejo. Lo de OpenAI con RFT marcó el patrón en 2024-2025; en 2026 está saliendo del experimental.&lt;/p>
&lt;p>&lt;strong>RAG como alternativa a Tune&lt;/strong>: aunque conceptualmente es otra etapa (vive en Data + Deploy), funcionalmente compite con fine-tuning para muchos casos. El veredicto 2026: &lt;strong>hybrid es default&lt;/strong> (60% de despliegues), fine-tune para behavior + RAG para conocimiento volátil.&lt;/p>
&lt;h3 id="herramientas">Herramientas&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Aspecto&lt;/th>
&lt;th>Herramientas 2026&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Framework base&lt;/td>
&lt;td>HuggingFace Transformers, PEFT, TRL&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Wrappers convenience&lt;/td>
&lt;td>Axolotl, llama-factory&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Velocidad consumer&lt;/td>
&lt;td>Unsloth (2-4× speedup en GPUs RTX)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Distributed training&lt;/td>
&lt;td>DeepSpeed, FSDP, NeMo Framework&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Experiment tracking&lt;/td>
&lt;td>MLflow, W&amp;amp;B, ClearML&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Adapter registry&lt;/td>
&lt;td>HuggingFace Hub privado, MLflow registry&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Hyperparameter&lt;/td>
&lt;td>W&amp;amp;B Sweeps, Optuna, Ray Tune&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="trampas-1">Trampas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Catastrophic forgetting&lt;/strong>: SFT muy agresivo destruye capacidades generales del modelo. Conservar small % del dataset original o usar regularización.&lt;/li>
&lt;li>&lt;strong>Overfitting al golden dataset&lt;/strong>: el modelo aprende a memorizar el set de eval. Mantener un &lt;strong>test set holdout&lt;/strong> que nadie del equipo mira hasta el release final.&lt;/li>
&lt;li>&lt;strong>Train/serve skew&lt;/strong>: prompts en training con formato distinto al de producción. &lt;strong>Mismo chat template&lt;/strong> en ambos.&lt;/li>
&lt;li>&lt;strong>Lora rank demasiado alto&lt;/strong>: parece mejorar metricas pero infla el adapter sin beneficio real. Empezar con &lt;code>r=8&lt;/code> o &lt;code>r=16&lt;/code>; subir solo si hay evidencia.&lt;/li>
&lt;/ul>
&lt;h2 id="etapa-3--eval-validar-antes-de-promover">Etapa 3 — Eval: validar antes de promover&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 90" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="estás aquí: Eval">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#7aafff;stroke-width:3}.idle{fill:#f4f4f4}.lbl{font:600 12px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#mn3)}.cyc{stroke:#888;stroke-width:1.2;fill:none;stroke-dasharray:4 2;marker-end:url(#mn3)}&lt;/style>
&lt;defs>&lt;marker id="mn3" 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;/defs>
&lt;text x="390" y="20" text-anchor="middle" class="lbl">Estás aquí: EVAL · CI gates + platform regression + human review&lt;/text>
&lt;rect x="30" y="35" width="110" height="35" class="box idle"/>&lt;text x="85" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="155" y="35" width="110" height="35" class="box idle"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="35" width="110" height="35" class="box active"/>&lt;text x="335" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="405" y="35" width="110" height="35" class="box idle"/>&lt;text x="460" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="530" y="35" width="110" height="35" class="box idle"/>&lt;text x="585" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="655" y="35" width="110" height="35" class="box idle"/>&lt;text x="710" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;path class="arr" d="M140,52 L155,52"/>&lt;path class="arr" d="M265,52 L280,52"/>&lt;path class="arr" d="M390,52 L405,52"/>&lt;path class="arr" d="M515,52 L530,52"/>&lt;path class="arr" d="M640,52 L655,52"/>
&lt;path class="cyc" d="M710,72 L710,82 L85,82 L85,72"/>
&lt;/svg>
&lt;/div>
&lt;h3 id="sub-tareas-operativas-2">Sub-tareas operativas&lt;/h3>
&lt;p>Cubierto en profundidad en &lt;a href="https://blog.lo0.es/posts/evals-llm-la-capa-despues-de-tracing/">Evals: la capa después del tracing&lt;/a>. Resumen estructurado para el pipeline:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Curación del golden dataset&lt;/strong>: 100-500 ejemplos como mínimo, mantenidos activamente con casos de incidentes.&lt;/li>
&lt;li>&lt;strong>Evaluators&lt;/strong>: heurísticos (regex, length), semánticos (embeddings), LLM-as-judge (G-Eval), humanos (golden labels).&lt;/li>
&lt;li>&lt;strong>Ejecución en CI&lt;/strong>: bloquear el merge si métricas críticas caen &amp;gt;X%.&lt;/li>
&lt;li>&lt;strong>Ejecución en platform&lt;/strong>: sobre tráfico de producción muestreado, persistir resultados, detectar regresión a largo plazo.&lt;/li>
&lt;li>&lt;strong>Calibración del judge&lt;/strong>: 85-90% agreement con humanos antes de aceptar el judge como productivo.&lt;/li>
&lt;li>&lt;strong>Eval gates&lt;/strong>: thresholds explícitos por métrica (faithfulness &amp;gt; 0.85, relevancy &amp;gt; 0.80, etc.).&lt;/li>
&lt;/ul>
&lt;h3 id="herramientas-1">Herramientas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>CI gates&lt;/strong>: DeepEval (Apache 2.0, pytest-style), Promptfoo (MIT, CLI), Ragas (RAG-specific), Inspect AI (safety/capability).&lt;/li>
&lt;li>&lt;strong>Platform&lt;/strong>: Langfuse (MIT, suite completa), LangSmith (LangChain), Phoenix (ELv2, OTel), Braintrust.&lt;/li>
&lt;li>&lt;strong>Judges&lt;/strong>: GPT-4 (caro pero referencia), Claude 3.5 Sonnet, Prometheus (OSS 0.897 correlación), JudgeLM.&lt;/li>
&lt;/ul>
&lt;h3 id="trampas-2">Trampas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Golden dataset envejecido&lt;/strong>: si no se actualiza, deja de reflejar producción.&lt;/li>
&lt;li>&lt;strong>Judge contaminado&lt;/strong>: el judge sabe del dataset (apareció en su training).&lt;/li>
&lt;li>&lt;strong>Sample size insuficiente&lt;/strong>: &amp;lt;50 ejemplos hace que diferencias parezcan ruido.&lt;/li>
&lt;li>&lt;strong>Costes runaway&lt;/strong>: G-Eval con GPT-4 sobre muchos casos cuesta miles USD/mes.&lt;/li>
&lt;li>&lt;strong>Olvidar el segmento&lt;/strong>: media 0.85 puede esconder 0.55 en alemán.&lt;/li>
&lt;/ul>
&lt;h2 id="etapa-4--deploy-poner-el-modelo-en-producción">Etapa 4 — Deploy: poner el modelo en producción&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 90" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="estás aquí: Deploy">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#7adb7a;stroke-width:3}.idle{fill:#f4f4f4}.lbl{font:600 12px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#mn4)}.cyc{stroke:#888;stroke-width:1.2;fill:none;stroke-dasharray:4 2;marker-end:url(#mn4)}&lt;/style>
&lt;defs>&lt;marker id="mn4" 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;/defs>
&lt;text x="390" y="20" text-anchor="middle" class="lbl">Estás aquí: DEPLOY · operators + serving + canary + autoscaling&lt;/text>
&lt;rect x="30" y="35" width="110" height="35" class="box idle"/>&lt;text x="85" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="155" y="35" width="110" height="35" class="box idle"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="35" width="110" height="35" class="box idle"/>&lt;text x="335" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="405" y="35" width="110" height="35" class="box active"/>&lt;text x="460" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="530" y="35" width="110" height="35" class="box idle"/>&lt;text x="585" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="655" y="35" width="110" height="35" class="box idle"/>&lt;text x="710" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;path class="arr" d="M140,52 L155,52"/>&lt;path class="arr" d="M265,52 L280,52"/>&lt;path class="arr" d="M390,52 L405,52"/>&lt;path class="arr" d="M515,52 L530,52"/>&lt;path class="arr" d="M640,52 L655,52"/>
&lt;path class="cyc" d="M710,72 L710,82 L85,82 L85,72"/>
&lt;/svg>
&lt;/div>
&lt;h3 id="sub-tareas-operativas-3">Sub-tareas operativas&lt;/h3>
&lt;p>Cubierto en profundidad en &lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">vLLM en Kubernetes&lt;/a> y &lt;a href="https://blog.lo0.es/posts/operators-llm-kubernetes/">Operators LLM K8s&lt;/a>. Resumen para el pipeline:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Selección del runtime&lt;/strong>: vLLM (default), SGLang (agentes con prefix caching alto), TensorRT-LLM (latencia pura), llama.cpp (edge).&lt;/li>
&lt;li>&lt;strong>Selección del operator&lt;/strong>: vLLM Production Stack, KServe, OME (LMSYS), NVIDIA Dynamo, llm-d (CNCF).&lt;/li>
&lt;li>&lt;strong>Configuración del serving&lt;/strong>: &lt;code>--tensor-parallel-size&lt;/code>, &lt;code>--kv-cache-dtype=fp8&lt;/code>, &lt;code>--enable-prefix-caching&lt;/code>, &lt;code>--enable-chunked-prefill&lt;/code>, &lt;code>--gpu-memory-utilization=0.92&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Routing entre modelos&lt;/strong>: LiteLLM como abstracción para multi-provider.&lt;/li>
&lt;li>&lt;strong>Estrategia de release&lt;/strong>: canary (1% → 10% → 100%), blue-green (todo o nada con rollback rápido), shadow (eval en paralelo sin afectar usuarios).&lt;/li>
&lt;li>&lt;strong>Autoscaling con métricas LLM&lt;/strong>: KEDA + Prometheus sobre &lt;code>vllm:num_requests_waiting&lt;/code> o equivalente.&lt;/li>
&lt;li>&lt;strong>Gateway / Inference Extension&lt;/strong>: Gateway API Inference Extension cuando esté GA.&lt;/li>
&lt;/ul>
&lt;h3 id="herramientas-dominantes-1">Herramientas dominantes&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Serving engines&lt;/strong>: vLLM, SGLang, TensorRT-LLM, llama.cpp, MLX.&lt;/li>
&lt;li>&lt;strong>Operators&lt;/strong>: OME, vLLM Production Stack, NVIDIA Dynamo, llm-d, KServe.&lt;/li>
&lt;li>&lt;strong>Routing&lt;/strong>: LiteLLM (100+ providers), OpenRouter (managed), LangChain Router.&lt;/li>
&lt;li>&lt;strong>GPU primitivas&lt;/strong>: NVIDIA GPU Operator, LeaderWorkerSet (LWS) para tensor parallel multi-pod, KEDA para autoscaling.&lt;/li>
&lt;/ul>
&lt;h3 id="trampas-3">Trampas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Rolling update naïve&lt;/strong> que corta sesiones: &lt;code>maxUnavailable: 0, maxSurge: 1&lt;/code> y &lt;code>terminationGracePeriodSeconds: 120+&lt;/code>.&lt;/li>
&lt;li>&lt;strong>readiness probe corta&lt;/strong> que mata pods cargando: &lt;code>startupProbe&lt;/code> con &lt;code>failureThreshold: 60&lt;/code>.&lt;/li>
&lt;li>&lt;strong>HPA por CPU%&lt;/strong> sin métricas LLM: vLLM bachea internamente, una réplica atiende decenas. KEDA por queue depth.&lt;/li>
&lt;li>&lt;strong>KV cache sin cuantizar&lt;/strong>: &lt;code>--kv-cache-dtype=fp8&lt;/code> casi siempre rentable.&lt;/li>
&lt;li>&lt;strong>Tensor parallel en GPUs sin NVLink&lt;/strong>: all-reduce satura PCIe, throughput se hunde.&lt;/li>
&lt;/ul>
&lt;h2 id="etapa-5--observe-ver-lo-que-pasa-en-producción">Etapa 5 — Observe: ver lo que pasa en producción&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 90" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="estás aquí: Observe">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#c47aff;stroke-width:3}.idle{fill:#f4f4f4}.lbl{font:600 12px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#mn5)}.cyc{stroke:#888;stroke-width:1.2;fill:none;stroke-dasharray:4 2;marker-end:url(#mn5)}&lt;/style>
&lt;defs>&lt;marker id="mn5" 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;/defs>
&lt;text x="390" y="20" text-anchor="middle" class="lbl">Estás aquí: OBSERVE · tracing + métricas + guardrails + drift + eBPF&lt;/text>
&lt;rect x="30" y="35" width="110" height="35" class="box idle"/>&lt;text x="85" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="155" y="35" width="110" height="35" class="box idle"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="35" width="110" height="35" class="box idle"/>&lt;text x="335" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="405" y="35" width="110" height="35" class="box idle"/>&lt;text x="460" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="530" y="35" width="110" height="35" class="box active"/>&lt;text x="585" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="655" y="35" width="110" height="35" class="box idle"/>&lt;text x="710" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;path class="arr" d="M140,52 L155,52"/>&lt;path class="arr" d="M265,52 L280,52"/>&lt;path class="arr" d="M390,52 L405,52"/>&lt;path class="arr" d="M515,52 L530,52"/>&lt;path class="arr" d="M640,52 L655,52"/>
&lt;path class="cyc" d="M710,72 L710,82 L85,82 L85,72"/>
&lt;/svg>
&lt;/div>
&lt;h3 id="sub-tareas-operativas-4">Sub-tareas operativas&lt;/h3>
&lt;p>Esta es la etapa que más profundamente hemos cubierto en series previas: toda la serie eBPF (4 posts) y la serie post-tracing (4 posts) tratan sub-tareas de Observe. Resumen estructurado:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Tracing&lt;/strong>: OpenLLMetry/Traceloop, Langfuse, Phoenix, LangSmith. Spans con OTel GenAI semantic conventions (&lt;code>gen_ai.*&lt;/code>, &lt;code>mcp.*&lt;/code>).&lt;/li>
&lt;li>&lt;strong>Métricas&lt;/strong>: Prometheus + Grafana. TTFT, TPOT, throughput, queue depth, KV cache usage, cost por tool.&lt;/li>
&lt;li>&lt;strong>Guardrails activos&lt;/strong> (no solo eval): NeMo Guardrails con rails de 5 tipos, Llama Guard 4 multimodal, Llama Prompt Guard 2 (86M/22M), LLM Guard.&lt;/li>
&lt;li>&lt;strong>eBPF observability&lt;/strong> (zero-instrumentation): Hubble (red), Tetragon (proceso/syscall), AgentSight (agente LLM con SSL uprobes + stdiocap MCP).&lt;/li>
&lt;li>&lt;strong>eBPF en motor local&lt;/strong> (inferencia): ProfInfer-style con uprobes en llama.cpp / vLLM / libcudart.&lt;/li>
&lt;li>&lt;strong>Drift detection&lt;/strong>: Evidently AI, NannyML, WhyLabs. KS, PSI, MMD sobre embeddings.&lt;/li>
&lt;li>&lt;strong>MCP observability&lt;/strong>: OpenTelemetry GenAI MCP semantic conventions, trace propagation via &lt;code>params._meta&lt;/code>, MCP Gateway centralizado.&lt;/li>
&lt;/ul>
&lt;h3 id="las-cuatro-métricas-obligatorias">Las cuatro métricas obligatorias&lt;/h3>
&lt;p>De todo lo cubierto, las cuatro que cualquier dashboard mínimo debe tener:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>TTFT p50/p95&lt;/strong> (time to first token) — lo que el usuario percibe.&lt;/li>
&lt;li>&lt;strong>TPOT p50/p95&lt;/strong> (time per output token) — velocidad de streaming.&lt;/li>
&lt;li>&lt;strong>Throughput&lt;/strong> (tokens/segundo agregados) — capacity planning.&lt;/li>
&lt;li>&lt;strong>Queue depth&lt;/strong> (&lt;code>vllm:num_requests_waiting&lt;/code>) — indicador adelantado.&lt;/li>
&lt;/ol>
&lt;p>A esto se suman, por dominio:&lt;/p>
&lt;ul>
&lt;li>Para RAG: faithfulness rolling mean, retrieval hit rate.&lt;/li>
&lt;li>Para agentes: tool call accuracy, multi-step task completion.&lt;/li>
&lt;li>Para multi-tenant: cost per tenant, p95 latency per tenant.&lt;/li>
&lt;/ul>
&lt;h3 id="trampas-4">Trampas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Cardinalidad en Prometheus&lt;/strong>: las métricas con todos los labels K8s explotan.&lt;/li>
&lt;li>&lt;strong>Tracing sin sampling&lt;/strong>: el storage crece sin control.&lt;/li>
&lt;li>&lt;strong>Guardrails permanentemente en monitoring mode&lt;/strong>: nunca llegan a enforce.&lt;/li>
&lt;li>&lt;strong>Drift sin alertas&lt;/strong>: detectas drift en el dashboard una vez al mes; mientras tanto el problema lleva semanas.&lt;/li>
&lt;li>&lt;strong>OTel sin propagación&lt;/strong>: spans MCP, Tetragon, AgentSight desconectados.&lt;/li>
&lt;/ul>
&lt;h2 id="etapa-6--retrain-cerrar-el-bucle">Etapa 6 — Retrain: cerrar el bucle&lt;/h2>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 90" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="estás aquí: Retrain">
&lt;style>.box{stroke:#444;stroke-width:1.4;rx:6}.active{fill:#ffd24a;stroke-width:3}.idle{fill:#f4f4f4}.lbl{font:600 12px sans-serif;fill:#222}.arr{stroke:#666;stroke-width:1.4;fill:none;marker-end:url(#mn6)}.cyc{stroke:#c66;stroke-width:2;fill:none;stroke-dasharray:4 2;marker-end:url(#mn6)}&lt;/style>
&lt;defs>&lt;marker id="mn6" 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="#c66"/>&lt;/marker>&lt;/defs>
&lt;text x="390" y="20" text-anchor="middle" class="lbl">Estás aquí: RETRAIN · cerrar el bucle hacia DATA&lt;/text>
&lt;rect x="30" y="35" width="110" height="35" class="box idle"/>&lt;text x="85" y="58" text-anchor="middle" class="lbl">1 · Data&lt;/text>
&lt;rect x="155" y="35" width="110" height="35" class="box idle"/>&lt;text x="210" y="58" text-anchor="middle" class="lbl">2 · Tune&lt;/text>
&lt;rect x="280" y="35" width="110" height="35" class="box idle"/>&lt;text x="335" y="58" text-anchor="middle" class="lbl">3 · Eval&lt;/text>
&lt;rect x="405" y="35" width="110" height="35" class="box idle"/>&lt;text x="460" y="58" text-anchor="middle" class="lbl">4 · Deploy&lt;/text>
&lt;rect x="530" y="35" width="110" height="35" class="box idle"/>&lt;text x="585" y="58" text-anchor="middle" class="lbl">5 · Observe&lt;/text>
&lt;rect x="655" y="35" width="110" height="35" class="box active"/>&lt;text x="710" y="58" text-anchor="middle" class="lbl">6 · Retrain&lt;/text>
&lt;path class="arr" d="M140,52 L155,52"/>&lt;path class="arr" d="M265,52 L280,52"/>&lt;path class="arr" d="M390,52 L405,52"/>&lt;path class="arr" d="M515,52 L530,52"/>&lt;path class="arr" d="M640,52 L655,52"/>
&lt;path class="cyc" d="M710,72 L710,82 L85,82 L85,72"/>
&lt;/svg>
&lt;/div>
&lt;h3 id="sub-tareas-operativas-5">Sub-tareas operativas&lt;/h3>
&lt;p>Esta es la etapa que más se descuida en proyectos GenAI. Cerrar el bucle convierte LLMOps en una práctica viva; no cerrarlo lo deja como un proyecto que envejece.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Feedback explícito&lt;/strong>: thumbs up/down en la UI, anotaciones por usuarios power, formularios para &amp;ldquo;qué falló&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>Feedback implícito&lt;/strong>: latencia anómala, abandonment rate, retries del usuario, sesiones abortadas.&lt;/li>
&lt;li>&lt;strong>Triaging de incidentes&lt;/strong>: clasificar incidentes por causa raíz (model issue, retrieval issue, prompt issue, infra issue).&lt;/li>
&lt;li>&lt;strong>Dataset enrichment&lt;/strong>: incorporar al golden dataset los casos donde el sistema falló, con la respuesta correcta etiquetada por humano.&lt;/li>
&lt;li>&lt;strong>Cadence de retrain&lt;/strong>: trimestral por defecto, &lt;strong>incident-driven&lt;/strong> cuando un patrón problemático supera threshold.&lt;/li>
&lt;li>&lt;strong>Promotion&lt;/strong>: el nuevo modelo/adapter pasa por las etapas Tune → Eval → Deploy, con eval gates que comparan contra el modelo en producción.&lt;/li>
&lt;/ul>
&lt;h3 id="las-dos-cadencias">Las dos cadencias&lt;/h3>
&lt;p>&lt;strong>Scheduled retrain&lt;/strong> (trimestral o semestral): un proceso establecido. Permite planificar capacity, presupuesto, riesgo. El default.&lt;/p>
&lt;p>&lt;strong>Incident-driven retrain&lt;/strong>: cuando un incidente serio (drift detectado, segmento que falla, ataque de prompt injection) supera threshold, se dispara un mini-ciclo. Más caro pero necesario para casos críticos.&lt;/p>
&lt;h3 id="herramientas-dominantes-2">Herramientas dominantes&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Annotation y feedback collection&lt;/strong>: Langfuse (UI built-in), Argilla (OSS), Label Studio.&lt;/li>
&lt;li>&lt;strong>Dataset enrichment&lt;/strong>: pipelines en Airflow o Argo Workflows.&lt;/li>
&lt;li>&lt;strong>Triaging&lt;/strong>: dashboards Langfuse + filtros por traces con eval bajo.&lt;/li>
&lt;li>&lt;strong>Promoting candidate&lt;/strong>: MLflow model registry stages.&lt;/li>
&lt;/ul>
&lt;h3 id="trampas-5">Trampas&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Bucle abierto&lt;/strong>: producción no informa al dataset; el modelo nunca mejora.&lt;/li>
&lt;li>&lt;strong>Feedback humano se pierde&lt;/strong>: thumbs down sin canal de captura estructurado.&lt;/li>
&lt;li>&lt;strong>Cadence sin definir&lt;/strong>: &amp;ldquo;ya retrenamos cuando haga falta&amp;rdquo; → nunca se retrena.&lt;/li>
&lt;li>&lt;strong>Sin holdout test set&lt;/strong>: el golden dataset se enriquece con los mismos casos que se usan para evaluar; eval mide memorización.&lt;/li>
&lt;li>&lt;strong>Promotion sin gates&lt;/strong>: el nuevo modelo entra a producción sin pasar las verificaciones de los modelos anteriores.&lt;/li>
&lt;/ul>
&lt;h2 id="el-ciclo-completo-cómo-encajan-las-etapas">El ciclo completo: cómo encajan las etapas&lt;/h2>
&lt;p>Ahora que vimos cada etapa por separado, el insight clave es &lt;strong>cómo se enganchan&lt;/strong>. Cinco propiedades emergentes del ciclo:&lt;/p>
&lt;p>&lt;strong>1. Data es la materia prima de todas las etapas&lt;/strong>. Tune lee del golden dataset. Eval lee del eval dataset. Deploy lee del RAG (vector store). Observe produce nuevos datos. Retrain crea datasets nuevos. &lt;strong>El log Kafka es el evangelio del sistema entero&lt;/strong> (post 2 de la serie).&lt;/p>
&lt;p>&lt;strong>2. Eval es el gatekeeper bidireccional&lt;/strong>. Antes de Deploy: bloquea release si el modelo regresa. Después de Observe: alimenta Retrain identificando casos peor evaluados. La calidad del eval determina la calidad del ciclo entero.&lt;/p>
&lt;p>&lt;strong>3. Observe alimenta a Retrain y a Eval simultáneamente&lt;/strong>. Las traces producen métricas para Observe; las traces problemáticas se anotan y van al dataset; los nuevos casos enriquecen el eval golden. &lt;strong>Observe es la fuente de verdad operativa&lt;/strong>.&lt;/p>
&lt;p>&lt;strong>4. Los componentes transversales (banda gris del mapa) no son una etapa, son una infraestructura&lt;/strong>. OpenTelemetry, prompt versioning, MCP gateway, model gateway, schema registry. Mal configurados, cada etapa sufre por separado. Bien configurados, las etapas se integran sin fricción.&lt;/p>
&lt;p>&lt;strong>5. El ciclo no es secuencial estricto, es concurrente&lt;/strong>. En cualquier momento dado, el sistema tiene: requests siendo servidas (Deploy + Observe), una versión nueva en training (Tune), eval continuo en CI (Eval), datos llegando del CDC (Data), análisis de incidentes (Retrain). &lt;strong>Todas las etapas están vivas a la vez&lt;/strong>.&lt;/p>
&lt;h2 id="trampas-cross-etapa-cosas-que-rompen-el-sistema-entero">Trampas cross-etapa: cosas que rompen el sistema entero&lt;/h2>
&lt;p>Hay errores que no son de una etapa, sino de las interfaces entre etapas. Los más comunes:&lt;/p>
&lt;h3 id="trainserve-skew">Train/serve skew&lt;/h3>
&lt;p>El formato exacto del prompt en training es distinto al de producción. Resultado: el modelo entrenado para responder a &lt;code>&amp;lt;|im_start|&amp;gt;user\n...\n&amp;lt;|im_end|&amp;gt;&lt;/code> recibe en producción &lt;code>User: ...\nAssistant:&lt;/code> y rinde peor. &lt;strong>Solución&lt;/strong>: extraer el chat template en una librería compartida que use el pipeline de Tune &lt;strong>y&lt;/strong> el de Deploy.&lt;/p>
&lt;h3 id="eval-que-no-refleja-producción">Eval que no refleja producción&lt;/h3>
&lt;p>Tu golden dataset son preguntas cuidadas; producción es preguntas reales con errores tipográficos, idiomas mezclados, etc. Eval pasa al 95%, producción rinde al 70%. &lt;strong>Solución&lt;/strong>: enriquecer continuamente el golden con muestras reales.&lt;/p>
&lt;h3 id="drift-sin-pipeline-de-respuesta">Drift sin pipeline de respuesta&lt;/h3>
&lt;p>Detectas drift en el dashboard de Observe; nadie tiene un workflow definido sobre qué hacer. &lt;strong>Solución&lt;/strong>: cada alerta de drift debe tener un runbook claro: investiga, clasifica, actúa (retrain, ajustar prompt, ampliar retrieval).&lt;/p>
&lt;h3 id="schema-break-cascada">Schema break cascada&lt;/h3>
&lt;p>Cambias el schema en la fuente OLTP; Debezium lo refleja; Flink job se rompe; topic embedded deja de actualizarse; vector store envejece; RAG responde sobre datos viejos. Tres etapas afectadas por un cambio en Data. &lt;strong>Solución&lt;/strong>: schema evolution &lt;strong>backward-compatible&lt;/strong> obligatoria, contracts entre productores y consumidores.&lt;/p>
&lt;h3 id="sin-observabilidad-del-propio-pipeline">Sin observabilidad del propio pipeline&lt;/h3>
&lt;p>El pipeline LLMOps es un sistema complejo. Si no tiene observabilidad propia (cuánto tarda el entrenamiento, cuántos jobs fallan, cuántas re-embedding pasan), debugar fallos es un proceso de spelunking. &lt;strong>Solución&lt;/strong>: OTel sobre el pipeline mismo, no solo sobre las llamadas LLM.&lt;/p>
&lt;h3 id="vendor-lock-in-invisible">Vendor lock-in invisible&lt;/h3>
&lt;p>Pipelines escritos contra LangChain, prompts pegados en LangSmith, embeddings en Pinecone, modelo en OpenAI. Migrar es un proyecto de meses. &lt;strong>Solución&lt;/strong>: abstracciones LiteLLM, OpenLLMetry, vendor-neutral desde el principio.&lt;/p>
&lt;h2 id="lo-que-viene-en-los-siguientes-posts">Lo que viene en los siguientes posts&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Post 4 — &lt;a href="https://blog.lo0.es/posts/postgresql-qdrant-ingestion-microservicios/">PostgreSQL + Qdrant en la etapa de ingestión&lt;/a>&lt;/strong> — primer post que aplica el patrón &amp;ldquo;estás aquí&amp;rdquo; sobre la etapa Data. Patrones de sincronización (outbox + CDC), arquitectura de microservicios, manifests de despliegue.&lt;/li>
&lt;li>&lt;strong>Próximos posts&lt;/strong> — pendientes de decidir: el cluster como plataforma multi-tenant, Constitutional AI / alignment runtime, fine-tuning continuo en profundidad, edge LLMs.&lt;/li>
&lt;li>En cualquier post posterior de esta o futuras series, el &lt;strong>mini-mapa &amp;ldquo;estás aquí&amp;rdquo;&lt;/strong> te dirá en qué etapa del ciclo encaja el tema. Si lees un post sobre quantization, sabrás que estás en Deploy. Si lees uno sobre evaluator ensembles, sabrás que estás en Eval. Si lees uno sobre RAG sobre Iceberg, sabrás que estás en Data.&lt;/li>
&lt;/ul>
&lt;h2 id="referencias">Referencias&lt;/h2>
&lt;p>Foundations:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://medium.com/@sanjeebmeister/the-complete-mlops-llmops-roadmap-for-2026-building-production-grade-ai-systems-bdcca5ed2771">The Complete MLOps/LLMOps Roadmap for 2026 (Sanjeeb Panda)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://hyscaler.com/insights/mlops-in-2026-guide/">MLOps in 2026: Architecture, Trends &amp;amp; Strategy (Hyscaler)&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Por etapa (entradas de la serie del blog):&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Data&lt;/strong>: &lt;a href="https://blog.lo0.es/posts/rag-kafka-datalake-arquitectura/">RAG sobre Kafka — arquitectura técnica&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Tune&lt;/strong>: cubierto parcialmente en &lt;a href="https://blog.lo0.es/posts/mlops-llms-panorama-2026/">Panorama 2026&lt;/a>; profundización en post 4 si se elige fine-tuning continuo.&lt;/li>
&lt;li>&lt;strong>Eval&lt;/strong>: &lt;a href="https://blog.lo0.es/posts/evals-llm-la-capa-despues-de-tracing/">Evals: la capa después del tracing&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Deploy&lt;/strong>: &lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">vLLM en Kubernetes&lt;/a> y &lt;a href="https://blog.lo0.es/posts/operators-llm-kubernetes/">Operators LLM K8s&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Observe&lt;/strong>: serie eBPF entera y serie post-tracing entera.&lt;/li>
&lt;li>&lt;strong>Retrain&lt;/strong>: cubierto en este post; profundización pendiente.&lt;/li>
&lt;/ul>
&lt;p>Componentes transversales:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Prompt versioning&lt;/strong>: en deep dive de Langfuse dentro del &lt;a href="https://blog.lo0.es/posts/agentsight-tracing-llm/">post de AgentSight&lt;/a>.&lt;/li>
&lt;li>&lt;strong>MCP&lt;/strong>: &lt;a href="https://blog.lo0.es/posts/mcp-observability-otel/">MCP observability profunda&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Drift detection&lt;/strong>: &lt;a href="https://blog.lo0.es/posts/ebpf-on-device-inference-drift/">eBPF + drift detection&lt;/a>.&lt;/li>
&lt;li>&lt;strong>Inferencia local&lt;/strong>: &lt;a href="https://blog.lo0.es/posts/pagedattention-deep-dive/">PagedAttention deep dive&lt;/a>, &lt;a href="https://blog.lo0.es/posts/kv-cache-fundamentos/">KV cache&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Frameworks y herramientas referenciadas:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://mlflow.org/">MLflow&lt;/a>, &lt;a href="https://wandb.ai/">W&amp;amp;B&lt;/a>, &lt;a href="https://www.kubeflow.org/">Kubeflow&lt;/a>, &lt;a href="https://www.zenml.io/">ZenML&lt;/a>, &lt;a href="https://www.bentoml.com/">BentoML&lt;/a>, &lt;a href="https://metaflow.org/">Metaflow&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://github.com/huggingface/peft">HuggingFace PEFT&lt;/a>, &lt;a href="https://github.com/huggingface/trl">TRL&lt;/a>, &lt;a href="https://github.com/axolotl-ai-cloud/axolotl">Axolotl&lt;/a>, &lt;a href="https://github.com/unslothai/unsloth">Unsloth&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://dvc.org/">DVC&lt;/a> + &lt;a href="https://lakefs.io/">lakeFS&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://langfuse.com/">Langfuse&lt;/a>, &lt;a href="https://www.evidentlyai.com/">Evidently AI&lt;/a>, &lt;a href="https://phoenix.arize.com/">Phoenix&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://github.com/vllm-project/production-stack">vLLM Production Stack&lt;/a>, &lt;a href="https://kserve.github.io/website/">KServe&lt;/a>, &lt;a href="https://github.com/ome-projects/ome">OME&lt;/a>, &lt;a href="https://developer.nvidia.com/dynamo">NVIDIA Dynamo&lt;/a>, &lt;a href="https://github.com/llm-d/llm-d">llm-d&lt;/a>.&lt;/li>
&lt;/ul></description></item><item><title>MLOps específico para LLMs en 2026: el panorama de tres modalidades, seis etapas y diez herramientas que las hacen funcionar</title><link>https://blog.lo0.es/posts/mlops-llms-panorama-2026/</link><pubDate>Thu, 21 May 2026 05:30:00 +0200</pubDate><guid>https://blog.lo0.es/posts/mlops-llms-panorama-2026/</guid><description>&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Esta es la cuarta serie del blog y se llama &lt;strong>MLOps específico para LLMs&lt;/strong>. Toma el oficio operativo de MLOps tradicional —pipelines reproducibles, model registries, dataset versioning, eval gates, despliegues controlados— y lo redibuja para un mundo donde el modelo es &lt;strong>probabilístico&lt;/strong>, las salidas son &lt;strong>subjetivas&lt;/strong>, las dependencias incluyen &lt;strong>vendors externos que actualizan pesos sin avisar&lt;/strong>, y la &amp;ldquo;aplicación&amp;rdquo; no es un modelo sino una &lt;strong>orquestación de modelos, embeddings, retrievers, guardrails y routers&lt;/strong>. Gartner predice que más del 50% de los despliegues GenAI empresariales fracasarán antes de que acabe 2026, y la causa principal no es el modelo: es que se aplicaron &lt;strong>suposiciones de software determinístico&lt;/strong> a sistemas probabilísticos. Este post abre la serie con el marco: las &lt;strong>siete diferencias estructurales&lt;/strong> entre LLMOps y MLOps clásico; el &lt;strong>pipeline de seis etapas&lt;/strong> (data → tune → eval → deploy → observe → retrain); las &lt;strong>tres modalidades&lt;/strong> de preparar un modelo (fine-tuning continuo, RAG sobre datalakes, agent training) con su matriz de decisión —el 60% de despliegues 2025-2026 usa &lt;strong>hybrid&lt;/strong> porque cada modalidad resuelve un problema distinto: &amp;ldquo;fine-tune para behavior, RAG para conocimiento volátil&amp;rdquo;—; y el &lt;strong>panorama de herramientas 2026&lt;/strong> que ya forma capas razonablemente estables: MLflow 3.10 (marzo 2026) como registry GenAI-aware, W&amp;amp;B Weave y ZenML para tracing y pipelines, Kubeflow + KServe vLLM 0.8.1+ para serving, BentoML para flexibilidad, DVC + lakeFS (unidos desde noviembre 2025) para data, Langfuse para prompts y observabilidad. Los tres posts siguientes bajarán al detalle de las piezas más críticas.&lt;/p>
&lt;blockquote>
&lt;p>Esta es la apertura de la &lt;strong>serie 4: MLOps para LLMs&lt;/strong>. Continúa la tradición de las series previas: &lt;a href="https://blog.lo0.es/posts/kv-cache-fundamentos/">inferencia LLM&lt;/a> (la primera), &lt;a href="https://blog.lo0.es/posts/ebpf-cilium-tcp-ip-bypass/">eBPF&lt;/a> (la segunda) y &lt;a href="https://blog.lo0.es/posts/evals-llm-la-capa-despues-de-tracing/">post-tracing&lt;/a> (la tercera). Aquí entramos en la disciplina que ata todas las piezas: cómo se opera un sistema LLM en producción durante meses, no solo se despliega una vez.&lt;/p>
&lt;/blockquote>
&lt;h2 id="la-analogía-el-oficio-del-sre-redibujado">La analogía: el oficio del SRE redibujado&lt;/h2>
&lt;p>Quien lleva años trabajando como SRE o como ingeniero de plataforma reconoce los pilares clásicos: &lt;strong>reproducibilidad&lt;/strong> (mismo código + misma data + misma config = mismo resultado), &lt;strong>observabilidad&lt;/strong> (lo que pasa se puede medir), &lt;strong>rollback seguro&lt;/strong> (si algo va mal, vuelvo atrás en minutos), &lt;strong>gradual rollout&lt;/strong> (lo nuevo entra al 1% antes que al 100%). Estos pilares no son negociables. La pregunta es si &lt;strong>se sostienen&lt;/strong> cuando el componente central es un LLM.&lt;/p>
&lt;p>La respuesta es: &lt;strong>mismos pilares, mecánica radicalmente distinta&lt;/strong>. Reproducibilidad: ya no basta con versionar código y datos; hay que versionar &lt;strong>prompts, configuraciones de retrieval, snapshots del modelo del vendor&lt;/strong> (que cambian sin avisar). Observabilidad: ya no basta con métricas de error y latencia; hay que medir &lt;strong>calidad subjetiva&lt;/strong> vía LLM-as-judge y drift de embeddings. Rollback: ya no basta con bajar la versión del binario; hay que &lt;strong>mantener el modelo viejo cacheado&lt;/strong> porque cargar uno nuevo tarda minutos. Gradual rollout: ya no basta con un % de tráfico; hay que decidir qué % de &lt;strong>qué tipo de queries&lt;/strong> por segmento.&lt;/p>
&lt;p>Es el mismo oficio, ejercido con herramientas y reflejos parcialmente nuevos. &lt;strong>MLOps específico para LLMs&lt;/strong> —o &amp;ldquo;LLMOps&amp;rdquo;, como el campo se ha autobautizado— es la disciplina que codifica esos reflejos.&lt;/p>
&lt;h2 id="las-siete-diferencias-estructurales-entre-llmops-y-mlops-tradicional">Las siete diferencias estructurales entre LLMOps y MLOps tradicional&lt;/h2>
&lt;p>Antes de bajar al pipeline, fijemos las diferencias que hacen este territorio nuevo, no una mera continuación. Cada una tiene consecuencias prácticas concretas.&lt;/p>
&lt;h3 id="1-salidas-no-determinísticas">1. Salidas no-determinísticas&lt;/h3>
&lt;p>MLOps tradicional: el modelo recibe input estructurado, devuelve &lt;strong>una predicción acotada y reproducible&lt;/strong>. Mismo input → mismo output. Tests unitarios funcionan.&lt;/p>
&lt;p>LLMOps: mismo input → output &lt;strong>distinto cada vez&lt;/strong> (por sampling, por temperature, por orden de tools invocadas, por el contexto retrieval que cambió). La idea de &amp;ldquo;test unitario&amp;rdquo; se rompe.&lt;/p>
&lt;p>&lt;strong>Consecuencia operativa&lt;/strong>: tests sobre &lt;strong>propiedades&lt;/strong> (¿se mantuvo el tono?, ¿menciona la fuente?, ¿respeta el JSON schema?), no sobre igualdad. Evals estadísticos sobre distribución, no sobre muestras.&lt;/p>
&lt;h3 id="2-métricas-behavior-no-statistical-accuracy">2. Métricas behavior, no statistical accuracy&lt;/h3>
&lt;p>MLOps tradicional: F1, accuracy, AUC, RMSE. Métricas con un número claro.&lt;/p>
&lt;p>LLMOps: &lt;strong>rubric scores&lt;/strong> subjetivos (G-Eval, faithfulness, helpfulness, toxicity), &lt;strong>judge LLMs&lt;/strong>, &lt;strong>human feedback&lt;/strong>. El &amp;ldquo;número&amp;rdquo; depende de quién juzga.&lt;/p>
&lt;p>&lt;strong>Consecuencia operativa&lt;/strong>: las plataformas tienen que tratar evals como &lt;strong>artifacts versionados&lt;/strong> —no solo &amp;ldquo;el modelo v3 sacó 0.87&amp;rdquo;, sino &amp;ldquo;el modelo v3 evaluado con el judge claude-3-5-sonnet-20251022 sobre el dataset gold-rag-v7 con el prompt judge-v2 sacó 0.87&amp;rdquo;—. Versionar el judge es tan importante como versionar el modelo evaluado.&lt;/p>
&lt;h3 id="3-el-modelo-es-dependencia-externa-no-asset-interno">3. El modelo es dependencia externa, no asset interno&lt;/h3>
&lt;p>MLOps tradicional: el modelo lo entrenas tú, vive en tu registry, no cambia hasta que lo cambies.&lt;/p>
&lt;p>LLMOps: el modelo base es de Anthropic, OpenAI, Google, Meta. &lt;strong>Te lo cambian sin avisar&lt;/strong>. La versión &lt;code>claude-3-5-sonnet&lt;/code> que respondía bien ayer responde algo distinto hoy.&lt;/p>
&lt;p>&lt;strong>Consecuencia operativa&lt;/strong>: &lt;strong>drift detection&lt;/strong> se vuelve mucho más crítico (&lt;a href="https://blog.lo0.es/posts/ebpf-on-device-inference-drift/">post anterior&lt;/a>). Pinning a snapshots específicos (&lt;code>claude-3-5-sonnet-20251022&lt;/code>) cuando el vendor lo permite. Para apps de alto compromiso, &lt;strong>self-host del modelo base&lt;/strong> para garantizar reproducibilidad.&lt;/p>
&lt;h3 id="4-la-aplicación-es-una-orquestación-no-un-modelo">4. La aplicación es una orquestación, no un modelo&lt;/h3>
&lt;p>MLOps tradicional: una app llama un modelo y consume su output.&lt;/p>
&lt;p>LLMOps 2026: una app conecta &lt;strong>foundation model + adapters LoRA + retrievers + vector stores + guardrails + routers + tool servers (MCP) + evaluators&lt;/strong>, todos componiendo el comportamiento final. Cualquier componente puede degradar el resultado.&lt;/p>
&lt;p>&lt;strong>Consecuencia operativa&lt;/strong>: el &lt;strong>debugging cross-componente&lt;/strong> requiere tracing distribuido con OTel (cubierto en posts previos). El registry no solo guarda &amp;ldquo;el modelo&amp;rdquo; sino la &lt;strong>composición&lt;/strong>: qué versión del prompt + qué adapter + qué vector store + qué retriever config.&lt;/p>
&lt;h3 id="5-coste-por-inferencia-no-por-training">5. Coste por inferencia, no por training&lt;/h3>
&lt;p>MLOps tradicional: el coste alto es entrenar; servir es barato. Optimizas training.&lt;/p>
&lt;p>LLMOps: el coste alto es &lt;strong>servir&lt;/strong> (cada token cuesta, cada llamada al vendor se paga, las GPUs que sirven están encendidas 24/7). Optimizas inferencia.&lt;/p>
&lt;p>&lt;strong>Consecuencia operativa&lt;/strong>: cost accountability por tenant, por agente, por tool. Métricas como &lt;code>gen_ai.usage.input_tokens&lt;/code> agregadas a nivel cliente y producto. Decisiones de modelo según coste por query, no solo según calidad.&lt;/p>
&lt;h3 id="6-infra-gpu-pesada-con-primitivas-específicas">6. Infra GPU-pesada con primitivas específicas&lt;/h3>
&lt;p>MLOps tradicional: CPU + algo de GPU para entrenamiento. Kubernetes estándar.&lt;/p>
&lt;p>LLMOps: GPUs Hopper/Blackwell SXM, NVLink/NVSwitch, tensor parallel, paged attention, KV cache. Infra que solo encaja en Kubernetes con primitivas como &lt;strong>LeaderWorkerSet, GPU Operator, KEDA con métricas LLM&lt;/strong> (cubierto en &lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">vLLM en Kubernetes&lt;/a>).&lt;/p>
&lt;p>&lt;strong>Consecuencia operativa&lt;/strong>: la pila de orquestación incluye operadores especializados (OME, vLLM Production Stack, NVIDIA Dynamo, llm-d, ver &lt;a href="https://blog.lo0.es/posts/operators-llm-kubernetes/">Operators LLM K8s&lt;/a>) que el MLOps tradicional no contempla.&lt;/p>
&lt;h3 id="7-rlhf-y-feedback-humano-como-ciudadano-de-primera">7. RLHF y feedback humano como ciudadano de primera&lt;/h3>
&lt;p>MLOps tradicional: el feedback humano es etiquetar datos antes del training.&lt;/p>
&lt;p>LLMOps: el feedback humano vive &lt;strong>dentro del modelo en producción&lt;/strong>, ya sea por RLHF de los foundation models (Anthropic, OpenAI), por RLAIF, por DPO, o por feedback explícito de usuarios que se reincorpora al fine-tuning.&lt;/p>
&lt;p>&lt;strong>Consecuencia operativa&lt;/strong>: pipelines bidireccionales producción → training. Datasets crecen con incidentes reales. Las decisiones de modelo se toman con feedback continuo, no en un proyecto de training cada N meses.&lt;/p>
&lt;h2 id="por-qué-gartner-predice-50-de-fracasos">Por qué Gartner predice 50%+ de fracasos&lt;/h2>
&lt;p>&lt;a href="https://medium.com/@sanjeebmeister/the-complete-mlops-llmops-roadmap-for-2026-building-production-grade-ai-systems-bdcca5ed2771">Gartner publicó que más del 50% de los despliegues GenAI empresariales fracasarán antes de 2026&lt;/a>. Las causas no son técnicas sobre el modelo sino sobre el sistema:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Hallucinated outputs por mal grounding&lt;/strong>: RAG mal diseñado, retrieval pobre, contexto insuficiente.&lt;/li>
&lt;li>&lt;strong>Arquitecturas de datos no preparadas&lt;/strong>: las empresas tienen datos en silos, sin schemas estables, sin freshness controlado. Conectar un LLM a estos datos sin pipeline serio produce respuestas erráticas.&lt;/li>
&lt;li>&lt;strong>Falta de workflows estructurados&lt;/strong> para sistemas prompt-driven: equipos que tratan los prompts como código en strings hardcodeados, sin versionado, sin tests, sin gates.&lt;/li>
&lt;/ul>
&lt;p>La conclusión que el campo extrae: &lt;strong>LLMOps no es opcional&lt;/strong>. Las empresas que despliegan GenAI sin disciplina operacional caen en uno de los tres modos de fracaso. Las que la aplican —MLflow/W&amp;amp;B para tracking, DVC/lakeFS para datos, Langfuse para prompts y evals, KServe o vLLM Production Stack para serving, drift detection en producción— son las que mantienen el sistema funcionando seis meses después del primer release.&lt;/p>
&lt;h2 id="el-pipeline-llmops-de-seis-etapas">El pipeline LLMOps de seis etapas&lt;/h2>
&lt;p>Vamos al pipeline. Las seis etapas que cualquier sistema LLM serio recorre, en orden:&lt;/p>
&lt;pre tabindex="0">&lt;code>[1. Data] → [2. Tune] → [3. Eval] → [4. Deploy] → [5. Observe] → [6. Retrain]
│
└─→ vuelve a 1
&lt;/code>&lt;/pre>&lt;p>Cada etapa es un dominio operacional propio con sus herramientas y trampas:&lt;/p>
&lt;h3 id="etapa-1--data">Etapa 1 — Data&lt;/h3>
&lt;p>&lt;strong>Qué pasa&lt;/strong>: ingestión, limpieza, curación, versionado, indexación del corpus. Es donde más se sufre en proyectos reales porque las empresas tienen datos en silos heterogéneos.&lt;/p>
&lt;p>&lt;strong>Sub-tareas típicas&lt;/strong>: extracción desde origen (CDC sobre Kafka, batch desde data lakes, scraping), limpieza (PII removal, dedup, formato), curación (labeling para fine-tuning, golden datasets para eval), versionado (DVC + lakeFS), indexación (embeddings + vector store para RAG).&lt;/p>
&lt;p>&lt;strong>Trampas&lt;/strong>: drift de schema en el origen, PII no detectada, dedup pobre que mete redundancia en training, vector store que no se actualiza.&lt;/p>
&lt;h3 id="etapa-2--tune">Etapa 2 — Tune&lt;/h3>
&lt;p>&lt;strong>Qué pasa&lt;/strong>: preparar el modelo para tu caso de uso. Tres modalidades (las profundizamos en breve): fine-tuning, RAG, agent training.&lt;/p>
&lt;p>&lt;strong>Sub-tareas típicas&lt;/strong>: selección de modelo base, preparación del adapter (LoRA, QLoRA), training loop con eval continuo, hyperparameter sweep (Optuna, W&amp;amp;B Sweeps), guardado del checkpoint.&lt;/p>
&lt;p>&lt;strong>Trampas&lt;/strong>: catastrophic forgetting si el fine-tuning es muy agresivo, overfitting al dataset golden, sin validation set independiente.&lt;/p>
&lt;h3 id="etapa-3--eval">Etapa 3 — Eval&lt;/h3>
&lt;p>&lt;strong>Qué pasa&lt;/strong>: validar que el modelo + adapters + RAG configuration es aceptable antes de promotar. Cubierto en &lt;a href="https://blog.lo0.es/posts/evals-llm-la-capa-despues-de-tracing/">Evals&lt;/a>.&lt;/p>
&lt;p>&lt;strong>Sub-tareas típicas&lt;/strong>: ejecución de eval framework (DeepEval, Promptfoo, Ragas) contra golden dataset, judge LLM evaluations, human review sobre muestreo, gates con thresholds.&lt;/p>
&lt;p>&lt;strong>Trampas&lt;/strong>: golden dataset que envejece, judge no calibrado, evals que pasan en CI pero fallan en producción por shift de distribución.&lt;/p>
&lt;h3 id="etapa-4--deploy">Etapa 4 — Deploy&lt;/h3>
&lt;p>&lt;strong>Qué pasa&lt;/strong>: pasar de &amp;ldquo;el modelo se evaluó bien&amp;rdquo; a &amp;ldquo;el modelo sirve tráfico real&amp;rdquo;. Cubierto en &lt;a href="https://blog.lo0.es/posts/operators-llm-kubernetes/">Operators LLM K8s&lt;/a>.&lt;/p>
&lt;p>&lt;strong>Sub-tareas típicas&lt;/strong>: serving con vLLM/SGLang/TRT-LLM, configuración del runtime, rollout gradual (canary, shadow, blue-green), routing entre modelos (LiteLLM, OpenRouter, LangChain routers).&lt;/p>
&lt;p>&lt;strong>Trampas&lt;/strong>: rolling update naive que corta sesiones, autoscaling por CPU% que no responde a métricas LLM (cubierto), modelo nuevo que rinde peor en producción que en eval.&lt;/p>
&lt;h3 id="etapa-5--observe">Etapa 5 — Observe&lt;/h3>
&lt;p>&lt;strong>Qué pasa&lt;/strong>: ver lo que está pasando en tiempo real. Cubierto en la serie post-tracing entera y la serie eBPF.&lt;/p>
&lt;p>&lt;strong>Sub-tareas típicas&lt;/strong>: tracing (Langfuse, LangSmith, Phoenix, OpenLLMetry), métricas (TTFT, TPOT, queue depth, cost per query), guardrails activos (NeMo, Llama Guard), drift detection (Evidently, NannyML, WhyLabs).&lt;/p>
&lt;p>&lt;strong>Trampas&lt;/strong>: explosión de cardinalidad en métricas, evals batch sin tail-sampling sobre traces reales, drift que se ignora hasta que el incidente lo materializa.&lt;/p>
&lt;h3 id="etapa-6--retrain">Etapa 6 — Retrain&lt;/h3>
&lt;p>&lt;strong>Qué pasa&lt;/strong>: cerrar el bucle. El feedback de producción (incidentes, casos peor evaluados, drift detectado) genera nuevos datos para volver a la etapa 1.&lt;/p>
&lt;p>&lt;strong>Sub-tareas típicas&lt;/strong>: extracción de logs problemáticos, labeling humano de la muestra, incorporación al dataset golden, re-fine-tuning si aplica, decisión sobre nuevo release.&lt;/p>
&lt;p>&lt;strong>Trampas&lt;/strong>: bucle &amp;ldquo;abierto&amp;rdquo; donde producción no informa nunca al dataset, feedback humano que se pierde, falta de cadencia clara de retrain.&lt;/p>
&lt;h2 id="las-tres-modalidades-de-preparar-el-modelo">Las tres modalidades de &amp;ldquo;preparar el modelo&amp;rdquo;&lt;/h2>
&lt;p>La etapa 2 (Tune) es donde más confusión hay. En 2026 conviven &lt;strong>tres modalidades&lt;/strong>, cada una resolviendo un problema distinto:&lt;/p>
&lt;h3 id="fine-tuning">Fine-tuning&lt;/h3>
&lt;p>&lt;strong>Qué hace&lt;/strong>: modificar los pesos del modelo (o de un adapter LoRA/QLoRA encima) para que aprenda &lt;strong>patrones de comportamiento&lt;/strong> específicos: tono, estructura de output, decisiones idiomáticas del dominio.&lt;/p>
&lt;p>&lt;strong>Cuándo&lt;/strong>: cuando tu fallo principal es &lt;strong>inconsistencia de comportamiento&lt;/strong> entre llamadas. El modelo a veces responde formal, a veces no; a veces estructura el JSON, a veces no; a veces sigue las convenciones de la empresa, a veces inventa. Fine-tuning lo estabiliza.&lt;/p>
&lt;p>&lt;strong>Cuándo NO&lt;/strong>: cuando lo que necesitas es &lt;strong>conocimiento actualizado&lt;/strong>. Fine-tuning fija conocimiento en pesos congelados; al día siguiente del fine-tuning, el modelo no sabe nada nuevo.&lt;/p>
&lt;h3 id="rag-retrieval-augmented-generation">RAG (Retrieval-Augmented Generation)&lt;/h3>
&lt;p>&lt;strong>Qué hace&lt;/strong>: dejar el modelo intacto y, en cada llamada, &lt;strong>recuperar contexto fresco&lt;/strong> de un knowledge base (vector store + lexical search típicamente) y pasárselo al modelo para que responda basándose en él.&lt;/p>
&lt;p>&lt;strong>Cuándo&lt;/strong>: cuando el conocimiento que necesitas es &lt;strong>dinámico o muy grande&lt;/strong>. Documentación que cambia, catálogo de productos que se actualiza, knowledge base interna que crece.&lt;/p>
&lt;p>&lt;strong>Cuándo NO&lt;/strong>: cuando el problema es behavioral (RAG no enseña al modelo a comportarse, solo le da información). O cuando el retrieval es tan ruidoso que el contexto que llega es peor que nada.&lt;/p>
&lt;h3 id="agent-training">Agent training&lt;/h3>
&lt;p>&lt;strong>Qué hace&lt;/strong>: ir más allá del fine-tuning convencional con técnicas de Reinforcement Learning. RFT (Reinforcement Fine-Tuning de OpenAI), RLHF clásico, RLAIF (con AI feedback), DPO (Direct Preference Optimization) sobre datasets de pares (good, bad).&lt;/p>
&lt;p>&lt;strong>Cuándo&lt;/strong>: cuando el modelo necesita aprender &lt;strong>trayectorias multistep complejas&lt;/strong> —cuando elegir cada tool, cómo descomponer una tarea, cuándo pedir confirmación al usuario—. Es lo que está convirtiendo a Claude, Gemini, GPT en agentes capaces de tareas largas.&lt;/p>
&lt;p>&lt;strong>Cuándo NO&lt;/strong>: cuando tu caso es chat simple o RAG. Es overkill, caro y complicado para problemas que las modalidades anteriores resuelven.&lt;/p>
&lt;h3 id="matriz-de-decisión">Matriz de decisión&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Problema observado&lt;/th>
&lt;th>Modalidad&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Respuestas inconsistentes en tono/estructura&lt;/td>
&lt;td>Fine-tuning&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>El modelo inventa cosas (alucina)&lt;/td>
&lt;td>RAG&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Conocimiento desactualizado (&amp;gt;1 año)&lt;/td>
&lt;td>RAG&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>El modelo elige mal las tools&lt;/td>
&lt;td>Agent training (RLAIF/RFT)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Behavior + conocimiento mixto&lt;/td>
&lt;td>&lt;strong>Hybrid (fine-tune + RAG)&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Multi-step trajectory falla&lt;/td>
&lt;td>Agent training&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Idioma/estilo regional concreto&lt;/td>
&lt;td>Fine-tuning&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h3 id="el-veredicto-2026-hybrid-es-el-default">El veredicto 2026: hybrid es el default&lt;/h3>
&lt;p>&lt;a href="https://www.scalacode.com/blog/rag-vs-fine-tuning/">Múltiples reports&lt;/a> coinciden en que en 2025-2026, &lt;strong>alrededor del 60% de proyectos productivos usan hybrid&lt;/strong>: fine-tuning para behavior + RAG para knowledge. El insight clave:&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Fine-tune para comportamiento (brand voice, decision protocol, output structure); usa RAG para conocimiento volátil que necesitas que el modelo cite. No fuerces una sola herramienta a hacer ambos trabajos.&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>Una observación práctica: las mejoras de calidad más grandes de 2025-2026 vienen de &lt;strong>mejor reranking en RAG&lt;/strong> (cross-encoders), no de mejores embeddings. Los rerankers añaden 15-35% de calidad con poca complejidad.&lt;/p>
&lt;p>Sobre coste: combined fine-tuning + RAG suele ser &lt;strong>30-50% más barato&lt;/strong> que RAG puro con frontier models a volumen alto, porque el modelo finetuneado puede ser más pequeño y barato manteniendo calidad equivalente.&lt;/p>
&lt;h2 id="el-panorama-de-herramientas-2026">El panorama de herramientas 2026&lt;/h2>
&lt;p>Vamos a las piezas concretas, agrupadas por función. El campo ha madurado lo suficiente para que cada pieza tenga 2-3 opciones razonables y un par de líderes.&lt;/p>
&lt;h3 id="experiment-tracking-y-model-registry">Experiment tracking y model registry&lt;/h3>
&lt;p>&lt;strong>&lt;a href="https://mlflow.org/">MLflow&lt;/a>&lt;/strong> sigue siendo el estándar de facto, ahora con tracción específica LLM. &lt;strong>MLflow 3&lt;/strong> se publicó en junio 2025; la versión 3.10.1 (marzo 2026) añadió:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GenAI Overview dashboard&lt;/strong> con métricas pre-hechas para LLM apps.&lt;/li>
&lt;li>&lt;strong>Multi-workspace support&lt;/strong> para equipos grandes.&lt;/li>
&lt;li>&lt;strong>Cost tracking en traces&lt;/strong> (gen_ai.usage.* agregados por experimento).&lt;/li>
&lt;li>&lt;strong>MemAlign&lt;/strong>: nuevo algoritmo de eval específico.&lt;/li>
&lt;li>&lt;strong>OpenTelemetry tracing nativo&lt;/strong> integrado.&lt;/li>
&lt;li>Soporte de primera para &lt;strong>LangChain, LlamaIndex, AutoGen&lt;/strong> como frameworks.&lt;/li>
&lt;/ul>
&lt;p>MLflow trata prompts y agents como &lt;strong>ciudadanos de primera clase&lt;/strong> junto a los modelos clásicos. Es el cambio mayor respecto a MLflow 2.x.&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://wandb.ai/">Weights &amp;amp; Biases (W&amp;amp;B)&lt;/a>&lt;/strong> con su producto &lt;strong>Weave&lt;/strong> específico para LLM ofrece tracing + eval + debug con UI muy pulida. Más comercial, menos self-host friendly, pero excelente UX.&lt;/p>
&lt;p>&lt;strong>&lt;a href="https://www.zenml.io/">ZenML&lt;/a>&lt;/strong> es la pieza que más limpia integra &amp;ldquo;MLOps clásico + LLMOps emergente&amp;rdquo; en un solo framework. Su artifact versioning &lt;strong>automático&lt;/strong> captura prompt templates, retrieval chunks, agent conversation histories sin trabajo extra. Open-source. La opción de unificación más completa que existe.&lt;/p>
&lt;h3 id="dataset-versioning">Dataset versioning&lt;/h3>
&lt;p>&lt;strong>&lt;a href="https://dvc.org/">DVC&lt;/a>&lt;/strong> sigue siendo el estándar OSS. Extiende Git a archivos grandes y pipelines. &lt;strong>Noticia importante de noviembre 2025&lt;/strong>: &lt;a href="https://medium.com/the-modern-scientist/reproducible-ai-versioning-models-prompts-and-data-96dd0337af65">lakeFS adquirió DVC&lt;/a>, consolidando los dos proyectos OSS de versionado de datos bajo una organización. La hoja de ruta combinada está orientada a LLM training y RAG datalakes específicamente.&lt;/p>
&lt;p>&lt;strong>Patrón típico&lt;/strong>: Git para código + DVC para data/modelos + MLflow o W&amp;amp;B para experiment tracking + registry. Pocas teams usan uno solo; la &lt;strong>combinación&lt;/strong> es lo que cubre el ciclo.&lt;/p>
&lt;h3 id="prompt-versioning-y-observability">Prompt versioning y observability&lt;/h3>
&lt;p>Cubierto en profundidad en el &lt;a href="https://blog.lo0.es/posts/agentsight-tracing-llm/">post de AgentSight&lt;/a> donde profundizamos en &lt;strong>Langfuse&lt;/strong> como referencia OSS. Resumen aquí:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://langfuse.com/">Langfuse&lt;/a>&lt;/strong>: MIT, self-host, prompt management con versionado v1/v2/v3 + labels + cache + linkage con traces.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://www.langchain.com/langsmith">LangSmith&lt;/a>&lt;/strong>: si tu stack es LangChain.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://phoenix.arize.com/">Arize Phoenix&lt;/a>&lt;/strong>: ELv2, OTel-native.&lt;/li>
&lt;/ul>
&lt;h3 id="pipeline-orchestration">Pipeline orchestration&lt;/h3>
&lt;p>Para los pasos del pipeline LLMOps, las opciones dominantes:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://www.kubeflow.org/docs/components/pipelines/">Kubeflow Pipelines&lt;/a>&lt;/strong>: el estándar K8s-native. KServe (la parte de serving de Kubeflow) tiene &lt;strong>vLLM runtime upgraded a v0.8.1+&lt;/strong> con soporte para reasoning models, tool calling, embeddings, reranking, Llama 4 y Qwen 3.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://www.zenml.io/">ZenML&lt;/a>&lt;/strong>: ya mencionado; también orquestador de pipelines.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://metaflow.org/">Metaflow&lt;/a>&lt;/strong> (Netflix-originated): pipelines Python-first, menos LLM-específico pero workable.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://argoproj.github.io/workflows/">Argo Workflows&lt;/a>&lt;/strong>: alternativa OSS pura K8s.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://flyte.org/">Flyte&lt;/a>&lt;/strong>: Kubernetes-native, OSS.&lt;/li>
&lt;/ul>
&lt;h3 id="serving">Serving&lt;/h3>
&lt;p>Cubierto en profundidad en &lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">vLLM en Kubernetes&lt;/a> y &lt;a href="https://blog.lo0.es/posts/operators-llm-kubernetes/">Operators LLM K8s&lt;/a>. Resumen:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;a href="https://github.com/vllm-project/production-stack">vLLM Production Stack&lt;/a>&lt;/strong>: Helm chart curado.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://kserve.github.io/website/">KServe vLLM runtime&lt;/a>&lt;/strong>: K8s-native, vLLM 0.8.1+ con soporte agentic completo.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://www.bentoml.com/">BentoML&lt;/a>&lt;/strong>: serving flexible, popular en startups por su simplicidad.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://developer.nvidia.com/dynamo">NVIDIA Dynamo&lt;/a>&lt;/strong>: el sucesor de Triton.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://github.com/llm-d/llm-d">llm-d&lt;/a>&lt;/strong>: CNCF Sandbox.&lt;/li>
&lt;li>&lt;strong>&lt;a href="https://github.com/ome-projects/ome">OME&lt;/a>&lt;/strong>: LMSYS operator con SGLang nativo.&lt;/li>
&lt;/ul>
&lt;h3 id="evals-y-guardrails">Evals y guardrails&lt;/h3>
&lt;p>Cubierto en &lt;a href="https://blog.lo0.es/posts/evals-llm-la-capa-despues-de-tracing/">Evals&lt;/a> y &lt;a href="https://blog.lo0.es/posts/guardrails-safety-llm/">Guardrails&lt;/a>. Resumen ultra-corto:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Evals CI&lt;/strong>: DeepEval, Promptfoo, Ragas.&lt;/li>
&lt;li>&lt;strong>Evals platform&lt;/strong>: Langfuse, LangSmith, Phoenix, Braintrust.&lt;/li>
&lt;li>&lt;strong>Guardrails&lt;/strong>: NeMo Guardrails, Llama Guard 4, Llama Prompt Guard 2, LLM Guard, Lakera.&lt;/li>
&lt;/ul>
&lt;h3 id="drift-detection-y-observability">Drift detection y observability&lt;/h3>
&lt;p>Cubierto en el &lt;a href="https://blog.lo0.es/posts/ebpf-on-device-inference-drift/">post de cierre eBPF&lt;/a>. Resumen:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Drift&lt;/strong>: Evidently AI, NannyML, WhyLabs.&lt;/li>
&lt;li>&lt;strong>Tracing&lt;/strong>: Langfuse, OpenLLMetry, Phoenix.&lt;/li>
&lt;li>&lt;strong>eBPF&lt;/strong>: AgentSight, Hubble, Tetragon, ProfInfer.&lt;/li>
&lt;/ul>
&lt;h3 id="la-tabla-de-stack-típico-2026">La tabla de stack típico 2026&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Etapa&lt;/th>
&lt;th>Pieza dominante&lt;/th>
&lt;th>Alternativas&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Data ingestión + versioning&lt;/td>
&lt;td>DVC + lakeFS (unificadas Nov 2025)&lt;/td>
&lt;td>Pachyderm, Quilt&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Vector store / RAG index&lt;/td>
&lt;td>Milvus, Qdrant, pgvector, Weaviate&lt;/td>
&lt;td>LanceDB, Pinecone, Chroma&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Experiment tracking&lt;/td>
&lt;td>MLflow 3.10&lt;/td>
&lt;td>W&amp;amp;B Weave, Neptune&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Pipeline orchestration&lt;/td>
&lt;td>Kubeflow + Argo&lt;/td>
&lt;td>ZenML, Metaflow, Flyte&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Model registry&lt;/td>
&lt;td>MLflow registry&lt;/td>
&lt;td>W&amp;amp;B Models, KServe ModelMesh&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Prompt versioning&lt;/td>
&lt;td>Langfuse&lt;/td>
&lt;td>LangSmith, MLflow Prompts&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Serving&lt;/td>
&lt;td>vLLM Production Stack&lt;/td>
&lt;td>KServe, BentoML, Dynamo, llm-d, OME&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Evals CI&lt;/td>
&lt;td>DeepEval, Ragas&lt;/td>
&lt;td>Promptfoo, OpenAI Evals&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Evals platform&lt;/td>
&lt;td>Langfuse, Phoenix&lt;/td>
&lt;td>LangSmith, Braintrust&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Guardrails&lt;/td>
&lt;td>NeMo + Llama Guard&lt;/td>
&lt;td>LLM Guard, Lakera&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Tracing&lt;/td>
&lt;td>OpenLLMetry + Langfuse&lt;/td>
&lt;td>Phoenix, LangSmith&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Drift detection&lt;/td>
&lt;td>Evidently AI&lt;/td>
&lt;td>NannyML, WhyLabs&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>eBPF observability&lt;/td>
&lt;td>AgentSight + Tetragon + Hubble&lt;/td>
&lt;td>(territorio nuevo, pocas alternativas)&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>13 piezas. Ninguna org usa todas; cualquier org seria usa al menos seis. &lt;strong>Esto es el LLMOps stack actual&lt;/strong>.&lt;/p>
&lt;h2 id="la-realidad-operativa-nadie-usa-una-sola-herramienta">La realidad operativa: nadie usa una sola herramienta&lt;/h2>
&lt;p>&lt;a href="https://medium.com/@kanerika/mlflow-vs-kubeflow-vs-w-b-which-mlops-tool-fits-your-stack-b59007460b25">Múltiples comparativas&lt;/a> coinciden en algo: &lt;strong>los equipos que ganan combinan&lt;/strong>. Patrones recurrentes:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>ZenML para orquestar + MLflow para tracking + KServe para serving&lt;/strong>: el stack OSS más popular en empresas que vienen de MLOps clásico.&lt;/li>
&lt;li>&lt;strong>Kubeflow + W&amp;amp;B + BentoML&lt;/strong>: para equipos con foco en research.&lt;/li>
&lt;li>&lt;strong>Langfuse + DeepEval + Phoenix + LiteLLM&lt;/strong>: para equipos LLM-puros sin background MLOps clásico.&lt;/li>
&lt;li>&lt;strong>MLflow + DVC + Argo + KServe&lt;/strong>: stack idiomático cloud-native sin LLM-specifics adicionales (con sus limitaciones).&lt;/li>
&lt;/ul>
&lt;p>La elección depende del background del equipo, del modelo de licencia que pueden permitirse, del nivel de self-hosting que necesitan, y de qué fricciones les bloquearon más en proyectos previos. &lt;strong>No hay &amp;ldquo;una respuesta correcta&amp;rdquo;&lt;/strong>; hay un meta-patrón estable de capas que conviene cubrir.&lt;/p>
&lt;h2 id="trampas-operativas-comunes">Trampas operativas comunes&lt;/h2>
&lt;h3 id="tratar-el-prompt-como-texto-en-código">Tratar el prompt como texto en código&lt;/h3>
&lt;p>Hardcodear prompts en strings en el repo. Cambiarlos requiere PR + redeploy. Resultado: equipos que no iteran sobre prompts porque cada cambio cuesta horas de pipeline. &lt;strong>Solución&lt;/strong>: prompt management externalizado (Langfuse, MLflow Prompts) con versionado, etiquetas, hot-reload.&lt;/p>
&lt;h3 id="saltarse-el-dataset-versioning">Saltarse el dataset versioning&lt;/h3>
&lt;p>&amp;ldquo;DVC es complicado, ya lo metemos después&amp;rdquo;. Resultado: dos meses después, nadie sabe qué dataset entrenó qué modelo. Imposible reproducir incidentes. &lt;strong>Solución&lt;/strong>: DVC + lakeFS desde el día 1, aunque sea con un subset pequeño.&lt;/p>
&lt;h3 id="mezclar-capas-en-el-mismo-pipeline">Mezclar capas en el mismo pipeline&lt;/h3>
&lt;p>Equipos que meten ingestión, fine-tuning, eval, deploy en un único pipeline gigante. Cuando algo falla, todo el pipeline falla. &lt;strong>Solución&lt;/strong>: pipelines independientes por etapa, con artifacts versionados como interfaces entre ellos.&lt;/p>
&lt;h3 id="tracking-sin-estructura">Tracking sin estructura&lt;/h3>
&lt;p>Loguear todo en stdout y &amp;ldquo;ya lo veremos en CloudWatch&amp;rdquo;. Resultado: imposible correlar, comparar, debugear. &lt;strong>Solución&lt;/strong>: OTel desde el día 1 con &lt;code>gen_ai.*&lt;/code> semantic conventions.&lt;/p>
&lt;h3 id="evals-que-no-bloquean-nada">Evals que no bloquean nada&lt;/h3>
&lt;p>Tienes evals, los corres, los miras, pero &lt;strong>no impiden el deploy&lt;/strong> si bajan. Eventualmente baja gradualmente y nadie lo nota. &lt;strong>Solución&lt;/strong>: eval gates en CI/CD que &lt;strong>bloquean merge&lt;/strong> si métricas críticas regresan más de X%.&lt;/p>
&lt;h3 id="sin-retrain-cadence">Sin retrain cadence&lt;/h3>
&lt;p>Lanzas v1 y nunca vuelves al modelo. Seis meses después, drift lo ha degradado pero el equipo está en otros proyectos. &lt;strong>Solución&lt;/strong>: cadencia formal de retrain (mensual, trimestral) ligada a la cola de incidentes de producción.&lt;/p>
&lt;h3 id="vendor-lock-in-invisible">Vendor lock-in invisible&lt;/h3>
&lt;p>Empiezas con OpenAI API + LangSmith + Pinecone. Cuando quieres self-host, &lt;strong>descubres&lt;/strong> que migrar es un proyecto de 3 meses. &lt;strong>Solución&lt;/strong>: capas de abstracción (LiteLLM, OpenLLMetry) y vendor-neutrality desde el principio.&lt;/p>
&lt;h2 id="lo-que-viene-en-los-siguientes-posts-de-la-serie">Lo que viene en los siguientes posts de la serie&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Post 2 — &lt;a href="https://blog.lo0.es/posts/rag-kafka-datalake-arquitectura/">RAG sobre datalakes con Kafka: arquitectura técnica end-to-end&lt;/a>&lt;/strong> — el más hands-on. Kafka como source-of-truth, Flink CDC, embedding pipelines, indexación continua en Milvus/Qdrant, ejemplo completo con números reales y manifests.&lt;/li>
&lt;li>&lt;strong>Post 3 — &lt;a href="https://blog.lo0.es/posts/pipeline-llmops-seis-etapas/">El pipeline LLMOps de seis etapas: arquitectura global&lt;/a>&lt;/strong> — el mapa maestro del sistema completo con SVG reutilizable de &amp;ldquo;estás aquí&amp;rdquo; para los siguientes posts. Deep dive en cada una de las seis etapas (Data, Tune, Eval, Deploy, Observe, Retrain).&lt;/li>
&lt;li>&lt;strong>Post 4 — &lt;a href="https://blog.lo0.es/posts/postgresql-qdrant-ingestion-microservicios/">PostgreSQL + Qdrant en la etapa de ingestión&lt;/a>&lt;/strong> — patrones de sincronización (dual-write, outbox + CDC, event-driven), arquitectura de microservicios completa, manifest de Qdrant cluster.&lt;/li>
&lt;li>&lt;strong>Próximos posts&lt;/strong> — pendientes de decidir: el cluster como plataforma multi-tenant, Constitutional AI / alignment runtime, fine-tuning continuo en profundidad, edge LLMs.&lt;/li>
&lt;/ul>
&lt;h2 id="referencias">Referencias&lt;/h2>
&lt;p>LLMOps vs MLOps:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://medium.com/@sanjeebmeister/the-complete-mlops-llmops-roadmap-for-2026-building-production-grade-ai-systems-bdcca5ed2771">The Complete MLOps/LLMOps Roadmap for 2026 (Sanjeeb Panda)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.iamraghuveer.com/posts/mlops-vs-llmops-what-changes/">MLOps vs LLMOps: What Changes (Raghuveer)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://hyscaler.com/insights/mlops-in-2026-guide/">MLOps in 2026: Architecture, Trends &amp;amp; Strategy (Hyscaler)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.ideas2it.com/blogs/llmops-vs-mlops-key-differences-and-evolution">LLMOps vs MLOps: Differences and Evolution (Ideas2IT)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://dev.to/apprecode/llmops-vs-mlops-whats-different-whats-the-same-and-how-to-run-both-in-production-2o52">LLMOps vs MLOps in production (DEV/Apprecode)&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Herramientas:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://mlflow.org/">MLflow&lt;/a> — registry + tracking + serving.&lt;/li>
&lt;li>&lt;a href="https://wandb.ai/site/weave">Weights &amp;amp; Biases Weave&lt;/a> — LLM tracing.&lt;/li>
&lt;li>&lt;a href="https://www.zenml.io/">ZenML&lt;/a> — pipeline orchestration MLOps + LLMOps.&lt;/li>
&lt;li>&lt;a href="https://www.kubeflow.org/">Kubeflow&lt;/a> — K8s-native MLOps.&lt;/li>
&lt;li>&lt;a href="https://kserve.github.io/website/">KServe&lt;/a> — model serving K8s.&lt;/li>
&lt;li>&lt;a href="https://www.bentoml.com/">BentoML&lt;/a> — serving flexible.&lt;/li>
&lt;li>&lt;a href="https://metaflow.org/">Metaflow&lt;/a> — Netflix&amp;rsquo;s pipelines.&lt;/li>
&lt;li>&lt;a href="https://dvc.org/">DVC&lt;/a> — dataset versioning.&lt;/li>
&lt;li>&lt;a href="https://lakefs.io/">lakeFS&lt;/a> — data versioning enterprise, adquirió DVC en Nov 2025.&lt;/li>
&lt;/ul>
&lt;p>Comparativas 2026:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://medium.com/@kanerika/mlflow-vs-kubeflow-vs-w-b-which-mlops-tool-fits-your-stack-b59007460b25">MLflow vs Kubeflow vs W&amp;amp;B (Kanerika)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.zenml.io/blog/mlflow-alternatives">9 MLflow alternatives tested (ZenML)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.zenml.io/blog/metaflow-vs-kubeflow">Metaflow vs Kubeflow vs ZenML (ZenML)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.zenml.io/blog/mlops-tools">12 Best MLOps Tools for Agentic AI (ZenML)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.spheron.network/blog/mlops-pipeline-gpu-cloud-kubeflow-zenml-metaflow-2026/">MLOps Pipeline on GPU Cloud 2026 (Spheron)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://northflank.com/blog/top-7-kubeflow-alternatives">Top 7 Kubeflow alternatives 2026 (Northflank)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.sganalytics.com/blog/mlops-tools/">Top 20 MLOps Tools 2026 (SG Analytics)&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>RAG vs Fine-Tuning:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://www.scalacode.com/blog/rag-vs-fine-tuning/">RAG Vs Fine-Tuning In 2026 (ScalaCode)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.arxiv.org/pdf/2510.01375">Fine-Tuning with RAG (ICLR 2026, arxiv)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://dev.to/tyson_cung/rag-vs-fine-tuning-what-actually-works-in-production-2026-20jg">RAG vs Fine-Tuning — What Actually Works in Production 2026 (DEV)&lt;/a>.&lt;/li>
&lt;li>&lt;a href="https://www.kapa.ai/blog/how-to-build-a-rag-pipeline-from-scratch-in-2026">How to Build a RAG Pipeline from Scratch in 2026 (kapa.ai)&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>Cross-references (las tres series previas):&lt;/p>
&lt;ul>
&lt;li>Serie inferencia LLM: &lt;a href="https://blog.lo0.es/posts/kv-cache-fundamentos/">KV cache&lt;/a>, &lt;a href="https://blog.lo0.es/posts/vllm-kubernetes/">vLLM en K8s&lt;/a>, &lt;a href="https://blog.lo0.es/posts/pagedattention-deep-dive/">PagedAttention&lt;/a>, &lt;a href="https://blog.lo0.es/posts/operators-llm-kubernetes/">Operators LLM K8s&lt;/a>.&lt;/li>
&lt;li>Serie eBPF: &lt;a href="https://blog.lo0.es/posts/ebpf-cilium-tcp-ip-bypass/">eBPF de cero a Cilium&lt;/a>, &lt;a href="https://blog.lo0.es/posts/tetragon-runtime-security/">Tetragon&lt;/a>, &lt;a href="https://blog.lo0.es/posts/hubble-observabilidad-ebpf/">Hubble&lt;/a>, &lt;a href="https://blog.lo0.es/posts/agentsight-tracing-llm/">AgentSight&lt;/a>.&lt;/li>
&lt;li>Serie post-tracing: &lt;a href="https://blog.lo0.es/posts/evals-llm-la-capa-despues-de-tracing/">Evals&lt;/a>, &lt;a href="https://blog.lo0.es/posts/guardrails-safety-llm/">Guardrails&lt;/a>, &lt;a href="https://blog.lo0.es/posts/mcp-observability-otel/">MCP observability&lt;/a>, &lt;a href="https://blog.lo0.es/posts/ebpf-on-device-inference-drift/">eBPF + drift&lt;/a>.&lt;/li>
&lt;/ul></description></item></channel></rss>