Voltar ao blog

Otimização de custosGuia

Linguagem natural para comando de shell com uma API de LLM: JSON e custo

Um script Python que pede a um modelo barato um comando de shell como JSON, recusa ou sinaliza pedidos incertos, nunca executa nada e precifica 1.000 requisições.

Por CheapTokens TeamPublicado em 7 min de leitura

Um pedido em linguagem comum transformado em um comando de shell em um objeto JSON com os tipos command, refuse e unsure
Nesta página
  1. Uma tarefa estreita: por que a resposta é curta
  2. O formato da resposta: comando, recusa ou incerteza
  3. O script
  4. Quanto custam 1.000 requisições
  5. Teste com seus próprios pedidos

Peça ao modelo um único objeto JSON com três campos (type, command, explanation), limite a resposta a algumas centenas de tokens e imprima o comando em vez de executá-lo. Em tokens, uma requisição assim é quase toda prompt com uma resposta curta e previsível: sob as premissas abaixo, 1.000 delas custam $0.012 no DeepSeek-V4-Flash.

Digamos que você esteja adicionando uma caixa "descreva o que você quer" a uma CLI interna. Alguém digita encontre arquivos maiores que 100 MB na minha pasta home, e você quer de volta uma linha que a pessoa possa ler, conferir e colar. Surgem duas perguntas: como impedir que o modelo chute ou faça algo perigoso, e quanto isso custa quando cem pessoas usam o dia todo?

Uma tarefa estreita: por que a resposta é curta#

Em 9 de novembro de 2026, um canal do Telegram repercutiu o model card do dale-0.8b, um modelo aberto que faz exatamente esse único trabalho. Segundo o model card no Hugging Face (verificado em 10 de novembro de 2026), o dale-0.8b é um fine-tune completo do Qwen3.5-0.8B sob Apache-2.0 que transforma um pedido em espanhol ou inglês em um comando bash Linux. O autor, Manuel García, relata 79,4% (374 de 471 casos) no próprio conjunto de teste, contra 62,8% do Qwen3.5-9B base e do Gemma 4 E4B-it sem fine-tuning. São números autorrelatados em um único conjunto de teste, então trate-os como um dado, não como um ranking.

O que é útil para nós é o formato da tarefa, não o modelo. O card descreve um system prompt fixo, uma linha de contexto (SO, distro, gerenciador de pacotes, ferramentas) mais o pedido, o raciocínio desligado e uma resposta limitada a 200 tokens. Esse limite é uma das duas alavancas de custo: quando a resposta é um único objeto JSON curto, o lado da saída é curto e previsível, porque o limite o restringe. A outra alavanca é o prompt. Qual parcela da conta cada lado representa, a tabela abaixo mostra; isso varia de modelo para modelo.

Você não precisa de um modelo 0.8B para isso. O mesmo formato funciona em qualquer modelo de API, e é isso que o restante deste artigo constrói.

O caminho de uma requisição: prompt entra, JSON sai, um humano decide
O fluxo da requisição no script: nada é executado até você mesmo fazer isso.

O formato da resposta: comando, recusa ou incerteza#

O truque é que o modelo sempre tem uma forma legítima de dizer "não". A resposta é um objeto:

json
{"type": "command | refuse | unsure", "command": "...", "explanation": "..."}
  • command: um comando bash, mais uma explicação de uma frase sobre o que ele faz.
  • refuse: o pedido é destrutivo ou não tem nada a ver com o shell. Nenhum comando.
  • unsure: o pedido é vago demais ("limpe meu disco"). A explicação contém uma pergunta de esclarecimento.

Sem unsure, um pedido vago força um chute, e um rm chutado é o que você lembra. O formato do card tem os mesmos três tipos; reutilizamos a ideia, não o modelo.

Emparelhar os pares

Relacione cada tipo de resposta ao que o script deve fazer

  • commandMostrar o comando e a explicação; a pessoa copia e executa por conta própria
  • refuseImprimir a explicação e não oferecer nada para executar
  • unsureImprimir a pergunta e deixar o usuário reformular

O script#

Um arquivo, o pacote openai, chave em uma variável de ambiente. A base URL e o id completo do modelo vêm da documentação do CheapTokens; ids curtos não são aceitos, então use deepseek-ai/DeepSeek-V4-Flash-0731.

python
import json
import os
import sys

from openai import OpenAI

client = OpenAI(
    base_url='https://api.cheaptokens.dev/v1',
    api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'deepseek-ai/DeepSeek-V4-Flash-0731'

SYSTEM = '''You turn a request into ONE Linux bash command.
Reply with a single JSON object and nothing else:
{"type": "command" | "refuse" | "unsure", "command": "<one command, or empty>", "explanation": "<one short sentence>"}
Use "refuse" when the request is destructive or not about the shell.
Use "unsure" when it is too vague, and put a clarifying question in "explanation".'''

CONTEXT = 'os: Ubuntu 24.04; package manager: apt; tools: git, curl, jq'


def parse(text):
    start = text.find('{')
    if start == -1:
        return None
    try:
        obj, _ = json.JSONDecoder().raw_decode(text[start:])
    except json.JSONDecodeError:
        return None
    if not isinstance(obj, dict) or obj.get('type') not in ('command', 'refuse', 'unsure'):
        return None
    return obj


def ask(request):
    resp = client.chat.completions.create(
        model=MODEL,
        max_tokens=200,
        temperature=0,
        messages=[
            {'role': 'system', 'content': SYSTEM},
            {'role': 'user', 'content': f'Context: {CONTEXT}\nRequest: {request}'},
        ],
    )
    return parse(resp.choices[0].message.content), resp.usage


if __name__ == '__main__':
    result, usage = ask(' '.join(sys.argv[1:]))
    if result is None:
        print('Could not read the reply as JSON. Try again.')
    elif result['type'] == 'command':
        print(result['explanation'])
        print('\n    ' + result['command'] + '\n')
        print('Read it, then copy it yourself. This script never runs it.')
    else:
        print(f"[{result['type']}] {result['explanation']}")
    print(f'tokens: {usage.prompt_tokens} in, {usage.completion_tokens} out')

Execute como python shellhelp.py find files bigger than 100 MB in my home folder. Três escolhas importam aqui:

  • Nenhum subprocess em lugar algum. O comando é texto na tela. Executá-lo é decisão sua, depois de lê-lo.
  • max_tokens=200, igual ao limite do card. Um objeto JSON cabe facilmente; uma resposta prolixa é cortada em 200 tokens em vez de continuar às suas custas. O limite se aplica à resposta inteira, então se um modelo escrever seu raciocínio, isso pode consumir o limite. Se alguma resposta terminar com finish_reason igual a length, aumente um pouco o limite. Mais sobre isso em cortando tokens de saída com max_tokens.
  • O formato é pedido no prompt e depois analisado defensivamente. raw_decode ignora uma cerca de código perdida ou uma frase antes do {. Se quiser ir além, veja JSON válido de uma API compatível com OpenAI e a correção para json.JSONDecodeError em uma resposta.

Antes de executar qualquer coisa, verifique se a ordem das etapas está clara:

Colocar em ordem

Coloque as etapas do script na ordem correta

  1. Montar o prompt: texto de sistema fixo, uma linha de contexto, o pedido
  2. Chamar a API com um max_tokens pequeno
  3. Analisar o JSON e verificar se type é um dos três
  4. Mostrar o comando e esperar que a pessoa o execute

Quanto custam 1.000 requisições#

A última linha do script imprime usage. Esse é o número real, e você deve ler o seu próprio. Até tê-lo, trabalhe com uma premissa: o prompt chega a cerca de 400 tokens de entrada (o prompt puro no script tem aproximadamente 150 tokens por uma contagem aproximada; o resto é espaço para os três ou quatro pares de exemplo de pedido e resposta que você provavelmente adicionaria), e a resposta JSON a cerca de 60 tokens de saída.

Para 1.000 requisições, isso dá 400 × 1.000 = 400.000 tokens de entrada e 60 × 1.000 = 60.000 tokens de saída. A tabela precifica exatamente isso para cada modelo do catálogo, com a coluna do OpenRouter ao lado; os números vêm de preços ao vivo, então permanecem atuais.

Modelo Por solicitação 1.000 solicitações OpenRouter, 1.000 solicitações
GLM-5.3-Flash $0.00001 $0.0104 $0.0184
DeepSeek-V4-Flash $0.000012 $0.012 $0.0364
MiniMax-M2.7 $0.000029 $0.029 $0.348

400 tokens de entrada e 60 tokens de saída por solicitação. Os preços por 1M de tokens são atuais e mudam junto com nossas tarifas; a coluna OpenRouter mostra preços de referência para a mesma carga de trabalho.

No total, somando entrada e saída, o DeepSeek-V4-Flash sai mais barato que o OpenRouter para essa carga de trabalho. Em tokens, a requisição é quase toda entrada e a resposta é curta, mas os dois lados são cobrados, então enxugue o prompt e a resposta igualmente. Os preços por modelo estão na página de preços, e o modelo em si é descrito na página do DeepSeek: contexto de 380K, até 32.768 tokens de saída, um preço a qualquer hora.

Uma forma rápida de sentir as proporções:

Verificação rápida

Qual parte da requisição o max_tokens=200 limita?

Mostrar resposta

Resposta: A resposta

max_tokens limita apenas a resposta; o prompt é cobrado como está, então enxugue-o separadamente.

Quer 100.000 requisições por mês? Multiplique por 100: 40.000.000 de entrada e 6.000.000 de saída. Coloque esses dois números em ::cost da mesma forma e leia a linha.

Teste com seus próprios pedidos#

Os 79,4% do card não dizem nada sobre o seu prompt, seu SO ou o jeito dos seus usuários. Escreva 20 pedidos reais com os comandos que você aceitaria e compare, exatamente como em testando um prompt em um pequeno conjunto de avaliação. Inclua alguns que o script deveria recusar ou sinalizar como incertos, como "apague tudo" ou "deixe meu computador mais rápido".

Quando algo dá errado, o sintoma geralmente aponta para a correção:

  • Could not read the reply as JSON: imprima o texto bruto uma vez. Um prefixo como "Sure!" é tratado; uma resposta cortada pelo limite não é, então verifique finish_reason.
  • 401 ou 404: chave, base URL ou id de modelo errados. A lista está em API 401 ou 404: chave, base URL, id do modelo.
  • Comandos que servem a outro sistema: a linha de contexto é a causa. Mantenha-a precisa (SO, gerenciador de pacotes, ferramentas); ela custa algumas dezenas de tokens e evita um apt errado em uma máquina Fedora.

Mesma tarefa, outro modelo? Troque MODEL pelo id do GLM ou MiniMax da documentação, mantenha o prompt e compare as contagens de tokens que o script imprime com a tabela acima.