# Treinamento do agente de atendimento (estágio 2) Fine-tuning (SFT com LoRA) do Llama-3.1-8B com os atendimentos reais do ifbot que foram **bem avaliados pelo estágio 1** (LLM-as-judge): nota do atendente ≥ 8, problema resolvido e cliente não-insatisfeito. O juiz funciona como filtro de qualidade do dataset — só "assim se atende" entra no treino. ## Fluxo completo ``` avaliações (estágio 1, MySQL) │ node backend/scripts/exportarDatasetTreinamento.js ▼ training/data/{train,valid}.jsonl ← formato chat {"messages":[...]} │ ./treinar_lora_mlx.sh ▼ training/adapters/ ← LoRA treinado (MLX, roda no M4 16GB) │ ./publicar_no_ollama.sh ▼ ollama: star-atendente ← modelo fundido + quantizado q4_K_M ``` ## Passo a passo 1. **Acumular avaliações** — o job do backend avalia sozinho; para acelerar: `cd backend && node scripts/avaliarTudo.js --lote 25` (~20s por atendimento no llama3.1). 2. **Exportar o dataset** (da pasta `backend/`): ``` node scripts/exportarDatasetTreinamento.js # score>=8, resolvido=sim node scripts/exportarDatasetTreinamento.js --score-min 7 --incluir-parcial # filtro mais frouxo ``` Gera `training/data/train.jsonl`, `valid.jsonl` e `manifest.json` (rastreia protocolos usados e filtros). Telefones são mascarados; mensagens do bot/sistema ficam de fora; cada amostra começa no cliente e termina na resposta do atendente. 3. **Treinar** (nesta máquina, Apple Silicon): ``` ./treinar_lora_mlx.sh # 3 épocas ./treinar_lora_mlx.sh 2 # 2 épocas ``` Usa `mlx-lm` com o modelo 4-bit (`mlx-community/Meta-Llama-3.1-8B-Instruct-4bit`), batch 1, seq 2048, gradient checkpointing — cabe nos 16 GB do M4, mas feche apps pesados e espere algumas horas com centenas de amostras. Acompanhe o `Val loss`: se começar a subir enquanto o train loss cai, reduza as épocas (overfitting). O script roda automaticamente, antes do treino: - `filtrar_por_tokens.py` — descarta amostras cujo tamanho real em tokens (tokenizer do próprio modelo) passa de 1600. `exportarDatasetTreinamento.js` só filtra por caracteres (`--max-chars`), que não é proxy confiável de tokens em pt-BR; uma amostra de 14-18 mil caracteres pode passar de 4000 tokens — bem acima do `--max-seq-length` de 2048 — e isso já causou OOM de GPU (e reinício da máquina) durante a validação em 04/08. - o treino roda via `run_lora_seguro.py`, que capa o `memory_limit`/`wired_limit` do MLX em 9 GiB antes de carregar o modelo. Por padrão o MLX permite até 1.5x o working set recomendado da GPU (~19 GiB neste M4), acima da RAM física (16 GiB) — sem teto explícito, um pico de memória derruba o sistema inteiro em vez de estourar uma exceção Python capturável. *Alternativa com GPU NVIDIA (mais rápido, datasets maiores):* os mesmos JSONL funcionam no [unsloth](https://github.com/unslothai/unsloth) ou axolotl — treinar lá, trazer o adapter PEFT e converter com `convert_lora_to_gguf.py` do llama.cpp. 4. **Testar o adapter antes de publicar**: ``` source .venv/bin/activate mlx_lm.generate --model mlx-community/Meta-Llama-3.1-8B-Instruct-4bit \ --adapter-path adapters --max-tokens 200 \ --prompt "Boa tarde, minha internet caiu" ``` 5. **Publicar no Ollama**: `./publicar_no_ollama.sh` — funde o LoRA, cria o modelo `star-atendente` quantizado e remove o intermediário fp16 (~16 GB temporários em disco). 6. **Validar e ativar**: compare respostas com o llama3.1 puro em perguntas típicas de suporte. O backend já usa `star-atendente` por default (`config.atendenteSugestao.model`, na feature de sugestão de resposta ao atendente) — só é preciso setar `OLLAMA_ATENDENTE_MODEL=star-atendente` no `backend/.env` se o modelo for publicado com outro nome. Não confundir com `OLLAMA_CHAT_MODEL`, que é o modelo do chat RAG geral. ## Quando re-treinar O dataset cresce conforme o sync importa protocolos novos e o juiz os avalia. Re-exportar + re-treinar vale a pena a cada leva significativa de amostras novas (ex.: +30%). O `manifest.json` diz o que entrou em cada rodada. ## Próximo estágio (futuro) Com volume maior, os scores viabilizam **DPO**: pares "atendimento nota alta" vs "nota baixa" para o mesmo tipo de problema, treinando por preferência em vez de imitação. Exige mais dados e curadoria — só faz sentido depois do SFT mostrar limite.