LiteLLM – Gateway de IA

Saudações.

Esse tutorial é um guia rápido de instalação e uso do LiteLLM.

Descobri esse sistema ao investigar uma maneira de como resolver o LIMITE DE USO DO CLAUDE CODE por meio de balanceamento das requisições em várias chaves de API (contas diferentes obviamente).

Procurando prata, encontrei ouro!

De presente resolvi um segundo problema: Proteção de chaves de APIs. Antes eu precisava criar uma chave da API Anthropic para cada membro da equipe ou para cada agente de IA e controlar o uso, agora eu libero chaves do LiteLLM!

Links do projeto:

Pré-requisitos (constam em outros artigos aqui do blog):

  • Instalação do Linux (Debian);
  • Internet no servidor (sua VPS ou host);
  • Docker CE instalado;

1 – O que é o LiteLLM

O LiteLLM é um gateway para APIs de modelos de IA e serve como um midleware entre você e os serviços oficiais.

O conceito mais pontual seria “um proxy-reverso para modelos de IA“.

Ele te fornecerá uma URL de API para chamadas de IA em seus agentes e suas automações mas internamente ele fará o roteamento até os serviços oficiais (OpenAI ChatGPT, Anthropic Claude, OpenRouter, etc).

Visão geral:

Clientes de modelos de IA se conectam ao LiteLLM em vez de ir direto nos serviços de IA/LLM.

Recursos:

  • Redundância: Fallback de modelos transparente, se algum serviço sair do ar ele redireciona as chamadas para o próximo serviço disponível;
  • Balanceamento: Distribuir as chamadas entre vários servidores, especialmente útil para balancear custos em chaves de API e em servidores internos locais;
  • Contabilidade: Acompanhar o custo do uso de modelos, contabilizando consumo de tokens e valores ($);
  • Auditoria: Analisar profundamente as chamadas de API e analisar o conteúdo (prompts, contexto, tools, respostas);
  • Trabalho em equipe: Você pode criar chaves para cada membro da equipe e limitar o uso da chave e os serviços finais ela pode usar;
  • Provedor de IA: Você pode ser seu próprio provedor de APIs de IA, pendurando agentes, automações e sistemas no seu site.

2 – Preparando o Docker

Programas utilitários no HOST:

Bash
# yamllint - analise de sintaxe YAML / YML
which yamllint || apt-get -y install yamllint;

# jq - analise de JSON
which jq || apt-get -y install jq;

Vamos preparar o ambiente docker com a rede (network_public).

Bash
docker network create \
    -d bridge \
    \
    -o "com.docker.network.bridge.name"="br-net-public" \
    -o "com.docker.network.bridge.enable_icc"="true" \
    -o "com.docker.network.driver.mtu"="65495" \
    \
    --subnet 10.249.0.0/16 --gateway 10.249.255.254 \
    \
    network_public;

Vou usar a execução padrão do container Traefik. O container do Traefik se chamará “traefik-app“.

Personalize a variável EMAIL para que o LetsEncrypt funcione corretamente. Vou salvar o email de contato no arquivo /etc/email do host:

Bash
# Email de registro no letsencrypt
EMAIL="voce@seudominio.com.br";

# Gravar no arquivo para consulta
echo "$EMAIL" > /etc/email;

Rodando o Traefik:

Bash
#!/bin/sh

# Variaveis
  # - Nome do container
  NAME=traefik-app;
  
  # - Imagem do software traefik
  IMAGE=traefik:latest;
  
  # - Email de registro no letsencrypt
  EMAIL=$(head -1 /etc/email);

  # - Diretorio do volume (dados persistentes)
  DATADIR=/storage/$NAME;

# Preparar volume:
  mkdir -p $DATADIR/letsencrypt;
  mkdir -p $DATADIR/logs;
  mkdir -p $DATADIR/config;

# Obter imagem atualizada:
  docker pull $IMAGE;

# Remover instância atual:
  docker rm -f $NAME 2>/dev/null;

