Pergunte a uma equipe de IA de onde veio determinado documento de treinamento e a resposta costuma ser o nome de um dataset, não uma fonte. Reguladores, clientes e tribunais agora querem a segunda resposta: qual página, obtida quando, sob quais termos, e o que foi feito com ela antes do treinamento. Para equipes que constroem modelos a partir de dados da web, a proveniência deixou de ser boa prática e passou a ser algo que é preciso comprovar.
A parte difícil é o momento certo. Quase tudo que um registro de proveniência precisa existe apenas no momento da coleta. Este guia aborda por que a questão se tornou urgente, o registro que vale a pena manter para cada documento, e como carregá-lo durante a extração, a filtragem e a deduplicação sem perder o fio da meada.
Por que a proveniência se tornou uma exigência
Três desenvolvimentos transformaram a proveniência de um tema de pesquisa em uma tarefa de conformidade.
O AI Act da UE pede um resumo público. O Artigo 53(1)(d) exige que fornecedores de modelos de IA de propósito geral publiquem “um resumo suficientemente detalhado sobre o conteúdo usado para treinamento”, usando um modelo fornecido pelo AI Office. As obrigações se aplicam a partir de 2 de agosto de 2025, e modelos já no mercado antes dessa data têm até 2 de agosto de 2027. A Comissão apresentou o modelo em julho de 2025 e declara que seu uso é obrigatório.
O modelo pede especificidades. Para dados obtidos por scraping, ele pede os nomes dos crawlers usados, o período de coleta, e uma lista dos nomes de domínio mais relevantes: os 10% principais de todos os domínios pelo tamanho do conteúdo obtido por scraping, ou, para pequenas e médias empresas, os 5% principais ou 1.000 domínios, o que for menor. Também pede que os fornecedores descrevam como respeitaram as reservas de mineração de texto e dados “antes e durante a coleta de dados”. O Artigo 53(1)(c) exige separadamente uma política de direitos autorais que identifique e cumpra essas reservas.
Os recursos comuns estão encolhendo, e os registros eram ruins. A Data Provenance Initiative auditou mais de 1.800 datasets de texto em 2023 e encontrou taxas de omissão de licença acima de 70% e taxas de erro acima de 50% em sites de hospedagem amplamente usados. Uma auditoria de acompanhamento de 14.000 domínios web descobriu que, em um único ano, cerca de 5% de todos os tokens do C4, e 28% de suas fontes mais ativamente mantidas, tinham se tornado totalmente restritos por robots.txt. Um dataset que era aceitável quando coletado pode não ser aceitável de coletar hoje, e só é possível mostrar a diferença se o estado foi registrado no momento.
O que registrar para cada documento
Um registro de proveniência é escrito uma única vez, pelo crawler, no momento da coleta. Tudo que vem depois acrescenta a ele em vez de substituí-lo.
| Campo | Por que importa |
|---|---|
| URL de origem | A base da lista de domínios e de qualquer solicitação de remoção |
| Horário de coleta (UTC) | Comprova o período de coleta e o estado do opt-out naquela data |
| Status da resposta | Separa conteúdo real de páginas de bloqueio e erros |
| Hash do corpo bruto | Vincula toda cópia posterior exatamente ao que foi recebido |
| Ponto de observação | A mesma URL pode servir conteúdo diferente por país e rede |
| Decisão do robots.txt | Mostra que o crawler respeitou as regras vigentes no momento da coleta |
| Reserva de TDM observada | O opt-out com o qual as regras de direitos autorais da UE e o modelo se preocupam |
| Licença ou termos declarados | O que a página dizia sobre reuso, se é que dizia algo |
| Nome e versão do crawler | O modelo pede nomes de crawlers; as versões explicam mudanças de comportamento |
| Registros de origem | Vincula uma cópia limpa ou deduplicada de volta à sua fonte |
Dois campos costumam ser esquecidos. O primeiro é o ponto de observação: uma página observada a partir de um país ou rede pode diferir da mesma URL vista em outro lugar, o que é o argumento do nosso artigo sobre registrar de onde os dados da web foram observados. O segundo é o corpo bruto em si. Um hash comprova quais bytes foram recebidos, mas manter a resposta, por exemplo arquivando páginas em arquivos WARC, permite demonstrá-lo.
Um registro de proveniência em código
O exemplo abaixo escreve um registro por documento coletado, mantém apenas os documentos que estavam permitidos e não reservados no momento da coleta, e vincula cada cópia extraída de volta à sua fonte por hash. Ele também produz o ranking de domínios que o modelo de resumo pede. Funciona em Python 3.9 e posterior, apenas com a biblioteca padrão.
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)
Output:
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
A página reservada, a página bloqueada e a página não permitida pelo robots.txt continuam todas no manifesto. Isso importa: o registro do que você escolheu não usar faz parte da prova. O modelo classifica os domínios pelo tamanho do conteúdo coletado, então, em produção, conte bytes ou tokens em vez de documentos.
Carregando a proveniência pelo pipeline
Um registro escrito no momento da coleta só é útil se cada etapa posterior mantiver o vínculo.
- Extração. O texto usado no treinamento não é o HTML coletado. Dê ao texto extraído seu próprio hash e vincule-o ao registro bruto, como
derived()faz acima. - Filtragem. Registre por que um documento foi descartado, além de registrar que foi descartado. “Abaixo do limiar de qualidade” e “reserva de TDM” são respostas diferentes para um regulador.
- Deduplicação. Quando quase duplicatas são mescladas, mantenha a lista de cada fonte que a cópia sobrevivente representa. Caso contrário, uma solicitação de remoção para uma URL não consegue encontrar o documento em que ela acabou.
- Mistura e amostragem. Registre qual versão do manifesto cada execução de treinamento usou, para que o resumo descreva os dados que um modelo realmente viu.
- Remoção. Mantenha uma lista de exclusão indexada por URL e hash. Quando um site mais tarde reserva seus direitos ou um detentor de direitos pede remoção, as mesmas chaves encontram o documento em todo dataset derivado.
O estado do opt-out merece atenção especial. Um arquivo robots.txt ou uma reserva de mineração de texto e dados pode mudar depois da coleta, em qualquer direção. Registre a decisão tomada no momento da coleta, e verifique novamente antes de cada nova coleta em vez de presumir que a resposta do ano passado ainda vale.
Padrões que vale a pena adotar
Não é preciso inventar um esquema do zero.
- Datasheets for Datasets (Gebru et al., Communications of the ACM, 2021) propõe que todo dataset documente sua motivação, composição, processo de coleta e usos recomendados. É o formato certo para o resumo no nível do dataset.
- Os Data Provenance Standards da Data & Trusted AI Alliance definem 22 campos de metadados em três grupos (origem, proveniência e uso), incluindo o intervalo de datas da geração dos dados, o método, a licença de uso e onde o consentimento está documentado. A versão 1.0.0 foi lançada em julho de 2024.
- C2PA Content Credentials anexam um manifesto de proveniência assinado a um ativo de mídia individual. São mais úteis para imagens, áudio e vídeo, onde o próprio ativo pode carregar seu registro.
Onde a proveniência costuma falhar
- Ela é adicionada depois do fato. Uma coleta sem registros por documento não pode ser auditada posteriormente, por melhor que seja a ficha do dataset.
- A licença é copiada da ficha do dataset. A auditoria mencionada acima constatou que é aí que os erros se concentram. Registre o que a fonte dizia, e trate rótulos agregados como afirmações a verificar.
- Páginas de bloqueio são contadas como conteúdo. Uma resposta 200 ainda pode ser uma página de desafio. Códigos de status e verificações de conteúdo pertencem ao registro.
- O ponto de observação é desconhecido. Coletar cada mercado a partir de uma conexão residencial local só ajuda a proveniência se o registro indicar qual país e qual rede cada coleta usou.
Conclusão
A proveniência é barata de registrar no momento da coleta e quase impossível de recuperar depois. Escreva um registro por documento no momento da coleta, carregue o hash por toda transformação, mantenha o que foi excluído tanto quanto o que foi mantido, e o resumo que o AI Act pede se torna uma consulta em vez de uma investigação.
Fontes e referências
- Regulamento (UE) 2024/1689 (AI Act), Artigos 53, 111 e 113: eur-lex.europa.eu
- Comissão Europeia, aviso explicativo e modelo para o resumo público do conteúdo de treinamento (julho de 2025): digital-strategy.ec.europa.eu
- Diretiva (UE) 2019/790, Artigo 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
- C2PA Specification: spec.c2pa.org