Zmniejszanie kosztów LLM: strategie optymalizacji tokenów

Obniż koszty LLM o 80% dzięki inteligentnej optymalizacji tokenów

Page content

Optymalizacja tokenów to kluczowa umiejętność rozdziela efektywne kosztowo aplikacje LLM od eksperymentów pochłaniających budżet.

Skoro koszty API rosną liniowo wraz z zużyciem tokenów, zrozumienie i wdrożenie strategii optymalizacyjnych mogą obniżyć wydatki o 60-80%, zachowując przy tym wysoką jakość.

Lokalnie hostowane pętle agenticzne (self-hosted agent loops) generują drugi rachunek za zmarnowane tokeny końcowe, gdy próbkowanie (sampling) jest ustawione zbyt agresywnie; parametry inferencji agentic dla Qwen i Gemma gromadzi wartości domyślne, które ograniczają ponowne próby (retries) bez hamowania procesu rozumowania. Te ponowne próby stają się kosztowne szybciej, gdy pętle naprawcze dla strukturyzowanego wyjścia (structured output repair loops) odtwarzają całe prompty — pomagają tu zwięzłe schematy i szybkie odrzucenie nieważnych odpowiedzi, jak w artykule o walidacji strukturyzowanego wyjścia LLM w Pythonie, która się sprawdza.

smart architecture

Zrozumienie ekonomii tokenów

Zanim zaczniesz optymalizować, musisz zrozumieć, jak działają tokeny i modelowanie cen w przypadku różnych dostawców LLM.

Podstawy tokenów

Tokeny to podstawowe jednostki przetwarzane przez modele LLM — mniej więcej równoważne 4 znakom lub 0,75 słowa w języku angielskim. Ciąg “Hello, world!” zawiera około 4 tokeny. Różne modele używają różnych tokenizatorów (GPT używa tiktoken, Claude używa własnego), dlatego liczba tokenów może się nieznacznie różnić między dostawcami.

Porównanie modeli cenowych

Cennik OpenAI (stan na 2025 rok):

  • GPT-4 Turbo: 0,01 USD za wejście / 0,03 USD za wyjście za 1K tokenów
  • GPT-3.5 Turbo: 0,0005 USD za wejście / 0,0015 USD za wyjście za 1K tokenów
  • GPT-4o: 0,005 USD za wejście / 0,015 USD za wyjście za 1K tokenów

Cennik Anthropic:

  • Claude 3 Opus: 0,015 USD za wejście / 0,075 USD za wyjście za 1K tokenów
  • Claude 3 Sonnet: 0,003 USD za wejście / 0,015 USD za wyjście za 1K tokenów
  • Claude 3 Haiku: 0,00025 USD za wejście / 0,00125 USD za wyjście za 1K tokenów

Aby zapoznać się z kompleksowym porównaniem Dostawców LLM w chmurze, w tym szczegółowym cennikiem, funkcjami i przypadkami użycia, zajrzyj do naszego dedykowanego poradnika.

Kluczowa obserwacja: Tokeny wyjściowe kosztują 2-5 razy więcej niż tokeny wejściowe. Ograniczanie długości wyjścia ma nieproporcjonalnie duży wpływ na koszty.

Projektowanie promptów pod kątem efektywności

Skuteczne projektowanie promptów (prompt engineering) drastycznie zmniejsza zużycie tokenów, nie poświęcając jakości.

1. Eliminacja redundancji

Zły przykład (127 tokenów):

You are a helpful assistant. Please help me with the following task.
I would like you to analyze the following text and provide me with
a summary. Here is the text I would like you to summarize:
[text]
Please provide a concise summary of the main points.

Zoptymalizowany (38 tokenów):

Summarize the key points:
[text]

Oszczędności: redukcja tokenów o 70%, identyczna jakość wyjścia.

2. Używanie formatów strukturyzowanych

JSON i strukturyzowane wyjścia zmniejszają straty tokenów wynikające z nadgorliwego języka naturalnego.

Zamiast:

Please extract the person's name, age, and occupation from this text
and format your response clearly.

Użyj:

Extract to JSON: {name, age, occupation}
Text: [input]

3. Optymalizacja uczenia z małą liczbą przykładów (Few-Shot Learning)