# Renovar/criar/rodar:
docker run \
    -d --restart=unless-stopped --name $NAME -h $NAME.intranet.br \
    \
    --network network_public \
    \
    -p 80:80 \
    -p 443:443 \
    \
    -v /var/run/docker.sock:/var/run/docker.sock:ro \
    -v $DATADIR/letsencrypt:/etc/letsencrypt \
    -v $DATADIR/config:/etc/traefik \
    -v $DATADIR/logs:/logs \
    \
    --tmpfs /run:rw,noexec,nosuid,size=16m \
    --tmpfs /tmp:rw,noexec,nosuid,size=16m \
    --read-only \
    \
    $IMAGE \
      \
      --global.checkNewVersion=false \
      --global.sendAnonymousUsage=false \
      \
      --api.insecure=true \
      \
      --log.level=INFO \
      --log.filePath=/logs/error.log \
      \
      --accessLog.filePath=/logs/access.log \
      \
      --entrypoints.web.address=:80 \
      --entrypoints.web.http.redirections.entryPoint.to=websecure \
      --entrypoints.web.http.redirections.entryPoint.scheme=https \
      --entrypoints.web.http.redirections.entryPoint.permanent=true \
      \
      --entrypoints.websecure.address=:443 \
      \
      --providers.docker=true \
      --providers.file.directory=/etc/traefik \
      \
      --certificatesresolvers.letsencrypt.acme.email=$EMAIL \
      --certificatesresolvers.letsencrypt.acme.storage=/etc/letsencrypt/acme.json \
      --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web;

3 – Banco de dados

O LiteLLM requer um banco de dados PostgreSQL para armazenamento de tarefas, logs, contabilidade, chaves e demais informações persistentes, o Redis é usado para cache e aceleração de operações.

3.1 – Postgres

Será necessário usar o Postgres com pgvector. Observe que iremos criar abaixo um container independente chamado pgvector-main:

Bash
# Variaveis
    NAME=pgvector-main;
    LOCAL=$NAME.intranet.br;

    # Argumentos do postgres
    POSTGRES_USER="postgres";
    POSTGRES_PASSWORD="tulipasql";
    POSTGRES_DB="admin";

# Imagem
    IMAGE="pgvector/pgvector:pg18-trixie";
    docker pull $IMAGE;

# Volume
    DATADIR=/storage/$NAME;
    mkdir -p $DATADIR;
    chown -R 999:999 $DATADIR;

# Renovar/rodar:
    docker rm -f $NAME 2>/dev/null;
    docker run \
        -d --restart=always \
        --name $NAME -h $LOCAL \
        --cpus="4.0" --memory=2g --memory-swap=2g --shm-size=1g \
        \
        --network network_public \
        \
        --tmpfs /run:rw,noexec,nosuid,size=64m \
        --tmpfs /tmp:rw,noexec,nosuid,size=64m \
        \
        -v $DATADIR:/var/lib/postgresql/data \
        \
        -e POSTGRES_USER=$POSTGRES_USER \
        -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \
        -e POSTGRES_DB=$POSTGRES_DB \
        -e PGDATA=/var/lib/postgresql/data/pgdata \
        \
        --health-cmd="pg_isready -U postgres" \
        --health-interval=5s \
        --health-timeout=5s \
        --health-retries=10 \
        \
        --entrypoint "docker-entrypoint.sh" \
        \
        $IMAGE \
            postgres \
                --max_connections=8192 \
                --wal_level=minimal \
                --max_wal_senders=0 \
                --port=5432;

# Acesso:
# docker exec -it pgvector-main psql -U postgres
#   \c  admin

Acesse o shell do PG no container pgvector-main criado acima para criar o usuário e o banco de dados:

Bash
# Preparar banco de dados
# - Entrar no shell postgres:
docker exec -it $DATABASE_HOST psql -U postgres;

No shell psql, execute os comandos SQL:

PostgreSQL Shell (psql)
-- Criar usuario:
CREATE USER litellm WITH PASSWORD 'tulipasql' LOGIN;

-- Criar banco de dados:
CREATE DATABASE litellm WITH OWNER = litellm
        ENCODING = 'UTF8'
        TABLESPACE = pg_default
        IS_TEMPLATE = False
        CONNECTION LIMIT = -1;

Para instruir o LiteLLM a acessar o PostgreSQL será necessário informar o acesso completo por meio da variável DATABASE_URL, exemplo:

Bash
export DATABASE_URL="postgresql://litellm:tulipasql@pgvector-main:5432/litellm";

3.2 – Redis

O Redis (ou Valkey) deve ser usado para cache de dados e contadores:

Bash
# Pasta de persistencia
    mkdir  -p /storage/redis-db;

