A la lliçó anterior vam protegir DocuBot dels qui intenten manipular-lo. Aquesta lliçó mira en l'altra direcció: què fa DocuBot amb les dades que li confien. Cada crida a l'API del proveïdor empaqueta el system prompt, l'historial de la conversa, la documentació interna recuperada i dades de projectes, i ho envia als servidors d'un tercer. Per a un desenvolupador això és una crida HTTPS més; per a l'organització és una transferència de dades amb implicacions contractuals i, de vegades, legals. Al mòdul 1 (01-04) vam deixar la privadesa apuntada a alt nivell amb remissió a aquesta lliçó; toca complir la promesa: entendre què surt exactament, minimitzar el que surt, conèixer les garanties contractuals disponibles i situar tot això en el marc de l'RGPD i el Reglament d'IA (AI Act) europeu.

⚠️ Advertència: aquesta lliçó és material formatiu i no constitueix assessorament jurídic. L'aplicació de l'RGPD, del Reglament d'IA o de qualsevol altra norma depèn del cas concret (tipus de dades, finalitat, sector, països implicats). Abans d'implantar en producció un sistema que processi dades personals o tingui implicacions regulatòries, revisa el disseny amb els equips de legal, compliance, protecció de dades (DPO) i seguretat de la teva organització.

Contingut

  1. Què surt de la teva organització a cada crida
  2. El cicle de vida de la dada al proveïdor
  3. Minimització de dades: la funció de redacció de DocuBot
  4. Garanties contractuals i arquitectures alternatives
  5. L'RGPD a alt nivell: el que un desenvolupador ha de saber
  6. El Reglament d'IA (AI Act) europeu i la transparència de DocuBot
  7. Decisions de dades per a DocuBot: la taula viatja / no viatja

Què surt de la teva organització a cada crida

Comencem per fer visible allò invisible. Quan docubot.py::respondre (o bucle_agent) crida l'API, el cos de la petició conté molt més que "la pregunta de l'usuari":

Component del prompt Origen a DocuBot Què pot contenir
System prompt prompts.py (SYSTEM_DOCUBOT_AGENT) Instruccions internes, to, polítiques — propietat intel·lectual, rarament dades personals
Historial de la conversa Conversa / GestorSessions (03-03), fins a 10 torns Tot el que l'usuari hagi escrit: noms, queixes, dades de clients que va enganxar sense pensar
Documentació recuperada rag.py::recuperar → chunks de docs_nubelia Contingut de la wiki interna: procediments, preus interns, de vegades noms d'empleats o clients
Definicions d'eines eines.py::EINES Noms i descripcions de les teves APIs internes (revelen la teva arquitectura)
Resultats d'eines tool_result de consultar_projecte, etc. Dades operatives de projectes: estats, responsables, dates, incidències
La pregunta actual L'usuari Qualsevol cosa

Tres observacions que canvien la perspectiva:

  • El RAG multiplica l'exposició. Abans del mòdul 4, sortia el que l'usuari escrivia. Des del mòdul 4, surt també el que la wiki conté — encara que l'usuari no ho vegi mai, perquè els chunks viatgen al prompt encara que la resposta no els citi.
  • L'historial acumula. Amb el truncament a 10 torns de 03-03, una dada personal esmentada al torn 2 reviatja a cada crida fins que surt de la finestra. Una dada enviada una vegada s'envia moltes vegades.
  • Les eines obren una tercera porta. consultar_projecte treu dades de l'API interna de Nubelia i les posa rumb al proveïdor sense que ningú les hagi escrit al xat.

La disciplina bàsica és poder respondre en tot moment a la pregunta: "si imprimeixo el prompt complet d'aquesta crida, què hi ha aquí que no hauria de sortir de Nubelia?". Un exercici sa és literalment aquest — bolcar el prompt final a consola en un entorn de desenvolupament i llegir-lo amb ulls d'auditor.

El cicle de vida de la dada al proveïdor

