Artigo

Como Criar um Chatbot RAG em Python que Responde a Documentos

Como Criar um Chatbot RAG em Python que Responde a Documentos
Tempo de leitura6 minutos

No mundo atual, os chatbots se tornaram uma ferramenta essencial para a automação de atendimentos e soluções rápidas. Neste guia, vamos explorar como criar um chatbot RAG (Retrieval-Augmented Generation) em Python que responderá a perguntas sobre documentos específicos. Este projeto é particularmente interessante pois combina inteligência artificial com processamento de linguagem natural (NLP) para extrair dados relevantes de textos.

Tecnologias usadas

  • Python
  • Flask
  • NLTK/SpaCy
  • OpenAI API
  • Pandas

Configuração

A primeira etapa na criação do nosso chatbot RAG envolve configurar o ambiente. Vamos usar o Python 3 e algumas bibliotecas essenciais. Abaixo, estão os comandos para instalação:


# Atualize seu sistema
sudo apt update && sudo apt upgrade

# Instale o Python e bibliotecas necessárias
sudo apt install python3-pip
pip install Flask pandas nltk spacy openai

Implementação principal

Agora que temos as ferramentas, vamos implementar o código do chatbot. O principal objetivo é receber perguntas do usuário e buscar respostas nos documentos fornecidos. Para isso, utilizaremos a biblioteca Flask para criar uma API REST, onde o usuário pode enviar suas perguntas.


from flask import Flask, request, jsonify
import pandas as pd
import nltk
from nltk.tokenize import word_tokenize

app = Flask(__name__)

# Carregue seus documentos aqui
documents = pd.read_csv('documentos.csv')

@app.route('/ask', methods=['POST'])
def ask():
    data = request.json
    question = data['question']

    # Tokenize a pergunta
    tokens = word_tokenize(question)
    # Aqui você pode adicionar o código para buscar a resposta no pandas
    response = buscar_resposta(tokens)

    return jsonify({'response': response})

def buscar_resposta(tokens):
    # Lógica de busca para encontrar resposta nos documentos
    return 'Resposta simulada para: ' + ' '.join(tokens)

if __name__ == '__main__':
    app.run(debug=True)

Execução e teste

Para testar o funcionamento do chatbot, vamos chamar a API usando curl ou Postman. No terminal, execute o seguinte comando:


curl -X POST http://localhost:5000/ask -H 'Content-Type: application/json' -d '{"question": "O que é RAG?"}'

Você deve receber uma resposta que indica que a pergunta foi processada. Com isso, já temos uma estrutura básica funcionando!

Conclusão

Construir um chatbot RAG em Python é um exercício incrível que combina diferentes áreas da tecnologia. Neste tutorial, cobrimos desde a configuração do ambiente de desenvolvimento até a implementação básica de uma API que responde a perguntas sobre documentos. Você pode expandir este projeto adicionando técnicas mais sofisticadas de NLP ou integrando inteligência artificial com modelos de aprendizado profundo, como opções de OpenAI.

FAQ

O que é um chatbot RAG?

Um chatbot RAG é um sistema que responde a perguntas baseando-se em um conjunto de documentos ou informações.

Quais tecnologias são usadas para criar chatbots?

Geralmente utilizam-se Python, bibliotecas de NLP como NLTK ou SpaCy, e frameworks como Flask ou Django.

Como funcionam os chatbots RAG?

Eles utilizam técnicas de recuperação de informações e aprendizado de máquina para entender e responder perguntas.

Posso usar esse chatbot para dados sensíveis?

Sim, mas é crucial implementar diretrizes de segurança e privacidade para proteger esses dados.

A implementação é complexa?

A complexidade depende da sua familiaridade com programação e a arquitetura do projeto.

Exemplo tecnico completo

Abaixo esta uma base mais realista para organizar configuracao, cliente de API, execucao e teste local.

Configuracao do projeto

# config.py
from dataclasses import dataclass
import os

@dataclass(frozen=True)
class Settings:
    api_url: str
    timeout: int
    dry_run: bool

def load_settings() -> Settings:
    return Settings(
        api_url=os.getenv("API_URL", "https://exemplo.com/api"),
        timeout=int(os.getenv("API_TIMEOUT", "30")),
        dry_run=os.getenv("DRY_RUN", "true").lower() == "true",
    )

Cliente principal

# client.py
from typing import Any
import requests

class AutomacaoError(RuntimeError):
    pass