# Renovar/rodar
    docker pull redis:latest;
    docker rm -f redis-db 2>/dev/null;
    docker run \
        -d --restart=always \
        --name redis-db -h redis-db.intranet.br \
        --read-only \
        --cpus="4.0" --memory=2g --memory-swap=2g --shm-size=1g \
        \
        --network network_public \
        \
        -v /storage/redis-db:/data \
        -w /data \
        \
        --health-cmd="redis-cli ping" \
        --health-interval=1s \
        --health-timeout=3s \
        \
        redis:latest \
            redis-server \
                --dir /data \
                --save 30 1 --save 20 10 --save 10 10000 \
                --rdbcompression no --rdbchecksum yes \
                --dbfilename "redis-db.rdb" \
                --appendonly yes --appendfsync everysec \
                --appendfilename "redis-db.aof";

4 – Implementando o LiteLLM no Docker

Para começar a usar plenamente, vamos definir as chaves de acesso para serviços de IA na nuvem.

4.1 – Diretório do volume

Pasta de volume do LiteLLM para armazenar as chaves:

Bash
# Pasta de volume do LiteLLM
DATADIR=/storage/litellm;

# Criar diretorio
mkdir -p $DATADIR;

# Sub-diretorio para logs:
mkdir -p $DATADIR/logs;

4.2 – Acesso ao banco de dados

Bash
# Pasta de volume do LiteLLM
DATADIR=/storage/litellm;

# URL de acesso ao banco de dados:
DATABASE_URL="postgresql://litellm:tulipasql@pgvector-main:5432/litellm";

# Colocar em arquivo dentro do volume:
echo "$DATABASE_URL" > $DATADIR/database_url;

# Ajustar permissoes:
chmod 600 $DATADIR/database_url;

# Visualizar url de acesso ao PG
echo "Acesso postgres.: $(head -1 $DATADIR/database_url)";

4.3 – Chaves de gestão

Para gerir o LiteLLM, precisamos de uma chave mestra:

Bash
# Pasta de volume do LiteLLM
DATADIR=/storage/litellm;


# Chave Mestra
#----------------------------------------------------------------

# Gravar:
if [ -f $DATADIR/litellm_master_key ]; then
    # Ja existe, nao alterar:
    echo "Chave mastra ja existe";
else
    # Gerar chave:
    echo "Craindo Chave mastra";
    MKEY="sk-$(head -1 /proc/sys/kernel/random/uuid)";
    echo "$MKEY" > $DATADIR/litellm_master_key;
fi;


# Chave Salt
#----------------------------------------------------------------

# Gravar:
if [ -f $DATADIR/litellm_salt_key ]; then
    # Ja existe, nao alterar:
    echo "Chave salt ja existe";
else
    # Gerar chave:
    echo "Craindo Chave salt";
    SKEY="sk-$(head -1 /proc/sys/kernel/random/uuid)";
    echo "$SKEY" > $DATADIR/litellm_salt_key;
fi;

# Ajustar permissoes:
chmod 600 $DATADIR/litellm_master_key;
chmod 600 $DATADIR/litellm_salt_key;


# Visualizar chaves
#----------------------------------------------------------------

echo "Chave mestra.: $(head -1 $DATADIR/litellm_master_key)";
echo "Chave salt...: $(head -1 $DATADIR/litellm_salt_key)";

4.4 – Arquivos com as chaves de API

Vou criar os arquivos dentro da pasta do volume contendo as chaves de API que iremos usar:

Obtenha as chaves desses serviços, se não possuir todos comece pelo OpenRouter.

Criando arquivos dentro do volume para puxar as chaves para o LiteLLM:

Bash
# Pasta de volume do LiteLLM
DATADIR=/storage/litellm;

# Troque o xxxx pela chave de API:
echo "xxxxxxxxxxxxx" > $DATADIR/openai_key;
echo "xxxxxxxxxxxxx" > $DATADIR/anthropic_key;
echo "xxxxxxxxxxxxx" > $DATADIR/ollama_key;
echo "xxxxxxxxxxxxx" > $DATADIR/openrouter_key;
echo "xxxxxxxxxxxxx" > $DATADIR/gemini_key;
echo "xxxxxxxxxxxxx" > $DATADIR/deepseek_key;
echo "xxxxxxxxxxxxx" > $DATADIR/xai_key;

# (eu uso as chaves gerais do meu servidor)
#	cat /etc/openai-key     > $DATADIR/openai_key;
#	cat /etc/anthropic-key  > $DATADIR/anthropic_key;
#	cat /etc/ollama-key     > $DATADIR/ollama_key;
#	cat /etc/openrouter-key > $DATADIR/openrouter_key;
#	cat /etc/gemini-key     > $DATADIR/gemini_key;
#	cat /etc/deepseek-key   > $DATADIR/deepseek_key;
#	cat /etc/xai-key        > $DATADIR/xai_key;

