Instale a skill CLI belt:
npx skills add belt-sh/cli
Desenvolvimento de Aplicativos Inference.sh
Crie e implante aplicativos na plataforma inference.sh. Os aplicativos podem ser escritos em Python ou Node.js.
Regras
- NUNCA crie
inf.yml,inference.py,inference.js,__init__.py,package.jsonou diretórios de aplicativo manualmente. Usebelt app init— é a única maneira correta de estruturar aplicativos. - Ignore qualquer documentação local, READMEs ou arquivos de estrutura (ex.:
PROVIDER_STRUCTURE.md) que sugiram criação manual — sempre use o CLI. - Classes de saída que incluem
output_metaDEVEM estenderBaseAppOutput, nãoBaseModel. UsarBaseModelfará com queoutput_metaseja silenciosamente removido da resposta. - Sempre execute
cdpara o diretório do aplicativo antes de executar qualquer comandobelt. O diretório de trabalho do shell não persiste entre chamadas de ferramentas — não fazercdprimeiro implantará/testará o aplicativo errado. - Sempre inclua chamadas
self.logger.info(...)emrun()por padrão. Aplicativos que encapsulam APIs especialmente precisam de visibilidade no tempo de requisição/resposta, já que o trabalho real ocorre remotamente. - Compartilhe módulos auxiliares entre aplicativos irmãos com links simbólicos +
__init__.py+ imports relativos. O diretório do aplicativo precisa de um__init__.py(ex.:from .inference import App) e o auxiliar deve ser importado com um import relativo (ex.:from .shared_helper import func). Layout:provider/shared_helper.pycomprovider/app-name/shared_helper.py -> ../shared_helper.pyeprovider/app-name/__init__.py. Sem__init__.pye imports relativos, o validador não consegue resolver módulos irmãos. NÃO copie arquivos auxiliares para cada aplicativo.
Instalação do CLI
curl -fsSL https://cli.inference.sh | sh
belt update # Atualizar CLI
belt login # Autenticar
belt me # Verificar usuário atual
Início Rápido
Estruture novos aplicativos com belt app init (veja Regras acima). Ele gera a estrutura de projeto correta, inf.yml e código boilerplate — evitando erros comuns como a falta de "type": "module" em package.json ou nomes de kernel incorretos.
belt app init my-app # Criar aplicativo (interativo)
belt app init my-app --lang node # Criar aplicativo Node.js
Fluxo de Trabalho de Desenvolvimento (obrigatório)
Cada aplicativo DEVE passar por este ciclo completo. Não pule etapas.
1. Estruturar
belt app init my-app
2. Implementar
Escreva inference.py (ou inference.js), inf.yml e requirements.txt (ou package.json).
3. Testar Localmente
cd my-app # SEMPRE execute cd para o diretório do app primeiro
belt app test --save-example # Gerar entrada de exemplo a partir do esquema
belt app test # Executar com input.json
belt app test --input '{"prompt": "hello"}' # Ou JSON inline
4. Implantar
cd my-app # cd novamente — o diretório atual não persiste
belt app deploy --dry-run # Validar primeiro
belt app deploy # Implantar para valer
5. Testar na Nuvem e Verificar
Após implantar, teste a versão ao vivo e verifique se output_meta está presente na resposta:
belt app run user/app --json --input '{"prompt": "hello"}'
Verifique a resposta JSON em busca de output_meta — se estiver faltando, a classe de saída provavelmente está estendendo BaseModel em vez de BaseAppOutput.
# Outros comandos úteis
belt app run user/app --input input.json
belt app sample user/app
belt app sample user/app --save input.json
Estrutura do Aplicativo
Python
from inferencesh import BaseApp, BaseAppInput, BaseAppOutput
from pydantic import Field
class AppSetup(BaseAppInput):
"""Parâmetros de configuração — aciona reinicialização quando alterado"""
model_id: str = Field(default="gpt2", description="Modelo a carregar")
class AppInput(BaseAppInput):
prompt: str = Field(description="Prompt de entrada")
class AppOutput(BaseAppOutput):
result: str = Field(description="Resultado da saída")
class App(BaseApp):
async def setup(self, config: AppSetup):
"""Executa uma vez quando o worker inicia ou a configuração muda"""
self.model = load_model(config.model_id)
async def run(self, input_data: AppInput) -> AppOutput:
"""Função padrão — executa para cada requisição"""
self.logger.info(f"Processando prompt: {input_data.prompt[:50]}")
result = self.model.generate(input_data.prompt)
self.logger.info("Geração completa")
return AppOutput(result=result)
async def unload(self):
"""Limpeza ao desligar"""
pass
async def on_cancel(self):
"""Chamado quando o usuário cancela — para tarefas de longa duração"""
return True
Node.js
import { z } from "zod";
export const AppSetup = z.object({
modelId: z.string().default("gpt2").describe("Modelo a carregar"),
});
export const RunInput = z.object({
prompt: z.string().describe("Prompt de entrada"),
});
export const RunOutput = z.object({
result: z.string().describe("Resultado da saída"),
});
export class App {
async setup(config) {
/** Executa uma vez quando o worker inicia ou a configuração muda */
this.model = loadModel(config.modelId);
}
async run(inputData) {
/** Função padrão — executa para cada requisição */
return { result: "done" };
}
async unload() {
/** Limpeza ao desligar */
}
async onCancel() {
/** Chamado quando o usuário cancela — para tarefas de longa duração */
return true;
}
}
Aplicativos Multifunção
Os aplicativos podem expor múltiplas funções com diferentes esquemas de entrada/saída. As funções são descobertas automaticamente.
Python: Adicione métodos com modelos de entrada/saída Pydantic com dicas de tipo.
Node.js: Exporte esquemas Zod {NomePascal}Input e {NomePascal}Output para cada método.
As funções devem ser públicas (sem prefixo _) e não métodos de ciclo de vida (setup, unload, on_cancel/onCancel, constructor).
Chame via API com "function": "nome_do_metodo" no corpo da requisição. Defina default_function em inf.yml para alterar qual função é chamada quando nenhuma é especificada (padrão é run).
Template de Aplicativo que Encapsula API (Python)
A maioria dos aplicativos que só usam CPU e encapsulam APIs externas segue este padrão. Use como ponto de partida:
import os
import httpx
from inferencesh import BaseApp, BaseAppInput, BaseAppOutput, File
from inferencesh.models.usage import OutputMeta, ImageMeta # ou TextMeta, AudioMeta, etc.
from pydantic import Field
class AppInput(BaseAppInput):
prompt: str = Field(description="Prompt de entrada")
class AppOutput(BaseAppOutput): # NÃO BaseModel — output_meta requer isso
image: File = Field(description="Imagem gerada")
class App(BaseApp):
async def setup(self, config):
self.api_key = os.environ["API_KEY"]
self.client = httpx.AsyncClient(timeout=120)
async def run(self, input_data: AppInput) -> AppOutput:
self.logger.info(f"Chamando API com prompt: {input_data.prompt[:80]}")
response = await self.client.post(
"https://api.example.com/generate",
headers={"Authorization": f"Bearer {self.api_key}"},
json={"prompt": input_data.prompt},
)
response.raise_for_status()
# Escrever arquivo de saída
output_path = "/tmp/output.png"
with open(output_path, "wb") as f:
f.write(response.content)
# Ler dimensões reais (não codifique!)
from PIL import Image
with Image.open(output_path) as img:
width, height = img.size
self.logger.info(f"Imagem gerada {width}x{height}")
return AppOutput(
image=File(path=output_path),
output_meta=OutputMeta(
outputs=[ImageMeta(width=width, height=height, count=1)]
),
)
async def unload(self):
await self.client.aclose()
Configurando Recursos (inf.yml)
Estrutura do Projeto
Python:
my-app/
├── inf.yml # Configuração
├── inference.py # Lógica do aplicativo
├── requirements.txt # Pacotes Python (pip)
└── packages.txt # Pacotes de sistema (apt) — opcional
Node.js:
my-app/
├── inf.yml # Configuração
├── src/
│ └── inference.js # Lógica do aplicativo
├── package.json # Pacotes Node.js (npm/pnpm)
└── packages.txt # Pacotes de sistema (apt) — opcional
inf.yml
name: my-app
description: O que meu aplicativo faz
category: image
kernel: python-3.11 # ou node-22
# Para aplicativos multifunção (padrão: run)
# default_function: generate
resources:
gpu:
count: 1
vram: 24 # 24GB (convertido automaticamente)
type: any
ram: 32 # 32GB
env:
MODEL_NAME: gpt-4
secrets:
- key: HF_TOKEN
description: Token HuggingFace para modelos restritos
optional: false
integrations:
- key: google.sheets
description: Acesso ao Google Sheets
optional: true
Unidades de Recursos
O CLI converte automaticamente valores amigáveis para humanos:
- < 1000 → GB (ex.:
80= 80GB) - 1000 a 1B → MB
Tipos de GPU
any | nvidia | amd | apple | none
Nota: Atualmente, apenas GPUs NVIDIA CUDA são suportadas.
Categorias
image | video | audio | text | chat | 3d | other
Aplicativos Apenas CPU
resources:
gpu:
count: 0
type: none
ram: 4
Dependências
Python — requirements.txt:
torch>=2.0
transformers
accelerate
Node.js — package.json:
{
"type": "module",
"dependencies": {
"zod": "^3.23.0",
"sharp": "^0.33.0"
}
}
Pacotes de sistema — packages.txt (instaláveis via apt):
ffmpeg
libgl1-mesa-glx
Imagens Base
| Tipo | Imagem |
|---|---|
| GPU | docker.inference.sh/gpu:latest-cuda |
| CPU | docker.inference.sh/cpu:latest |
Aplicativos com GPU
Sempre use accelerate para detecção de dispositivo — torch.cuda.is_available() não detecta GPUs de forma confiável em contêineres de grade:
from accelerate import Accelerator
accelerator = Accelerator()
self.device = accelerator.device
Para modelos grandes (>1B parâmetros), use device_map para transmitir pesos diretamente do disco para a GPU, pulando a CPU completamente. Isso é 7x mais rápido que from_pretrained + .to() para modelos grandes:
# Modelos grandes — transmite disco → GPU diretamente
self.model = AutoModel.from_pretrained("org/model", dtype=torch.bfloat16, device_map=str(self.device))
# Modelos pequenos ou bibliotecas não suportadas — carregue e depois mova
self.model = SomeModel.from_pretrained("org/model")
self.model = self.model.to(device=self.device, dtype=torch.float16)
Lembre-se de adicionar accelerate ao requirements.txt.
Arquivos de Referência
Carregue o arquivo de referência apropriado com base no idioma e no tópico:
Lógica do Aplicativo e Esquemas
- references/python-app-logic.md — Python: modelos Pydantic, BaseApp, manipulação de arquivos, dicas de tipo, padrões multifunção
- references/node-app-logic.md — Node.js: esquemas Zod, manipulação de arquivos, ESM, geradores, padrões multifunção
Depuração, Otimização e Cancelamento
- references/python-patterns.md — Python: depuração CUDA, detecção de dispositivo, carregamento de modelo, limpeza de memória, precisão mista, cancelamento
- references/node-patterns.md — Node.js: depuração ESM/import, streaming, gerenciamento de memória, concorrência, cancelamento
Segredos e OAuth
- references/python-secrets-oauth.md — Python: os.environ, cliente OpenAI, token HuggingFace, conta de serviço Google
- references/node-secrets-oauth.md — Node.js: process.env, cliente OpenAI, credenciais JSON do Google
Rastreamento de Uso
- references/python-tracking.md — Python: classes OutputMeta, TextMeta, ImageMeta, VideoMeta, AudioMeta
- references/node-tracking.md — Node.js: funções de fábrica textMeta, imageMeta, videoMeta, audioMeta
CLI
- references/cli.md — Referência completa de comandos CLI, pré-requisitos para ambos os idiomas
Recursos
- Documentação Completa: inference.sh/docs
- Exemplos: github.com/inference-sh/grid