Gymnasia: arquitetura de um agente de IA que roda no celular

Gymnasia: arquitetura de um agente de IA que roda no celular

O que é o Gymnasialink image

O Gymnasia é um aplicativo móvel de treino pessoal feito com React Native e Expo. Dentro dele há dois agentes de IA: um coach conversacional e um subagente de visão que estima calorias e macronutrientes a partir de fotos de comida.

O interessante, e o assunto deste post, é que os dois são executados inteiramente no dispositivo. Não existe backend próprio: a orquestração, as ferramentas e o armazenamento vivem em App.tsx e no AsyncStorage, e as chaves de API são fornecidas pelo usuário. Os dados do usuário nunca saem do celular, com uma única exceção explicada mais abaixo.

Este é o post principal da série. Abaixo estão os dois grafos de arquitetura e, no final, o índice da série com os posts que cobrem cada parte do desenvolvimento.

O agente geral: Gymnasia Coachlink image

Nós = passos e decisões, linhas = passagem de dados. O ciclo tracejado claro é o laço agentic de uso de ferramentas; a linha vermelha tracejada é a única chamada que sai para um serviço externo diferente do fornecedor de LLM.
sim não create_feature_issue repete com tool_result
Utilizador (chat)
System promptGitHub AGENTS.md + cache local
Fornecedor ativoBYOK · 1 de 3 (is_active)
Chamada ao modelostreaming SSE/XHR
Pede para usar uma ferramenta?
handleToolCall()12 ferramentas, 100% local
Resposta finalao utilizador, em streaming
AsyncStoragedieta · rotinas · medidas · memória
GitHub Issues APIúnico destino externo

Deslize o grafo na horizontal para o ver inteiro.

Fluxo normal Laço agentic (tool result → modelo) Chamada externa (não LLM)

O Gymnasia Coach é o agente conversacional geral do app, o da aba Chat IA. É um agente BYOK (Bring Your Own Key): o utilizador configura a sua própria chave de API da OpenAI, Anthropic ou Google, e o app chama diretamente o fornecedor escolhido a partir do dispositivo. Não existe backend próprio: toda a lógica de orquestração, ferramentas e armazenamento vive em App.tsx e no AsyncStorage local.

Configuração e fornecedor ativolink image

Definições BYOK

O utilizador guarda a sua API key

Uma das 3 chaves (OpenAI / Anthropic / Google) é marcada como is_active. Só essa é usada no chat geral.

SecureStore / AsyncStorage
System prompt remoto

prompts/AGENTS.md no GitHub

É descarregado de raw.githubusercontent.com/maximofn/gymnasia, guardado em cache local e recorre a um prompt por omissão embutido se a rede falhar.

Editável sem publicar o app

Chamada ao fornecedorlink image

OpenAIResponses API · streaming SSE/XHR
AnthropicMessages API · thinking ativado
GoogleGemini generateContent

Cada fornecedor tem o seu próprio adaptador de request/response, porque os formatos de tools, de streaming e de blocos de conteúdo são diferentes nos três. Mas partilham o mesmo laço agentic que vem a seguir.

Laço agentic (tool use)link image

Passo 1

O modelo responde

Texto em streaming e/ou blocos tool_use / function_call.

Passo 2

handleToolCall()

Executa 100% localmente sobre o estado do app (AsyncStorage, repositórios JSON).

Passo 3

Resultado → modelo

É reinjetado como tool_result / function_call_output. Repete-se até não pedir mais ferramentas.

As 12 ferramentaslink image

🧠 Memória pessoal
list_personal_data_keysLista as chaves de dados pessoais guardadas do utilizador.
read_field_descriptionLê a descrição de um campo antes de o interpretar.
read_field_valueLê o valor de um campo concreto (por exemplo nome ou objetivo).
save_personal_dataGuarda ou atualiza um array de campos {key, description, value}.
🍽️ Dieta
search_foodsProcura no repositório JSON de alimentos por nome, categoria ou intervalo de macros.
read_meal_foodsLê os alimentos já registados numa refeição e data.
add_meal_foodAdiciona um alimento (gramas + macros) a uma refeição e data concretas.
🏋️ Treino
search_exercisesProcura exercícios por músculo, equipamento ou dificuldade no repositório local.
read_routinesLê as rotinas (templates) já criadas pelo utilizador.
create_routineCria uma rotina nova e liga imagens de exercício pelo nome exato do repositório.
📏 Medidas e meta
read_measurement / write_measurementLê ou guarda medidas corporais (peso, % de gordura, perímetros) por data.
create_feature_issueA única ferramenta que sai do dispositivo: cria um issue no GitHub (maximofn/gymnasia) quando deteta um pedido de melhoria.

Armazenamento e saídalink image

Sem base de dados

LocalStore (AsyncStorage)

Dieta, rotinas, medidas e dados pessoais vivem no dispositivo. Os repositórios de alimentos e exercícios são JSON estáticos empacotados com o app.

Exceção

GitHub Issues API

Único ponto de saída para um serviço externo diferente do fornecedor de LLM: create_feature_issue.

Externo
Ressalva de plataforma: no navegador, a Anthropic exige um proxy CORS local (apps/anthropic_proxy/cors-proxy.py) porque o navegador bloqueia a chamada direta a api.anthropic.com. OpenAI e Google funcionam diretamente a partir do navegador.

O subagente de visão: Food Estimatorlink image

Nós = passos e decisões, linhas = passagem de dados. O ciclo tracejado claro é o laço agentic de uso de ferramentas; a linha tracejada escura é a rota alternativa sem foto.
sim não repete com tool_result alternativa sem foto
Utilizador1–6 fotos + texto opcional
System promptFood Estimator (visão)
Seleção por prioridadeGoogle → OpenAI → Anthropic
O modelo analisa imagens
Deteta código de barras?
scan_barcode()→ OpenFoodFacts API
Estimativatexto livre ou JSON se pedido
Confirmação do utilizadorrequestStructuredNutritionJSON
add_meal_food()→ Dieta local (AsyncStorage)
MiniChat manualFOOD_AI_SYSTEM_PROMPT, sem fotos

Deslize o grafo na horizontal para o ver inteiro.

Fluxo normal Laço agentic (tool result → modelo) Rota alternativa

O Food Estimator é o subagente de visão que estima calorias e macros a partir de fotos de comida (aba Dieta → Estimativa IA). É independente do chat geral: tem o seu próprio system prompt, a sua própria ferramenta e a sua própria política de seleção de fornecedor.

Entradalink image

Input do utilizador

1–6 fotos da refeição

Câmara ou galeria. Também aceita texto (perguntas de seguimento sobre a estimativa), reutilizando o contexto da conversa.

Seleção de fornecedor por prioridadelink image

Ao contrário do chat geral, aqui não se usa o fornecedor ativo: tenta-se por ordem até encontrar o primeiro com chave de API configurada.

1GoogleGemini · visão
2OpenAIResponses API · visão
3AnthropicNão aceita imagens na web

System prompt especializadolink image

Nutricionista visual

Estima sempre kcal, proteína (g), hidratos de carbono (g), gordura (g) e peso total (g). Dá intervalos se houver incerteza.

Classificação

Determina se é producto_comercial, receta ou alimento base genérico.

Saída estruturada

Se o utilizador pedir "Devuelve json", responde apenas com JSON: dish_name, calories_kcal, protein_g, carbs_g, fat_g.

Laço agentic com o código de barraslink image

Deteção

Há um código de barras na foto?

O prompt obriga o modelo a usar a ferramenta se detetar um EAN/UPC em qualquer das imagens.

Única tool

scan_barcode(barcode)

Chama o OpenFoodFacts (API pública) com o código lido e devolve dados nutricionais exatos do produto.

Externo · world.openfoodfacts.org

Produto comercial confirmado

Se foi usado scan_barcode, a classificação é sempre producto_comercial, com dados exatos em vez de estimados.

Tal como no agente geral, o resultado da ferramenta é reinjetado no modelo e o laço repete-se, com um máximo de 5 rondas, até obter uma resposta final.

Persistência do resultadolink image

requestStructuredNutritionJSON

Confirmação do utilizador

Quando o utilizador aceita a estimativa, é pedido o bloco JSON final e feito o parse.

add_meal_food

É adicionado à dieta local do dia e refeição selecionados, no mesmo store que o agente geral usa.

Variante: estimativa manuallink image

MiniChat · FOOD_AI_SYSTEM_PROMPT

O utilizador descreve um alimento por texto

Fluxo conversacional: o utilizador nomeia o alimento, o modelo pergunta ingredientes e quantidades em falta, calcula valores por 100 g ou unidade, o utilizador confirma e devolve o JSON para guardar no repositório de alimentos.

Sem ferramentas · sem imagens
Decisão de design: o Food Estimator dá prioridade ao fornecedor com melhor relação custo/qualidade em visão (Google primeiro) em vez de usar o fornecedor ativo do utilizador, porque a estimativa por fotos é a operação mais frequente e mais sensível ao custo do app.

A sérielink image

Este post é a capa. Cada parte do desenvolvimento do agente tem o seu próprio post, e todos são ligados a partir daqui.

  • Ainda não há posts publicados na série. Os primeiros serão o de planeamento e o de tool calling.

Entretanto, a página do projeto está em maximofn.com/pt-br/gymnasia e o código é aberto, no GitHub.

Continuar lendo

Últimos posts -->

Você viu esses projetos?

Gymnasia

Gymnasia Gymnasia
Expo
React Native
TypeScript
OpenAI
Anthropic

App de fitness com dois agentes que são executados integralmente no dispositivo, sem backend, de forma que os dados do usuário nunca saem do celular. Um coach conversacional BYOK com adaptadores para OpenAI, Anthropic e Google, 12 tools locais e system prompt remoto com fallback offline, e um subagente de visão que estima macronutrientes a partir de fotos de comida, com leitura de códigos de barras contra o OpenFoodFacts.

LangGraph Deep Researcher

LangGraph Deep Researcher LangGraph Deep Researcher
Python
LangGraph
FastAPI
React
TypeScript
Docker

Sistema multiagente de pesquisa construído com LangGraph. Um supervisor decompõe sua pergunta em tópicos e lança subagentes de busca em paralelo; cada um comprime seus achados antes de repassá-los a um agente redator que escreve o relatório final em markdown com suas fontes. Streaming ao vivo por WebSockets, modelo configurável por papel e chaves de API próprias que nunca são armazenadas no servidor.

Tau

Tau Tau
Python
LangChain

Sistema multiagente de tutoria para estudantes do ensino médio, com um agente por disciplina e material de curso elaborado e validado por uma equipe de professores. Chegou a ser usado com alunos reais em um colégio privado na Espanha e em uma escola de ensino médio na Colômbia.

Ver todos os projetos -->
>_ Disponível para projetos

Tem um projeto com IA?

Vamos conversar.

maximofn@gmail.com

Especialista em Machine Learning e Inteligência Artificial. Desenvolvo soluções com IA generativa, agentes inteligentes e modelos personalizados.

Quer assistir alguma palestra?

Últimas palestras -->

Quer melhorar com essas dicas?

Últimos tips -->

Use isso localmente

Os espaços do Hugging Face nos permitem executar modelos com demos muito simples, mas e se a demo quebrar? Ou se o usuário a deletar? Por isso, criei contêineres docker com alguns espaços interessantes, para poder usá-los localmente, aconteça o que acontecer. Na verdade, se você clicar em qualquer botão de visualização de projeto, ele pode levá-lo a um espaço que não funciona.

Flow edit

Flow edit Flow edit

Edite imagens com este modelo de Flow. Baseado em SD3 ou FLUX, você pode editar qualquer imagem e gerar novas

FLUX.1-RealismLora

FLUX.1-RealismLora FLUX.1-RealismLora
Ver todos os contêineres -->
>_ Disponível para projetos

Tem um projeto com IA?

Vamos conversar.

maximofn@gmail.com

Especialista em Machine Learning e Inteligência Artificial. Desenvolvo soluções com IA generativa, agentes inteligentes e modelos personalizados.

Você quer treinar seu modelo com esses datasets?

short-jokes-dataset

HuggingFace

Dataset com piadas em inglês

Uso: Fine-tuning de modelos de geração de texto humorístico

231K linhas 2 colunas 45 MB
Ver no HuggingFace →

opus100

HuggingFace

Dataset com traduções de inglês para espanhol

Uso: Treinamento de modelos de tradução inglês-espanhol

1M linhas 2 colunas 210 MB
Ver no HuggingFace →

netflix_titles

HuggingFace

Dataset com filmes e séries da Netflix

Uso: Análise de catálogo Netflix e sistemas de recomendação

8.8K linhas 12 colunas 3.5 MB
Ver no HuggingFace →
Ver mais datasets -->