Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

2
respostas

[Projeto] Faça como eu fiz: construindo um sistema especialista

Variação: Sistema Dinâmico e Interativo (Chatbot Especialista)

Sistemas reais não recebem todos os fatos de uma vez. Muitas vezes, eles leem as regras e perguntam ao usuário os sintomas faltantes para tentar validar uma hipótese.

O que muda?
Se o sistema esbarrar em uma regra onde falta uma informação, ele pausa e pergunta ao paciente (via input) se ele tem aquele sintoma específico.

class SistemaEspecialistaInterativo:
    def __init__(self, base_conhecimento):
        self.base = base_conhecimento
        self.perguntas_feitas = set() # Evita fazer a mesma pergunta duas vezes

    def inferir_interativamente(self):
        print("=== INICIANDO TRIAGEM MÉDICA ===\n")
        novos_fatos = True
        
        while novos_fatos:
            novos_fatos = False
            
            for condicoes, conclusao in self.base.regras:
                # Se o diagnóstico já foi feito, pula a regra
                if conclusao in self.base.fatos:
                    continue
                
                condicoes_atendidas = True
                
                for condicao in condicoes:
                    if condicao not in self.base.fatos:
                        # Se não sabemos desse fato e ainda não perguntamos, perguntamos agora!
                        if condicao not in self.perguntas_feitas and "infecção" not in condicao: 
                            # O 'infecção' é checado para ele não perguntar diagnósticos intermediários
                            resposta = input(f"O paciente apresenta '{condicao}'? (S/N): ").strip().upper()
                            self.perguntas_feitas.add(condicao)
                            
                            if resposta == 'S':
                                self.base.fatos.append(condicao)
                            else:
                                condicoes_atendidas = False
                                break # Falhou nesta regra, vai para a próxima
                        else:
                            condicoes_atendidas = False
                            break
                            
                # Se passou por todas as condições (sendo S ou já estando na base)
                if condicoes_atendidas:
                    print(f"\n[!] DIAGNÓSTICO INFERIDO: {conclusao.upper()} [!]\n")
                    self.base.fatos.append(conclusao)
                    novos_fatos = True

# --- TESTANDO A VARIAÇÃO 2 ---
# Usando a mesma BaseDeConhecimento original do seu exemplo
base_v2 = BaseDeConhecimento() # Supondo que a classe original está importada
base_v2.adicionar_regra(["febre alta", "tosse"], "infecção respiratória")
base_v2.adicionar_regra(["infecção respiratória", "dificuldade para respirar"], "pneumonia")

sistema_v2 = SistemaEspecialistaInterativo(base_v2)
# Ao rodar, ele perguntará: "O paciente apresenta 'febre alta'? (S/N):"
# sistema_v2.inferir_interativamente()
2 respostas

Olá, Carlos. Tudo bem com você?

A ideia de transformar a solução em um sistema dinâmico e interativo aproxima bastante o exercício de situações encontradas em aplicações reais. Em vez de depender de todos os fatos previamente cadastrados, o sistema coleta novas informações durante a inferência, tornando o processo mais flexível e permitindo que o diagnóstico seja construído conforme as respostas do usuário.

A utilização do conjunto perguntas_feitas evita perguntas repetidas e contribui para uma melhor experiência durante a interação. Como sugestão de evolução, você poderia validar as respostas recebidas pelo input, aceitando apenas S ou N. Dessa forma, caso o usuário digite outro valor, o sistema pode solicitar uma nova resposta antes de continuar. Outra possibilidade seria armazenar as perguntas e respostas em um histórico, permitindo explicar posteriormente quais evidências levaram ao diagnóstico. Por exemplo, ao inferir pneumonia, o sistema poderia informar que essa conclusão foi obtida porque foram confirmados os sintomas de febre alta, tosse e dificuldade para respirar.

Na sua opinião, como esse sistema poderia ser adaptado para trabalhar com níveis de confiança nas respostas, em vez de utilizar apenas respostas binárias?

Parabéns por explorar uma solução além da proposta inicial e por compartilhar sua implementação. Continue contribuindo com suas ideias. O fórum está à disposição para acompanhar seu aprendizado.

Alura Conte com o apoio da comunidade Alura na sua jornada. Abraços e bons estudos!

Boa tarde Mike, tudo bem?

