Voltar ao blog
12 de maio de 20265 min de leitura

Sistema de Curiosidade Autônoma: IA que Busca o que Não Sabe

pythonaiautomation

A maioria das IAs só fala quando você pergunta. São reativas por natureza: input entra, output sai, fim. Mas e se a IA olhasse para o próprio grafo de conhecimento, percebesse que tem lacunas, formulasse perguntas sobre essas lacunas, pesquisasse na web e integrasse os resultados sozinha? Sem ninguém pedir. Só porque detectou que não sabe algo que deveria saber.

Eu implementei esse comportamento usando entropia como sinal de ignorância. A cada 60 segundos, o sistema varre todas as crenças do grafo procurando distribuições de probabilidade com entropia alta (acima de 0.7). Quando encontra, gera queries de pesquisa inteligentes, busca na web, extrai fatos dos resultados e atualiza o grafo. A entropia cai, o sistema "aprendeu", e na próxima varredura aquela crença não é mais selecionada para investigação. É um loop de feedback que converge naturalmente.

Guia de tópicos:

  • Entropia como Sinal de Ignorância
  • O Ciclo de Curiosidade: A Cada 60 Segundos
  • Gerando Queries que Fazem Sentido
  • Integração de Novos Fatos no Grafo
  • Quando NÃO Ser Curioso
  • Exemplo Prático em Python
  • Considerações Finais

Entropia como Sinal de Ignorância

No sistema, cada crença não é um fato binário. É uma distribuição de probabilidade sobre múltiplas hipóteses. Se o grafo tem (Brasil, capital, ?) com 90% Brasília e 10% Rio de Janeiro, a entropia é baixa: o sistema está confiante. Mas se tem 40% Brasília, 35% Rio e 25% São Paulo, a entropia é alta. O sistema genuinamente não sabe a resposta.

A entropia de Shannon mede exatamente isso: quão "espalhada" está a distribuição. Entropia zero significa certeza absoluta (uma hipótese com 100%). Entropia máxima significa total incerteza (todas as hipóteses com probabilidade igual). O threshold de 0.7 foi calibrado na prática: abaixo disso, o sistema está confiante o suficiente e investigar não traria benefício significativo. Acima, vale gastar recursos para resolver a incerteza.

O Ciclo de Curiosidade: A Cada 60 Segundos

Uma task assíncrona roda em background com intervalo configurável. A cada tick, ela varre todos os mundos de conhecimento, lista todas as crenças, e filtra as que têm entropia acima do threshold. Se encontra alguma, passa para a fase de geração de queries.

O intervalo de 60 segundos é um equilíbrio: frequente o suficiente para manter o conhecimento atualizado, mas não tão frequente que sobrecarregue APIs de busca ou o LLM. Em cenários com muita interação, pode ser reduzido. Em cenários de baixo uso, pode ser aumentado ou até pausado.

O ciclo é resiliente: se uma busca falha, se o LLM não responde, se a extração não encontra nada, o erro é capturado e logado sem derrubar o sistema. Na próxima iteração, a mesma crença incerta será selecionada novamente e terá outra chance.

Gerando Queries que Fazem Sentido

A geração de queries não é trivial. Não adianta jogar "Brasil capital" no Google e esperar resultado útil. A estratégia depende do estado da distribuição:

Se a confiança dominante é baixa (abaixo de 0.4), a query é genérica: "qual a capital do Brasil". O sistema realmente não sabe e precisa de informação básica.

Se a confiança é moderada mas tem alternativas fortes, a query inclui as alternativas para forçar uma comparação: "capital do Brasil Brasília ou Rio de Janeiro". Isso tende a retornar resultados que esclarecem a diferença.

Se a confiança é alta mas a entropia ainda passa o threshold (porque tem uma alternativa persistente), a query busca confirmação: "Brasília capital do Brasil confirmação".

O limite é de 2 queries por ciclo por mundo. Isso evita bombardear a web com dezenas de buscas simultâneas e mantém o custo controlado.

Integração de Novos Fatos no Grafo

Os resultados da busca web passam pelo mesmo pipeline de extração de triplas que as mensagens do usuário: LLM + regex com cross-validation. Os fatos extraídos são aplicados ao grafo do mundo correspondente, atualizando as distribuições bayesianamente.

Se a busca confirma a hipótese dominante com alta confiança, a distribuição se concentra e a entropia cai. Na próxima varredura, essa crença não será mais selecionada. O sistema "aprendeu" e está satisfeito.

Se a busca traz informação contraditória, a entropia pode até subir temporariamente. Isso é esperado e correto: o sistema agora sabe que existe controvérsia real, e pode continuar investigando em ciclos futuros com queries mais específicas.

