Phase 05 - Lesson 25
Vinculação e Desambiguação de Entidades
O NER encontrou "Paris". A vinculação de entidades decide: Paris, França? Paris Hilton? Paris, Texas? Paris (o príncipe troiano)? Sem a vinculação, seu grafo de conhecimento permanece ambíguo.
Tipo: Build Linguagens: Python Pré-requisitos: Fase 5 · 06 (NER), Fase 5 · 24 (Resolução de Correferência) Tempo: ~60 minutos
O Problema
Uma frase diz: "Jordan beat the press." Seu NER marca "Jordan" como PERSON. Ótimo. Mas qual Jordan?
- Michael Jordan (basquete)?
- Michael B. Jordan (ator)?
- Michael I. Jordan (professor de ML em Berkeley — sim, essa confusão é real em artigos de ML)?
- Jordan (o país)?
- Jordan (nome próprio hebraico)?
A vinculação de entidades (EL) resolve cada menção para uma entrada única em uma base de conhecimento: Wikidata, Wikipedia, DBpedia ou sua KB de domínio. Duas subtarefas:
- Geração de candidatos. Dado "Jordan", quais entradas da KB são plausíveis?
- Desambiguação. Dado o contexto, qual candidato é o correto?
Ambas as etapas são aprendíveis. Ambas têm benchmarks. O pipeline combinado tem se mantido estável por uma década — o que muda é a qualidade do desambiguador.
O Conceito
Geração de candidatos. Dada a forma de superfície da menção ("Jordan"), busque candidatos em um índice de aliases. Os dicionários de aliases da Wikipedia cobrem a maioria das entidades nomeadas: "JFK" → John F. Kennedy, Jacqueline Kennedy, aeroporto JFK, JFK (filme). Um índice típico retorna de 10 a 30 candidatos por menção.
Desambiguação: três abordagens.
- Prior + contexto (Milne & Witten, 2008).
P(entity | mention) × context-similarity(entity, text). Funciona bem, é rápido, não exige treinamento. - Baseada em embeddings (ESS / REL / Blink). Codifique a menção + contexto. Codifique a descrição de cada candidato. Escolha o cosseno máximo. O padrão de 2020 a 2024.
- Generativa (GENRE, 2021; baseada em LLM, 2023+). Decodifica o nome canônico da entidade token a token. Restrita a uma trie de nomes de entidade válidos, de modo que a saída tem garantia de ser um id de KB válido.
Ponta a ponta vs pipeline. Modelos modernos (ELQ, BLINK, ExtEnD, GENRE) executam NER + geração de candidatos + desambiguação em uma única passagem. Sistemas em pipeline ainda dominam em produção porque você pode trocar componentes.
As duas medições
- Recall de menção (geração de candidatos). Fração de menções de referência em que a entrada correta da KB aparece na lista de candidatos. É o piso de todo o pipeline.
- Acurácia de desambiguação / F1. Dados os candidatos corretos, com que frequência o top-1 está certo.
Sempre relate ambas. Um sistema com 99% de desambiguação sobre 80% de recall de candidatos é um pipeline de 80%.
Construa
Passo 1: construa um índice de aliases a partir dos redirecionamentos da Wikipedia
alias_to_entities = {
"jordan": ["Q41421 (Michael Jordan)", "Q810 (Jordan, country)", "Q254110 (Michael B. Jordan)"],
"paris": ["Q90 (Paris, France)", "Q663094 (Paris, Texas)", "Q55411 (Paris Hilton)"],
"apple": ["Q312 (Apple Inc.)", "Q89 (apple, fruit)"],
}
Dados de aliases da Wikipedia: ~18M de pares (alias, entidade). Baixe dos dumps do Wikidata. Armazene como índice invertido.
Passo 2: desambiguação baseada em contexto
def disambiguate(mention, context, alias_index, entity_desc):
candidates = alias_index.get(mention.lower(), [])
if not candidates:
return None, 0.0
context_words = set(tokenize(context))
best, best_score = None, -1
for entity_id in candidates:
desc_words = set(tokenize(entity_desc[entity_id]))
union = len(context_words | desc_words)
score = len(context_words & desc_words) / union if union else 0.0
if score > best_score:
best, best_score = entity_id, score
return best, best_score
A sobreposição de Jaccard é um brinquedo. Substitua por similaridade de cosseno sobre embeddings (veja o passo 2 em code/main.py para a versão com transformer).
Passo 3: baseado em embeddings (estilo BLINK)
from sentence_transformers import SentenceTransformer
encoder = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
def embed_mention(text, mention_span):
start, end = mention_span
marked = f"{text[:start]} [MENTION] {text[start:end]} [/MENTION] {text[end:]}"
return encoder.encode([marked], normalize_embeddings=True)[0]
def embed_entity(entity_id, description):
return encoder.encode([f"{entity_id}: {description}"], normalize_embeddings=True)[0]
No momento de indexação, codifique cada entidade da KB uma vez. No momento da consulta, codifique a menção + contexto uma vez, faça o produto escalar contra o pool de candidatos e escolha o máximo.
Passo 4: vinculação generativa de entidades (conceito)
O GENRE decodifica o título da Wikipedia da entidade caractere a caractere. A decodificação restrita (veja a lição 20) garante que apenas títulos válidos possam ser gerados. Integração estreita com uma trie respaldada pela KB. O descendente moderno é o REL-GEN e a EL via prompt de LLM com saída estruturada.
prompt = f"""Text: {text}
Mention: {mention}
List the best Wikipedia title for this mention.
Respond with JSON: {{"title": "..."}}"""
Combinado com uma whitelist (o choice do Outlines), este é o pipeline de EL mais simples de colocar em produção em 2026.
Passo 5: avalie no AIDA-CoNLL
O AIDA-CoNLL é o benchmark padrão de EL: 1.393 artigos da Reuters, 34 mil menções, entidades da Wikipedia. Relate a acurácia in-KB (P@1) e a taxa de detecção de NIL out-of-KB.
Armadilhas
- Tratamento de NIL. Algumas menções não estão na KB (entidades emergentes, pessoas obscuras). Os sistemas precisam prever NIL em vez de chutar a entidade errada. Medido separadamente.
- Erros de fronteira de menção. O NER a montante perde spans parciais ("Bank of America" marcado apenas como "Bank"). O recall da EL cai.
- Viés de popularidade. Sistemas treinados superestimam entidades frequentes. Uma menção a "Michael I. Jordan" em um artigo de ML muitas vezes é vinculada ao Jordan do basquete.
- EL multilíngue. Mapear menções em texto chinês para entidades da Wikipedia em inglês. Requer um codificador multilíngue ou uma etapa de tradução.
- Desatualização da KB. Novas empresas, eventos e pessoas não estão no dump da Wikipedia do ano passado. Pipelines de produção precisam de um ciclo de atualização.
Use
A pilha de 2026:
| Situação | Escolha |
|---|---|
| Inglês de propósito geral + Wikipedia | BLINK ou REL |
| Multilíngue, KB = Wikipedia | mGENRE |
| Amigável a LLM, poucas menções/dia | Faça prompt no Claude/GPT-4 com lista de candidatos + JSON restrito |
| KB específica de domínio (médica, jurídica) | BERT customizado com recuperação ciente da KB + fine-tune em conjunto de domínio no estilo AIDA |
| Latência extremamente baixa | Apenas prior de correspondência exata (baseline Milne-Witten) |
| SOTA de pesquisa | GENRE / ExtEnD / EL generativa por LLM |
Padrão de produção que entra em produção em 2026: NER → correferência → EL em cada menção → colapsar clusters para uma entidade canônica por cluster. Saída: um id de KB por entidade no documento, não um por menção.
Entregue
Salve como outputs/skill-entity-linker.md:
---
name: entity-linker
description: Design an entity linking pipeline — KB, candidate generator, disambiguator, evaluation.
version: 1.0.0
phase: 5
lesson: 25
tags: [nlp, entity-linking, knowledge-graph]
---
Given a use case (domain KB, language, volume, latency budget), output:
1. Knowledge base. Wikidata / Wikipedia / custom KB. Version date. Refresh cadence.
2. Candidate generator. Alias-index, embedding, or hybrid. Target mention recall @ K.
3. Disambiguator. Prior + context, embedding-based, generative, or LLM-prompted.
4. NIL strategy. Threshold on top score, classifier, or explicit NIL candidate.
5. Evaluation. Mention recall @ 30, top-1 accuracy, NIL-detection F1 on held-out set.
Refuse any EL pipeline without a mention-recall baseline (you cannot evaluate a disambiguator without knowing candidate gen surfaced the right entity). Refuse any pipeline using LLM-prompted EL without constrained output to valid KB ids. Flag systems where popularity bias affects minority entities (e.g. name-clashes) without domain fine-tuning.
Exercícios
- Fácil. Implemente o desambiguador prior+contexto em
code/main.pysobre 10 menções ambíguas (Paris, Jordan, Apple). Rotule manualmente a entidade correta. Meça a acurácia. - Médio. Codifique 50 menções ambíguas com um sentence transformer. Faça o embedding da descrição de cada candidato. Compare a desambiguação baseada em embeddings com a sobreposição de contexto via Jaccard.
- Difícil. Construa uma KB de domínio com 1k entidades (por exemplo, funcionários + produtos da sua empresa). Implemente NER + EL ponta a ponta. Meça precisão e recall sobre 100 frases reservadas.
Termos-Chave
| Termo | O que as pessoas dizem | O que realmente significa |
|---|---|---|
| Vinculação de entidades (EL) | Vincular à Wikipedia | Mapear uma menção para uma entrada única da KB. |
| Geração de candidatos | Quem poderia ser? | Retornar uma lista curta de entradas plausíveis da KB para uma menção. |
| Desambiguação | Escolher a correta | Pontuar candidatos usando o contexto e escolher o vencedor. |
| Índice de aliases | A tabela de consulta | Mapear da forma de superfície → entidades candidatas. |
| NIL | Não está na KB | Previsão explícita de que nenhuma entrada da KB corresponde. |
| KB | Base de conhecimento | Wikidata, Wikipedia, DBpedia ou sua KB de domínio. |
| AIDA-CoNLL | O benchmark | 1.393 artigos da Reuters com vínculos de entidade de referência. |
Leituras Adicionais
- Milne, Witten (2008). Learning to Link with Wikipedia — a abordagem fundacional de prior+contexto.
- Wu et al. (2020). Zero-shot Entity Linking with Dense Entity Retrieval (BLINK) — o cavalo de batalha baseado em embeddings.
- De Cao et al. (2021). Autoregressive Entity Retrieval (GENRE) — EL generativa com decodificação restrita.
- Hoffart et al. (2011). Robust Disambiguation of Named Entities in Text (AIDA) — o artigo do benchmark.
- REL: An Entity Linker Standing on the Shoulders of Giants (2020) — a pilha aberta de produção.