Distribuições de Hipóteses: Modelando Incerteza em vez de Respostas Absolutas
A maioria dos sistemas de IA trata conhecimento como binário: sabe ou não sabe, verdadeiro ou falso. Mas pergunte a qualquer especialista "qual a melhor linguagem de programação?" e a resposta será "depende". Não existe uma resposta certa, existem múltiplas hipóteses com probabilidades diferentes dependendo do contexto. Como modelar isso computacionalmente sem perder a nuance?
A estrutura que uso é uma HypothesisDistribution: um conjunto de até 8 hipóteses competindo entre si, cada uma com sua probabilidade, atualizadas bayesianamente conforme evidências chegam. Não é "Python é a melhor linguagem com 70% de certeza". É "60% Python, 25% JavaScript, 15% Go para backend". A distribuição inteira é a resposta, não apenas o dominante.
Guia de tópicos:
- Por Que Múltiplas Hipóteses em vez de Uma Resposta
- A Estrutura: Max 8 Hipóteses Competindo
- O Papel do "Desconhecido"
- Atualização Bayesiana Simplificada
- Limite de Hipóteses e Evicção
- Exemplo Prático em Python
- Considerações Finais
Por Que Múltiplas Hipóteses em vez de Uma Resposta
Se o sistema recebe "a capital do Brasil é Brasília" de uma fonte e "a capital do Brasil é Rio de Janeiro" de outra (talvez um texto histórico pré-1960), o que fazer? Com fato único, você escolhe um e descarta o outro, perdendo informação. Com distribuição, mantém ambos: {Brasília: 0.7, Rio: 0.3}. A próxima evidência resolve naturalmente.
Isso é especialmente importante para domínios onde não existe resposta única: "melhor framework web", "causa da inflação", "linguagem mais rápida". Manter a distribuição preserva a nuance que um fato binário destruiria. E permite que o sistema responda "existem opiniões divergentes sobre isso" em vez de escolher um lado arbitrariamente.
A Estrutura: Max 8 Hipóteses Competindo
É um dicionário simples: {hipótese: probabilidade}. As probabilidades sempre somam 1.0 (normalização obrigatória). O dominante é a hipótese com maior probabilidade. A entropia mede quão "espalhada" está a distribuição.
O limite de 8 hipóteses é um trade-off entre expressividade e eficiência. Na prática, raramente uma crença tem mais de 4-5 alternativas relevantes. O limite evita que distribuições cresçam indefinidamente com hipóteses de probabilidade ínfima que nunca serão relevantes.
O Papel do "Desconhecido"
Quando a primeira evidência chega para um par (sujeito, verbo) novo, o sistema automaticamente cria uma hipótese "desconhecido" com probabilidade complementar. Se a evidência diz (Brasil, capital, Brasília) com likelihood 0.8, a distribuição fica {Brasília: 0.8, desconhecido: 0.2}.
Isso é epistemologicamente importante: uma única fonte não deveria gerar certeza absoluta. O "desconhecido" representa "talvez exista outra resposta que eu ainda não vi". Conforme mais evidências confirmam, o desconhecido vai para quase zero. Mas nunca chega a zero absoluto (MIN_PROB = 0.02), mantendo sempre uma porta aberta para correção futura.
Atualização Bayesiana Simplificada
Quando nova evidência chega: para cada hipótese, multiplica probabilidade anterior pela verossimilhança da evidência dado aquela hipótese. A hipótese favorecida recebe likelihood alto, as outras recebem (1 - likelihood) / (n - 1). Depois normaliza.
O efeito: evidência forte (likelihood 0.9) concentra rapidamente. Evidência fraca (0.55) muda pouco. Múltiplas fracas na mesma direção convergem tanto quanto uma forte. É acúmulo bayesiano natural.
Limite de Hipóteses e Evicção
Quando uma nova hipótese chega e o limite de 8 é atingido, a mais fraca é removida. Sua probabilidade é redistribuída na normalização. Isso é aceitável porque hipóteses com probabilidade < 0.02 já são praticamente irrelevantes para qualquer decisão.
Probabilidades nunca vão abaixo de 0.02 (MIN_PROB) e likelihood de entrada é clampada entre 0.01 e 0.99. Nenhuma evidência gera certeza absoluta. Isso permite correção futura: mesmo uma crença com 0.98 pode ser revertida com evidência contrária suficiente.
Exemplo Prático em Python
import numpy as np
class HypothesisDistribution:
"""Distribution over competing hypotheses with Bayesian updates."""
MAX_HYPS = 8
MIN_PROB = 0.02
def __init__(self):
self.hyps: dict[str, float] = {}
def update(self, obj: str, likelihood: float) -> str:
"""Update with evidence favoring 'obj'. Returns status string."""
likelihood = float(np.clip(likelihood, 0.01, 0.99))
# Add hypothesis if new
if obj not in self.hyps:
if len(self.hyps) >= self.MAX_HYPS:
# Evict weakest
weakest = min(self.hyps, key=self.hyps.get)
del self.hyps[weakest]
self.hyps[obj] = max(1.0 - sum(self.hyps.values()), 0.05)
# Epistemic humility: single evidence shouldn't mean certainty
if len(self.hyps) == 1:
self.hyps["_unknown"] = 1.0 - likelihood
# Bayesian update
def p_ev(h):
return likelihood if h == obj else (1-likelihood)/max(len(self.hyps)-1, 1)
unnorm = {h: p_ev(h) * p for h, p in self.hyps.items()}
total = sum(unnorm.values())
self.hyps = {h: v/total for h, v in unnorm.items() if v/total >= self.MIN_PROB}
# Renormalize
t = sum(self.hyps.values())
self.hyps = {h: p/t for h, p in self.hyps.items()}
dom, conf = self.dominant()
return f"dominant='{dom}' 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 show(self):
for h, p in sorted(self.hyps.items(), key=lambda x: -x[1]):
bar = "█" * int(p * 40)
print(f" {h:20s} {bar} {p:.3f}")
# Demo: competing hypotheses converging
print("=== Best backend language (subjective, multiple valid answers) ===\n")
dist = HypothesisDistribution()
opinions = [
("python", 0.6, "Dev 1 prefers Python"),
("go", 0.7, "Dev 2 strongly prefers Go"),
("python", 0.65, "Dev 3 also likes Python"),
("javascript", 0.5, "Dev 4 suggests Node.js"),
("python", 0.7, "Dev 5 confirms Python"),
("go", 0.6, "Dev 6 likes Go too"),
]
for obj, lk, source in opinions:
result = dist.update(obj, lk)
print(f" {source} → {result}")
dist.show()
print()
print(f"Final: {dist.dominant()}")
print(f"The distribution preserves the nuance: Python leads but Go is a strong alternative.")
Considerações Finais
Modelar conhecimento com distribuições de hipóteses em vez de fatos absolutos é mais trabalho, mas produz um sistema fundamentalmente mais honesto. Ele nunca está "errado de forma irrecuperável" (qualquer crença pode ser corrigida). Ele nunca está "certo demais" (sempre mantém dúvida residual). E ele preserva nuance em vez de forçar respostas binárias.
O padrão é aplicável a qualquer sistema que lida com informação incerta: recomendação, diagnóstico, classificação. Em vez de forçar uma resposta, mantenha a distribuição e deixe a evidência convergir naturalmente.
Links indicativos:
- Bayesian Updating: https://en.wikipedia.org/wiki/Bayesian_inference
- Probability Distributions: https://en.wikipedia.org/wiki/Probability_distribution
- Epistemic Uncertainty: https://en.wikipedia.org/wiki/Uncertainty_quantification