Optymalizacja kosztówPrzewodnik
Język naturalny na polecenie powłoki z API LLM: JSON i koszt
Skrypt w Pythonie, który prosi tani model o jedno polecenie powłoki jako JSON, odrzuca lub oznacza niepewne żądania, nigdy niczego nie uruchamia i wycenia 1 000 żądań.

Na tej stronie
Poproś model o jeden obiekt JSON z trzema polami (type, command, explanation), ogranicz odpowiedź do kilkuset tokenów i wypisz polecenie zamiast je uruchamiać. Pod względem tokenów takie żądanie to głównie prompt z krótką, przewidywalną odpowiedzią: przy poniższych założeniach 1 000 z nich kosztuje $0.012 na DeepSeek-V4-Flash.
Załóżmy, że dodajesz do wewnętrznego CLI pole „opisz, czego chcesz”. Ktoś wpisuje znajdź pliki większe niż 100 MB w moim katalogu domowym i chcesz dostać z powrotem jedną linię, którą może przeczytać, sprawdzić i wkleić. Nasuwają się dwa pytania: jak powstrzymać model przed zgadywaniem lub zrobieniem czegoś niebezpiecznego i ile to kosztuje, gdy stu ludzi używa tego przez cały dzień?
Wąskie zadanie: dlaczego odpowiedź jest krótka#
9 listopada 2026 kanał na Telegramie przypomniał kartę modelu dale-0.8b, otwartego modelu, który robi dokładnie to jedno zadanie. Według karty modelu na Hugging Face (sprawdzonej 10 listopada 2026) dale-0.8b to pełny fine-tune Qwen3.5-0.8B na licencji Apache-2.0, który zamienia żądanie po hiszpańsku lub angielsku w jedno polecenie bash dla Linuksa. Autor, Manuel García, podaje 79,4% (374 z 471 przypadków) na własnym zbiorze testowym, wobec 62,8% dla bazowego Qwen3.5-9B i dla Gemma 4 E4B-it bez fine-tuningu. To liczby raportowane samodzielnie na zbiorze testowym jednej osoby, więc traktuj je jako punkt odniesienia, a nie ranking.
Dla nas przydatny jest kształt zadania, a nie model. Karta opisuje stały prompt systemowy, linię kontekstu (system, dystrybucja, menedżer pakietów, narzędzia) plus żądanie, wyłączone myślenie i odpowiedź ograniczoną do 200 tokenów. Ten limit to jedna z dwóch dźwigni kosztu: gdy odpowiedź to jeden krótki obiekt JSON, strona wyjściowa jest krótka i przewidywalna, bo limit ją ogranicza. Drugą dźwignią jest prompt. Jaki udział w rachunku ma każda ze stron, pokazuje poniższa tabela; różni się on w zależności od modelu.
Nie potrzebujesz do tego modelu 0.8B. Ten sam format działa na dowolnym modelu API i to właśnie buduje reszta tego artykułu.