class AutomacaoClient:
    def __init__(self, api_url: str, timeout: int = 30) -> None:
        self.api_url = api_url.rstrip("/")
        self.timeout = timeout

    def buscar_dados(self) -> dict[str, Any]:
        try:
            response = requests.get(f"{self.api_url}/status", timeout=self.timeout)
            response.raise_for_status()
        except requests.RequestException as exc:
            raise AutomacaoError(f"Falha ao buscar dados: {exc}") from exc
        return response.json()

    def executar_acao(self, payload: dict[str, Any], dry_run: bool = True) -> dict[str, Any]:
        if dry_run:
            return {"modo": "teste", "payload": payload}

        try:
            response = requests.post(f"{self.api_url}/executar", json=payload, timeout=self.timeout)
            response.raise_for_status()
        except requests.RequestException as exc:
            raise AutomacaoError(f"Falha ao executar acao: {exc}") from exc
        return response.json()

Execucao local

# main.py
from config import load_settings
from client import AutomacaoClient

def montar_payload() -> dict:
    return {
        "tema": "chatbot RAG",
        "origem": "blog-tecnologia",
        "prioridade": "normal",
    }

def main() -> None:
    settings = load_settings()
    client = AutomacaoClient(settings.api_url, settings.timeout)

    status = client.buscar_dados()
    print("Status da API:", status)

    resultado = client.executar_acao(montar_payload(), dry_run=settings.dry_run)
    print("Resultado:", resultado)

if __name__ == "__main__":
    main()

Comandos de teste

python -m venv .venv
source .venv/bin/activate
pip install requests
export API_URL="https://exemplo.com/api"
export DRY_RUN="true"
python main.py

Docker para producao

# docker-compose.yml
services:
  app:
    build: .
    command: python main.py
    environment:
      API_URL: "https://exemplo.com/api"
      API_TIMEOUT: "30"
      DRY_RUN: "false"
    restart: unless-stopped
    volumes:
      - ./logs:/app/logs

  worker:
    build: .
    command: python worker.py
    environment:
      API_URL: "https://exemplo.com/api"
      DRY_RUN: "false"
    restart: unless-stopped

Teste automatizado

# test_client.py
from client import AutomacaoClient

class FakeResponse:
    def __init__(self, payload):
        self.payload = payload

    def raise_for_status(self):
        return None

    def json(self):
        return self.payload

def test_execucao_em_dry_run():
    client = AutomacaoClient("https://exemplo.com/api")
    payload = {"tema": "chatbot RAG", "prioridade": "normal"}
    resultado = client.executar_acao(payload, dry_run=True)

    assert resultado["modo"] == "teste"
    assert resultado["payload"]["tema"] == "chatbot RAG"

Gestao de risco e logs

# risk.py
from decimal import Decimal
import logging

logger = logging.getLogger(__name__)

class RiskManager:
    def __init__(self, saldo_total: Decimal, reserva: Decimal = Decimal("0.30")) -> None:
        self.saldo_total = saldo_total
        self.reserva = reserva

    @property
    def saldo_protegido(self) -> Decimal:
        return self.saldo_total * self.reserva

    @property
    def saldo_operacional(self) -> Decimal:
        return self.saldo_total - self.saldo_protegido

    def calcular_tamanho(self, risco_por_operacao: Decimal, stop_percentual: Decimal) -> Decimal:
        if stop_percentual <= 0:
            raise ValueError("stop_percentual precisa ser maior que zero")

        valor_em_risco = self.saldo_operacional * risco_por_operacao
        tamanho = valor_em_risco / stop_percentual
        logger.info("Tamanho calculado: %s", tamanho)
        return tamanho

    def pode_abrir_nova_posicao(self, posicoes_abertas: int, limite: int) -> bool:
        if posicoes_abertas >= limite:
            logger.warning("Limite de posicoes atingido")
            return False
        if self.saldo_operacional <= 0:
            logger.warning("Saldo operacional indisponivel")
            return False
        return True

Arquitetura tecnica de chatbot RAG

Uma implementacao solida nao deve misturar interface, regra de negocio, integracao externa e logs no mesmo arquivo. O caminho mais seguro e separar o projeto em camadas pequenas: configuracao, cliente de API, servico principal, fila de execucao, persistencia e painel de acompanhamento.

Essa divisao facilita teste, manutencao e evolucao. Se uma API externa muda, voce altera o cliente. Se a regra de negocio muda, voce altera o servico. Se a interface muda, o nucleo continua funcionando.

Camada de configuracao

A configuracao deve vir de variaveis de ambiente. Isso evita senhas no codigo, permite ambientes separados e deixa mais simples rodar o mesmo projeto em desenvolvimento, staging e producao.

Camada de execucao

A execucao deve sempre ter logs claros, tratamento de erro e modo de teste. Em automacoes reais, o modo de teste evita que uma rotina execute acoes definitivas antes de voce validar parametros, permissao e formato dos dados.

Observabilidade

Logs nao servem apenas para erro. Eles mostram decisoes tomadas pelo sistema: quando a rotina iniciou, quais dados recebeu, quais filtros aplicou, qual acao ignorou e qual acao executou. Sem isso, qualquer automacao vira uma caixa preta dificil de confiar.

