Preguntale a un equipo de IA de dónde salió un documento de entrenamiento y la respuesta suele ser el nombre de un dataset, no una fuente. Reguladores, clientes y tribunales quieren ahora la segunda respuesta: qué página, obtenida cuándo, bajo qué términos, y qué se hizo con ella antes de entrenar. Para los equipos que construyen modelos a partir de datos web, la procedencia ha pasado de ser una buena práctica a algo que hay que poder demostrar.
La parte difícil es el momento. La mayor parte de lo que necesita un registro de procedencia solo existe en el momento de la recopilación. Esta guía repasa por qué la cuestión se volvió urgente, qué registro vale la pena mantener para cada documento, y cómo llevarlo a través de la extracción, el filtrado y la deduplicación sin perder el hilo.
Por qué la procedencia se convirtió en un requisito
Tres novedades convirtieron la procedencia de un tema de investigación en una tarea de cumplimiento.
La Ley de IA de la UE pide un resumen público. El artículo 53(1)(d) exige a los proveedores de modelos de IA de propósito general publicar “un resumen suficientemente detallado sobre el contenido utilizado para el entrenamiento”, usando una plantilla de la Oficina de IA. Las obligaciones se aplican desde el 2 de agosto de 2025, y los modelos ya en el mercado antes de esa fecha tienen hasta el 2 de agosto de 2027. La Comisión presentó la plantilla en julio de 2025 y declara que su uso es obligatorio.
La plantilla pide detalles concretos. Para los datos obtenidos mediante scraping, pide los nombres de los crawlers utilizados, el periodo de recopilación, y una lista de los nombres de dominio más relevantes: el 10% superior de todos los dominios según el tamaño del contenido extraído, o para pequeñas y medianas empresas el 5% superior o 1.000 dominios, lo que sea menor. También pide a los proveedores que describan cómo respetaron las exclusiones de minería de textos y datos “antes y durante la recopilación de datos”. El artículo 53(1)(c) exige por separado una política de derechos de autor que identifique y cumpla esas reservas.
El acervo común se está reduciendo, y los registros eran deficientes. La Data Provenance Initiative auditó más de 1.800 datasets de texto en 2023 y encontró tasas de omisión de licencia superiores al 70% y tasas de error superiores al 50% en sitios de alojamiento ampliamente usados. Una auditoría posterior de 14.000 dominios web encontró que, en un solo año, alrededor del 5% de todos los tokens de C4, y el 28% de sus fuentes más activamente mantenidas, se habían vuelto totalmente restringidos por robots.txt. Un dataset que era aceptable cuando se rastreó puede no ser aceptable de rastrear hoy, y solo se puede mostrar la diferencia si se registró el estado en ese momento.
Qué registrar para cada documento
Un registro de procedencia se escribe una vez, por el crawler, en el momento de la obtención. Todo lo que viene después añade a ese registro en lugar de reemplazarlo.
| Campo | Por qué importa |
|---|---|
| URL de origen | La base de la lista de dominios y de cualquier solicitud de retirada |
| Momento de obtención (UTC) | Demuestra el periodo de recopilación y el estado de exclusión en esa fecha |
| Código de estado de respuesta | Separa el contenido real de las páginas de bloqueo y los errores |
| Hash del cuerpo bruto | Vincula cada copia posterior exactamente con lo que se recibió |
| Punto de observación | La misma URL puede servir contenido distinto según el país y la red |
| Decisión de robots.txt | Muestra que el crawler respetó las reglas vigentes en el momento de la obtención |
| Reserva de TDM observada | La exclusión que les importa a las normas de derechos de autor de la UE y a la plantilla |
| Licencia o términos declarados | Lo que la página decía sobre la reutilización, si decía algo |
| Nombre y versión del crawler | La plantilla pide nombres de crawlers; las versiones explican cambios de comportamiento |
| Registros parentales | Enlaza una copia limpiada o deduplicada con su fuente |
Dos campos se pasan por alto con frecuencia. El primero es el punto de observación: una página observada desde un país o red puede diferir de la misma URL vista desde otro lugar, que es el argumento de nuestro artículo sobre registrar desde dónde se observaron los datos web. El segundo es el propio cuerpo bruto. Un hash demuestra qué bytes se recibieron, pero conservar la respuesta, por ejemplo archivando páginas en archivos WARC, permite demostrarlo.
Un registro de procedencia en código
El siguiente ejemplo escribe un registro por cada documento obtenido, conserva solo los documentos que estaban permitidos y no reservados en el momento de la obtención, y enlaza cada copia extraída con su fuente mediante hash. También produce la clasificación de dominios que pide la plantilla de resumen. Funciona en Python 3.9 y versiones posteriores solo con la biblioteca estándar.
from __future__ import annotations
import hashlib
import json
from collections import Counter
from dataclasses import asdict, dataclass, field
from datetime import datetime, timezone
from urllib.parse import urlsplit
def sha256(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
@dataclass
class Provenance:
"""One record per fetched document, written at collection time."""
url: str
fetched_at: str # ISO 8601, UTC
status: int
content_sha256: str # hash of the raw response body
vantage: str # where it was observed from, e.g. "residential:de"
robots_allowed: bool # robots.txt decision for our crawler, at fetch time
tdm_reserved: bool # machine-readable TDM opt-out seen, at fetch time
license: str | None # licence or terms as stated on the page, if any
collector: str # crawler name and version
parents: list[str] = field(default_factory=list) # hashes this record derives from
step: str = "fetch" # fetch, extract, filter, dedup ...
def fetched(url, body, status, vantage, robots_allowed, tdm_reserved, license=None,
collector="corpus-crawler/1.4"):
return Provenance(
url=url,
fetched_at=datetime.now(timezone.utc).isoformat(timespec="seconds"),
status=status,
content_sha256=sha256(body),
vantage=vantage,
robots_allowed=robots_allowed,
tdm_reserved=tdm_reserved,
license=license,
collector=collector,
)
def derived(parent: Provenance, new_body: bytes, step: str) -> Provenance:
"""A transformed copy keeps the source fields and points back at its parent."""
rec = Provenance(**{**asdict(parent), "parents": [parent.content_sha256], "step": step})
rec.content_sha256 = sha256(new_body)
return rec
def eligible(rec: Provenance) -> bool:
"""Only documents that were allowed and not reserved at fetch time go further."""
return rec.status == 200 and rec.robots_allowed and not rec.tdm_reserved
def domain_summary(records, top_share=0.1):
"""Domains by document count, and the top share of them, for a training-data summary."""
counts = Counter(urlsplit(r.url).hostname for r in records)
ranked = [d for d, _ in counts.most_common()]
keep = max(1, round(len(ranked) * top_share))
return counts, ranked[:keep]
if __name__ == "__main__":
raw = [
fetched("https://news.example/a", b"<html>a</html>", 200, "residential:de", True, False),
fetched("https://news.example/b", b"<html>b</html>", 200, "residential:de", True, False),
fetched("https://shop.example/p/1", b"<html>p1</html>", 200, "residential:fr", True, True),
fetched("https://blog.example/x", b"<html>x</html>", 403, "residential:us", True, False),
fetched("https://forum.example/t/9", b"<html>t9</html>", 200, "residential:us", False, False),
]
kept = [r for r in raw if eligible(r)]
texts = [derived(r, r.url.encode() + b" text", "extract") for r in kept]
with open("manifest.jsonl", "w") as f:
for rec in raw + texts:
f.write(json.dumps(asdict(rec)) + "\n")
counts, top = domain_summary(raw)
print(f"fetched {len(raw)}, eligible {len(kept)}, extracted {len(texts)}")
print("domains:", dict(counts))
print("top domains:", top)
child = texts[0]
print("lineage ok:", child.parents == [kept[0].content_sha256], child.step, child.url)
Salida:
fetched 5, eligible 2, extracted 2
domains: {'news.example': 2, 'shop.example': 1, 'blog.example': 1, 'forum.example': 1}
top domains: ['news.example']
lineage ok: True extract https://news.example/a
La página reservada, la página bloqueada y la página no permitida por robots.txt siguen todas en el manifiesto. Eso importa: el registro de lo que se decidió no usar forma parte de la prueba. La plantilla clasifica los dominios por el tamaño del contenido extraído, así que en producción conviene contar bytes o tokens en lugar de documentos.
Llevar la procedencia a través del pipeline
Un registro escrito en el momento de la obtención solo es útil si cada paso posterior mantiene el enlace.
- Extracción. El texto con el que se entrena no es el HTML que se obtuvo. Dale al texto extraído su propio hash y haz que apunte al registro bruto, tal como hace
derived()arriba. - Filtrado. Registra por qué se descartó un documento, además de que se descartó. “Por debajo del umbral de calidad” y “reserva de TDM” son respuestas distintas para un regulador.
- Deduplicación. Cuando se fusionan casi duplicados, conserva la lista de todas las fuentes que representa la copia superviviente. De lo contrario, una solicitud de retirada para una URL no puede encontrar el documento en el que terminó.
- Mezcla y muestreo. Registra qué versión del manifiesto usó cada ejecución de entrenamiento, para que el resumen describa los datos que el modelo realmente vio.
- Eliminación. Mantén una lista de exclusión indexada por URL y hash. Cuando un sitio reserve posteriormente sus derechos o un titular de derechos pida la eliminación, las mismas claves encuentran el documento en cada dataset derivado.
El estado de exclusión merece especial cuidado. Un archivo robots.txt o una reserva de minería de textos y datos puede cambiar después de rastrear, en cualquier dirección. Registra la decisión que tomaste en el momento de la obtención, y vuelve a comprobarla antes de cada nueva recopilación en lugar de asumir que la respuesta del año pasado sigue siendo válida.
Estándares que vale la pena adoptar
No hace falta inventar un esquema desde cero.
- Datasheets for Datasets (Gebru et al., Communications of the ACM, 2021) propone que cada dataset documente su motivación, composición, proceso de recopilación y usos recomendados. Es la forma adecuada para el resumen a nivel de dataset.
- Data Provenance Standards, de la Data & Trusted AI Alliance, define 22 campos de metadatos en tres grupos (fuente, procedencia y uso), incluyendo el rango de fechas de generación de los datos, el método, la licencia de uso y dónde se documenta el consentimiento. La versión 1.0.0 se publicó en julio de 2024.
- C2PA Content Credentials adjunta un manifiesto de procedencia firmado a un activo multimedia individual. Son más útiles para imágenes, audio y vídeo, donde el propio activo puede llevar su registro.
Dónde suele fallar la procedencia
- Se añade a posteriori. Un rastreo sin registros por documento no se puede auditar después, por muy bueno que sea el dataset card.
- La licencia se copia del dataset card. La auditoría mencionada antes encontró que ahí es donde se concentran los errores. Registra lo que decía la fuente, y trata las etiquetas agregadas como afirmaciones que hay que comprobar.
- Las páginas de bloqueo se cuentan como contenido. Una respuesta 200 puede seguir siendo una página de desafío. Los códigos de estado y las comprobaciones de contenido pertenecen al registro.
- El punto de observación es desconocido. Recopilar cada mercado desde una conexión residencial local solo ayuda a la procedencia si el registro indica qué país y qué red usó cada obtención.
La conclusión
La procedencia es barata de escribir en el momento de la recopilación y casi imposible de recuperar después. Escribe un registro por documento en el momento de la obtención, lleva el hash a través de cada transformación, conserva lo que excluiste además de lo que conservaste, y el resumen que pide la Ley de IA se convierte en una consulta en lugar de una investigación.
Fuentes y referencias
- Reglamento (UE) 2024/1689 (Ley de IA), artículos 53, 111 y 113: eur-lex.europa.eu
- Comisión Europea, nota explicativa y plantilla para el resumen público del contenido de entrenamiento (julio de 2025): digital-strategy.ec.europa.eu
- Directiva (UE) 2019/790, artículo 4(3): eur-lex.europa.eu
- Longpre et al., The Data Provenance Initiative (2023): arxiv.org/abs/2310.16787
- Longpre et al., Consent in Crisis: The Rapid Decline of the AI Data Commons (2024): arxiv.org/abs/2407.14933
- Gebru et al., Datasheets for Datasets: doi.org/10.1145/3458723
- Data & Trusted AI Alliance, Data Provenance Standards v1.0.0: dtaalliance.org
- Especificación C2PA: spec.c2pa.org