L'avaluació de 06-03 respon a "puc desplegar això?" amb casos que tu vas triar. Aquesta lliçó respon a la pregunta següent: què està passant ara mateix en producció, amb les preguntes que ningú no va triar? Un sistema amb LLM falla de maneres que el software clàssic no coneix: no llança excepcions quan al·lucina, no retorna un 500 quan respon amb desgana, i pot duplicar el seu cost sense que res no "es trenqui". A 05-02 vam sembrar traces.py::registrar_pas() anunciant que germinaria aquí; toca complir-ho: definir què registrar a cada petició, estructurar els logs perquè siguin explotables, destil·lar mètriques i panells que expliquin la salut del sistema d'un cop d'ull, muntar alertes que diguin què fer (no només que alguna cosa passa), i tancar el cercle amb el feedback dels usuaris alimentant el conjunt d'avaluació. És la diferència entre operar DocuBot i resar per DocuBot.

Contingut

  1. De les traces de l'agent a l'observabilitat del sistema
  2. Què registrar a cada petició
  3. Logs estructurats: JSON per línia amb logging
  4. Què NO loguejar
  5. Mètriques agregades i panells
  6. Alertes accionables: símptoma, causa probable, acció
  7. El feedback dels usuaris: el cicle de millora contínua
  8. L'ecosistema d'eines, per categories

De les traces de l'agent a l'observabilitat del sistema

registrar_pas() va néixer a 05-02 amb una missió modesta: apuntar cada iteració del bucle agèntic (què va pensar, quina eina va cridar, què va obtenir) per poder depurar. Això és una traça: la biografia d'una petició. L'observabilitat completa hi afegeix dos pisos:

  • Logs: esdeveniments individuals estructurats, consultables ("ensenya'm totes les peticions d'ahir amb confiança < 0.3").
  • Mètriques: agregats numèrics en el temps ("taxa de fallback per hora", "cost acumulat del dia").

La distinció pràctica: les traces expliquen una petició; les mètriques vigilen totes; els logs són la matèria primera de totes dues. En una aplicació amb LLM hi ha, a més, una peculiaritat: bona part dels "errors" són degradacions silencioses (respostes pitjors, costos més alts, més "no ho sé") que només es veuen als agregats. Per això un sistema que només té traces de depuració està cec en producció.

Què registrar a cada petició

El disseny comença per l'esdeveniment central: una línia per petició completa (a més de les línies per pas de l'agent que ja emet traces.py). Camps, agrupats pel que permeten respondre:

Grup Camps Per a què
Identitat id_peticio (UUID), timestamp, id_sessio i usuari pseudonimitzats (06-02) Correlacionar: unir aquesta línia amb els passos de l'agent, el feedback posterior i la conversa, sense exposar identitats
Versions prompt_version, chunking_version, model L'eix de tota anàlisi: "ha empitjorat res després del desplegament d'ahir?" exigeix saber quina versió va atendre cada petició (mateix principi que el CSV de 06-03)
Recuperació chunks_recuperats (ids i similituds), llindar_superat Diagnosticar RAG en producció: la pregunta va fallar perquè no es va recuperar res o perquè es va recuperar brossa?
Agent eines_cridades (nom, resultat ok/error), iteracions, confirmacio_humana (proposada/acceptada/rebutjada) Vigilar el comportament agèntic i el human-in-the-loop
Rendiment tokens_entrada, tokens_sortida, cost (via estimar_cost()), ttft_ms, latencia_total_ms (de mesurar_crida(), 03-04), cache (exacte/semantic/miss) Cost i latència per petició; agregats per a panells
Qualitat categoria (del classificador), confianca (del contracte JSON), frase_sense_info (bool), fallback (bool), error Els senyals de qualitat que el sistema ja emet sense cost extra
Tancament del cicle feedback (👍/👎/nul, s'adjunta a posteriori via id_peticio) La veritat de l'usuari

Fixa't en l'economia del disseny: gairebé tot això ja existia. estimar_cost() i mesurar_crida() venen de 03-04, la confianca del contracte de 02-03, les similituds de recuperar() de 04-04, les eines i confirmacions de 05-02, la pseudonimització de 06-02. L'observabilitat no inventa dades; recol·lecta amb disciplina les que el sistema ja produeix.

Logs estructurats: JSON per línia amb logging

Un log de text lliure ("L'usuari va preguntar per facturació, va anar bé") no es pot consultar ni agregar. L'estàndard de facto és una línia = un objecte JSON (JSON Lines): el llegeix un humà amb grep, l'ingereix qualsevol plataforma de logs, i l'agrega un script de vint línies.

Implementació amb el mòdul logging de la biblioteca estàndard:

# observabilitat.py
import json
import logging
import time
import uuid
from datetime import datetime, timezone

class FormatadorJson(logging.Formatter):
    """Converteix cada registre en una línia JSON."""
    def format(self, record: logging.LogRecord) -> str:
        esdeveniment = {
            "ts": datetime.now(timezone.utc).isoformat(),
            "nivell": record.levelname,
            "esdeveniment": record.getMessage(),
        }
        # Els camps estructurats viatgen a `extra={"dades": {...}}`
        esdeveniment.update(getattr(record, "dades", {}))
        return json.dumps(esdeveniment, ensure_ascii=False)

logger = logging.getLogger("docubot")
_handler = logging.StreamHandler()          # en producció: fitxer o col·lector
_handler.setFormatter(FormatadorJson())
logger.addHandler(_handler)
logger.setLevel(logging.INFO)

def log_peticio(**camps):
    """Registra l'esdeveniment central: una petició completa."""
    logger.info("peticio", extra={"dades": camps})

I la seva integració al punt de sortida de docubot.py::respondre (versió abreujada):

from preus import estimar_cost
from observabilitat import log_peticio

def respondre(pregunta, sessio):
    id_peticio = str(uuid.uuid4())
    t0 = time.time()
    # ... pipeline complet: redacció (06-02), RAG o agent, validació ...
    log_peticio(
        id_peticio=id_peticio,
        id_sessio=sessio.id_pseudonim,          # pseudònim, mai la identitat
        prompt_version=PROMPT_VERSION,
        chunking_version=CHUNKING_VERSION,
        model=MODEL,
        categoria=sortida.get("categoria"),
        confianca=sortida.get("confianca"),
        frase_sense_info=FRASE_SENSE_INFO in sortida.get("resposta", ""),
        fallback=sortida is RESPOSTA_FALLBACK,
        chunks=[{"id": c["id"], "sim": round(c["similitud"], 3)}
                for c in chunks_recuperats],
        eines=[e["nom"] for e in eines_cridades],
        tokens_entrada=consum.tokens_entrada,
        tokens_sortida=consum.tokens_sortida,
        cost=estimar_cost(consum.tokens_entrada, consum.tokens_sortida),
        ttft_ms=metriques.ttft_ms,
        latencia_total_ms=int((time.time() - t0) * 1000),
    )
    return sortida

Una línia resultant (formatada aquí per llegir-la; al fitxer va en una sola línia):

{"ts": "2026-07-06T10:14:03+00:00", "nivell": "INFO", "esdeveniment": "peticio",
 "id_peticio": "9f2c...", "id_sessio": "ses_a41b", "prompt_version": "v7",
 "chunking_version": "encapcalaments-v1-1800-300", "model": "…",
 "categoria": "facturacio", "confianca": 0.86, "frase_sense_info": false,
 "fallback": false, "chunks": [{"id": "doc_fact_03#2", "sim": 0.71}],
 "eines": [], "tokens_entrada": 2140, "tokens_sortida": 312,
 "cost": 0.0093, "ttft_ms": 640, "latencia_total_ms": 3820}

Detalls didàctics del codi: el Formatter personalitzat és l'únic punt on es decideix el format (canviar-lo no toca la resta del codi); els camps van per extra per no concatenar strings; ensure_ascii=False manté llegibles els accents; i id_peticio és la clau que uneix aquesta línia amb les traces per pas de registrar_pas() (que ara també l'inclou) i amb el feedback de l'usuari que arribarà minuts després.

Què NO loguejar

