Commit 705a7fb7 authored by jg5dev's avatar jg5dev 💬
Browse files

better

parent 3e6fc425
Loading
Loading
Loading
Loading
+43 −1
Original line number Diff line number Diff line
@@ -135,6 +135,48 @@ response = client.chat.completions.create(
print(response.choices[0].message.content)
```

### Tasques del servidor d'inferència

Fins aquí el servidor d'inferència ha aparegut com un generador de text, però els servidors moderns serveixen més d'una família de models. Un pipeline RAG complet en necessita tres: un model **generatiu** que escriu la resposta, un model d'**embeddings** (*bi-encoder*) que converteix textos en vectors per indexar-los i cercar-los, i un **reranker** (*cross-encoder*) que reordena els candidats recuperats puntuant cada parella (consulta, fragment). Els dos últims són models encoder petits, no LLMs — la família que la nota de [Variants modernes](ml_transformers.md#variants-modernes) contraposa als generatius — però s'exposen amb el mateix mecanisme: una ruta HTTP per tasca.

| Tasca | Família de model | Ruta | Estàndard |
| --- | --- | --- | --- |
| Generació | decoder generatiu (LLM) | `/v1/chat/completions`, `/v1/completions` | OpenAI |
| Embeddings | bi-encoder | `/v1/embeddings` | OpenAI |
| Reranking | cross-encoder | `/rerank`, `/v1/rerank`, `/v2/rerank` | cap — convencions de Jina i de Cohere |

Ollama serveix generació i embeddings; `llama-server` (llama.cpp) serveix exactament les tres tasques de la taula (amb els flags `--embeddings` i `--reranking`); vLLM hi afegeix classificació (`/classify`), scoring i transcripció d'àudio. La fila del reranking mostra un fet instructiu: no hi ha ruta estàndard perquè OpenAI no ofereix aquest producte, i cada servidor imita les APIs dels proveïdors que sí que l'ofereixen (Jina, Cohere). L'estandardització de facto la fa qui té el producte dominant, no cap comitè.

**Fins on arriba la compatibilitat.** Per a la generació i els embeddings, l'estàndard té un artefacte normatiu: OpenAI publica una especificació OpenAPI contra la qual tothom programa. La compatibilitat entre servidors és sòlida al nucli de cada esquema (`messages``choices`; `input``data[].embedding`) i difusa a les vores: cada servidor afegeix extensions pròpies (la sortida estructurada és `guided_json` a vLLM i gramàtiques GBNF a llama-server) i els paràmetres opcionals no estan garantits — `dimensions`, amb què OpenAI exposa el truncament Matryoshka dels embeddings, no existeix a llama-server.

El reranking no té ni això. El format que tots dos servidors accepten és el que van fixar Cohere i Jina:

```json
{"query": "com es defineix la quota d'un dataset?",
 "documents": ["fragment A", "fragment B", "fragment C"],
 "top_n": 2}
```

i la resposta reordena per rellevància: `{"results": [{"index": 2, "relevance_score": 0.94}, ...]}`. Però el compromís de cada servidor és diferent, i és una lliçó sobre què val un estàndard sense propietari: vLLM declara compatibilitat explícita amb l'API de Jina (v1) i les de Cohere (v1 i v2); llama-server només diu que la seva ruta és "similar a la de Jina, però pot canviar". Avui els cossos coincideixen; cap especificació no obliga que demà també. I com que l'SDK d'OpenAI no té cap mètode de rerank, la crida es fa amb HTTP pla (`httpx`, `requests`) o amb l'SDK d'un proveïdor.

Que els servidors hagin convergit exactament en aquestes tres tasques no és casualitat: són els tres rols de model del patró RAG (vegeu [Recuperació, embeddings i índexs](llm_systems.md#recuperació-embeddings-i-índexs)), que és el cas d'ús que ha empès la infraestructura. La línia de producte de Cohere ho fa explícit: Command (generar), Embed, Rerank.

### Model servit o model en procés

El principi que obre [el rol del servidor de models](#el-rol-del-servidor-de-models) — el model és un servei, no una llibreria — és cert per als LLMs generatius, on carregar desenes de GB per procés és inviable. Però els models d'embeddings i els rerankers solen ser encoders de ~100M paràmetres que corren bé en CPU, i aquests sí que es poden importar com a llibreria (`sentence-transformers`) dins del procés de l'aplicació. Apareix, doncs, una decisió arquitectònica real: servir el model o executar-lo **en procés** (*in-process*). Els criteris:

**Consistència entre consumidors** — el criteri més fort, i específic dels embeddings: els vectors de l'índex i els de les consultes han de sortir del mateix model exacte, i canviar-lo obliga a re-indexar. Quan més d'un procés o més d'una persona toquen el mateix índex, un servidor únic és la manera de garantir-ho — i el punt únic on una actualització de versió (amb la seva re-indexació) passa una sola vegada. El reranking no té aquest acoblament: és sense estat, cap dada persistida en depèn.

**Encaix de maquinari** — un model generatiu de 7B+ necessita una GPU que els clients normalment no tenen: servit. Un cross-encoder de ~90 MB corre a qualsevol CPU: executar-lo en procés no costa res.

**Utilització** — un model servit es carrega una vegada i agrupa peticions de molts clients (batching continu); un model en procés es carrega a cada worker i resta ociós entre crides. Molts consumidors amb poc ús cadascun afavoreixen servir; un sol consumidor intensiu no hi guanya res.

**Dependències i arrencada** — en procés vol dir PyTorch i els pesos dins de cada aplicació consumidora, i pagar la càrrega del model a cada arrencada de procés. Servit vol dir una crida HTTP i una URL de configuració.

**Privadesa i desconnexió** — dades que no poden sortir de la màquina o treball sense xarxa forcen l'execució local (en procés o amb un servidor a la mateixa màquina).

La regla pràctica: **prototipa en procés; serveix un model quan guanya un segon consumidor, quan no cap al maquinari del client o quan la seva versió comença a importar.** Aplicat a les tres tasques: la generació es serveix gairebé sempre (maquinari); els embeddings es serveixen tan bon punt l'índex es comparteix (consistència); el reranker es queda en procés fins que l'escala justifiqui el contrari (utilització).

### Abstraure múltiples proveïdors: la capa de routing

Quan un sistema necessita suportar diversos proveïdors (per fallback, per A/B testing de models, o per centralitzar el control de costos), afegir una **capa de routing** entre el backend i els proveïdors és el patró adequat. Aquesta capa exposa una única API estàndard cap al backend i gestiona la distribució cap als proveïdors de forma transparent.
@@ -169,7 +211,7 @@ La regla pràctica és començar amb el model més petit que compleixi aquestes
Un model amb \\(N\\) paràmetres en precisió FP16 ocupa aproximadament \\(2N\\) bytes de memòria GPU **només per emmagatzemar els pesos**:

| Model | Paràmetres | Pesos (FP16) | Entrenament (estimat) |
|-------|-----------|---------------------------|----------------------|
| --- | --- | --- | --- |
| Petit (BERT) | 110M | ~0.2 GB | ~1 GB |
| Mitjà (LLaMA 7B) | 7B | ~14 GB | ~56 GB |
| Gran (LLaMA 70B) | 70B | ~140 GB | ~560 GB |