Quando NÃO Ser Curioso

O sistema tem salvaguardas para não gastar recursos desnecessariamente:

Só investiga crenças com entropia acima do threshold. Não gasta com o que já sabe. Limita a 2 queries por mundo por ciclo. Não sobrecarrega APIs. Só roda se o motor está ativo (para no shutdown). Erros são capturados sem derrubar o sistema.

Conversas puramente sociais (mensagens curtas de small talk) não geram triplas e portanto não criam crenças incertas. O sistema não vai pesquisar "como vai?" na web. A curiosidade só se ativa para conhecimento factual que foi explicitamente armazenado com incerteza.

Exemplo Prático em Python

import numpy as np
import asyncio

def entropy(distribution: dict[str, float]) -> float:
    """Shannon entropy of a probability distribution."""
    probs = np.array(list(distribution.values()))
    probs = probs[probs > 0]
    return float(-np.sum(probs * np.log2(probs + 1e-12)))


def generate_curiosity_queries(beliefs: list[dict], threshold=0.7) -> list[str]:
    """Generate search queries for beliefs with high uncertainty."""
    queries = []
    uncertain = [b for b in beliefs if entropy(b["distribution"]) > threshold]
    uncertain.sort(key=lambda b: -entropy(b["distribution"]))

    for belief in uncertain[:2]:  # max 2 per cycle
        s, v = belief["subject"], belief["verb"]
        dominant = max(belief["distribution"], key=belief["distribution"].get)
        conf = belief["distribution"][dominant]

        if conf < 0.4:
            # Low confidence: generic query
            queries.append(f"{s} {v}")
        else:
            # Moderate confidence with alternatives: comparative query
            alts = [k for k, p in belief["distribution"].items()
                    if k != dominant and p > 0.15]
            if alts:
                queries.append(f"{s} {v} {dominant} ou {alts[0]}")
            else:
                queries.append(f"{s} {v} {dominant}")

    return queries


async def curiosity_cycle(worlds: list, search_fn, extract_fn, threshold=0.7):
    """One cycle of autonomous curiosity."""
    discoveries = []

    for world in worlds:
        queries = generate_curiosity_queries(world["beliefs"], threshold)
        if not queries:
            continue

        for query in queries:
            # Search web
            results = await search_fn(query)
            if not results:
                continue

            # Extract facts from results
            new_facts = extract_fn(results)

            # Update beliefs (simplified bayesian update)
            for fact in new_facts:
                key = (fact["s"], fact["v"])
                for belief in world["beliefs"]:
                    if belief["subject"] == fact["s"] and belief["verb"] == fact["v"]:
                        # Bayesian update would go here
                        discoveries.append(fact)

    return discoveries


# Demo
beliefs = [
    {
        "subject": "plutão", "verb": "classificação",
        "distribution": {"planeta_anão": 0.45, "planeta": 0.40, "outro": 0.15}
    },
    {
        "subject": "brasil", "verb": "capital",
        "distribution": {"brasília": 0.92, "rio": 0.08}
    },
    {
        "subject": "luz", "verb": "velocidade",
        "distribution": {"300000 km/s": 0.50, "150000 km/s": 0.30, "desconhecido": 0.20}
    },
]

print("Belief analysis:")
for b in beliefs:
    h = entropy(b["distribution"])
    status = "🔍 INVESTIGATE" if h > 0.7 else "✓ confident"
    print(f"  ({b['subject']}, {b['verb']}) H={h:.3f} {status}")

queries = generate_curiosity_queries(beliefs)
print(f"\nGenerated queries: {queries}")
# Output:
#   (plutão, classificação) H=1.530 🔍 INVESTIGATE
#   (brasil, capital) H=0.402 ✓ confident
#   (luz, velocidade) H=1.485 🔍 INVESTIGATE
#   Generated queries: ['plutão classificação planeta_anão ou planeta', 'luz velocidade']

Considerações Finais

Curiosidade autônoma transforma uma IA reativa em uma IA proativa. Em vez de só responder quando perguntada, ela ativamente melhora seu próprio conhecimento nos pontos onde tem mais a ganhar. O custo é controlado (poucas queries por ciclo), o benefício é cumulativo (cada ciclo reduz entropia), e o resultado é um sistema que fica mais informado com o tempo mesmo sem interação do usuário.

O princípio por trás é elegante: use entropia como métrica de ignorância, e trate ignorância como motivação para buscar conhecimento. É o mesmo princípio que guia a curiosidade humana, implementado em código com um loop de feedback que converge naturalmente.


Links indicativos: