On-device inference mobile: ExecuTorch, MediaPipe, Core ML
- ⬜🍎 MLX: rodar LLM nativo em M3/M4 Apple Silicon(Local LLMs & Edge AI)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Em 2026, o LLM no seu bolso virou realidade. iPhone 16 Pro roda Apple Foundation ~3B no Neural Engine, Pixel 9 Pro roda Gemma 2 2B via MediaPipe, Galaxy S24 Ultra roda Phi-3 mini via Qualcomm AI Engine. A infraestrutura que viabiliza isso é discreta — ExecuTorch (Meta), MediaPipe LLM Inference (Google), Core ML (Apple), Qualcomm QNN, MediaTek NeuroPilot — mas cada uma resolve o mesmo problema fundamental: como rodar redes de bilhões de parâmetros em dispositivos com 8-12GB de RAM e 5W de TDP.
O cenário 2026: SLMs dominam o mobile
| Modelo | Params | Tamanho INT4 | iPhone 16 Pro | Pixel 9 Pro | S24 Ultra |
|---|---|---|---|---|---|
| Llama 3.2 1B-Instruct | 1.23B | ~650 MB | ~45 tok/s | ~38 tok/s | ~42 tok/s |
| Llama 3.2 3B-Instruct | 3.21B | ~1.8 GB | ~22 tok/s | ~18 tok/s | ~20 tok/s |
| Gemma 2 2B | 2.5B | ~1.4 GB | ~28 tok/s | ~32 tok/s (GPU TPU) | ~24 tok/s |
| Phi-3.5-mini 4B | 3.8B | ~2.1 GB | ~18 tok/s | ~16 tok/s | ~17 tok/s |
| Qwen 2.5 1.5B | 1.5B | ~850 MB | ~38 tok/s | ~32 tok/s | ~35 tok/s |
| Apple Foundation ~3B | ~3B | ~1.5 GB ANE | Nativa, latência baixa | N/A | N/A |
A regra prática: modelo INT4 com size ≤ 1/3 da RAM total do device, idealmente ≤ 2GB. Excedendo isso, pressure de memória mata o app em background, throttle térmico aparece em conversas longas, bateria drena visivelmente.
ExecuTorch: o padrão multi-plataforma da Meta
# ExecuTorch — pipeline de exportação Llama 3.2 1B para iOS
import torch
from executorch.examples.models.llama2 import Llama2Model
from executorch.exir import to_edge
from executorch.backends.apple.coreml.partition.coreml_partitioner import CoreMLPartitioner
# 1. Carrega modelo PyTorch
model = Llama2Model("Llama-3.2-1B-Instruct", checkpoint_path="./consolidated.pth")
model.eval()
# 2. Quantização INT4 (groupwise) via PT2E
from torch.ao.quantization.quantizer.embedding_quantizer import EmbeddingQuantizer
from torch.ao.quantization.quantizer.coreml_quantizer import CoreMLQuantizer
quantizer = CoreMLQuantizer(bits=4, group_size=64)
m = torch._export.capture_pre_autograd_graph(model, example_inputs)
m = prepare_pt2e(m, quantizer)
# calibração
for batch in calib_loader: m(batch)
m = convert_pt2e(m)
# 3. Exporta para Edge IR
edge = to_edge(torch.export(m, example_inputs))
# 4. Delegate para Core ML (otimiza para ANE)
edge = edge.to_backend(CoreMLPartitioner())
# 5. Salva .pte
prog = edge.to_executorch()
with open("llama-3.2-1b-coreml-int4.pte", "wb") as f:
f.write(prog.buffer)// Runtime em iOS (Swift) — usando ExecuTorch
import ExecuTorchLLM
let modelPath = Bundle.main.path(forResource: "llama-3.2-1b-coreml-int4", ofType: "pte")!
let tokenizerPath = Bundle.main.path(forResource: "tokenizer", ofType: "json")!
let runner = try LLMRunner(modelPath: modelPath, tokenizerPath: tokenizerPath)
let prompt = "Resuma este email em 2 frases: ..."
try await runner.generate(prompt: prompt, maxTokens: 200) { token in
DispatchQueue.main.async { self.streamingText += token }
}MediaPipe LLM Inference (Google)
// Android Kotlin — MediaPipe LLM Inference
import com.google.mediapipe.tasks.genai.llminference.LlmInference
class GemmaService(context: Context) {
private val llm: LlmInference
init {
val options = LlmInference.LlmInferenceOptions.builder()
.setModelPath("/data/local/tmp/gemma-2b-it-gpu-int4.task")
.setMaxTokens(2048)
.setMaxTopK(40)
.setTemperature(0.7f)
.setPreferredBackend(LlmInference.Backend.GPU) // ou CPU
.build()
llm = LlmInference.createFromOptions(context, options)
}
suspend fun generate(prompt: String): String = withContext(Dispatchers.IO) {
llm.generateResponse(prompt)
}
}// Web — MediaPipe LLM Inference no browser via WebGPU
import { FilesetResolver, LlmInference } from "@mediapipe/tasks-genai";
const genai = await FilesetResolver.forGenAiTasks(
"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-genai/wasm",
);
const llm = await LlmInference.createFromOptions(genai, {
baseOptions: { modelAssetPath: "/models/gemma-2b-it-gpu-int4.bin" },
maxTokens: 1024,
topK: 40,
temperature: 0.7,
randomSeed: 101,
});
const response = await llm.generateResponse("Explique RAG em 2 frases.");Apple Foundation Models (iOS 26+)
Anunciada na WWDC 2025 e disponível em iOS 26+, a FoundationModels.framework expõe o LLM on-device do Apple Intelligence para apps de terceiros. Modelo base ~3B parâmetros INT4 no ANE, adapters específicos por tarefa (~10-50MB) baixados sob demanda e ativados em runtime.
// Apple Foundation Models — iOS 26+
import FoundationModels
// 1. Verifica disponibilidade (iPhone 15 Pro+, iPad M-series, todos Mac)
guard SystemLanguageModel.default.availability == .available else { return }
// 2. Sessão com guided generation (Swift macros para schema-aware output)
@Generable struct EmailSummary {
@Guide(description: "Resumo em 2 frases, PT-BR")
let summary: String
@Guide(description: "Lista de action items")
let actions: [String]
let urgency: Urgency
enum Urgency: String, Generable {
case low, medium, high
}
}
let session = LanguageModelSession(instructions: """
Você resume emails profissionais em português.
""")
let result = try await session.respond(
to: emailContent,
generating: EmailSummary.self,
)
print(result.content.summary) // typed!
print(result.content.actions)
print(result.content.urgency)A FoundationModels.framework usa guided generation: o sistema garante que o output obedece o schema declarado via macros Swift, fazendo constrained decoding por baixo. Permite que apps tratem o LLM como uma função typed sem regex parsing nem JSON validation manual.
Comparativo de runtimes
| Runtime | Maintainer | Plataformas | Formato | Force |
|---|---|---|---|---|
| ExecuTorch | Meta | iOS, Android, Linux, embedded | .pte | Cross-platform, runtime tiny (~250KB), PyTorch direto |
| MediaPipe LLM | Android, iOS, Web (WebGPU), Linux | .task | Integração Google, GPU delegate maduro, web first-class | |
| Core ML | Apple | iOS, macOS, watchOS, visionOS | .mlpackage | Apple-only, ANE total, App Store nativo |
| Apple Foundation | Apple | iOS 26+, macOS 15+ | Embarcado SO | Sem download, swift macros, gratuito |
| llama.cpp + bindings | Comunidade | Todas | .gguf | Flexibilidade total, modelos OSS abertos |
| Qualcomm QNN | Qualcomm | Android Snapdragon | .dlc | NPU Hexagon dedicado, latência mínima Android premium |
| MediaTek NeuroPilot | MediaTek | Android Dimensity | .dla | NPU MediaTek; mercado Asia/Europa |
| ONNX Runtime Mobile | Microsoft | iOS, Android, Web | .onnx | Polígrafo de formatos; menos otimizado em mobile que ET/MediaPipe |
Qual é a regra prática de tamanho para um modelo embarcado num aplicativo móvel?
Padrões de uso e arquitetura híbrida
Limites reais e armadilhas
Thermal throttling: gerar texto contínuo em mobile aquece. Após 2-5 minutos de uso sustentado, OS reduz freq → tok/s cai 30-50%. Mitigar com batches curtos, streaming, dar respiros.
Memória de KV cache: contexto de 4k tokens em Llama 3.2 3B INT4 já come ~600MB. Em mobile com 8GB RAM, isso pressiona o sistema. Use ctx-size enxuto (1-2k típico) ou KV cache quantizado quando suportado.
Bateria: inferência GPU sustentada consome 3-5W. 10 minutos contínuos = 5-8% da bateria. Apps devem usar com parcimônia ou em background com cota.
Perguntas frequentes
❓ Posso usar ExecuTorch e Core ML juntos?
❓ React Native ou Flutter têm bindings?
❓ Como atualizar modelo sem app update?
❓ Modelos com vision (multimodal) em mobile?
Referências
Fixando
Por que gerar texto continuamente num aparelho móvel degrada com o tempo?
O arcabouço da plataforma da Apple oferece geração guiada por esquema. Qual é o ganho para quem desenvolve?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…