Após algumas pesquisas voltei ao projeto e descobri que entraria numa lógica tipo fuzzy e de fatores de certeza e concluí que um modelo híbrido resolveria o problema:

Com mudanças na coleta e uma nova estrutura de base cheguei a essa nova lógica:

class SistemaEspecialistaConfianca:
    def __init__(self, base_conhecimento, limiar_aceitacao=0.4):
        self.base = base_conhecimento
        self.perguntas_feitas = set()
        # limiar_aceitacao: Diagnósticos com confiança abaixo de 40% são descartados
        self.limiar_aceitacao = limiar_aceitacao 

    def fazer_pergunta_com_validacao(self, condicao):
        """Garante que o usuário digite um valor válido entre 0 e 10."""
        while True:
            try:
                resposta = input(f"De 0 a 10, qual a intensidade do sintoma '{condicao}'? ")
                valor = float(resposta)
                if 0 <= valor <= 10:
                    return valor / 10.0  # Converte para uma escala de 0.0 a 1.0
                else:
                    print("Erro: O valor deve estar entre 0 e 10.\n")
            except ValueError:
                print("Erro: Por favor, digite apenas números.\n")

    def inferir_com_confianca(self):
        print("=== INICIANDO TRIAGEM COM NÍVEIS DE CONFIANÇA ===\n")
        novos_fatos = True
        
        while novos_fatos:
            novos_fatos = False
            
            for condicoes, conclusao in self.base.regras:
                if conclusao in self.base.fatos:
                    continue
                
                condicoes_atendidas = True
                confiancas_temporarias = []
                
                for condicao in condicoes:
                    if condicao not in self.base.fatos:
                        if condicao not in self.perguntas_feitas and "infecção" not in condicao:
                            # 1. Faz a pergunta usando o método com validação!
                            nivel_confianca = self.fazer_pergunta_com_validacao(condicao)
                            self.perguntas_feitas.add(condicao)
                            
                            # Só adiciona o fato se a confiança for maior que zero
                            if nivel_confianca > 0:
                                self.base.fatos[condicao] = nivel_confianca
                                confiancas_temporarias.append(nivel_confianca)
                            else:
                                condicoes_atendidas = False
                                break
                        else:
                            condicoes_atendidas = False
                            break
                    else:
                        confiancas_temporarias.append(self.base.fatos[condicao])
                        
                # 2. Se todas as condições existem, calcula a confiança do diagnóstico
                if condicoes_atendidas:
                    # Regra do E (AND): pega o menor valor de confiança
                    confianca_final = min(confiancas_temporarias)
                    
                    if confianca_final >= self.limiar_aceitacao:
                        print(f"\n[!] DIAGNÓSTICO INFERIDO: {conclusao.upper()} (Confiança: {confianca_final*100:.1f}%) [!]\n")
                        self.base.fatos[conclusao] = confianca_final
                        novos_fatos = True

E adicionando um histórico de confiança, mais um agente que checa o resultado chegamos a um moleto mais preciso.

O que acontece quando roda o código?

O Machine Learning diz: "Historicamente, com esses sintomas aqui no hospital, costuma ser Infecção Bacteriana (88%)."
O Agente RAG diz: "Espere, os artigos que saíram ontem dizem que essa combinação é sintoma de uma Nova Variante Viral (92%)."
O if/elif entra em ação, detecta a divergência e emite o nosso ⚠️ STATUS: ALERTA DE DIVERGÊNCIA.

O sistema exige que o médico peça o Hemograma (para testar a bactéria) E o Painel Viral (para testar o vírus), protegendo o paciente.

Ao unir regras (que garantem que o sistema siga protocolos estritos), dados históricos (que trazem a realidade local) e um agente de literatura (que traz a ciência global), cria-se um assistente médico de alto nível.

Com as regras e um agente de checagem essa abordagem traz os benefícios:

  1. Prevenção do viés de dados, em caso de um surto no hospital o modelo vai ficar confiante de que tudo se trata de doença X, com o agente médico atua como um freio de emergência, mostrar ambas as visões (dados de amostragem com os dados da literatura médica), impede que o médico caia no viés da máquina.

  2. Escalabilidade.

  3. Responsabilidade Ética e legal.

Essa arquitetura resolveria o problema com o "Código do Sistema Híbrido com Alerta de Empate (continua na próxima resposta)":