Knowledge Graphs Probabilísticos: Modelando Incerteza como Distribuições
A maioria dos grafos de conhecimento que você encontra por aí funciona com fatos absolutos: "Paris é capital da França" é verdadeiro ou falso, ponto final. Mas o mundo real não funciona assim. Informações são incertas, fontes discordam, e o que era verdade ontem pode não ser hoje. Se você está construindo um sistema que aprende de múltiplas fontes ao longo do tempo, precisa de um grafo que aceita incerteza como cidadã de primeira classe.
A abordagem que adotei é tratar cada crença como uma distribuição de probabilidade sobre múltiplas hipóteses. Se o sistema recebe informações conflitantes sobre algo, ele não escolhe uma e descarta a outra. Ele mantém ambas com probabilidades diferentes e atualiza bayesianamente conforme novas evidências chegam. O resultado é um grafo que sabe o que sabe, sabe o que não sabe, e quantifica exatamente quão incerto está sobre cada crença.
Guia de tópicos:
- Fatos Absolutos vs Distribuições de Probabilidade
- Atualização Bayesiana: Como Evidências Mudam Crenças
- Entropia como Métrica de Incerteza
- Decay Temporal: Crenças que Enfraquecem
- Normalização e Limites de Segurança
- Exemplo Completo em Python
- Considerações Finais
Fatos Absolutos vs Distribuições de Probabilidade
Em um grafo tradicional, a tripla (Brasil, capital, Brasília) é um fato. Existe ou não existe. Se você recebe informação dizendo que a capital é Rio de Janeiro, ou substitui o fato anterior (perdendo informação), ou ignora (perdendo evidência), ou cria um conflito que precisa ser resolvido manualmente.
Com distribuições, a tripla (Brasil, capital, ?) é: {Brasília: 0.75, Rio de Janeiro: 0.20, São Paulo: 0.05}. A "resposta" é Brasília (dominante), mas o sistema sabe que existe incerteza. Se uma nova fonte confirma Brasília, a probabilidade sobe para 0.85 e as outras caem proporcionalmente. Se uma fonte diz Rio de Janeiro, a distribuição se reequilibra.
A distinção é sutil mas importante. Não é "Brasília com 75% de certeza". É "75% de chance de ser Brasília, 20% de ser Rio, 5% de ser São Paulo". Isso permite raciocinar sobre alternativas, não apenas sobre o dominante. Permite perguntar "quais são as alternativas?" e "quão incerto estou?".
Atualização Bayesiana: Como Evidências Mudam Crenças
Quando nova evidência chega favorecendo uma hipótese, a atualização segue o teorema de Bayes simplificado. Para cada hipótese existente, calcula-se: probabilidade posterior ∝ verossimilhança × probabilidade anterior. Depois normaliza para somar 1.
Na prática: se a distribuição atual é {Brasília: 0.7, Rio: 0.3} e chega evidência favorecendo Brasília com likelihood 0.9, o cálculo é: P(Brasília) = 0.9 × 0.7 = 0.63, P(Rio) = 0.1 × 0.3 = 0.03. Normalizando: Brasília ≈ 0.95, Rio ≈ 0.05. A evidência forte concentrou a distribuição rapidamente.
Se a evidência fosse fraca (likelihood 0.55), o efeito seria menor. Isso é o comportamento correto: evidências fortes mudam muito, evidências fracas mudam pouco. E múltiplas evidências fracas na mesma direção eventualmente convergem tanto quanto uma evidência forte. É o acúmulo bayesiano funcionando como deveria.
Entropia como Métrica de Incerteza
A entropia de Shannon quantifica quão "espalhada" está a distribuição. Fórmula: H = -Σ p(x) × log2(p(x)). Se uma hipótese tem 100%, entropia é 0 (certeza total). Se duas hipóteses têm 50% cada, entropia é 1 (máxima incerteza para 2 opções). Se 8 hipóteses têm 12.5% cada, entropia é 3.
Uso entropia para duas coisas: decidir quando o sistema de curiosidade deve investigar (entropia > 0.7 = vale pesquisar), e como métrica de maturidade do mundo (média das entropias de todas as crenças). Um mundo com entropia média baixa é maduro e confiante. Um mundo com entropia média alta tem muitas incertezas e precisa de mais informação.
Decay Temporal: Crenças que Enfraquecem
Crenças que não são reforçadas decaem lentamente com o tempo. O decay é exponencial com taxa base muito pequena (1e-5), atenuada pelo número de reforços. Uma crença confirmada 10 vezes decai muito mais devagar que uma mencionada uma única vez.
Na prática, o decay redistribui probabilidade: a hipótese dominante perde um pouco, e esse "resíduo" é espalhado entre as alternativas. Com o tempo, uma crença não reforçada volta a ter entropia alta, sinalizando que precisa ser re-verificada. É como memória humana: o que você não revisita, esquece gradualmente.
Normalização e Limites de Segurança
Duas salvaguardas mantêm o sistema estável. Primeiro, probabilidades nunca vão abaixo de 0.02. Isso evita que hipóteses sejam completamente eliminadas por uma única evidência contrária. Sempre resta um resíduo que permite recuperação se evidência futura contradizer.
Segundo, a likelihood de entrada é clampada entre 0.01 e 0.99. Nenhuma evidência pode gerar certeza absoluta ou impossibilidade absoluta. Isso é epistemologicamente saudável: na prática, quase nada é 100% certo. Manter dúvida residual permite que o sistema se corrija no futuro.
Terceiro, o número máximo de hipóteses por crença é 8. Quando uma nova chega e o limite é atingido, a mais fraca é removida. Isso mantém o custo de armazenamento e computação constante por crença.
Exemplo Completo em Python
import numpy as np
class HypothesisDistribution:
"""Bayesian probability distribution over competing hypotheses."""
MAX_HYPS = 8
MIN_PROB = 0.02
def __init__(self):
self.hyps: dict[str, float] = {}
def update(self, obj: str, likelihood: float) -> str:
"""Bayesian update with new evidence favoring 'obj'."""
likelihood = float(np.clip(likelihood, 0.01, 0.99))
# Add new hypothesis if not seen before
if obj not in self.hyps:
if len(self.hyps) >= self.MAX_HYPS:
weakest = min(self.hyps, key=self.hyps.get)
del self.hyps[weakest]
self.hyps[obj] = max(1.0 - sum(self.hyps.values()), 0.05)
# Ensure at least 2 hypotheses (epistemic humility)
if len(self.hyps) == 1:
self.hyps["_unknown"] = 1.0 - likelihood
# Bayesian update: P(h|e) ∝ P(e|h) * P(h)
def p_evidence_given(h):
return likelihood if h == obj else (1 - likelihood) / max(len(self.hyps) - 1, 1)
unnormalized = {h: p_evidence_given(h) * p for h, p in self.hyps.items()}
total = sum(unnormalized.values())
self.hyps = {h: v/total for h, v in unnormalized.items() if v/total >= self.MIN_PROB}
# Renormalize after filtering
t = sum(self.hyps.values())
self.hyps = {h: p/t for h, p in self.hyps.items()}
best, conf = self.dominant()
return f"→ {best} (p={conf:.3f}, H={self.entropy():.3f})"
def dominant(self) -> tuple[str, float]:
if not self.hyps:
return ("unknown", 0.0)
best = max(self.hyps, key=self.hyps.get)
return best, self.hyps[best]
def entropy(self) -> float:
probs = np.array(list(self.hyps.values()))
probs = probs[probs > 0]
return float(-np.sum(probs * np.log2(probs + 1e-12)))
def __repr__(self):
items = sorted(self.hyps.items(), key=lambda x: -x[1])
return " | ".join(f"{h}:{p:.3f}" for h, p in items)
# Demo: watch entropy decrease as evidence accumulates
print("=== Accumulating evidence about Brazil's capital ===\n")
dist = HypothesisDistribution()
evidences = [
("brasília", 0.6, "Wikipedia says Brasília"),
("rio de janeiro", 0.5, "Old textbook says Rio"),
("brasília", 0.8, "Government site confirms Brasília"),
("brasília", 0.75, "Another source says Brasília"),
]
for obj, lk, source in evidences:
result = dist.update(obj, lk)
print(f" Evidence: {source} (lk={lk})")
print(f" Result: {result}")
print(f" Distribution: {dist}\n")
print(f"Final: dominant={dist.dominant()}, entropy={dist.entropy():.3f}")
Considerações Finais
Modelar conhecimento com distribuições de probabilidade em vez de fatos absolutos é mais trabalho de implementação, mas produz um sistema fundamentalmente mais honesto e robusto. Ele nunca está "errado de forma irrecuperável": qualquer crença pode ser corrigida com evidência suficiente. Ele nunca está "certo demais": sempre mantém um resíduo de dúvida que permite correção futura.
O custo computacional é mínimo: cada distribuição tem no máximo 8 hipóteses, e a atualização bayesiana é uma multiplicação seguida de normalização. O benefício é um sistema que lida com incerteza de forma madura em vez de fingir que tudo é binário.
Links indicativos:
- Bayesian Networks: https://en.wikipedia.org/wiki/Bayesian_network
- Probabilistic Knowledge Graphs: https://arxiv.org/abs/2003.03214
- Shannon Entropy: https://en.wikipedia.org/wiki/Entropy_(information_theory)