Seguranca operacional

Projetos conectados a APIs precisam de limites. Use timeouts, retries com cuidado, validacao de payload, permissao minima e nunca exponha chaves em frontend, repositorio ou print de terminal.

Como eu estruturaria a evolucao

Depois da primeira versao funcionando, eu separaria o projeto em tres ciclos. O primeiro ciclo cuida da confiabilidade: logs melhores, tratamento de erro, testes automatizados e ambiente de homologacao. O segundo ciclo cuida da experiencia: painel mais claro, filtros, historico de execucoes e mensagens de status compreensiveis. O terceiro ciclo cuida da escala: filas, workers, cache, monitoramento e deploy com rollback.

Essa ordem evita um erro comum em projetos de automacao: tentar escalar antes de entender se o fluxo e confiavel. Uma automacao pequena, mas bem observavel, e melhor do que um sistema grande que executa acoes sem explicar por que tomou cada decisao.

Validacao antes de producao

Antes de colocar qualquer rotina em producao, eu validaria entradas, saidas e limites. Isso inclui testar payloads vazios, respostas lentas, indisponibilidade da API, credenciais invalidas e cenarios de execucao duplicada. Tambem manteria um modo dry-run para simular a rotina sem executar a acao final.

Em projetos financeiros, operacionais ou integrados a contas reais, essa validacao e ainda mais importante. O sistema precisa falhar de forma segura, registrar o motivo da falha e nunca tomar uma acao irreversivel sem parametros bem definidos.

Checklist tecnico recomendado

  • Separar credenciais em variaveis de ambiente.
  • Registrar logs de inicio, decisao, sucesso e erro.
  • Usar timeout em toda chamada externa.
  • Ter modo de teste antes do modo real.
  • Persistir historico das execucoes importantes.
  • Revisar permissoes de API com principio do menor privilegio.
  • Documentar comandos de execucao e rollback.

Notas de implementacao para um projeto real

Quando o projeto sai do exemplo e entra em uso real, a parte mais importante nao e apenas fazer a automacao funcionar uma vez. O mais importante e garantir que ela consiga funcionar varias vezes, em dias diferentes, com dados diferentes e com falhas externas acontecendo. Por isso eu costumo pensar em idempotencia, auditoria e recuperacao desde o inicio.

Idempotencia significa evitar que a mesma acao seja executada duas vezes por acidente. Em uma integracao com API, por exemplo, voce pode registrar um identificador unico para cada execucao e consultar esse identificador antes de repetir a acao. Isso reduz risco quando existe timeout, queda de rede ou reinicio do servidor.

Auditoria significa deixar rastros claros. Cada execucao relevante deve registrar horario, entrada recebida, decisao tomada, resultado e eventual erro. Isso ajuda na manutencao e tambem cria confianca para o usuario final, porque o sistema consegue explicar o que aconteceu.

Recuperacao significa projetar o fluxo para voltar a operar depois de uma falha. Se uma chamada externa falha, o sistema precisa saber se deve tentar novamente, ignorar, pausar ou pedir revisao manual. Essa decisao nao deve ficar escondida em um bloco generico de excecao.

Outro ponto essencial e separar o que e regra de negocio do que e detalhe de infraestrutura. O codigo que calcula uma decisao nao deveria depender diretamente de Flask, Django, WordPress, Binance ou qualquer biblioteca especifica. Quanto mais isolada a regra, mais facil testar, reutilizar e migrar.

Por fim, eu manteria um painel simples para acompanhar status. Mesmo que a automacao rode em terminal ou worker, um painel com ultimas execucoes, erros recentes, tempo medio, modo atual e botoes de pausa ajuda muito. Em automacoes que mexem com dinheiro, publicacao, vendas ou atendimento, visibilidade vale tanto quanto velocidade.

Tambem vale criar um roteiro de revisao antes de cada deploy. Eu verificaria se as variaveis de ambiente estao presentes, se o modo de teste esta funcionando, se os logs estao sendo gravados, se os limites de seguranca continuam ativos e se existe um caminho claro para pausar a automacao. Esse tipo de checklist parece simples, mas evita muitos problemas quando o sistema passa a rodar todos os dias.

Em resumo, a implementacao tecnica precisa equilibrar tres coisas: capacidade de executar, capacidade de explicar e capacidade de parar. Um sistema que executa mas nao explica vira risco. Um sistema que explica mas nao tem botao de parada tambem vira risco. O ideal e construir a automacao com controles desde o primeiro prototipo.

Esse cuidado muda tudo.

Livros e leituras recomendadas

Anterior e próximo

Leituras recentes

Temas parecidos para continuar navegando no blog.

Conteúdo criado para leitura limpa, boa hierarquia visual e navegação clara.