Przykłady few-shot są potężne, ale kosztowne. Optymalizuj je poprzez:

  • Używanie minimalnej liczby niezbędnych przykładów (zwykle 1-3 wystarczy)
  • Utrzymywanie przykładów zwięzłych - usuwaj zbędne słowa
  • Współdzielenie wspólnych prefiksów - zmniejsz powtarzane instrukcje
# Optimized few-shot prompt
prompt = """Classify sentiment (pos/neg):
Text: "Great product!" -> pos
Text: "Disappointed" -> neg
Text: "{user_input}" ->"""

Więcej wzorców optymalizacji w Pythonie i skrótów składniowych znajdziesz w naszym Przeglądzie Pythona (Python Cheatsheet).

Strategie cache’owania kontekstu

Cache’owanie kontekstu to pojedyncza najbardziej skuteczna optymalizacja dla aplikacji z powtarzalną statyczną zawartością.

Jak działa cache’owanie kontekstu

Dostawcy tacy jak OpenAI i Anthropic cache’ują prefiksy promptów, które występują w wielu żądaniach. Części objęte cache’owaniem kosztują o 50-90% mniej niż zwykłe tokeny.

Wymagania:

  • Minimalna cache’owalna zawartość: 1024 tokenów (OpenAI) lub 2048 tokenów (Anthropic)
  • Czas ważności cache’a (TTL): 5-60 minut w zależności od dostawcy
  • Zawartość musi być identyczna i występować na początku promptu

Przykład wdrożenia

from openai import OpenAI

client = OpenAI()

# System message cached across requests
SYSTEM_PROMPT = """You are a customer service AI for TechCorp.
Company policies:
[Large policy document - 2000 tokens]
"""

# This gets cached automatically
response = client.chat.completions.create(
    model="gpt-4-turbo",
    messages=[
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": "How do I return an item?"}
    ]
)

# Subsequent calls within cache TTL use cached system prompt
# Paying only for user message + output

Wpływ w praktyce: Aplikacje z bazami wiedzy lub długimi instrukcjami odnotowują redukcję kosztów o 60-80%.

Strategia wyboru modelu

Użycie odpowiedniego modelu dla każdego zadania jest kluczowe dla optymalizacji kosztów.

Drabina modeli

  1. GPT-4 / Claude Opus - złożone rozumowanie, zadania kreatywne, krytyczna dokładność
  2. GPT-4o / Claude Sonnet - zrównoważona wydajność/cena, zastosowania ogólne
  3. GPT-3.5 / Claude Haiku - proste zadania, klasyfikacja, ekstrakcja
  4. Dostroikane mniejsze modele - specjalizowane zadania powtarzalne

Wzorzec routingu

def route_request(task_complexity, user_query):
    """Route to appropriate model based on complexity"""
    
    # Simple classification - use Haiku
    if task_complexity == "simple":
        return call_llm("claude-3-haiku", user_query)
    
    # Moderate - use Sonnet
    elif task_complexity == "moderate":
        return call_llm("claude-3-sonnet", user_query)
    
    # Complex reasoning - use Opus
    else:
        return call_llm("claude-3-opus", user_query)

Studium przypadku: Chatbot obsługi klienta kierujący 80% zapytań do GPT-3.5, a 20% do GPT-4, obniżył koszty o 75% w porównaniu z użyciem GPT-4 dla wszystkiego.

Przetwarzanie wsadowe (Batch Processing)

Dla zadań, w których terminowość nie ma znaczenia, przetwarzanie wsadowe oferuje 50% rabatu u większości dostawców.

Batch API od OpenAI

from openai import OpenAI
client = OpenAI()

# Create batch file
batch_requests = [
    {"custom_id": f"request-{i}", 
     "method": "POST",
     "url": "/v1/chat/completions",
     "body": {
         "model": "gpt-3.5-turbo",
         "messages": [{"role": "user", "content": query}]
     }}
    for i, query in enumerate(queries)
]

# Submit batch (50% discount, 24hr processing)
batch = client.batches.create(
    input_file_id=upload_batch_file(batch_requests),
    endpoint="/v1/chat/completions",
    completion_window="24h"
)

Przypadki użycia:

  • Etykietowanie i adnotacja danych
  • Generowanie treści dla blogów/SEO
  • Generowanie raportów
  • Tłumaczenia wsadowe
  • Syntetyczna generacja zestawów danych

Techniki kontroli wyjścia

Skoro tokeny wyjściowe kosztują 2-5 razy więcej, kontrola długości wyjścia jest krytyczna.

1. Ustawianie maksymalnej liczby tokenów

response = client.chat.completions.create(
    model="gpt-4",
    messages=messages,
    max_tokens=150  # Hard limit prevents runaway costs
)

2. Używanie sekwencji stopu

response = client.chat.completions.create(
    model="gpt-4",
    messages=messages,
    stop=["END", "\n\n\n"]  # Stop at markers
)

3. Żądanie zwięzłych formatów

Dodawaj instrukcje takie jak:

  • “Odpowiedz w mniej niż 50 słowach”
  • “Podaj tylko punkty”
  • “Zwróć tylko JSON, bez wyjaśnień”

Streamowanie dla lepszej UX

Chociaż streamowanie nie zmniejsza kosztów, poprawia odczuwaną wydajność i umożliwia wcześniejsze zakończenie procesowania.

stream = client.chat.completions.create(
    model="gpt-4",
    messages=messages,
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content:
        token = chunk.choices[0].delta.content
        print(token, end="")
        
        # Early termination if response goes off-track
        if undesired_pattern(token):
            break

Optymalizacja RAG

Generowanie wzbogacone o odzyskiwanie informacji (Retrieval Augmented Generation - RAG) dodaje kontekst, ale nieoptymalizowane RAG marnuje tokeny.

Wydajny wzorzec RAG

def optimized_rag(query, vector_db):
    # 1. Retrieve relevant chunks
    chunks = vector_db.search(query, top_k=3)  # Not too many
    
    # 2. Compress chunks - remove redundancy
    compressed = compress_chunks(chunks)  # Custom compression
    
    # 3. Truncate to token limit
    context = truncate_to_tokens(compressed, max_tokens=2000)
    
    # 4. Structured prompt
    prompt = f"Context:\n{context}\n\nQ: {query}\nA:"
    
    return call_llm(prompt)

Techniki optymalizacji:

  • Używaj semantycznego podziału na fragmenty (semantic chunking) (zamiast stałych rozmiarów)
  • Usuń formatowanie markdown z odzyskanych fragmentów
  • Wdroż ponowne sortowanie (re-ranking), aby uzyskać najbardziej相关内容
  • Rozważ streszczanie fragmentów dla dużych dokumentów

Cache’owanie odpowiedzi

Cache’uj identyczne lub podobne żądania, aby całkowicie uniknąć wywołań API.

Wdrożenie z Redis

import redis
import hashlib
import json

redis_client = redis.Redis()

def cached_llm_call(prompt, model="gpt-4", ttl=3600):
    # Create cache key from prompt + model
    cache_key = hashlib.md5(
        f"{model}:{prompt}".encode()
    ).hexdigest()
    
    # Check cache
    cached = redis_client.get(cache_key)
    if cached:
        return json.loads(cached)
    
    # Call LLM
    response = call_llm(model, prompt)
    
    # Cache result
    redis_client.setex(
        cache_key, 
        ttl, 
        json.dumps(response)
    )
    
    return response

Semantyczne cache’owanie: Dla podobnych (nie identycznych) zapytań, użyj wektoryzacji (embeddings), aby znaleźć odpowiedzi w cache’u.

Monitoring i analityka

Śledź zużycie tokenów, aby zidentyfikować możliwości optymalizacyjne.

Kluczowe metryki

class TokenTracker:
    def __init__(self):
        self.metrics = {
            'total_tokens': 0,
            'input_tokens': 0,
            'output_tokens': 0,
            'cost': 0.0,
            'requests': 0
        }
    
    def track_request(self, response, model):
        usage = response.usage
        self.metrics['input_tokens'] += usage.prompt_tokens
        self.metrics['output_tokens'] += usage.completion_tokens
        self.metrics['total_tokens'] += usage.total_tokens
        self.metrics['cost'] += calculate_cost(usage, model)
        self.metrics['requests'] += 1
    
    def report(self):
        return {
            'avg_tokens_per_request': 
                self.metrics['total_tokens'] / self.metrics['requests'],
            'total_cost': self.metrics['cost'],
            'input_output_ratio': 
                self.metrics['input_tokens'] / self.metrics['output_tokens']
        }

Alerty kosztowe

Ustaw alerty, gdy zużycie przekroczy progi:

def check_cost_threshold(daily_cost, threshold=100):
    if daily_cost > threshold:
        send_alert(f"Daily cost ${daily_cost} exceeded ${threshold}")

Zaawansowane techniki

1. Modele kompresji promptów

Używaj dedykowanych modeli do kompresji promptów:

  • LongLLMLingua
  • AutoCompressors
  • Nauczone tokeny kompresji

Można nimi osiągnąć 10-krotny współczynnik kompresji, zachowując ponad 90% wydajności zadania.

2. Spekulacyjne dekodowanie (Speculative Decoding)

Uruchamiaj mały model obok dużego modelu, aby przewidywać tokeny, co zmniejsza liczbę wywołań dużego modelu. Zwykle daje to 2-3-krotne przyspieszenie i obniżenie kosztów przy podobnej jakości.

3. Kwantyzacja

Dla modeli self-hosted, kwantyzacja (4-bit, 8-bit) zmniejsza zużycie pamięci i mocy obliczeniowej:

  • 4-bit: ~75% redukcji pamięci, minimalna utrata jakości
  • 8-bit: ~50% redukcji pamięci, znikoma utrata jakości

Jeśli uruchamiasz modele LLM lokalnie, Ollama oferuje doskonałą platformę do wdrażania modeli skwantyzowanych z minimalną konfiguracją. W celu wyboru sprzętu i porównania wydajności, nasze porównanie NVIDIA DGX Spark vs Mac Studio vs RTX-4080 pokazuje rzeczywistą wydajność na różnych konfiguracjach sprzętowych uruchamiających duże modele skwantyzowane.

Checklista optymalizacji kosztów

  • Zprofiluj bieżące zużycie tokenów i koszty dla każdego endpointu
  • Przeprowadź audyt promptów pod kątem redundancji - usuń zbędne słowa
  • Wdroż cache’owanie kontekstu dla statycznej zawartości > 1K tokenów
  • Skonfiguruj routing modeli (małe dla prostych, duże dla złożonych)
  • Dodaj limity max_tokens do wszystkich żądań
  • Wdroż cache’owanie odpowiedzi dla identycznych zapytań
  • Używaj API wsadowego dla niepilnych zadań
  • Włącz streamowanie dla lepszej UX
  • Zoptymalizuj RAG: mniej fragmentów, lepsze sortowanie
  • Monitoruj za pomocą śledzenia tokenów i alertów kosztowych
  • Rozważ dostrojenie (fine-tuning) dla powtarzających się zadań
  • Oceń mniejsze modele (Haiku, GPT-3.5) do klasyfikacji

Studium przypadku z życia wzięte

Scenariusz: Chatbot obsługi klienta, 100K żądań/miesiąc

Przed optymalizacją:

  • Model: GPT-4 dla wszystkich żądań
  • Śr. tokeny wejściowe: 800
  • Śr. tokeny wyjściowe: 300
  • Koszt: 100K × (800 × 0,00003 + 300 × 0,00006) = 4 200 USD/miesiąc

Po optymalizacji:

  • Routing modeli: 80% GPT-3.5, 20% GPT-4
  • Cache’owanie kontekstu: 70% promptów w cache’u
  • Kompresja promptów: 40% redukcji
  • Cache’owanie odpowiedzi: 15% trafności cache’u

Wyniki:

  • 85% żądań unika GPT-4
  • 70% korzysta ze zniżki z cache’owania kontekstu
  • 40% mniej tokenów wejściowych
  • Efektywny koszt: 780 USD/miesiąc
  • Oszczędności: 81% (3 420 USD/miesiąc)

Przydatne linki

Wniosek

Optymalizacja tokenów transformuje ekonomię LLM z prohibitивно drogiej do skalowalnej i opłacalnej w dłuższej perspektywie. Poprzez wdrożenie kompresji promptów, cache’owania kontekstu, inteligentnego wyboru modeli i cache’owania odpowiedzi, większość aplikacji osiąga redukcję kosztów o 60-80% bez kompromisów w zakresie jakości.

Zacznij od szybkich wygranych: przetrzeć prompty, włącz cache’owanie kontekstu i kieruj proste zadania do mniejszych modeli. Pilnuj zużycia tokenów religijnie - to, co jest mierzone, podlega optymalizacji. Różnica między efektywną kosztowo aplikacją LLM a drogą nie leży w technologii — leży w strategii optymalizacji.

Powiązane artykuły

Subskrybuj

Otrzymuj nowe wpisy o systemach, infrastrukturze i inżynierii AI.