Format odpowiedzi: polecenie, odmowa lub niepewność#
Sztuczka polega na tym, że model zawsze ma legalny sposób, by powiedzieć „nie”. Odpowiedź to jeden obiekt:
{"type": "command | refuse | unsure", "command": "...", "explanation": "..."}command: jedno polecenie bash plus jednozdaniowe wyjaśnienie, co robi.refuse: żądanie jest destrukcyjne lub nie ma nic wspólnego z powłoką. Brak polecenia.unsure: żądanie jest zbyt niejasne („posprzątaj mój dysk”). Wyjaśnienie zawiera pytanie doprecyzowujące.
Bez unsure niejasne żądanie wymusza zgadywanie, a zgadnięty rm to ten, który zapamiętasz. Format z karty ma te same trzy typy; wykorzystujemy pomysł, a nie model.
Dopasuj pary
Dopasuj każdy typ odpowiedzi do tego, co powinien zrobić skrypt
Dotknij element po lewej, a następnie jego parę
- commandPokaż polecenie i wyjaśnienie; osoba sama je kopiuje i uruchamia
- refuseWypisz wyjaśnienie i nie proponuj niczego do uruchomienia
- unsureWypisz pytanie i pozwól użytkownikowi przeformułować
Skrypt#
Jeden plik, pakiet openai, klucz w zmiennej środowiskowej. Bazowy URL i pełny identyfikator modelu pochodzą z dokumentacji CheapTokens; krótkie identyfikatory nie są akceptowane, więc użyj deepseek-.
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')Uruchom go jako python shellhelp.. Trzy wybory mają tu znaczenie:
- Nigdzie
subprocess. Polecenie to tekst na ekranie. Uruchomienie go to twoja decyzja, po przeczytaniu. max_tokens=200, tak jak limit z karty. Jeden obiekt JSON mieści się bez problemu; rozwlekła odpowiedź zostanie ucięta na 200 tokenach, zamiast ciągnąć się na twój koszt. Limit dotyczy całej odpowiedzi, więc jeśli model wypisze swoje rozumowanie, może to zjeść limit. Jeśli odpowiedź kiedykolwiek kończy się zfinish_reasonrównymlength, podnieś limit nieco. Więcej na ten temat w cięciu tokenów wyjściowych za pomocą max_tokens.- Format jest wymagany w prompcie, a potem parsowany defensywnie.
raw_decodepomija zabłąkowany blok kodu lub zdanie przed{. Jeśli chcesz pójść dalej, zobacz poprawny JSON z API zgodnego z OpenAI i poprawkę na json.JSONDecodeError przy odpowiedzi.
Zanim cokolwiek uruchomisz, sprawdź, czy kolejność kroków jest jasna:
Ustaw w kolejności
Ułóż kroki skryptu we właściwej kolejności
Przeciągnij elementy lub użyj strzałek
- Zbuduj prompt: stały tekst systemowy, linia kontekstu, żądanie
- Wywołaj API z małym max_tokens
- Sparsuj JSON i sprawdź, czy type jest jednym z trzech
- Pokaż polecenie i poczekaj, aż osoba je uruchomi
Ile kosztuje 1 000 żądań#
Ostatnia linia skryptu wypisuje usage. To jest prawdziwa liczba i powinieneś odczytać swoją własną. Dopóki jej nie masz, pracuj z założeniem: prompt to około 400 tokenów wejściowych (sam prompt w skrypcie to z grubsza 150 tokenów według przybliżonego liczenia; reszta to miejsce na trzy lub cztery przykładowe pary żądanie-odpowiedź, które prawdopodobnie dodasz), a odpowiedź JSON to około 60 tokenów wyjściowych.
Dla 1 000 żądań to 400 × 1 000 = 400 000 tokenów wejściowych i 60 × 1 000 = 60 000 tokenów wyjściowych. Tabela wycenia dokładnie to dla każdego modelu w katalogu, z kolumną OpenRouter obok; liczby pochodzą z aktualnych cen, więc pozostają aktualne.
| Model | Wejście $/1M | Wyjście $/1M | Za żądanie | 1000 żądań | OpenRouter, 1000 żądań |
|---|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.00001 | $0.0104 | $0.0184 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.000012 | $0.012 | $0.0364 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.000029 | $0.029 | $0.348 |
400 tokenów wejściowych i 60 tokenów wyjściowych na żądanie. Ceny za 1 mln tokenów są aktualne i zmieniają się wraz z naszymi taryfami; kolumna OpenRouter pokazuje ceny referencyjne dla tego samego obciążenia.
W sumie, licząc wejście i wyjście razem, DeepSeek-V4-Flash wypada taniej niż OpenRouter dla tego obciążenia. Pod względem tokenów żądanie to prawie samo wejście, a odpowiedź jest krótka, ale obie strony są rozliczane, więc przycinaj zarówno prompt, jak i odpowiedź. Ceny poszczególnych modeli są na stronie z cenami, a sam model jest opisany na stronie DeepSeek: kontekst 380K, do 32 768 tokenów wyjściowych, jedna cena o każdej porze.
Szybki sposób, by poczuć proporcje:
Szybkie sprawdzenie
Którą część żądania ogranicza max_tokens=200?
Pokaż odpowiedź
Odpowiedź: Odpowiedź
max_tokens ogranicza tylko odpowiedź; prompt jest rozliczany tak, jak jest, więc przycinaj go osobno.
Chcesz 100 000 żądań miesięcznie? Pomnóż przez 100: 40 000 000 wejściowych i 6 000 000 wyjściowych tokenów. Wstaw te dwie liczby do ::cost w ten sam sposób i odczytaj wiersz.
Sprawdź to na własnych żądaniach#
79,4% z karty nic nie mówi o twoim prompcie, twoim systemie ani sformułowaniach twoich użytkowników. Napisz 20 prawdziwych żądań z poleceniami, które byś zaakceptował, i porównaj, dokładnie jak w testowaniu promptu na małym zbiorze ewaluacyjnym. Dodaj kilka takich, które skrypt powinien odrzucić lub oznaczyć jako niepewne, na przykład „usuń wszystko” albo „przyspiesz mój komputer”.
Gdy coś pójdzie nie tak, objaw zwykle wskazuje poprawkę:
Could not read the reply as JSON: wypisz raz surowy tekst. Prefiks typu „Jasne!” jest obsługiwany; odpowiedź ucięta przez limit nie jest, więc sprawdźfinish_reason.401lub404: zły klucz, bazowy URL lub identyfikator modelu. Lista jest w API 401 lub 404: klucz, bazowy URL, identyfikator modelu.- Polecenia pasujące do innego systemu: przyczyną jest linia kontekstu. Utrzymuj ją dokładną (system, menedżer pakietów, narzędzia); kosztuje kilkadziesiąt tokenów i oszczędza błędny
aptna maszynie z Fedorą.
To samo zadanie, inny model? Zamień MODEL na identyfikator GLM lub MiniMax z dokumentacji, zachowaj prompt i porównaj liczby tokenów wypisywane przez skrypt z powyższą tabelą.