Els logs són un tractament de dades més (ho vam veure a 06-02: entren al perímetre de l'RGPD i dels exercicis de drets). Regles per a DocuBot:

  • Ni la pregunta ni la resposta en cru al log de producció. Contenen el que l'usuari va escriure — potencialment dades personals sense redactar. Opcions intermèdies, de menys a més exposició: només metadades (el que hem mostrat més amunt); text redactat amb redactar() (06-02) i retenció curta; text complet únicament en entorns de desenvolupament amb dades fictícies. Si el negoci necessita revisar converses reals, que sigui una decisió explícita amb legal, amb accés restringit i caducitat — no un default del logger.
  • Identitats reals: sempre el pseudònim de sessió/usuari, amb la taula de correspondència protegida a part.
  • Claus d'API i secrets: mai. Compte amb els bolcats alegres d'objectes de configuració o d'excepcions que arrosseguen headers.
  • Prompts complets del sistema: prompts.py està versionat a git; amb prompt_version al log n'hi ha prou. Loguejar el prompt sencer a cada petició és soroll, cost i exposició de propietat intel·lectual.
  • I la regla general: logueja referències i mesures, no continguts. {"id": "doc_fact_03#2", "sim": 0.71} en lloc del text del chunk: l'id permet recuperar el contingut si cal investigar, sense duplicar-lo pel sistema de logs.

Mètriques agregades i panells

Sobre els logs es calculen els agregats. Aquests són els indicadors amb millor relació senyal/esforç per a DocuBot, i el que cadascun explica:

Mètrica Què vigila Lectura
Taxa de "No trobo aquesta informació..." % de respostes amb frase_sense_info El termòmetre dels buits de documentació: estable ≈ normal; pujada = o arriben preguntes noves (llançament recent?) o la wiki s'ha quedat curta. Agrupada per categoria et diu què documentar
Distribució de confianca Histograma setmanal Un desplaçament cap avall és degradació silenciosa que cap error HTTP no delatarà
Cost diari Suma de cost vs el pressupost de 03-04 (~417 €/mes base, ~270 € amb palanques) La projecció de 03-04 era una hipòtesi; això és la dada. registrar_crida() ja va definir els senyals: ok / alerta al 80% / sostre al 150% amb decisió humana
Latència p50 / p95 i TTFT Percentils de latencia_total_ms i ttft_ms El p95 (no la mitjana) és l'experiència dels teus usuaris descontents; el TTFT vigila la sensació de vivor de l'streaming (03-02)
Taxa de fallback i d'errors % de fallback=true, errors de reintents.py, obertures del circuit breaker La fiabilitat clàssica; aquí sí que valen els reflexos de sempre
Taxa d'encert de la cache % exacte / semàntic / miss (CacheRespostes, CacheSemantic) Si cau, l'estalvi projectat a 03-04 s'està evaporant: ha canviat el patró de preguntes?
Taxa de confirmacions rebutjades % de propostes de crear_amb_confirmacio() que l'humà rebutja L'indicador de salut de l'agent: pujada = l'agent proposa tiquets dolents (prompt? eina confusa?) — o alguna cosa pitjor, com una injection (06-01) empenyent accions
Volum per categoria Peticions per categoria del classificador Context per a tota la resta i radiografia de què necessita l'organització

Un panell raonable per a DocuBot són aquestes 8 sèries amb comparació contra la setmana anterior. La regla d'or en dissenyar-lo: cada gràfic ha de tenir un amo de la pregunta "i si això canvia, què faig?" — un panell que ningú no sap interpretar és decoració.

Alertes accionables: símptoma, causa probable, acció

Una alerta que només diu "alguna cosa va malament" genera fatiga i acaba silenciada. Una alerta accionable porta incorporat el diagnòstic diferencial — exactament el format de la taula de diagnòstic de 04-05, ara estesa a tot el sistema:

Símptoma (alerta) Causa probable Primera acció
La taxa de frase_sense_info puja del 10% al 25% a la categoria integracions Buit de documentació (integració nova sense documentar?) o regressió de recuperació després d'un canvi de chunking_version Revisar les preguntes afectades als logs; si són sobre un tema nou → escriure docs i ingerir; si són temes que abans funcionaven → eval_rag.py (recall@k) per confirmar regressió del retriever i revertir
Cost diari al 80% del pressupost a mitjan mes Més trànsit (mira el volum), respostes més llargues, caiguda de la cache, o bucles agèntics llargs (mira iteracions) Descompondre el cost per categoria i per cache; aplicar les palanques de 03-04 (caching, límits de sortida) abans de demanar més pressupost
El p95 de latència es duplica sense canvi de versió Degradació del proveïdor, chunks més llargs entrant al prompt, o caiguda de la taxa de cache Comparar TTFT vs latència total: si el TTFT puja → proveïdor/xarxa; si el TTFT és normal i el total puja → hi ha més tokens a generar: mirar mida de context i cache
La confiança mitjana cau després de pujar prompt_version v7→v8 Regressió del prompt que l'avaluació no va capturar (conjunt sense casos d'aquest tipus?) Revertir a v7 (per això versionem), reproduir amb el runner de 06-03 i afegir els casos que van fallar al conjunt
La taxa de confirmacions rebutjades passa del 5% al 30% L'agent proposa accions dolentes: descripcions d'eina ambigües, prompt degradat, o contingut hostil empenyent accions (06-01) Llegir les traces de les propostes rebutjades (id_peticio → passos de l'agent); si hi ha patró d'instruccions intruses → revisar la ingesta i activar revisió de la font
Pics d'is_error en una eina L'API interna de Nubelia ha canviat o està caiguda Reflexos clàssics: provar l'API directament; el circuit breaker de 03-02 hauria d'estar limitant el dany mentrestant

Dos principis en configurar llindars: alerta sobre tendències i ràtios (taxa que es duplica) més que sobre valors absoluts amb soroll; i cada alerta disparada ha d'acabar o en una acció o en un ajust del llindar — les alertes que s'ignoren tres vegades s'eliminen o s'arreglen.

El feedback dels usuaris: el cicle de millora contínua

Tots els senyals anteriors són indirectes. La directa és preguntar: un 👍/👎 al peu de cada resposta (opcionalment amb comentari al 👎). Barat d'implementar — un endpoint que adjunta el veredicte a l'id_peticio — i valuosíssim si s'explota bé:

# feedback.py
def registrar_feedback(id_peticio: str, util: bool, comentari: str = ""):
    logger.info("feedback", extra={"dades": {
        "id_peticio": id_peticio,       # uneix amb la petició original
        "util": util,
        "comentari": comentari[:500],   # acotat; i redactat si es mostra
    }})

L'ús ingenu és calcular el "% de polzes amunt" i posar-lo al panell (útil, amb biaixos: vota una minoria, i els descontents voten més). L'ús potent és tancar el cercle amb 06-03:

  1. Cada 👎 s'uneix, via id_peticio, amb el seu log complet: pregunta (redactada), chunks, similituds, versions, resposta.
  2. Revisió periòdica dels 👎: recuperació dolenta? resposta infidel? buit de documentació? La taula de símptomes de més amunt, aplicada cas a cas.
  3. Els errors reals representatius es converteixen en casos nous del conjunt d'avaluació de 06-03, amb el seu resultat esperat anotat.
  4. La següent iteració de prompt/chunking es valida ja contra ells: aquell mode de fallada no torna sense que el runner el detecti.
flowchart LR
    A[Producció:<br>peticions reals] --> B[Logs + feedback 👎]
    B --> C[Revisió periòdica:<br>diagnòstic per cas]
    C --> D[Casos nous al<br>conjunt de 06-03]
    D --> E[Runner valida el<br>canvi següent]
    E --> A

Aquest bucle és la resposta madura a una pregunta que ronda el curs des de 02-04: "d'on surten els bons casos d'avaluació?". Al principi, de la teva imaginació i de preguntes recopilades; en règim permanent, de les fallades reals de producció. L'observabilitat no és només vigilància: és la pedrera del conjunt d'avaluació.

L'ecosistema d'eines, per categories

Tot l'anterior està construït amb la biblioteca estàndard a propòsit: entendre el mecanisme abans que adoptar la plataforma (la mateixa filosofia del bucle agèntic a mà de 05-03). En un sistema en creixement, avalua per categories:

  • Plataformes d'observabilitat específiques de LLM (comercials i open source): capturen automàticament traces de crides/agents amb prompts, tokens i costos; ofereixen visualització de converses, avaluacions integrades i anotació de datasets. Aporten molt de 06-03 + 06-04 empaquetat; a canvi, els teus prompts i dades passen per una altra plataforma més — l'anàlisi de 06-02 també els aplica.
  • Observabilitat generalista + OpenTelemetry: l'estàndard obert de traces/mètriques/logs del món cloud. Existeixen convencions semàntiques per a IA generativa, de manera que les crides al LLM apareixen com a spans al mateix sistema on ja observes la resta de la teva plataforma. Atractiu si la teva organització ja opera aquest stack: DocuBot deixa de ser una illa.
  • Agregadors de logs clàssics: si ja en tens un, els teus JSON Lines hi entren tal qual; els panells i alertes d'aquesta lliçó es munten al damunt sense res específic d'IA.

Criteri d'elecció honest: el valor diferencial de les plataformes LLM és a la visualització de traces d'agents i a integrar avaluació i anotació; si els teus logs estructurats ja responen a les teves preguntes, no corris a afegir infraestructura. L'important — què registrar, què no, què mirar i què fer-hi — és el que has dissenyat en aquesta lliçó, i és portable a qualsevol eina.

Errors Comuns i Consells

  • Loguejar-ho tot "per si de cas". Prompts complets i converses en cru són cost, soroll i un problema de privadesa (06-02). Referències i mesures, no continguts; i retenció definida.
  • Observabilitat de software clàssic sense senyals de LLM. L'uptime i els errors HTTP no veuen al·lucinacions, degradació de confiança ni buits de documentació. Les mètriques específiques (frase anti-al·lucinació, confiança, confirmacions rebutjades) són les que detecten les fallades silencioses.
  • Logs sense versions. Si cada línia no porta prompt_version/chunking_version/model, no podràs respondre a l'única pregunta que importa després d'un desplegament: "això va començar amb el canvi?".
  • Mirar la latència mitjana. La mitjana amaga la cua; l'usuari del p95 és el que abandona. Percentils sempre (ja els calculaves amb mesurar_crida() a 03-04).
  • Alertes sense acció associada. Cada alerta ha de néixer amb la seva fila de la taula símptoma→causa→acció. Si en disparar-se ningú no sap què fer, no és una alerta: és soroll programat.
  • Recollir feedback i no explotar-lo. El % de polzes en un panell és la part petita; el valor és convertir els 👎 en casos del conjunt de 06-03. Feedback sense cicle és una bústia de suggeriments sense fons.
  • Confondre monitorització amb avaluació. Els panells et diuen que alguna cosa ha empitjorat; el runner de 06-03 et diu si el teu arranjament ho corregeix sense trencar una altra cosa. Són les dues meitats del mateix múscul: producció alimenta el conjunt; el conjunt protegeix producció.

Exercicis

Exercici 1: diagnosticar amb els panells

És dilluns. El panell de DocuBot mostra, respecte a la setmana passada: taxa de frase_sense_info estable (11%), confiança mitjana estable, cost diari +40%, latència p95 +35%, TTFT estable, taxa de cache exacta caiguda del 30% al 8%, volum de peticions +5%. Divendres no es va desplegar cap versió nova. Quina és la teva hipòtesi principal, quins camps dels logs la confirmarien i què miraries primer?

Exercici 2: ampliar el log de peticions

Afegeix a log_peticio la informació del human-in-the-loop: un camp confirmacio que valgui null si la petició no va proposar accions, "acceptada" o "rebutjada" si en va proposar. Escriu a més la consulta conceptual (en pseudocodi o Python sobre les línies JSON) que calcula la taxa setmanal de rebuig, i explica amb quina alerta de la taula connecta.

Exercici 3: del polze avall al cas d'avaluació

Un usuari vota 👎 en una resposta sobre la categoria permisos amb el comentari "em va dir que els convidats poden editar tasques, i no és veritat". El log mostra: confianca: 0.82, dos chunks recuperats amb similituds 0.58 i 0.47, frase_sense_info: false. Descriu el diagnòstic pas a pas (què miraries i en quin ordre) i redacta el cas d'avaluació resultant per al conjunt de 06-03.

Solucions

Exercici 1:

La peça clau és la caiguda de la cache exacta (30% → 8%) amb volum gairebé pla i sense desplegament: cada petició que abans sortia gratis de CacheRespostes ara va al model — això explica simultàniament el cost (+40%) i el p95 (+35%: les respostes en cache eren instantànies i abaixaven el percentil), amb TTFT estable (el proveïdor està bé; simplement hi ha més crides reals). Hipòtesi principal: ha canviat el patró de les preguntes — preguntes noves que no són a la cache. Per què en dilluns? Un candidat típic: Nubelia va llançar alguna cosa el cap de setmana i arriben preguntes inèdites. Confirmació als logs: distribució de cache (miss disparat), volum per categoria (ha crescut alguna categoria?), i mostreig de les preguntes noves (redactades). Nota fina: frase_sense_info estable suggereix que la wiki sí que cobreix els temes nous — si a més pugés, la hipòtesi del llançament sense documentar guanyaria força. Primera acció: mirar la distribució de cache per categoria; si és un tema nou legítim, el cost extra és demanda real (i la cache es reescalfarà sola en qüestió de dies).

Exercici 2:

A respondre, en registrar:

log_peticio(
    # ... camps anteriors ...
    confirmacio=(None if not propostes_accio
                 else "acceptada" if propostes_accio.acceptada
                 else "rebutjada"),
)

Consulta sobre els JSON Lines:

import json

def taxa_rebuig(ruta_log: str) -> float:
    amb_proposta = rebutjades = 0
    with open(ruta_log, encoding="utf-8") as f:
        for linia in f:
            e = json.loads(linia)
            if e.get("esdeveniment") == "peticio" and e.get("confirmacio") is not None:
                amb_proposta += 1
                if e["confirmacio"] == "rebutjada":
                    rebutjades += 1
    return rebutjades / amb_proposta if amb_proposta else 0.0

Detall important: el denominador són les peticions amb proposta (confirmacio is not None), no totes — per això el camp distingeix null dels altres dos valors. Connecta amb l'alerta "taxa de confirmacions rebutjades 5% → 30%": rebuig alt = l'agent proposa malament (prompt/descripcions d'eina degradats) o, en el pitjor cas, contingut hostil empenyent accions — cosa que remet a les traces per pas i a les defenses de 06-01.

Exercici 3:

Diagnòstic ordenat: (1) Amb id_peticio, recuperar la traça completa i els ids dels chunks (0.58 i 0.47 — el segon frega el LLINDAR_RELLEVANCIA=0.45: recuperació mediocre). (2) Llegir els chunks pel seu id: n'hi ha cap que afirmi que els convidats poden editar tasques? Dues branques: si cap chunk no ho diu → resposta infidel (al·lucinació amb confiança 0.82: el perfil perillós), problema de generació; si un chunk desactualitzat ho diu → el problema és de contingut/ingesta, no del model — corregir el document i reingerir (04-03). (3) Segons la branca: branca infidelitat → cas per al runner amb jutge de fidelitat; branca document → arranjament editorial + verificació. Cas d'avaluació (branca infidelitat):

{
    "id": "prod-perm-014",
    "origen": "feedback_produccio",        # la pedrera nova
    "tipus": "ambigu",
    "categoria": "permisos",
    "pregunta": "Poden els usuaris convidats editar tasques d'un projecte?",
    "fonts_esperades": ["doc_permisos_roles"],
    "criteri_exit": "afirma que els convidats NO poden editar tasques "
                    "(només lectura i comentaris), cita doc_permisos_roles, "
                    "i no atribueix als convidats permisos d'edició",
}

Amb això, la propera variació de prompt o chunking es valida també contra la fallada real: el cicle de millora contínua, tancat.

Conclusió

Les traces sembrades a 05-02 han germinat en un sistema nerviós complet: cada petició deixa una línia JSON amb la seva identitat pseudonimitzada (la lliçó de 06-02 aplicada als mateixos logs), les seves versions de prompt/chunking/model (sense elles cap anàlisi post-desplegament no és possible), els seus chunks i similituds, les seves eines i confirmacions, els seus tokens, cost i percentils de latència, i els senyals de qualitat que el sistema ja emetia gratis — la confiança del contracte i la frase anti-al·lucinació, la taxa de la qual resulta ser el millor termòmetre dels buits de la documentació. Damunt dels logs, vuit mètriques amb amo i una taula d'alertes que no criden "alguna cosa va malament" sinó "això és el que probablement passa i això és el primer que has de mirar". I el tancament del cercle: els polzes avall d'usuaris reals es converteixen, via id_peticio, en casos nous del conjunt de 06-03 — producció alimenta l'avaluació, l'avaluació protegeix producció. Amb això, el casc està complet: DocuBot resisteix la manipulació (06-01), respecta les dades (06-02), s'avalua abans de canviar (06-03) i es vigila mentre opera (06-04). Només queda una cosa, i és la més satisfactòria: ajuntar totes les peces construïdes al llarg de sis mòduls, mirar l'arquitectura completa d'una vegada, recórrer una petició real de punta a punta i passar la checklist final de producció. La propera lliçó és el projecte final — DocuBot, sencer.

© Copyright 2026. Tots els drets reservats