Que una dada "surti" no és un esdeveniment binari; importa què passa després. Les preguntes la resposta de les quals és als termes de servei i acords del teu proveïdor (llegir-los, no assumir-los — canvien entre proveïdors, entre plans del mateix proveïdor i amb el temps):

  • Retenció: quant de temps conserva el proveïdor els prompts i les respostes? Existeix una opció de retenció zero o reduïda? La retenció és diferent per a les peticions marcades pels seus filtres d'abús?
  • Ús per a entrenament: fa servir el proveïdor les teves dades per entrenar models? A les APIs de pagament orientades a empresa l'habitual és que no per defecte, a diferència d'alguns productes gratuïts de consum — però és una clàusula que es verifica al contracte, no un rumor que es repeteix.
  • Subencarregats i ubicació: en quina regió es processen i s'emmagatzemen les dades? Quins tercers hi intervenen?
  • Accés humà: en quins supòsits pot el personal del proveïdor llegir els teus prompts (suport, revisió d'abusos)?

Dos hàbits d'enginyeria derivats:

  1. Documenta la resposta a aquestes preguntes per al proveïdor i pla que facis servir, amb data. És el tipus d'evidència que legal i compliance et demanaran, i la base per reavaluar si canvies de proveïdor (el panorama de 01-03).
  2. Tracta els teus propis logs com a part del cicle de vida. De res no serveix que el proveïdor retingui 30 dies si tu guardes els prompts complets indefinidament a les teves traces. Aquest fil — dades personals als logs — el reprenem a 06-04.

Minimització de dades: la funció de redacció de DocuBot

El principi més rendible de tota la lliçó és el de minimització: no enviar allò que no cal per a la tasca. Pregunta guia amb un exemple concret: quan un empleat de suport demana a DocuBot ajuda per redactar la resolució d'un tiquet, necessita el LLM saber el nom del client? Gairebé mai. "El client no pot exportar l'informe" produeix exactament la mateixa resposta que la versió amb nom, email i telèfon — i no exposa ningú.

Quan la dada ve incrustada en text lliure (l'usuari enganxa el tiquet sencer al xat), la minimització s'implementa amb redacció o pseudonimització prèvia a l'enviament. Una versió pedagògica amb expressions regulars:

# redaccio.py
import re

# Cada patró: (nom, regex compilada, marcador de substitució)
PATRONS_PII = [
    ("email",   re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+"),                 "[EMAIL]"),
    ("telefon", re.compile(r"(?:\+?\d{1,3}[ .-]?)?(?:\d[ .-]?){9,12}"), "[TELEFON]"),
    ("iban",    re.compile(r"\b[A-Z]{2}\d{2}(?:[ ]?[\dA-Z]{4}){3,7}\b"), "[IBAN]"),
    ("targeta", re.compile(r"\b(?:\d[ -]?){13,19}\b"),                  "[TARGETA]"),
]

def redactar(text: str) -> tuple[str, dict[str, int]]:
    """Substitueix patrons de dades personals per marcadors.
    Retorna el text redactat i un recompte per tipus (útil per a mètriques)."""
    recompte = {}
    for nom, patro, marcador in PATRONS_PII:
        text, n = patro.subn(marcador, text)
        if n:
            recompte[nom] = n
    return text, recompte

I el seu ús, amb dades fictícies i genèriques:

missatge_usuari = (
    "El client (contacte: [email protected], "
    "tel. 600 000 000) no pot exportar l'informe setmanal del projecte."
)

text_net, recompte = redactar(missatge_usuari)
print(text_net)
# El client (contacte: [EMAIL], tel. [TELEFON]) no pot exportar
# l'informe setmanal del projecte.
print(recompte)   # {'email': 1, 'telefon': 1}

On s'enganxa? A la frontera, abans que res no viatgi: a docubot.py::respondre (i a l'entrada de bucle_agent), com a primer pas sobre el missatge de l'usuari; i opcionalment sobre els tool_result si l'API interna retorna camps sensibles. El recompte no és decoratiu: registrat com a mètrica (sense el contingut), a 06-04 et dirà quantes dades personals intenten esmunyir-se pel xat cada setmana.

Matisos que un professional ha de conèixer:

  • Redacció ≠ pseudonimització. Redactar substitueix per un marcador genèric ([EMAIL]) i és irreversible. Pseudonimitzar substitueix per un identificador consistent ([CLIENT_7]) mantenint una taula de correspondència que no viatja mai; permet que el LLM raoni sobre "el mateix client" en diversos torns i que tu repersonalitzis la resposta en rebre-la. Més útil, més delicada (la taula és en si mateixa una dada a protegir).
  • Les regex tenen sostre. Cacen formats (emails, telèfons, IBANs) però no noms propis ni dades contextuals ("el director financer de l'empresa de Saragossa que ens va trucar ahir"). Per a això existeixen els sistemes NER (reconeixement d'entitats anomenades) i biblioteques especialitzades de detecció de PII; l'arquitectura és la mateixa — un filtre a la frontera — amb un detector millor.
  • La minimització també aplica al RAG: la millor redacció és la que no cal. Si la wiki de Nubelia no hauria de contenir dades de clients, el moment de comprovar-ho és la ingesta de 04-03 — el mateix ganxo on 06-01 va posar el detector de patrons sospitosos pot executar redactar() o encuar per a revisió.

Garanties contractuals i arquitectures alternatives

La minimització redueix el que surt; les garanties governen el que surt de totes maneres. De menys a més control:

Opció Què aporta Cost/contrapartida
API estàndard + DPA (Data Processing Agreement / acord d'encàrrec de tractament) Marc contractual: el proveïdor actua com a encarregat, amb obligacions de seguretat, confidencialitat i subencarregats declarats És el mínim exigible si viatgen dades personals; revisa que estigui signat, no només publicat
Residència de dades / regió UE El processament i/o l'emmagatzematge passa a la regió triada; simplifica l'anàlisi de transferències internacionals No tots els proveïdors/models ho ofereixen; de vegades amb latència o catàleg reduït
Plans enterprise / via cloud (els grans proveïdors cloud ofereixen els mateixos models sota els seus propis marcs contractuals) Retenció configurable, compromisos reforçats, integració amb el paraigua contractual cloud que l'empresa ja té signat Cost i complexitat de contractació
Autoallotjament de models oberts (panorama de 01-03) Les dades no surten de la teva infraestructura: la conversa d'aquesta lliçó gairebé desapareix Cost de GPUs i operació, models generalment menys capaços, i la seguretat passa a ser 100% problema teu

La decisió no és global sinó per flux de dades: DocuBot pot fer servir l'API comercial per a preguntes generals sobre documentació pública i exigir regió UE (o redacció agressiva) per al flux que toca tiquets amb dades de clients. L'arquitectura modular del curs (el client encapsulat a client.py, amb client i MODEL com a punts únics de configuració) és el que fa aquesta decisió barata d'implementar.

L'RGPD a alt nivell: el que un desenvolupador ha de saber

L'RGPD (Reglament General de Protecció de Dades, GDPR en la sigla anglesa) aplica quan es tracten dades personals: qualsevol informació sobre una persona física identificada o identificable. Nota important: els noms i emails corporatius ("[email protected]") també són dades personals — l'RGPD no distingeix entre "dades d'empresa" i "dades de consumidor". El que és generalment acceptat que un desenvolupador de DocuBot ha de tenir al radar:

  • Rols: Nubelia decideix les finalitats i els mitjans del tractament → és responsable; el proveïdor del LLM tracta les dades per compte de Nubelia → típicament encarregat (d'aquí el DPA de la secció anterior).
  • Base de legitimació: tot tractament necessita una base legal (consentiment, execució de contracte, interès legítim...). Quina correspon a un assistent intern concret és una decisió del DPO/legal, no del desenvolupador — la teva feina és poder explicar amb precisió quines dades es tracten, per a què i per on passen. Els diagrames de flux de dades que estàs construint en aquesta lliçó són exactament l'insum que legal necessita.
  • Minimització i limitació de finalitat són principis literals del reglament — la secció de redacció no era només bona pràctica d'enginyeria.
  • Drets dels interessats (accés, rectificació, supressió...): si els prompts amb dades personals acaben als teus logs i traces, aquests logs entren al perímetre d'un exercici de drets ("esborreu el que teniu sobre mi"). Dissenyar els logs amb pseudonimització i retenció definida (06-04) és el que fa aquests drets exercitables sense arqueologia.
  • Transferències internacionals: enviar dades personals a servidors fora de l'EEE requereix garanties adequades (d'aquí el valor pràctic de la residència UE).
  • Avaluacions d'impacte (DPIA): per a tractaments de risc alt pot ser obligatòria una avaluació formal prèvia. Si el teu assistent ha de tractar categories especials de dades (salut, per exemple), frena i consulta abans d'escriure codi.

Insistim: això és un mapa per conversar amb els experts, no la conversa sencera.

El Reglament d'IA (AI Act) europeu i la transparència de DocuBot

El Reglament d'IA (AI Act, el Reglament Europeu d'Intel·ligència Artificial) regula els sistemes d'IA amb un enfocament basat en el risc: obligacions proporcionals a la categoria del sistema.

Categoria Idea general Exemples típics citats per la norma
Risc inacceptable Prohibits Manipulació subliminal danyosa, social scoring generalitzat
Alt risc Requisits estrictes (gestió de riscos, documentació, supervisió humana, registre) IA en selecció de personal, crèdit, infraestructures crítiques, certs usos en educació/sanitat/justícia
Risc limitat Obligacions de transparència Chatbots i assistents conversacionals
Risc mínim Sense obligacions específiques Filtres de spam, IA en videojocs

Un assistent intern de documentació com DocuBot encaixa en principi al terreny de les obligacions de transparència — però la classificació concreta depèn del cas i de l'ús real, i decidir-la correspon a legal/compliance, no a aquesta lliçó: el mateix motor, aplicat a decidir sobre persones (contractacions, avaluacions), canviaria de casella. A més, els proveïdors dels models de propòsit general tenen les seves pròpies obligacions sota la norma, diferents de les teves com a integrador.

El que sí que és accionable ja per a DocuBot, i barat:

  • L'usuari ha de saber que parla amb una IA. Res de disfressar DocuBot de company humà: la interfície l'identifica com a assistent automàtic.
  • Honestedat sobre els límits: la frase anti-al·lucinació del curs — "No trobo aquesta informació a la documentació disponible." — i el camp confianca del contracte JSON són, a més de qualitat, transparència: el sistema comunica la seva incertesa en lloc d'aparentar omnisciència.
  • Supervisió humana on hi ha acció: el human-in-the-loop de crear_amb_confirmacio() (05-02) és exactament el patró de supervisió que la regulació afavoreix. Les bones pràctiques d'enginyeria i les expectatives regulatòries apunten en la mateixa direcció — no és casualitat.
# A la interfície de DocuBot: transparència com a requisit, no com a ornament
MISSATGE_BENVINGUDA = (
    "Hola, soc DocuBot, l'assistent automàtic de documentació de Nubelia. "
    "Soc un sistema d'IA: puc equivocar-me i les meves respostes poden requerir "
    "verificació. Indico sempre les fonts en què em baso."
)

Decisions de dades per a DocuBot: la taula viatja / no viatja

La síntesi operativa de la lliçó és un inventari de fluxos amb una decisió explícita per dada. Aquesta taula (adaptada al teu cas) és també un lliurable excel·lent per a la conversa amb el DPO:

Dada Viatja al proveïdor? Com Justificació
Pregunta de l'usuari Sí, redactada redactar() a la frontera de respondre Necessària per a la tasca; les dades personals incrustades, no
Historial (10 torns) Sí, redactat a l'origen Es redacta en entrar a Conversa, així no reviatja mai sense netejar L'historial reenvia cada dada moltes vegades
System prompt Sí, tal qual prompts.py Sense dades personals per disseny; es revisa a cada canvi de PROMPT_VERSION
Chunks de la wiki Sí, tal qual rag.py La wiki no ha de contenir dades de clients; es verifica a la ingesta (04-03)
Nom/email de l'empleat que pregunta No S'identifica la sessió amb un pseudònim (GestorSessions); la identitat real no entra al prompt El LLM no necessita saber qui pregunta
Dades de contacte de clients en tiquets No (viatja el text redactat) redactar() + pseudonimització si cal consistència El LLM no necessita el nom per redactar la resolució
Resultats de consultar_projecte Sí, filtrats L'eina retorna només els camps necessaris (estat, fites), no la fitxa completa Minimització aplicada al disseny de l'eina
Claus d'API, secrets Mai Variables d'entorn, mai en prompts ni en codi Sense excepcions
Logs i traces propis No viatgen al proveïdor, però són tractament Pseudonimitzats i amb retenció definida Es desenvolupa a 06-04

Fixa't en el patró de les files "No": gairebé mai la solució no és un filtre heroic d'última hora, sinó dissenyar el flux perquè la dada no arribi ni a acostar-se al prompt (l'eina retorna menys camps; la sessió fa servir pseudònims). La millor redacció és la que no té res a redactar.

Errors Comuns i Consells

  • Creure que "només surt la pregunta de l'usuari". Surt el prompt complet: system, historial, chunks del RAG, definicions i resultats d'eines. Fes l'exercici de bolcar un prompt real (de desenvolupament) i llegir-lo sencer.
  • Assumir els termes del proveïdor en lloc de llegir-los. "Segur que no entrenen amb les meves dades" no és una política de privadesa. Llegeix-los per al teu pla concret, documenta la resposta amb data, i revisa-la quan canviïs de proveïdor o de pla.
  • Redactar l'entrada i oblidar les altres portes. L'historial (que reenvia dades antigues), els tool_result i els chunks del RAG són vies d'entrada tan reals com el missatge de l'usuari. Redacta a l'origen, no només a la porta principal.
  • Confondre redacció amb anonimització. Un text amb [EMAIL] pot continuar identificant una persona pel context ("la directora de l'oficina de Conca"). La redacció per patrons redueix el risc; no l'elimina, i rarament converteix les dades en anònimes en sentit estricte (per això el terme prudent és pseudonimització).
  • Tractar el compliment com un sprint final. La minimització afecta el disseny d'eines, sessions i logs; retroencaixar-la és molt més car que dissenyar-la. I a la inversa: no deixis que la paràlisi regulatòria ho bloquegi tot — la major part d'aquesta lliçó (minimitzar, redactar, DPA, transparència) és l'abc acceptat a la indústria.
  • Jugar a fer d'advocat. El teu lliurable com a desenvolupador és un sistema minimitzador i un mapa precís de fluxos de dades; la base de legitimació, la classificació sota el Reglament d'IA i la DPIA són decisions de legal/DPO. Arriba a aquesta reunió amb la taula viatja/no-viatja feta i seràs el seu desenvolupador favorit.

Exercicis

Exercici 1: auditoria d'un prompt

Un empleat de suport manté aquesta conversa amb DocuBot (dades fictícies):

Torn 1: "El client Exemple SL (CIF fictici, contacte: [email protected]) diu que li hem cobrat dues vegades la quota de març." Torn 2: "Em pots dir com es tramita un abonament?"

Al torn 2, DocuBot fa servir RAG (recupera 3 chunks de la wiki de facturació) i respon. Enumera tot el que viatja al proveïdor a la crida del torn 2, assenyala quins elements contenen dades que la minimització hauria d'haver tractat, i explica per què el problema del torn 1 continua present al torn 2.

Exercici 2: ampliar la redacció amb pseudonimització consistent

Modifica redaccio.py perquè els emails no se substitueixin tots per [EMAIL], sinó per pseudònims consistents ([EMAIL_1], [EMAIL_2]...) dins d'un mateix text: el mateix email rep sempre el mateix marcador, emails diferents reben marcadors diferents. Retorna també la taula de correspondència (que no viatjaria mai al proveïdor).

Exercici 3: classificar fluxos de dades

Per a cada dada nova, decideix (com a la taula viatja/no-viatja) si hauria de viatjar, no viatjar o viatjar redactada, i justifica-ho: (a) el nom del projecte intern ("Atlas") en una pregunta sobre el seu estat; (b) el salari d'un empleat esmentat en un tiquet de la categoria facturacio; (c) l'identificador de sessió que GestorSessions fa servir per agrupar la conversa.

Solucions

Exercici 1:

Viatja al torn 2: (1) el system prompt complet (SYSTEM_DOCUBOT_EINES o el que apliqui); (2) l'historial: el torn 1 íntegre — amb el nom de l'empresa client, el CIF i l'email — més la resposta prèvia de l'assistent, perquè Conversa reenvia els últims 10 torns; (3) la pregunta del torn 2; (4) els 3 chunks de la wiki de facturació; (5) si opera com a agent, les definicions d'eines.

S'hauria d'haver tractat: les dades del client del torn 1 (nom, CIF, email → redacció/pseudonimització). El punt clau és el tercer: encara que el torn 2 sigui innocent, el torn 1 reviatja dins de l'historial a cada crida fins que surt de la finestra de 10 torns. Per això la redacció s'ha d'aplicar quan el missatge entra a la conversa (a l'origen), no només a l'últim missatge: una dada que va entrar sense redactar contamina totes les crides següents.

Exercici 2:

import re

EMAIL_RE = re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+")

def pseudonimitzar_emails(text: str) -> tuple[str, dict[str, str]]:
    """Substitueix cada email per un marcador consistent [EMAIL_n].
    Retorna el text i la taula de correspondència (privada: NO viatja)."""
    taula: dict[str, str] = {}

    def _substitucio(match: re.Match) -> str:
        email = match.group(0)
        if email not in taula:
            taula[email] = f"[EMAIL_{len(taula) + 1}]"
        return taula[email]

    return EMAIL_RE.sub(_substitucio, text), taula

text = ("Escriuen [email protected] i [email protected]; "
        "responeu a [email protected] amb còpia al segon.")
net, taula = pseudonimitzar_emails(text)
print(net)
# Escriuen [EMAIL_1] i [EMAIL_2]; responeu a [EMAIL_1] amb còpia al segon.

Com funciona: re.sub accepta una funció de reemplaçament; la funció consulta/omple taula, de manera que el mateix email sempre obté el mateix marcador. Així el LLM pot raonar "responeu a [EMAIL_1]" amb coherència, i el teu codi pot repersonalitzar la resposta invertint la taula — que es queda a la teva infraestructura, perquè és en si mateixa una dada personal a protegir.

Exercici 3:

  • (a) Viatja tal qual. "Atlas" és un identificador intern de projecte, no una dada personal; sense ell, ni el RAG ni consultar_projecte poden funcionar. Risc residual: confidencialitat empresarial (no privadesa), coberta pel DPA.
  • (b) No viatja. És una dada personal de categoria sensible a la pràctica (informació econòmica d'una persona identificable) i el LLM no la necessita per tramitar res: es redacta ([IMPORT] o eliminació del passatge) abans de l'enviament, i la seva presència en un tiquet hauria de disparar, a més, una revisió del procés (per què hi ha salaris en tiquets de suport?).
  • (c) No viatja (i no li cal). L'identificador de sessió és fontaneria del teu costat: GestorSessions el fa servir per recuperar l'historial, però el prompt no té per què contenir-lo. Si algun dia calgués correlacionar (p. ex. per depurar amb el proveïdor), viatjaria un identificador pseudònim i opac, mai un que reveli la identitat de l'empleat — i aquesta correlació reapareix, ben feta, als logs de 06-04.

Conclusió

DocuBot ja té les dues cares del casc: la 06-01 el protegeix de qui el vol manipular; aquesta lliçó protegeix els altres del que DocuBot podria explicar. Les idees que s'han de quedar amb tu: a cada crida viatja el prompt complet — system, historial que reenvia el passat, chunks del RAG, dades d'eines —, no "la pregunta"; el cicle de vida de la dada al proveïdor (retenció, entrenament, regió) es llegeix als termes i es documenta, no s'assumeix; la minimització és la palanca del desenvolupador — la funció redactar() a la frontera, eines que retornen només els camps necessaris, sessions pseudònimes — i la millor redacció és la de la dada que mai no es va acostar al prompt; els DPA, la residència UE i l'autoallotjament són l'escala de garanties quan la dada viatja de totes maneres; i el marc normatiu (RGPD i Reglament d'IA, sense jugar a fer d'advocats) premia exactament el que el curs ja practicava: transparència que es parla amb una IA, honestedat sobre la incertesa i supervisió humana a les accions. Queda una pregunta incòmoda que ni la seguretat ni la privadesa no responen: tot això està molt bé, però DocuBot funciona? Com saps que el canvi de prompt d'ahir no va trencar vint respostes que abans sortien bé? A 02-04 i 04-05 vam avaluar a mà i vam prometre automatitzar-ho; la propera lliçó salda aquest deute: unit tests per al codi determinista, tests de contracte per a les sortides del model, el runner que executa el conjunt complet — adversarials inclosos — i un LLM fent de jutge calibrat contra el teu patró or.

© Copyright 2026. Tots els drets reservats