Como Construir um Agente de IA: Guardrails, Function Calling e RAG Local com TypeScript, Bun e LanceDB
Como Construir um Agente de IA: Guardrails, Function Calling e RAG Local com TypeScript, Bun e LanceDB
Muito se fala sobre agentes autônomos resolvendo problemas corporativos complexos, mas quem senta na cadeira de engenharia para colocar um LLM em produção logo se depara com a dura realidade: alucinações com dados críticos, chamadas desnecessárias de ferramentas e respostas imprevisíveis.
Recentemente, desenhei e implementei um assistente virtual voltado para o varejo farmacêutico — um cenário impiedoso com erros. Na dispensação de medicamentos, um assistente de IA não pode chutar estoque, não pode receitar antibióticos e não pode sugerir substitutos sem validação regulatória da Anvisa.
Neste artigo, compartilho as decisões de arquitetura e padrões técnicos que utilizei para transformar um modelo local open source em um agente transacional determinístico usando TypeScript, Bun, Ollama (Llama 3.1 8B) e LanceDB.
💡 Código do projeto: Você pode conferir o código desse estudo no GitHub: github.com/luanyata/laura-pharma-agent
1. O Problema da Confiança: Por que um Simples Chatbot Falha
Colocar um modelo generalista para conversar com clientes em setores regulados expõe três gargalos clássicos:
- Pressão de Ferramenta (Phantom Tool Calls): Modelos compactos (como 7B ou 8B) tendem a chamar tools mesmo quando o usuário diz apenas “Olá, bom dia!” ou “Onde fica a loja?”.
- Alucinação Factual e de Balcão: O modelo “inventa” que tem o produto em estoque ou sugere outro medicamento por analogia biológica — o que constitui exercício ilegal da medicina e infração sanitária.
- Dependência Excessiva de Fine-Tuning: Há um mito comum de que transformar um modelo em atendente exige fine-tuning dos pesos. Na esmagadora maioria dos casos de uso, isso é desperdício de recurso computacional; o que você realmente precisa é de In-Context Learning (RAG + Prompt Engineering rigoroso).
2. A Arquitetura do Sistema
Para garantir confiabilidade, a arquitetura foi desenhada em camadas estritamente desacopladas:
Arquitetura do Sistema
Abaixo, detalho os pilares práticos dessa implementação.
3. Padrão 1: Roteador de Intenções e Tool Gating
Um dos maiores erros em arquiteturas de agentes é passar todas as ferramentas (tools/schemas) disponíveis para a LLM em todas as requisições.
- Para eliminar chamadas fantasmas, implementamos um Classificador de Intenção que executa antes do agente principal:
Código de classificação em Typescript
Por que isso é crucial?
- Zero Fantasmas: Se a intenção for GREETING, a chamada seguinte para a LLM vai com o array de ferramentas vazio. O modelo não tem como disparar chamadas aleatórias de API.
- Segurança Ativa (MEDICAL_ADVICE): Se o usuário diz “Estou com dor no peito há 2 dias, o que tomo?”, o roteador classifica imediatamente a violação ética, permitindo responder com uma recusa padronizada sem sequer consultar o banco.
4. Padrão 2: Function Calling com Resolução de Filiais e Normalização
A ferramenta de estoque (checkInventory) não se limita a um SELECT simples no banco. Ela precisa lidar com a realidade da língua portuguesa e as particularidades do varejo físico:
- Normalização Diacrítica (NFD): Busca textual resistente a acentos (ex.: o usuário busca “oximetrico”, o catálogo armazena “oximétrico”).
- Resolução de Falta com Alternativa de Filial: Quando a matriz não tem o produto, a ferramenta não retorna um erro seco: ela consulta filiais próximas e já devolve no payload o endereço físico da loja que tem o item.
- Mapeamento de Genéricos e Princípio Ativo: Reconhecimento de substâncias e tags, evitando que o modelo diga que não tem o item caso o usuário busque pelo princípio ativo em vez do nome comercial.
5. Padrão 3: RAG Local com LanceDB e Modelos MoE
Nem toda informação de uma empresa deve viver em código ou tabelas relacionais. Regras sobre retenção de receita digital, políticas de entrega e horários de funcionamento mudam com frequência e pertencem à documentação institucional.
Utilizamos o LanceDB como banco vetorial local embutido, associado ao modelo de embedding nomic-embed-text-v2-moe:
- Sem infraestrutura pesada: O LanceDB roda in-process com zero overhead de servidores dedicados de busca vetorial.
- Task Prefixes: O modelo de embedding da Nomic se beneficia de prefixos contextuais. Indexamos documentos com search_document: e processamos a pergunta do cliente com search_query:, aumentando significativamente a precisão semântica em perguntas curtas.
Quando o cliente pergunta “Vocês aceitam foto de receita pelo celular?”, o agente despacha a consulta para a base de conhecimento institucional e responde embasado nas normas vigentes de assinatura digital e portarias da Anvisa.
6. Padrão 4: Engenharia de Prompt e Contraste com Few-Shots
Durante os testes, descobrimos que calibrar o comportamento da IA não depende de prompts gigantescos, mas de exemplos contrastantes
Get Luan Lima’s stories in your inbox
Join Medium for free to get updates from this writer.
Se você instrui o modelo a ser rígido contra alucinações e só mostra exemplos de falha (produto inexistente), ele tende a responder de maneira ríspida, quase como um código HTTP 404 Not Found.
Ao balancear o prompt com pares claros de sucesso e falha usando dados fictícios:
- Um exemplo mostrando produto encontrado com confirmação de preço e filial;
- Um exemplo mostrando produto indisponível, redigido com polidez e acolhimento;
O Llama 3.1 8B estabilizou sua postura: caloroso e empático no atendimento, porém inflexível e exato com a verdade dos dados.
7. Como Garantir que Nada Quebrou? A Importância dos Evals
Software tradicional possui testes unitários determinísticos. Como testar um sistema cujo núcleo é probabilístico?
A resposta são testes automatizados de regressão (Evals). Desenvolvemos uma suíte de testes ponta a ponta executada diretamente pelo runtime do Bun que simula conversas de múltiplos turnos:
- Teste de Resolução de Contexto: Se o assistente avisa que o produto só tem na Filial Areias e o usuário pergunta em seguida “qual o endereço da filial?”, o teste valida se o agente recuperou o endereço do histórico recente com zero novas chamadas de ferramenta.
- Teste de Blindagem Médica: Garante que tentativas de diagnóstico ou solicitação de antibióticos sem receita recebam recusa imediata.
- Teste de Ausência de Item: Garante que produtos fictícios retornem indisponibilidade sem que o modelo invente marcas substitutas.
Rodar evals na pipeline de CI garante que alterações nos prompts, esquemas de ferramentas ou parâmetros de temperatura não degradem o comportamento do agente.
8. Do Laboratório para a Produção: O que Vem a Seguir?
Embora essa arquitetura resolva os gargalos imediatos de precisão, isolamento de ferramentas e segurança básica, colocar um sistema desse porte diante de milhares de usuários reais em escala exige passos adicionais.
Em um ambiente produtivo de missão crítica, a evolução natural dessa base inclui:
- Reescrita de Consultas (Query Rewriting): Resolver dependências anafóricas e perguntas curtas que dependem do contexto de turnos anteriores (ex.: “E o genérico dele?”).
- Camadas de Segurança em Profundidade (Defense in Depth): Adicionar filtros determinísticos por código (sem uso de GPU) para interceptar termos restritos da Anvisa antes mesmo do roteador.
- Estratégias Avançadas de Busca: Implementar busca híbrida (BM25 + vetorial) para códigos SKU/normas exatas, combinada com reranking para maximizar a precisão do contexto.
- Streaming de Respostas: Consumir Server-Sent Events (SSE) para reduzir o tempo até o primeiro token percebido pelo usuário final no chat ou WhatsApp.
- Especialização Multi-Agente: Separar responsabilidades em agentes cooperativos (triagem, farmacêutico institucional e fechamento de pedidos).
Cada um desses tópicos merece uma discussão técnica à parte e será abordado em publicações futuras.
Conclusão: O Valor da Engenharia de Software na IA
Modelos de linguagem são motores de inferência e raciocínio textual extraordinários, mas não operam de forma confiável sozinhos em ambientes corporativos. A verdadeira robustez de um agente de IA não vem do tamanho do modelo ou de mágicas de fine-tuning, mas dos princípios fundamentais da boa engenharia de software:
- Desacoplamento de responsabilidades;
- Tipagem estrita de ponta a ponta (TypeScript);
- Classificação prévia e isolamento de ferramentas;
- Bases de conhecimento auditáveis (RAG);
- Testes contínuos de regressão (Evals).
Com essa fundação bem estabelecida, o caminho para incorporar técnicas mais complexas torna-se previsível e seguro, permitindo executar agentes transacionais de alta performance e baixo custo rodando 100% em infraestrutura local.
Repositório do projeto:
Você pode ver o código completo e os testes desse estudo:
https://github.com/luanyata/laura-pharma-agent
Você tem trabalhado com agentes de IA locais ou arquiteturas de Tool Calling em produção? Quais têm sido seus maiores desafios com chamadas fantasmas e alucinações? Vamos trocar experiências nos comentários! 💬🚀










