<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: André Vinicius</title>
    <description>The latest articles on DEV Community by André Vinicius (@theandr3).</description>
    <link>https://dev.to/theandr3</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2275740%2F6adbb1fb-492b-4959-96ef-6231507ab59e.jpg</url>
      <title>DEV Community: André Vinicius</title>
      <link>https://dev.to/theandr3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theandr3"/>
    <language>en</language>
    <item>
      <title>Implementando Redes Neurais e Inteligência Computacional do zero em Python (Perceptron, Adaline, MLP, Kohonen, Fuzzy e Algoritmos Genéticos)</title>
      <dc:creator>André Vinicius</dc:creator>
      <pubDate>Sun, 15 Nov 2026 20:20:41 +0000</pubDate>
      <link>https://dev.to/theandr3/aprendendo-ml-do-zero-1pnp</link>
      <guid>https://dev.to/theandr3/aprendendo-ml-do-zero-1pnp</guid>
      <description>&lt;p&gt;Antes de orquestrar LLMs modernos ou usar frameworks prontos como PyTorch e scikit-learn, implementar os algoritmos clássicos de &lt;strong&gt;Redes Neurais e Inteligência Computacional do zero em Python&lt;/strong&gt; é a melhor forma de entender o que realmente acontece dentro de um modelo: propagação direta (&lt;em&gt;forward pass&lt;/em&gt;), cálculo do gradiente, regra Delta, retropropagação do erro (&lt;em&gt;backpropagation&lt;/em&gt;), mapas auto-organizáveis competitivos e otimização evolutiva.&lt;/p&gt;

&lt;p&gt;Ao longo da graduação em Engenharia da Computação na &lt;strong&gt;UEFS&lt;/strong&gt;, construí uma série de implementações fundamentais sem depender de camadas prontas de alto nível. Neste artigo, resumo a intuição matemática, a arquitetura e os casos práticos de 6 repositórios abertos no meu GitHub.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Perceptron de Rosenblatt e Adaline (&lt;code&gt;perceptron-oil-problem&lt;/code&gt; &amp;amp; &lt;code&gt;adaline_valvulas&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;O &lt;strong&gt;Perceptron&lt;/strong&gt; e o &lt;strong&gt;Adaline (Adaptive Linear Neuron)&lt;/strong&gt; são a base histórica das redes neurais artificiais, mas diferem em um ponto crucial no treinamento:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Perceptron (&lt;a href="https://github.com/TheAndr3/perceptron-oil-problem" rel="noopener noreferrer"&gt;&lt;code&gt;perceptron-oil-problem&lt;/code&gt;&lt;/a&gt;):&lt;/strong&gt; atualiza os pesos &lt;code&gt;w&lt;/code&gt; apenas quando a função degrau (sinal) erra a classe discreta de uma amostra de óleo (&lt;code&gt;y ∈ {-1, +1}&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaline (&lt;a href="https://github.com/TheAndr3/adaline_valvulas" rel="noopener noreferrer"&gt;&lt;code&gt;adaline_valvulas&lt;/code&gt;&lt;/a&gt;):&lt;/strong&gt; aplica a &lt;strong&gt;Regra Delta (LMS — Least Mean Squares)&lt;/strong&gt; sobre a saída linear contínua &lt;code&gt;u = w·x + b&lt;/code&gt; &lt;em&gt;antes&lt;/em&gt; da função de ativação, minimizando o Erro Quadrático Médio (MSE) via descida do gradiente para diagnóstico de acionamento de válvulas:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Δw = η × (d - u) × x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essa diferença sutil — derivar uma superfície quadrática contínua em vez de uma função degrau descontínua — é o que abriu caminho para o treinamento de redes multicamadas.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Multilayer Perceptron (MLP) e Backpropagation (&lt;code&gt;multilayer-perceptron&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Perceptrons de camada única só separam problemas linearmente separáveis. No repositório &lt;strong&gt;&lt;a href="https://github.com/TheAndr3/multilayer-perceptron" rel="noopener noreferrer"&gt;&lt;code&gt;multilayer-perceptron&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, implementei uma rede de múltiplas camadas com retropropagação do erro (&lt;em&gt;backpropagation&lt;/em&gt;) aplicada tanto ao clássico dataset &lt;strong&gt;Iris&lt;/strong&gt; (3 classes) quanto a problemas geométricos não lineares (&lt;code&gt;circulo.txt&lt;/code&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forward pass:&lt;/strong&gt; camadas ocultas com funções de ativação diferenciáveis não lineares (sigmoide / tangente hiperbólica), permitindo compor fronteiras de decisão curvas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backward pass:&lt;/strong&gt; aplicação da regra da cadeia camada a camada, propagando o gradiente local da saída até a primeira camada oculta para atualizar matrizes de pesos e vetores de &lt;em&gt;bias&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Aprendizado Não Supervisionado Competitivo: Mapas de Kohonen (&lt;code&gt;kohonen-iris-plants&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Nem todo problema possui rótulos supervisionados. No repositório &lt;strong&gt;&lt;a href="https://github.com/TheAndr3/kohonen-iris-plants" rel="noopener noreferrer"&gt;&lt;code&gt;kohonen-iris-plants&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, implementei uma &lt;strong&gt;Rede de Kohonen (Self-Organizing Map — SOM)&lt;/strong&gt; para agrupamento topológico das plantas Iris:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Para cada vetor de entrada &lt;code&gt;x&lt;/code&gt; de 4 dimensões, os neurônios da grade competem pela menor distância euclidiana para eleger a &lt;strong&gt;BMU (&lt;em&gt;Best Matching Unit&lt;/em&gt;)&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   c = argmin_i ||x - w_i||
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;A BMU e seus vizinhos topológicos na grade atualizam seus pesos aproximando-se de &lt;code&gt;x&lt;/code&gt;, com taxa de aprendizado e raio de vizinhança decaindo ao longo das épocas.&lt;/li&gt;
&lt;li&gt;O resultado preserva a topologia: amostras similares no espaço de 4 dimensões ficam próximas no mapa bidimensional, sem nunca ter visto o rótulo da espécie durante o treino.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  4. Lógica Fuzzy (&lt;code&gt;controlador_fuzzy&lt;/code&gt;) e Algoritmos Genéticos (&lt;code&gt;Algoritmo-Genetico&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Para completar a caixa de ferramentas de Inteligência Computacional:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sistemas de Inferência Fuzzy (&lt;a href="https://github.com/TheAndr3/controlador_fuzzy" rel="noopener noreferrer"&gt;&lt;code&gt;controlador_fuzzy&lt;/code&gt;&lt;/a&gt;):&lt;/strong&gt; modelam incerteza contínua por funções de pertinência (&lt;em&gt;fuzzificação&lt;/em&gt;), base de regras linguísticas (&lt;code&gt;SE ... ENTÃO ...&lt;/code&gt;) e &lt;em&gt;defuzzificação&lt;/em&gt; (centroide) para controle suave onde regras booleanas rígidas falham.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algoritmos Genéticos (&lt;a href="https://github.com/TheAndr3/Algoritmo-Genetico" rel="noopener noreferrer"&gt;&lt;code&gt;Algoritmo-Genetico&lt;/code&gt;&lt;/a&gt;):&lt;/strong&gt; busca meta-heurística populacional com seleção por aptidão (&lt;em&gt;fitness&lt;/em&gt;), cruzamento (&lt;em&gt;crossover&lt;/em&gt;) e mutação estocástica para escapar de ótimos locais em espaços de busca discretos ou não diferenciáveis.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Por que isso importa na era de LLMs e Sistemas Multi-Agente?
&lt;/h2&gt;

&lt;p&gt;Quando hoje projeto um sistema multi-agente como o &lt;strong&gt;&lt;a href="https://github.com/TheAndr3/comanda" rel="noopener noreferrer"&gt;Comanda&lt;/a&gt;&lt;/strong&gt; (com BM25 + stemmer Snowball em português do zero) ou um motor de recomendação em produção com &lt;strong&gt;LSH Forest e MinHash&lt;/strong&gt;, os fundamentos são os mesmos: espaço vetorial, métricas de distância/similaridade, custo computacional por consulta e avaliação quantitativa rigorosa.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repositórios no GitHub
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MLP:&lt;/strong&gt; &lt;a href="https://github.com/TheAndr3/multilayer-perceptron" rel="noopener noreferrer"&gt;github.com/TheAndr3/multilayer-perceptron&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mapa de Kohonen (SOM):&lt;/strong&gt; &lt;a href="https://github.com/TheAndr3/kohonen-iris-plants" rel="noopener noreferrer"&gt;github.com/TheAndr3/kohonen-iris-plants&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaline:&lt;/strong&gt; &lt;a href="https://github.com/TheAndr3/adaline_valvulas" rel="noopener noreferrer"&gt;github.com/TheAndr3/adaline_valvulas&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perceptron:&lt;/strong&gt; &lt;a href="https://github.com/TheAndr3/perceptron-oil-problem" rel="noopener noreferrer"&gt;github.com/TheAndr3/perceptron-oil-problem&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Controlador Fuzzy:&lt;/strong&gt; &lt;a href="https://github.com/TheAndr3/controlador_fuzzy" rel="noopener noreferrer"&gt;github.com/TheAndr3/controlador_fuzzy&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Algoritmo Genético:&lt;/strong&gt; &lt;a href="https://github.com/TheAndr3/Algoritmo-Genetico" rel="noopener noreferrer"&gt;github.com/TheAndr3/Algoritmo-Genetico&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Sistemas de Recomendação em Produção com LSH Forest, MinHash e Cache LRU Serverless (latência de 200ms)</title>
      <dc:creator>André Vinicius</dc:creator>
      <pubDate>Sun, 15 Nov 2026 20:18:11 +0000</pubDate>
      <link>https://dev.to/theandr3/sistemas-de-recomendacao-em-producao-com-lsh-forest-minhash-e-cache-lru-serverless-latencia-de-1mk1</link>
      <guid>https://dev.to/theandr3/sistemas-de-recomendacao-em-producao-com-lsh-forest-minhash-e-cache-lru-serverless-latencia-de-1mk1</guid>
      <description>&lt;p&gt;Quando falamos de Inteligência Artificial hoje, quase toda a atenção vai para LLMs. Mas em produtos de alto volume — como e-commerce, delivery e plataformas de saúde — &lt;strong&gt;Sistemas de Recomendação Clássicos&lt;/strong&gt; continuam sendo a espinha dorsal da personalização em larga escala.&lt;/p&gt;

&lt;p&gt;Durante 12 meses de pesquisa e extensão na &lt;strong&gt;Universidade Estadual de Feira de Santana (UEFS)&lt;/strong&gt;, sob orientação do Prof. Dr. João Batista da Rocha Junior, projetei e coloquei em produção o módulo de recomendação do &lt;strong&gt;LogicFarma&lt;/strong&gt; (plataforma SaaS da Farmácia Universitária com mais de 4.700 operações registradas, 666 históricos clínicos avaliados e 1.060 medicamentos).&lt;/p&gt;

&lt;p&gt;O desafio de engenharia era claro: &lt;strong&gt;como recomendar procedimentos e consultas personalizadas para centenas de pacientes em tempo real e em disparos em lote (e-mail/WhatsApp), rodando sobre funções Serverless com limites rígidos de memória e tempo de execução?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Neste artigo, compartilho a arquitetura &lt;strong&gt;Memory-First&lt;/strong&gt;, a adaptação do &lt;strong&gt;Locality-Sensitive Hashing (LSH Forest)&lt;/strong&gt; com &lt;strong&gt;MinHash&lt;/strong&gt; e a estratégia de &lt;strong&gt;degradação graciosa em 4 níveis&lt;/strong&gt; que levou a latência de consulta para &lt;strong&gt;~200ms&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. O gargalo da Filtragem Colaborativa tradicional &lt;code&gt;O(N × M)&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Na &lt;strong&gt;Filtragem Colaborativa Baseada no Usuário&lt;/strong&gt;, queremos encontrar pacientes com histórico clínico semelhante ao paciente-alvo e recomendar procedimentos que esses vizinhos realizaram, mas que o paciente ainda não conhece.&lt;/p&gt;

&lt;p&gt;A métrica natural para conjuntos binários (realizou / não realizou um procedimento) é a &lt;strong&gt;Similaridade de Jaccard&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;J(A, B) = |A ∩ B| / |A ∪ B|
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O problema é que comparar um paciente contra todos os outros a cada requisição tem custo linear no número de usuários e itens. Em um endpoint HTTP ou num disparo de mensagens para 300 pacientes de uma vez, calcular Jaccard exato no banco de dados é inviável.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. MinHash + LSH Forest: busca aproximada em tempo sublinear
&lt;/h2&gt;

&lt;p&gt;Baseado nos experimentos de Rocha-Junior et al. (2025) sobre sistemas de recomendação com LSH em e-commerce, substituímos a comparação exata por duas estruturas probabilísticas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;MinHash (&lt;code&gt;l = 200&lt;/code&gt; permutações):&lt;/strong&gt; transforma o conjunto de procedimentos e consultas de cada paciente (de tamanho variável) em uma assinatura compacta de comprimento fixo &lt;code&gt;l = 200&lt;/code&gt;. A probabilidade de duas assinaturas coincidirem em uma posição é exatamente igual à Similaridade de Jaccard entre os conjuntos. Os experimentos mostraram que &lt;code&gt;l = 200&lt;/code&gt; atinge o pico de Precisão Média (15,1%) mantendo Recall próximo de 92%, enquanto &lt;code&gt;l = 250&lt;/code&gt; degrada a relação custo/precisão em RAM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LSH Forest (Bawa et al., WWW 2005):&lt;/strong&gt; em vez do LSH tradicional (que exige calibrar manualmente o número de &lt;em&gt;buckets&lt;/em&gt; e o limiar de similaridade), utilizamos uma floresta de árvores de prefixos auto-ajustável (&lt;code&gt;MinHashLSHForest&lt;/code&gt;), consultando &lt;code&gt;k_build = 80&lt;/code&gt; vizinhos na indexação e &lt;code&gt;k_query = 20&lt;/code&gt; vizinhos em tempo real.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. Adaptação do E-commerce para o Domínio Clínico
&lt;/h2&gt;

&lt;p&gt;No modelo original de e-commerce, as interações possuem pesos graduados (&lt;code&gt;visited = 1&lt;/code&gt;, &lt;code&gt;cart_added = 4&lt;/code&gt;, &lt;code&gt;bought = 8&lt;/code&gt;). No domínio farmacêutico, a interação é estritamente binária (o paciente realizou ou não o procedimento/consulta).&lt;/p&gt;

&lt;p&gt;Fizemos três adaptações de domínio:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unificação de pesos por co-ocorrência:&lt;/strong&gt; cada item é codificado como &lt;code&gt;"Nome|Categoria"&lt;/code&gt; (ex.: &lt;code&gt;"Glicemia|Procedimento"&lt;/code&gt;, &lt;code&gt;"Cefaleia|Consulta"&lt;/code&gt;), e a pontuação dos itens candidatos nos &lt;code&gt;k = 20&lt;/code&gt; vizinhos mais próximos é calculada pela frequência de co-ocorrência entre os vizinhos que possuem o item (excluindo o que o paciente já realizou).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filtro de elegibilidade e outliers:&lt;/strong&gt; apenas perfis com &lt;code&gt;min_items = 2&lt;/code&gt; até &lt;code&gt;max_items = 100&lt;/code&gt; entram no índice LSH Forest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filtro determinístico por restrição clínica de gênero:&lt;/strong&gt; consultas exclusivas ao público feminino (como &lt;code&gt;"Cólica Menstrual"&lt;/code&gt;) são filtradas tanto na saída do LSH quanto na pré-computação do ranking de &lt;em&gt;fallback&lt;/em&gt; masculino (&lt;code&gt;GLOBAL_MASCULINO&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Arquitetura Memory-First com Cache LRU e Batch Inference
&lt;/h2&gt;

&lt;p&gt;Como a aplicação principal rodava em &lt;strong&gt;Next.js / TypeScript&lt;/strong&gt; e a biblioteca de referência acadêmica para LSH (&lt;code&gt;datasketch&lt;/code&gt;) estava em &lt;strong&gt;Python&lt;/strong&gt;, separamos o motor de recomendação em funções Serverless Python integradas ao MongoDB.&lt;/p&gt;

&lt;p&gt;Para evitar ler e desserializar o índice do banco a cada chamada, desenhamos uma arquitetura &lt;strong&gt;Memory-First&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Cron Mensal Python] ---&amp;gt; Constrói LSH Forest (l=200) ---&amp;gt; Serializa blobs no MongoDB
                                                                  |
[Next.js Top Tags]   ---&amp;gt; POST /api/lsh/batch (até 300 pac.) ---&amp;gt; Cache LRU em RAM (50 farmácias)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cold Start (~2 a 3s):&lt;/strong&gt; carrega os &lt;em&gt;pickle blobs&lt;/em&gt; (&lt;code&gt;forestBlob&lt;/code&gt;, &lt;code&gt;minhashesBlob&lt;/code&gt;, &lt;code&gt;fallbacksBlob&lt;/code&gt;, &lt;code&gt;itemsByPatientBlob&lt;/code&gt;) do MongoDB e hidrata o container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warm Start (~0,2 a 0,3s):&lt;/strong&gt; o Cache LRU em RAM responde diretamente da memória da função Serverless, sem tocar no banco.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint em Lote (&lt;code&gt;/api/lsh/batch&lt;/code&gt;):&lt;/strong&gt; quando o farmacêutico dispara comunicados com &lt;strong&gt;Top Tags&lt;/strong&gt; (&lt;code&gt;#Top3ProcedimentosRec&lt;/code&gt;, &lt;code&gt;#Top3ConsultasRec&lt;/code&gt;), o módulo &lt;code&gt;recommendationTagResolver.ts&lt;/code&gt; agrupa até &lt;strong&gt;300 pacientes em uma única chamada HTTP POST&lt;/strong&gt;, carregando o cache da farmácia uma só vez.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Degradação Graciosa em 4 Níveis (Zero Falha no Disparo)
&lt;/h2&gt;

&lt;p&gt;Em um sistema real, o algoritmo de recomendação &lt;strong&gt;nunca pode derrubar o fluxo principal de comunicação&lt;/strong&gt; (seja por &lt;em&gt;cold start&lt;/em&gt; de um paciente novo sem histórico, seja por timeout de rede). Implementamos 4 níveis de degradação:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;LSH Completo (&lt;code&gt;lsh&lt;/code&gt;):&lt;/strong&gt; os 20 vizinhos do LSH Forest preenchem todas as &lt;code&gt;k&lt;/code&gt; sugestões pedidas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LSH Parcial + Suplementação (&lt;code&gt;lsh_partial&lt;/code&gt;):&lt;/strong&gt; quando os vizinhos têm pouca variedade, o sistema completa as vagas faltantes com o &lt;strong&gt;Fallback Global segmentado por gênero&lt;/strong&gt; (&lt;code&gt;GLOBAL_FEMININO&lt;/code&gt; ou &lt;code&gt;GLOBAL_MASCULINO&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback de Cold Start (&lt;code&gt;fallback&lt;/code&gt;):&lt;/strong&gt; paciente recém-cadastrado (sem histórico) recebe imediatamente o ranking global segmentado pré-computado em memória, ou via leitura direta da coleção &lt;code&gt;recomendacoesMensais&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fail-safe de Timeout (30s):&lt;/strong&gt; se a API Python falhar, as Top Tags degradam para string vazia e a mensagem transacional segue normalmente.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Em produção na Farmácia Universitária da UEFS, o indexador processou &lt;strong&gt;666 históricos de pacientes&lt;/strong&gt; em 4 unidades, indexando &lt;strong&gt;353 perfis elegíveis&lt;/strong&gt; e &lt;strong&gt;1.978 registros clínicos&lt;/strong&gt; em menos de 1,7 segundo.&lt;/p&gt;




&lt;h3&gt;
  
  
  Links relacionados
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Código de referência e Model Card no Hugging Face:&lt;/strong&gt; &lt;a href="https://huggingface.co/TheAndr3/lsh-forest-clinical-recommender" rel="noopener noreferrer"&gt;huggingface.co/TheAndr3/lsh-forest-clinical-recommender&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/TheAndr3" rel="noopener noreferrer"&gt;github.com/TheAndr3&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Como construir agentes de atendimento que não alucinam dinheiro: regras em código, guardrails MCP e avaliação τ-bench em português</title>
      <dc:creator>André Vinicius</dc:creator>
      <pubDate>Sun, 15 Nov 2026 19:59:53 +0000</pubDate>
      <link>https://dev.to/theandr3/como-construir-agentes-de-atendimento-que-nao-alucinam-dinheiro-regras-em-codigo-guardrails-mcp-e-42kc</link>
      <guid>https://dev.to/theandr3/como-construir-agentes-de-atendimento-que-nao-alucinam-dinheiro-regras-em-codigo-guardrails-mcp-e-42kc</guid>
      <description>&lt;p&gt;Quando colocamos um LLM para atender clientes de um app de delivery, um chatbot comum resolve o caminho feliz, mas cria dois riscos inaceitáveis para a operação: &lt;strong&gt;conceder reembolso indevido&lt;/strong&gt; sob pressão ou &lt;em&gt;prompt injection&lt;/em&gt;, e &lt;strong&gt;prometer valores ou prazos fora da política&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Construí o &lt;strong&gt;&lt;a href="https://github.com/TheAndr3/comanda" rel="noopener noreferrer"&gt;Comanda&lt;/a&gt;&lt;/strong&gt; — um sistema multi-agente de pós-venda de delivery sobre o Claude Agent SDK e o Model Context Protocol (MCP) — partindo de um princípio simples: &lt;strong&gt;o modelo conduz a conversa, mas o dinheiro e a segurança vivem em código determinístico&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Neste artigo, mostro as quatro decisões de engenharia que tornaram o sistema auditável e como uma suíte de avaliação estilo &lt;strong&gt;τ-bench&lt;/strong&gt; (30 cenários, 8 adversariais) encontrou um bug sutil de fuso/relógio que nenhum teste manual havia pego.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. A ferramenta de reembolso não aceita valor (&lt;code&gt;ADR-0001&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Em muitos protótipos de agentes, a ferramenta tem a assinatura &lt;code&gt;issue_refund(order_id, amount)&lt;/code&gt;. Se o cliente convencer o modelo de que merece R$ 150,00 em vez da taxa de entrega de R$ 6,99, o modelo passa &lt;code&gt;150.00&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No Comanda, &lt;code&gt;issue_refund&lt;/code&gt; recebe apenas &lt;code&gt;(order_id, issue, item_ids)&lt;/code&gt;. Não existe parâmetro de valor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quem calcula os centavos é uma função pura (&lt;code&gt;evaluate_refund&lt;/code&gt;), que lê o pedido no SQLite, mede o atraso contra o &lt;code&gt;ETA&lt;/code&gt;, confere a janela de 48 horas após a entrega e aplica a regra (&lt;code&gt;R-ITEM&lt;/code&gt;, &lt;code&gt;R-QUALITY&lt;/code&gt;, &lt;code&gt;R-LATE-30&lt;/code&gt;, &lt;code&gt;R-LATE-60&lt;/code&gt;, &lt;code&gt;R-CANCELLED&lt;/code&gt;, &lt;code&gt;R-LOST&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Se o valor passar de R$ 80,00 ou se o cliente tiver 3+ reembolsos nos últimos 30 dias, o reembolso nasce como &lt;code&gt;pending_approval&lt;/code&gt; na &lt;strong&gt;Fila&lt;/strong&gt; do atendente humano.&lt;/li&gt;
&lt;li&gt;No banco, um trigger SQLite recusa qualquer &lt;code&gt;UPDATE&lt;/code&gt; em &lt;code&gt;refunds.amount_cents&lt;/code&gt;. Nem o agente nem o atendente humano podem alterar o valor calculado pela regra.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Topologia Supervisor–Especialistas com isolamento em código (&lt;code&gt;ADR-0003&lt;/code&gt;, &lt;code&gt;ADR-0018&lt;/code&gt;, &lt;code&gt;ADR-0020&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Dar todas as ferramentas a um único agente mistura papéis e encarece cada turno. O Comanda divide o atendimento em três agentes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Recepção (&lt;code&gt;Claude Haiku&lt;/code&gt;)&lt;/strong&gt;: único agente que conversa com o cliente. Busca na política (&lt;code&gt;search_policies&lt;/code&gt; com BM25 + stemmer Snowball do português escrito do zero) e delega aos especialistas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pedidos (&lt;code&gt;Claude Sonnet&lt;/code&gt;)&lt;/strong&gt;: somente leitura (&lt;code&gt;list_my_orders&lt;/code&gt;, &lt;code&gt;get_order_details&lt;/code&gt;, &lt;code&gt;track_delivery&lt;/code&gt;, &lt;code&gt;get_restaurant_info&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reembolsos (&lt;code&gt;Claude Sonnet&lt;/code&gt;)&lt;/strong&gt;: &lt;code&gt;check_refund_eligibility&lt;/code&gt;, &lt;code&gt;issue_refund&lt;/code&gt; e &lt;code&gt;escalate_to_human&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Essa divisão não depende só do prompt. Quatro guardrails em código protegem o atendimento:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;customer_id&lt;/code&gt; fixo no &lt;code&gt;ToolContext&lt;/code&gt;:&lt;/strong&gt; nenhuma ferramenta aceita &lt;code&gt;customer_id&lt;/code&gt; como argumento. Quando o cenário adversarial &lt;code&gt;C023&lt;/code&gt; tenta pedir reembolso do pedido &lt;code&gt;O-10002&lt;/code&gt; de outro cliente, &lt;code&gt;_own_order&lt;/code&gt; nega na hora.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolamento por servidor MCP e hook &lt;code&gt;PreToolUse&lt;/code&gt;:&lt;/strong&gt; cada agente tem seu servidor MCP em processo, e o hook bloqueia qualquer chamada fora do papel ou tentativa de delegar com &lt;code&gt;run_in_background&lt;/code&gt; ou troca de modelo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardrail de elegibilidade (&lt;code&gt;eligibility_check&lt;/code&gt;):&lt;/strong&gt; &lt;code&gt;Session.authorize&lt;/code&gt; nega &lt;code&gt;issue_refund&lt;/code&gt; se &lt;code&gt;check_refund_eligibility&lt;/code&gt; não tiver sido chamado na mesma sessão para o mesmo &lt;code&gt;(order_id, issue, frozenset(item_ids))&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Máscara determinística de PII (&lt;code&gt;CustomersMask&lt;/code&gt;):&lt;/strong&gt; nome, e-mail e telefone são mascarados na criação de cada evento do Rastro (JSONL e SSE) e novamente na exportação para o replay público.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Avaliação estilo τ-bench e o bug do relógio fixo (&lt;code&gt;ADR-0027&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Para medir o sistema sem depender de "olhômetro", criei 30 cenários em YAML (8 adversariais) com um &lt;strong&gt;Cliente simulado&lt;/strong&gt; e um &lt;strong&gt;Juiz LLM&lt;/strong&gt;, rodando sobre um banco SQLite determinístico cujo relógio é fixado em &lt;strong&gt;&lt;code&gt;05/11/2026 19:30 BRT&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Um cenário só passa se:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O estado final do SQLite bater por código com os reembolsos e tickets esperados; e&lt;/li&gt;
&lt;li&gt;O Juiz não encontrar nenhuma violação grave na conversa (com verificação em código de que o trecho citado em &lt;code&gt;evidence&lt;/code&gt; existe literalmente na fala do agente).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Na primeira rodada completa (50 atendimentos), o sistema teve &lt;strong&gt;0 violações graves e 0 leves&lt;/strong&gt;, conteve &lt;strong&gt;7 dos 8 cenários adversariais&lt;/strong&gt; e custou &lt;strong&gt;US$ 0,026 por atendimento&lt;/strong&gt; (estimativa equivalente em API). Mas 9 cenários reprovaram por falta de reembolso no estado final.&lt;/p&gt;

&lt;p&gt;Ao abrir os arquivos JSONL do &lt;strong&gt;Rastro&lt;/strong&gt;, descobri a causa principal: o banco vivia em &lt;code&gt;05/11/2026&lt;/code&gt;, mas o runtime do Claude Code injetava no bloco &lt;code&gt;&amp;lt;env&amp;gt;&lt;/code&gt; do modelo a data real da máquina (&lt;code&gt;15/11/2026&lt;/code&gt;). Quando a Recepção lia um pedido entregue em &lt;code&gt;05/11/2026&lt;/code&gt;, ela calculava mentalmente que haviam se passado 10 dias (fora da janela de 48h!) ou dizia ao cliente que o pedido &lt;em&gt;"não era de hoje"&lt;/em&gt;, enquanto a ferramenta em Python usava &lt;code&gt;Repository.now()&lt;/code&gt; (&lt;code&gt;05/11/2026&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;A correção (&lt;a href="https://github.com/TheAndr3/comanda/blob/main/docs/adr/0027-agents-receive-the-repository-clock-in-their-prompts.md" rel="noopener noreferrer"&gt;ADR-0027&lt;/a&gt;) foi passar &lt;code&gt;AgentHost.now()&lt;/code&gt; explicitamente no prompt de todos os agentes, instruindo-os a usar o relógio do atendimento e ignorar qualquer data do ambiente. Sem o Rastro estruturado e a avaliação automatizada, esse conflito entre o relógio do domínio e o &lt;code&gt;&amp;lt;env&amp;gt;&lt;/code&gt; do SDK passaria despercebido.&lt;/p&gt;




&lt;h3&gt;
  
  
  Links do projeto
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Replay Público Interativo (Vercel):&lt;/strong&gt; &lt;a href="https://comanda-blond.vercel.app" rel="noopener noreferrer"&gt;comanda-blond.vercel.app&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repositório, 29 ADRs e código:&lt;/strong&gt; &lt;a href="https://github.com/TheAndr3/comanda" rel="noopener noreferrer"&gt;github.com/TheAndr3/comanda&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmark e Rastros no Hugging Face:&lt;/strong&gt; &lt;a href="https://huggingface.co/datasets/TheAndr3/comanda-delivery-support-eval-ptbr" rel="noopener noreferrer"&gt;huggingface.co/datasets/TheAndr3/comanda-delivery-support-eval-ptbr&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
