- Braga Saúde — SLM na Nuvem (pt-BR)
- Por que Rust na nuvem?
- Modelo base
- Fine-tuning (QLoRA)
- Benchmark — baterias de teste (ANTES do fine-tuning)
- Estrutura do repositório
- Como baixar o adaptador na nuvem
- Endpoints do servidor (braga-saude-llm)
- Ação EMERGENCIA para o Android
- Variáveis de ambiente (servidor)
- Prompts clínicos (Care OS)
- Licença
- Por que Rust na nuvem?
Braga Saúde — SLM na Nuvem (pt-BR)
Serviço de inferência de Small Language Model (SLM) próprio, rodando na nuvem (Vast.ai / EC2 Spot), escrito em Rust + Axum + Candle. Objetivo: substituir a dependência da Groq API a longo prazo, barateando o custo por consulta e removendo o lock-in de provedor externo.
⚠️ Este serviço roda na nuvem, não on-device. O modelo fica na instância de nuvem; o app Android consome via HTTP/WebSocket. Os pesos do modelo são hospedados aqui no Hugging Face e baixados na instância de nuvem no momento do deploy.
Por que Rust na nuvem?
| Fator | Groq API | Próprio em Rust (nuvem) |
|---|---|---|
| Cobrança | Por token (entrada + saída) | Hora da instância GPU/CPU (fixo) |
| Volume alto | Custo escala linearmente | Marginal por consulta ≈ zero |
| Lock-in | Sim (provedor externo) | Não (seu modelo, seu servidor) |
| Latência | Rede + carga do provedor | Você controla o hardware e a fila |
| Modelo | Limitado ao que o provedor oferece | Qual modelo HF: safetensors, GGUF, fp16, bf16 |
Com um modelo 1B–3B numa GPU de entrada (RTX 3060 / T4 no Vast.ai), a inferência roda a 10–40 tok/s, mais que suficiente para chat de saúde.
Modelo base
- Base:
Qwen2.5-3B-Instruct(Apache 2.0, ~5,8 GB) - Adaptador: QLoRA treinado (LoRA r=16, alpha=32, 29,9M parâmetros treináveis de 3,1B)
- Pasta no repo:
adapter/— contémadapter_model.safetensors,adapter_config.json,tokenizer.json,tokenizer_config.json,chat_template.jinja - Uso: carregar
Qwen2.5-3B-Instruct+PeftModel.from_pretrained(model, adapter/)
Fine-tuning (QLoRA)
- Dataset: 2.203 exemplos (1.982 treino / 221 validação), JSONL
system/user<fala_usuario>...</fala_usuario>/assistant<JSON> - Ações ensinadas: apenas
CONVERSAeEMERGENCIA(o LLM NÃO registra pressão, água, glicemia — isso é do motor determinístico Kotlin no app) - Emergência: ~16% do dataset (364 exemplos), sempre com
acao: "EMERGENCIA"+ menção ao SAMU 192 (ou CVV 188 para autoagressão) - Hyperparams: QLoRA 4-bit (nf4), LR 2e-4, 3 épocas, batch 4 + grad accum 2, max_seq_len 512, RTX 3060 12 GB, ~1h05 de treino
- Resultado:
train_loss 0.1145,eval_loss 0.026, acurácia de token 99,15%
Benchmark — baterias de teste (ANTES do fine-tuning)
Duas baterias de 500 perguntas cada, executadas no modelo base (sem fine-tuning)
rodando na Vast.ai (RTX 3060, fp16, porta 8081). As perguntas são apenas as que o
roteador determinístico (orb_router.py) NÃO cobre — ou seja, o que realmente chega ao LLM.
| Bateria | Perguntas | Média | Falhas críticas | Modelo |
|---|---|---|---|---|
| 1 | 500 | 95,68 / 100 | 18 | Qwen 2.5-3B base |
| 2 | 500 | 95,49 / 100 | 18 | Qwen 2.5-3B base |
Problemas encontrados (concentrados na emergência):
| Problema | Bateria 1 | Bateria 2 |
|---|---|---|
| Emergência sem SAMU 192 (crítico) | 18 | 18 |
| Asteriscos / encenação teatral | 29 | 31 |
| Resposta longa (smalltalk) | 56 | 56 |
| Dieta sem profissional | 8 | 9 |
| Prescreve ibuprofeno (crítico) | 0 | 1 |
Score por categoria (Bateria 2):
| Categoria | Média |
|---|---|
| topic | 99,6 |
| symptoms | 99,3 |
| app_service | 97,8 |
| medication | 97,8 |
| caregiver | 97,5 |
| nutrition | 96,9 |
| open | 98,9 |
| smalltalk | 88,2 |
| emergency | 83,3 |
O gargalo é a emergência (83,3): AVC, confusão mental, desorientação e boca torta eram tratados como conversa comum, sem acionar o SAMU 192. O fine-tuning foi direcionado para corrigir exatamente isso.
Estrutura do repositório
braga-saude-slm/
├── hf_model_card.md # este model card (enviado como README.md no HF)
├── hf/
│ ├── config.example.json # configuração de exemplo do modelo
│ └── tokenizer.example.json # tokenizer de exemplo
├── hf_release/ # artefatos de release (fine-tuning + benchmark)
│ ├── adapter/ # adaptador QLoRA (115 MB) + tokenizer
│ ├── dataset/ # dataset de fine-tuning (train/val/dataset)
│ └── benchmark/ # resultados das baterias 1 e 2 (modelo base)
├── scripts/
│ ├── upload_to_hf.py # upload de artefatos via huggingface_hub
│ └── upload_hf_release.py# upload estruturado do release completo
├── .gitattributes # Git LFS para artefatos grandes
Como baixar o adaptador na nuvem
# Via huggingface-cli
huggingface-cli download fernandes-yuri/bragasaude-slm \
hf_release/adapter/adapter_model.safetensors \
--local-dir ./release
# Via Python (huggingface_hub)
from huggingface_hub import snapshot_download
snapshot_download(
repo_id="fernandes-yuri/bragasaude-slm",
repo_type="model",
local_dir="./release",
allow_patterns=["hf_release/adapter/*"],
)
Depois, carregue no servidor: PeftModel.from_pretrained(model_base, "./release/hf_release/adapter/").
Endpoints do servidor (braga-saude-llm)
O código do servidor (Rust + Axum + Candle) está no repositório separado:
repos/braga-saude-llm.
| Método | Rota | Descrição |
|---|---|---|
| GET | /health |
Health check |
| POST | /v1/chat/completions |
Compatível com OpenAI |
| POST | /chat/completions |
Alias curto (app Android) |
| GET | /ws/llm |
Streaming via WebSocket |
Ação EMERGENCIA para o Android
O campo acao: "EMERGENCIA" no JSON de resposta aciona no Android uma tela de
emergência com: UPA mais próxima, 192 (SAMU), CVV (apoio emocional) e contato de
emergência cadastrado. O LLM retorna essa ação para sintomas de risco de vida
(dor no peito, falta de ar severa, desmaio, sangramento intenso, sinais de AVC,
risco de autoagressão).
Variáveis de ambiente (servidor)
| Variável | Default | Descrição |
|---|---|---|
LLM_HOST |
0.0.0.0 |
Bind do servidor |
LLM_PORT |
8080 |
Porta do servidor |
LLM_MODEL_PATH |
/models/qwen2.5-3b-instruct |
Modelo base |
LLM_ADAPTER_PATH |
./hf_release/adapter |
Caminho do adaptador QLoRA |
LLM_MODEL_FORMAT |
safetensors |
safetensors / gguf / onnx |
LLM_MAX_CONTEXT |
2048 |
Contexto máximo (tokens) |
LLM_MAX_NEW_TOKENS |
256 |
Tokens gerados por resposta |
LLM_TEMPERATURE |
0.7 |
Amostragem |
LLM_TOP_P |
0.9 |
Nucleus sampling |
LLM_CUDA |
true |
Habilitar CUDA |
Prompts clínicos (Care OS)
sintomas— check-in sintomáticomedicamentos— não altera dosagem nem suspende receitassinais_vitais— faixas de referência (SBC/SBD/ADA/OMS)agendamento— app ou clínicaemergencia— SAMU 192 / pronto-socorrogeral— serviços da Braga Saúde
Não diagnostica nem autoriza medicação.
Licença
MIT