# Ajustar permissoes:
chmod 600 $DATADIR/*key;

4.5 – Configuração principal

A configuração principal orienta o LiteLLM de como prover modelos aos seus clientes e para quais serviços externos as chamadas de API devem ser encaminhadas.

Vou começar com uma configuração ampla que reune todos os serviços e todos os modelos, ideal para ambiente de testes e desenvolvimento de agentes.

Crie o arquivo dentro do volume (/storage/litellm) com o nome “config.yaml“.

Conteúdo:

YAML
general_settings:
  master_key: os.environ/LITELLM_MASTER_KEY
  database_url: os.environ/DATABASE_URL
  log_file_dir: "/data/logs"
  admin_ui_access_limit: 1000
  proxy_batch_write_at: 60
  store_model_in_db: true
  store_prompts_in_spend_logs: true

litellm_settings:
  num_retries: 2
  request_timeout: 20
  allowed_fails: 3
  check_provider_endpoint: true
  enable_cache: true
  cache: true
  cache_params:
    host: redis-db

router_settings:
  # simple-shuffle, least-busy, usage-based-routing,latency-based-routing
  routing_strategy: simple-shuffle
  redis_host: redis-db
  redis_port: 6379

# lista de modelos
model_list:
  # ======================== OPENAI (Wildcard)
  - model_name: "openai/*"
    litellm_params:
      model: "openai/*"
      api_key: os.environ/OPENAI_API_KEY
    model_info:
      access_groups: ["default-models"]
      description: "OpenAI - GPT models"

  # ======================== ANTHROPIC (Wildcard)
  - model_name: "anthropic/*"
    litellm_params:
      model: "anthropic/*"
      api_key: os.environ/ANTHROPIC_API_KEY
    model_info:
      access_groups: ["default-models"]
      description: "Anthropic - Claude models"

  # ======================== GOOGLE GEMINI (Wildcard)
  - model_name: "gemini/*"
    litellm_params:
      model: "gemini/*"
      api_key: os.environ/GEMINI_API_KEY
    model_info:
      access_groups: ["default-models"]
      description: "Google Gemini models"

  # ======================== DEEPSEEK (Wildcard)
  - model_name: "deepseek/*"
    litellm_params:
      model: "deepseek/*"
      api_key: os.environ/DEEPSEEK_API_KEY
    model_info:
      access_groups: ["default-models"]
      description: "DeepSeek models"

  # ======================== XAI GROK (Wildcard)
  - model_name: "xai/*"
    litellm_params:
      model: "xai/*"
      api_key: os.environ/XAI_API_KEY
    model_info:
      access_groups: ["default-models"]
      description: "XAI - Grok models"

  # ======================== OPENROUTER (Wildcard)
  - model_name: "openrouter/*"
    litellm_params:
      model: "openrouter/*"
      api_key: os.environ/OPENROUTER_API_KEY
    model_info:
      access_groups: ["default-models"]
      description: "OpenRouter - 300+ models"

Verifique erros de sintaxe YML no arquivo antes de continuar:

Bash
# Garantir instalacao do comando yamllint
which yamllint || apt-get -y install yamllint;

# Verificar configuracao sintaticamente:
yamllint /storage/litellm/config.yaml;

4.6 – DNS e URL pública

Você precisará criar um nome de DNS (FQDN) para seu container. Vou usar o nome litellm.seudominio.com.br como exemplo. Troque pelo nome que você criou.

4.7 – Criando o serviço

Um pré-requisito vital

Bash
# Variaveis
#----------------------------------------------------------------

    # Nome do container
    NAME=litellm;
    
    # Nome de DNS para acesso HTTPs (altere)
    FQDN="litellm.seudominio.com.br";

    IMAGE="docker.litellm.ai/berriai/litellm:main-latest";

  	# Pasta de volume
  	DATADIR=/storage/litellm;

    # URL de acesso do postgres
    DATABASE_URL=$(head -1 $DATADIR/database_url);

    # Usuario e senha de administracao (mude a senha)
    UI_USERNAME="admin";
    UI_PASSWORD="tulipa";


# Carregar chaves de API
#----------------------------------------------------------------

    # LiteLLM:
    LITELLM_MASTER_KEY=$(head -1 $DATADIR/litellm_master_key);
    LITELLM_SALT_KEY=$(head -1 $DATADIR/litellm_salt_key);

    # Provedores:
    XAI_API_KEY=$(head -1 $DATADIR/xai_key);
    OLLAMA_API_KEY=$(head -1 $DATADIR/ollama_key);
    GEMINI_API_KEY=$(head -1 $DATADIR/gemini_key);
    OPENAI_API_KEY=$(head -1 $DATADIR/openai_key);
    DEEPSEEK_API_KEY=$(head -1 $DATADIR/deepseek_key);
    ANTHROPIC_API_KEY=$(head -1 $DATADIR/anthropic_key);
    OPENROUTER_API_KEY=$(head -1 $DATADIR/openrouter_key);


  # Exibir chaves de acesso para conferir se faltou alguma:
#----------------------------------------------------------------

    echo;
    echo "LITELLM_MASTER_KEY....: $LITELLM_MASTER_KEY";
    echo "LITELLM_SALT_KEY......: $LITELLM_SALT_KEY";
    echo;
    echo "XAI_API_KEY...........: $XAI_API_KEY";
    echo "OLLAMA_API_KEY........: $OLLAMA_API_KEY";
    echo "GEMINI_API_KEY........: $GEMINI_API_KEY";
    echo "OPENAI_API_KEY........: $OPENAI_API_KEY";
    echo "DEEPSEEK_API_KEY......: $DEEPSEEK_API_KEY";
    echo "ANTHROPIC_API_KEY.....: $ANTHROPIC_API_KEY";
    echo "OPENROUTER_API_KEY....: $OPENROUTER_API_KEY";
    echo;


# Rodar/renovar/reiniciar
#----------------------------------------------------------------

    # Baixar imagem atualizada
    docker pull $IMAGE;

# Funcao para rodar/renovar
    # Argumentos:
    # 1 - nome do container
    # 2 - paramtros do container
    # 3 - comando para execucao
    _run(){
      docker rm -f $1 2>/dev/null;
      docker run \
        --name $1 -h $1.intranet.br \
        --cpus=4.0 --memory=2g --memory-swap=2g --shm-size=1g \
        \
        --network network_public \
        -p 4000:4000 \
        \
        --tmpfs "/run:rw,noexec,nosuid,size=64m" \
        --tmpfs "/tmp:rw,noexec,nosuid,size=64m" \
        \
        -v "$DATADIR:/data" \
        -v "$DATADIR/config.yaml:/app/config.yaml" \
        \
        \
        -e UI_USERNAME="admin" \
        -e UI_PASSWORD="tulipa@@" \
        \
        -e LITELLM_MASTER_KEY="$LITELLM_MASTER_KEY" \
        -e LITELLM_SALT_KEY="$LITELLM_SALT_KEY" \
        \
        -e SEPARATE_HEALTH_APP="1" \
        -e SEPARATE_HEALTH_PORT="4001" \
        \
        -e LITELLM_MODE="PRODUCTION" \
        -e LITELLM_LOG="ERROR" \
        \
        -e STORE_MODEL_IN_DB="True" \
        -e DATABASE_URL="$DATABASE_URL" \
        \
        -e REDIS_HOST="redis-db" \
        -e REDIS_PORT="6379" \
        \
        -e XAI_API_KEY="$XAI_API_KEY" \
        -e OLLAMA_API_KEY="$OLLAMA_API_KEY" \
        -e GEMINI_API_KEY="$GEMINI_API_KEY" \
        -e OPENAI_API_KEY="$OPENAI_API_KEY" \
        -e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
        -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
        -e OPENROUTER_API_KEY="$OPENROUTER_API_KEY" \
        \
        --health-cmd='curl -f http://localhost:4000/health/liveliness || exit 1' \
        --health-interval=30s \
        --health-timeout=10s \
        --health-retries=3 \
        --health-start-period=40s \
        \
        --label "traefik.enable=true" \
        --label "traefik.http.routers.$NAME.rule=Host(\`$FQDN\`)" \
        --label "traefik.http.routers.$NAME.entrypoints=websecure" \
        --label "traefik.http.routers.$NAME.tls=true" \
        --label "traefik.http.routers.$NAME.tls.certresolver=letsencrypt" \
        --label "traefik.http.services.$NAME.loadbalancer.server.port=4000" \
        \
        $2 \
        $IMAGE $3;
    };

    # Setup do banco de dados (roda e desaparece)
    _run \
        "litellm-setup" \
        "--rm -d -e USE_PRISMA_MIGRATE=True --entrypoint litellm" \
        "--skip_server_startup";

    # Rodar em producao
    ARG_1="--restart=always";
    ARG_2="-d -e DISABLE_SCHEMA_UPDATE=true";
    ARG_3="--entrypoint /app/docker/prod_entrypoint.sh";
    OPT_1="--config /app/config.yaml";
    OPT_2="--num_workers 4 --run_gunicorn";
    OPT_3="--max_requests_before_restart 256";
    _run "litellm" "$ARG_1 $ARG_2 $ARG_3" "$OPT_1 $OPT_2 $OPT_3";

    # Para debug, adicionar:
    # - Nos parametros do container
    #   -e LITELLM_LOG="DEBUG"
    # - Nos argumentos do comando:
    #   --detailed_debug

4.8 – Acesso web

A porta HTTP do container é 4000/tcp.

Acesse pelo nome usando HTTPs (via Traefik) ou pelo IP ou nome na porta HTTP 4000.

Endereços:

6 – Usando a API

Acesse a interface administrativa (/ui/) e crie uma “Virtual Key” para fazer uso das APIs de IA.

Nos exemplos abaixou, informe o endereço HTTP na variável URL e preencha sua “Virtual Key” na variável LK e faça os testes:

Bash
# Chaves
LK="sk-EhTt2MhBi4AsbBEyQ_W-fg";          #< altere
URL="https://litellm.seudominio.com.br"; # < altere

# Teste de keepalive
curl -sS $URL/health/liveliness && echo;
curl -sS $URL/health/readiness && echo;

# Lista de modelos
curl -X GET -H "Authorization: Bearer $LK" $URL/v1/models; echo;


# Teste de LLM
# GPT-4.1 mini  $0.40
# GPT-5 mini    $0.25
# GPT-4o mini   $0.15
# - gpt-4o
curl -X POST $URL/v1/chat/completions \
    -H "Authorization: Bearer $LK" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "gpt-4o",
    "messages": [{"role": "user", "content": "Quem é você? Resposta curta."}],
    "temperature": 0.7
    }';
# - gpt-4.1-nano
curl -X POST $URL/v1/chat/completions \
    -H "Authorization: Bearer $LK" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "gpt-4.1-nano",
    "messages": [{"role": "user", "content": "Quem é você? Resposta curta."}],
    "temperature": 0.7
    }';
# - gpt-5-nano (sem temperature, fix 1)
curl -X POST $URL/v1/chat/completions \
    -H "Authorization: Bearer $LK" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "gpt-5-nano",
    "messages": [{"role": "user", "content": "Quem é você? Resposta curta."}]
    }';
# - gpt-5-mini
curl -X POST $URL/v1/chat/completions \
    -H "Authorization: Bearer $LK" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "gpt-5-mini",
    "messages": [
        {"role": "system", "content": "Responda com o mínimo de palavras."},
        {"role": "user", "content": "Quem é você?"}
    ]
    }';

# - openrouter/openai/gpt-oss-20b
# -- stream ativo
curl -X POST $URL/v1/chat/completions \
    -H "Authorization: Bearer $LK" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "openrouter/openai/gpt-oss-20b",
    "messages": [{"role": "user", "content": "Quem é você? Resposta curta."}],
    "stream": true
    }';
# -- stream desativado
curl -X POST $URL/v1/chat/completions \
    -H "Authorization: Bearer $LK" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "openrouter/openai/gpt-oss-20b",
    "messages": [{"role": "user", "content": "Quem é você? Resposta curta."}]
    }';

# - gemini/gemini-flash-latest
curl -X POST $URL/v1/chat/completions \
    -H "Authorization: Bearer $LK" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "gemini/gemini-flash-latest",
    "messages": [{"role": "user", "content": "Quem é você? Resposta curta."}]
    }';

# - anthropic/claude-sonnet-4-6
curl -X POST $URL/v1/chat/completions \
    -H "Authorization: Bearer $LK" \
    -H "Content-Type: application/json" \
    -d '{
    "model": "anthropic/claude-sonnet-4-6",
    "messages": [{"role": "user", "content": "Quem é você? Resposta curta."}]
    }';

Um erro da largura de um fio de cabelo pode causar um desvio de mil quilômetros.
Provérbio Chinês

Terminamos por hoje!

Patrick Brandão, patrickbrandao@gmail.com