Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Sistemes LLM en producció

Aquest document cobreix tres dimensions que converteixen un sistema LLM funcional en un sistema desplegable: com observar-lo quan funciona en producció (observabilitat), com empaquetar-lo perquè qualsevol el pugui executar (integració i desplegament), i com gestionar la seva evolució al llarg del temps (cicle de vida del sistema). Per a la metodologia d’avaluació (evals, graders, pass@k), consulta Avaluació de sistemes LLM. Per als patrons de programació (prompts, RAG, eines), consulta Patrons de programació amb LLMs.

Una intuïció que ordena tot el que segueix: és temptador pensar que un sistema LLM és el model. No ho és. La crida a l’API és la part trivial; la complexitat real resideix en tot el que l’envolta — validació, observabilitat, cicle de vida, desplegament. El model canvia de versió o de proveïdor; la infraestructura que l’envolta és el que realment construeixes i mantens.

Observabilitat

Per què l’observabilitat és una exigència de producció

Un sistema desplegable no és només un sistema que funciona — és un sistema que es pot monitorar, diagnosticar i millorar un cop en producció. Sense observabilitat, les fallades dels sistemes LLM són invisibles fins que l’usuari les reporta: el model pot estar al·lucinant, el cost pot estar disparant-se, o la qualitat pot estar degradant-se progressivament sense que cap alarma salti.

Els sistemes LLM tenen modes de fallada específics que les eines d’observabilitat convencionals no capturen bé:

  • Regressions silencioses: un canvi de model o de prompt degrada la qualitat sense errors HTTP.
  • Explosions de cost: una crida amb un context molt gran pot costar 100× el cas habitual.
  • Latència variable: el temps de resposta d’un LLM depèn de la longitud de la sortida, no de la complexitat de la petició.
  • Fallades d’agent: un bucle d’agent pot convergir a respostes incorrectes sense llançar cap excepció.

Traces: la unitat d’observació

En un sistema LLM, la unitat d’observació rellevant no és una línia de log — és una traça: el registre complet de tot el que ha passat per a processar una petició de l’usuari. Una traça inclou:

Traça (una petició d'usuari)
    ├── Prompt enviat al model (system + user)
    ├── Resposta rebuda
    ├── Tokens consumits (entrada / sortida)
    ├── Cost total de la petició (USD)
    ├── Latència total i per pas
    ├── Crides a eines (arguments i resultats)
    ├── Consultes de recuperació RAG (query, fragments retornats)
    └── Errors i reintentos

Tenir totes aquestes dades associades a una mateixa petició permet diagnosticar exactament per qué una resposta ha estat incorrecta, cara o lenta — sense necessitat de reproduir el problema manualment.

LangSmith és la plataforma de traçabilitat de referència per a sistemes LLM: registra totes les crides automàticament quan s’usa LangChain o LangGraph, i ofereix una interfície per explorar traces, comparar versions de prompt i executar evals. La integració és mínima:

export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY="ls-..."

Per a crides directes amb l’OpenAI SDK sense LangChain, cal embolcallar el client manualment o usar la integració de LangSmith per al SDK d’OpenAI.

Mètriques clau

Les traces permeten diagnosticar una petició concreta; les mètriques agreguen el comportament del sistema al llarg del temps. Les dues disciplines són complementàries i no intercanviables: una traça diu per què va fallar una petició; les mètriques diuen si el sistema es degrada.

A part de les traces individuals, cal agregar mètriques al llarg del temps per detectar tendències:

MètricaQuè mesuraSenyal d’alarma
Latència p50 / p99Temps de resposta típic i en el pitjor casp99 molt superior a p50 indica cues o crides molt llargues
Tokens per peticióCost i ús del contextCreixement sostigut indica context que s’acumula sense control
Cost diariDespesa total en inferènciaPics sobtats indiquen peticions aberrants o abús
Taxa d’errorCrides fallides, sortides malformadesQualsevol augment sostigut requereix investigació
Puntuació d’evalsQualitat de les respostes al llarg del tempsDegradació progressiva indica deriva del model o del prompt

La notació pXX indica un percentil: p50 és la mediana (la meitat de les peticions acaben per sota d’aquest temps); p99 significa que el 99% de les peticions acaben per sota — representa el pitjor cas habitual, excloent els outliers extrems. Un sistema pot tenir un p50 acceptable però un p99 molt elevat si hi ha crides ocasionalment molt lentes.

Control de costos

En sistemes que usen APIs comercials, els tokens es tradueixen directament en diners. Sense control actiu, un bug (un bucle que genera context il·limitat, una crida que s’executa amb tots els documents en lloc dels rellevants) pot generar una factura inesperada en hores.

Pràctiques mínimes per a sistemes desplegables:

  • Límit de tokens de sortida: establir max_tokens a totes les crides (client.chat.completions.create(..., max_tokens=512)). Un model sense límit pot generar sortides molt llargues.
  • Alerta de cost diari: configurar un límit de despesa a la plataforma d’inferència (OpenAI, Anthropic) que notifiqui o bloquegi quan se supera.
  • Registre de tokens per petició: incloure els tokens consumits a cada traça per poder identificar les peticions més cares.
  • Cache de respostes: per a consultes repetides o deterministes, una cache a nivell de prompt pot eliminar crides redundants.
  • Prompt caching: les APIs d’Anthropic i OpenAI permeten marcar fragments estables del context (system prompt llarg, documents de referència) perquè el proveïdor en reutilitzi la representació interna entre crides. Els tokens de cache hit es facturen a un preu molt reduït (típicament 80-90% de descompte). Útil quan el system prompt és extens i constant entre peticions.

Detecció de regressions

L’observabilitat i les evals estan connectades: les mètriques de qualitat recollides en producció retroalimenten la suite d’evals, i les evals validen els canvis abans de desplegar-los.

Canvi de prompt / model
        │
        ▼
Execució d'evals (offline)
        │
        ├── millora → desplega
        └── regressió → no desplega
                │
                ▼
        Monitoratge en producció
                │
                ├── qualitat estable → ok
                └── deriva detectada → nova ronda d'evals i ajust

Llegir traces de producció regularment — especialment les de peticions amb puntuació baixa o errors — és la font més valuosa per ampliar la suite d’evals amb casos reals.

La detecció de regressions en sistemes LLM és una forma de concept drift adaptada a models generatius: el que canvia no és la distribució de les dades d’entrada sinó el comportament del model davant d’entrades similars. Els patrons generals de detecció de deriva estadística i els seus sistemes d’alertes estan desenvolupats a Drifting i Monitoratge.

Evals online en producció

Llegir traces manualment és útil però no escalable. Les evals online automatitzen aquest procés: s’executen de forma asíncrona, fora del camí crític de la petició, de manera que el worker de fons processa les traces sense afectar la latència de l’usuari.

Petició d'usuari → resposta → traça registrada
                                    │
                     (fora del camí crític)
                                    │
                         mostreig (5–20%)
                                    │
                                    ▼
                            cua d'avaluació
                                    │
                                    ▼
                         LLM-as-judge (asíncron)
                                    │
                          ┌─────────┴──────────┐
                     puntuació alta         puntuació baixa
                          │                     │
                     registrar              alerta + afegir
                                           al dataset offline

Estratègia de mostreig: avaluar el 100% del tràfic no és pràctic. El patró habitual és 5–10% per a aplicacions d’alt volum (per controlar el cost del jutge) i 20–50% per a volum baix o durant les primeres setmanes de desplegament. Quan hi ha múltiples criteris, es poden configurar taxes diferenciades: criteris avaluats per codi al 100%, criteris amb LLM-as-judge al 5–10%.

Connexió amb el dataset offline: les traces que reben puntuació per sota del llindar entren automàticament al dataset offline com a casos nous. Aquesta és la font més valuosa per ampliar la cobertura sense treball manual — els casos reals capturen els modes de fallada que el dissenyador no anticipava.

Alertes: el patró estàndard és alertar quan la puntuació mitjana cau per sota d’un llindar en una finestra de temps (p.ex. taxa d’aprovació < 80% en les darreres 24 hores). Langfuse i LangSmith permeten configurar-les directament sobre els scores registrats.

En producció: Langfuse és l’alternativa open source auto-allotjada a LangSmith — mateixa funcionalitat de traces i evals, sense enviar dades a un servei extern. Adequat quan les dades no poden sortir de la infraestructura pròpia. Helicone és una altra opció com a proxy transparent davant qualsevol API compatible amb OpenAI.

Integració i desplegament

La diferència entre un prototip i una solució desplegable no és la complexitat del codi — és l’empaquetament: el sistema ha de poder arrencar en qualsevol entorn amb configuració mínima, sense dependències implícites en l’entorn local del desenvolupador.

Els patrons de contenització, health checks, versionat i CI/CD desenvolupats a Desplegament de models s’apliquen directament. La diferència clau respecte al desplegament de models ML clàssics és que en sistemes LLM el model no és un artefacte serialitzat que el backend carrega — és un servei extern al qual el backend fa crides. El que es desplega i versiona és el backend i els seus prompts, no els pesos del model.

Integrar el model en el sistema

La forma més habitual d’integrar la funcionalitat LLM és exposar-la com un endpoint HTTP que encapsula tota la lògica: validació de l’entrada, construcció del prompt, crida al model, validació de la sortida i formatació de la resposta. El client (frontend o altre servei) no sap res del model subjacent. Altres formes d’integració — plugins, extensions, workers de fons — segueixen el mateix principi d’encapsulació; canvia com es crida la lògica, no com es construeix.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Petició(BaseModel):
    text: str

class Resposta(BaseModel):
    sentiment: str
    resum: str

@app.post("/analitzar", response_model=Resposta)
async def analitzar(petició: Petició) -> Resposta:
    resultat = analitzar_sentiment(petició.text)  # lògica LLM encapsulada
    return Resposta(**resultat)

Encapsular la lògica LLM en una funció separada de l’endpoint té dos avantatges: és més fàcil de testar de forma aïllada, i permet canviar el model o el prompt sense tocar el codi de la API.

⚠️ Autenticació: un endpoint LLM sense protecció permet que qualsevol cridi al model en nom teu, consumint quota i generant cost. Com a mínim, protegeix l’endpoint amb una clau d’API en la capçalera (Authorization: Bearer <token>) validada al backend. Per a aplicacions amb usuaris, usa OAuth2 o sessions. Consulta Control d’accés per als patrons generals.

Patrons de comunicació amb el model

Hi ha quatre patrons per consumir un servei d’inferència, cadascun adequat a un context diferent:

Síncron (per defecte): el backend fa una crida, espera la resposta completa i la processa com a JSON. És el patró habitual en sistemes B2B — classificació, extracció, presa de decisions — perquè el consumidor no pot actuar fins a tenir la resposta sencera. La implementació és una crida directa a chat.completions.create amb stream=False.

Streaming: el backend reenvia cada token al client a mesura que arriba del model (Server-Sent Events). Rellevant quan l’endpoint serveix una UI directament i es vol eliminar la percepció d’espera en respostes llargues. Si el consumidor és un altre sistema backend, l’stream afegeix complexitat sense cap benefici.

Batch: múltiples inputs s’envien conjuntament per ser processats de forma asíncrona; els resultats es recuperen més tard. El patró adequat per a volums alts sense requisit de latència — enriquiment de documents, etiquetatge de datasets, generació d’informes offline. La majoria de proveïdors ofereixen una API de batch a cost per token reduït.

Async amb cua: la petició HTTP retorna immediatament (202 Accepted), la crida al model s’encua en un worker de fons, i el resultat s’emmagatzema per a consulta posterior (polling) o notificació (webhook). Necessari quan la latència del model supera els límits de timeout HTTP acceptables, o per desacoblar pics de càrrega del processament.

Configuració per entorn

El codi és el mateix en tots els entorns; la configuració canvia. Les variables d’entorn són la interfície estàndard entre el codi i l’entorn de desplegament:

import os
from openai import OpenAI

client = OpenAI(
    base_url=os.getenv("MODEL_BASE_URL", "http://localhost:11434/v1"),
    api_key=os.getenv("MODEL_API_KEY", "ollama"),
)
MODEL = os.getenv("MODEL_NAME", "nom-del-model")
VariableLocal (dev)Producció
MODEL_BASE_URLhttp://localhost:11434/v1http://gpu-server:8000/v1
MODEL_NAMEmodel-petitmodel-gran
MODEL_API_KEYollamasecret de producció
CHROMA_PATH./vector_dbvolum persistent muntat

Amb aquest patró, el mateix contenidor que s’executa en local es desplega a producció sense canvis — només canvia el fitxer .env o les variables d’entorn del sistema de desplegament.

Empaquetament i consideracions de producció

Els patrons de contenització (Docker, health checks, CI/CD) i les consideracions generals de producció (timeouts, rate limiting, reintentos amb backoff, degradació elegant) estan coberts a Desplegament de models i s’apliquen directament als sistemes LLM.

La particularitat dels sistemes LLM és que el servidor de models és un servei addicional amb el seu propi temps d’arrencada: el backend ha d’esperar que estigui llest amb un health check explícit (depends_on: condition: service_healthy) en lloc d’assumir disponibilitat immediata. Pel que fa a l’escalat, el backend FastAPI és sense estat i escala sense problema; el coll d’ampolla és el servidor d’inferència — vLLM gestiona múltiples peticions concurrents eficientment, Ollama no. Per a tràfic elevat, un servidor vLLM compartit amb cua de peticions és el patró adequat.

Cicle de vida del sistema

Els sistemes LLM s’actualitzen per raons diferents als models ML clàssics (que s’actualitzen principalment perquè les dades canvien, veure Aprenentatge continu): el proveïdor canvia el model sense avisar, els prompts evolucionen a mesura que es descobreixen casos límit, o la cobertura de la tasca ha de créixer. Gestionar aquest cicle de forma controlada és el que separa un sistema mantenible d’un que es degrada silenciosament.

Versionat de prompts

Els prompts no són codi, però han de rebre el mateix tractament que la configuració crítica: versió controlada i desplegament explícit. Un canvi de prompt passa pel cicle d’evals com qualsevol altra modificació del sistema (veure El cicle prompt → eval → millora).

Emmagatzemar els prompts en fitxers de text versionats (no hardcodejats al codi) facilita la revisió de canvis i permet associar cada versió del sistema a un conjunt de prompts concret. Evitar la deriva de prompts — modificacions informals fetes directament en producció sense passar per les evals — és un dels hàbits d’operació més importants en sistemes LLM.

Avaluació

Per automatitzar el cicle de validació, les evals offline s’integren com a pas de CI: cada canvi al prompt, al codi o al model dispara l’execució de la suite i compara el resultat amb la línia base. El mecanisme concret (hook de git, pipeline de CI, script de pre-deploy) no afecta la lògica:

#!/usr/bin/env bash
# executa evals i bloqueja si hi ha regressió
python evals/run_suite.py --output evals/results/current.json
python evals/compare.py \
  --baseline evals/results/baseline.json \
  --current  evals/results/current.json \
  --threshold 0.05   # surt amb error si la puntuació baixa més d'un 5%

La línia base s’actualitza explícitament quan es desplega una versió nova — mai automàticament en cada canvi, perquè llavors derivaria silenciosament i perdria el seu valor de referència.

canvi → evals → comparació amb baseline → desplegament
                                               │
                                   (si és una versió nova)
                                               │
                                   actualitzar baseline.json

Per equilibrar velocitat i cobertura: una suite ràpida de 20–30 casos amb avaluador de codi s’executa en cada canvi (menys de 2 minuts); la suite completa amb LLM-as-judge s’executa abans del desplegament o com a tasca nocturna.

Canvis del model base

Models de tercers (API comercial): els proveïdors actualitzen models periòdicament. Un model identificat com gpt-4o o claude-3-5-sonnet pot canviar de comportament sense que el codi canviï. Per a sistemes on la consistència és crítica, cal fixar la versió específica del model (gpt-4o-2024-08-06, claude-sonnet-4-6) i tractar qualsevol actualització com una migració: executar les evals sobre la nova versió, comparar amb la línia base i desplegar explícitament.

Models auto-allotjats: les actualitzacions de model (nova versió de Llama, nou quantitzat) són sempre explícites. El procés és equivalent: pull de la nova versió → evals → desplegament. La suite d’evals és el mecanisme de seguretat que permet actualitzar amb confiança.

Models propis (fine-tuning)

Si el sistema usa un model amb fine-tuning propi, el cicle d’actualització és similar al de l’aprenentatge continu en ML, però els desencadenants acostumen a ser qualitatius, no estadístics:

  • Qualitat insuficient: les evals mostren que el model no cobreix correctament casos nous o dominis ampliats.
  • Dades acumulades: s’ha recollit prou feedback de producció per justificar un reentrenament.
  • Canvi del model base: el proveïdor publica una versió nova del model base i cal re-fer el fine-tuning.

El flux és: acumular dades de qualitat (inclòs feedback de producció i transcripts etiquetats) → reentrenar → evaluar contra la versió anterior → desplegar si millora. Els patrons generals d’automatització d’aquest pipeline (triggers, validació, desplegament progressiu) segueixen el mateix esquema que Aprenentatge continu; la diferència és que el desencadenant rarament és deriva estadística de les dades — les evals sobre casos concrets solen ser suficients per detectar quan el model ha deixat de ser adequat.

Last change: , commit: afd0d14