Powrót do bloga

Optymalizacja kosztówPrzewodnik

Przycinaj historię rozmowy, aby obniżyć koszty: okno przesuwne czy podsumowanie

Ogranicz to, co wysyłasz ponownie w każdej turze: zachowaj kilka ostatnich wiadomości lub krótkie podsumowanie. Arytmetyka tokenów dla 50-turowej rozmowy i helper w Pythonie.

Autor: CheapTokens TeamOpublikowano 6 min czytania

Okładka: utrzymaj długą rozmowę tanio, z helperem trim_history
Na tej stronie
  1. Co faktycznie wysyła tura 50
  2. Opcja 1: okno przesuwne
  3. Opcja 2: podsumowanie starych tur
  4. Ile kosztują trzy konfiguracje
  5. Co wybrać

Twój bot wsparcia prowadzi rozmowę od 50 tur, a każda nowa wiadomość kosztuje więcej niż poprzednia. API niczego nie pamięta, więc twój kod przy każdym wywołaniu wysyła całą rozmowę od nowa. Rozwiązaniem jest ograniczenie tego, co wysyłasz: zachowaj system prompt i kilka ostatnich tur (okno przesuwne) albo zamień stare tury na krótkie podsumowanie. Poniżej arytmetyka dla 50-turowej rozmowy i gotowy do skopiowania helper.

Przewodnik DeepSeek po rozmowach wieloturówych (api-docs.deepseek.com, sprawdzony 1 listopada 2026) mówi to wprost: serwer nie zapisuje kontekstu wcześniejszych żądań, więc klient przy każdym wywołaniu wysyła pełną listę messages. Format zgodny z OpenAI na CheapTokens działa tak samo. Jeśli to dla ciebie nowość, zacznij od dlaczego długa rozmowa kosztuje więcej i jak działa tablica messages.

Co faktycznie wysyła tura 50#

Załóżmy, że prowadzisz bota wsparcia z system promptem o długości 400 tokenów. W typowej turze użytkownik pisze około 60 tokenów, a bot odpowiada około 190. Jedna pełna tura dodaje do historii 250 tokenów. To założenia: zastąp je liczbami z pola usage własnych odpowiedzi.

W turze 50 żądanie niesie system prompt, 49 wcześniejszych tur i nową wiadomość: 400 + 49 × 250 + 60 = 12,710 tokenów wejściowych, żeby dostać odpowiedź o długości 190 tokenów. Zsumuj całą rozmowę. System prompt i nowa wiadomość są wysyłane za każdym razem: 50 × 460 = 23,000. Powtarzana historia dodaje 250 × 1,225 = 306,250. Razem: 23,000 + 306,250 = 329,250 tokenów wejściowych wobec 50 × 190 = 9,500 tokenów wyjściowych.

Historia w każdym żądaniu rośnie o jedną turę, więc suma rośnie z kwadratem długości rozmowy. Przejdź z 50 do 100 tur, a część z powtarzaną historią wzrośnie mniej więcej czterokrotnie.

Spróbuj samSprawdź się: gdybyś wysyłał tylko system prompt, ostatnie 4 tury i nową wiadomość, ile tokenów wejściowych niósłby w turze 50?Pokaż odpowiedź

1 460 (400 + 4 × 250 + 60) wobec 12 710 przy pełnej historii. To samo pytanie, ta sama długość odpowiedzi, ułamek wejścia.

Opcja 1: okno przesuwne#

Idea: zawsze wysyłaj system prompt, odrzuć wszystko poza ostatnimi N turami. Pełną historię trzymasz we własnym magazynie i przycinasz tylko kopię, którą wysyłasz.

python
def trim_history(messages, keep_pairs=4):
    """System prompt + the last keep_pairs turns + the new user message."""
    system = [m for m in messages if m["role"] == "system"]
    rest = [m for m in messages if m["role"] != "system"]
    return system + rest[-(keep_pairs * 2 + 1):]

Wywołaj to po dodaniu nowej wiadomości użytkownika. Przy keep_pairs=4 to 4 pary użytkownik/asystent plus nowa wiadomość, 9 wiadomości, a wycinek zawsze zaczyna się od wiadomości użytkownika. Oto jak to podłączyć do prawdziwego wywołania:

python
import os
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"

history = [{"role": "system", "content": "You are a concise support assistant."}]

def ask(text):
    history.append({"role": "user", "content": text})
    resp = client.chat.completions.create(
        model=MODEL,
        messages=trim_history(history),
        max_tokens=500,
    )
    answer = resp.choices[0].message.content
    history.append({"role": "assistant", "content": answer})
    print(resp.usage.prompt_tokens, resp.usage.completion_tokens)
    return answer

Przydatna jest linia print: obserwuj pierwszą liczbę. Bez przycinania rośnie z każdą turą. Z oknem przestaje rosnąć, gdy rozmowa przekroczy turę 4.

Python helper trim_history: system prompt, ostatnie 4 tury, nowa wiadomość
Helper przycinający z tego artykułu

W liczbach: od tury 5 wzwyż każde żądanie to 400 + 4 × 250 + 60 = 1,460 tokenów wejściowych. Pierwsze cztery tury nadal rosną normalnie i sumują się do 3 340. Cała rozmowa: 3,340 + 46 × 1,460 = 70,500 tokenów wejściowych, około jednej piątej z 329 250 wysyłanych przy pełnej historii. Wyjście pozostaje 50 × 190 = 9,500.

Żądanie w turze 50: pełna historia kontra okno 4 tur
Części tokenowe żądania w turze 50, zgodnie z powyższymi założeniami

W kodzie cała zmiana to jeden argument w wywołaniu:

Porównaj

Zmiana w jednej linii

Przed

python
messages=history

Po

python
messages=trim_history(history)

Haczyk: okno zapomina. Jeśli użytkownik w turze 40 zapyta „jaki był mój numer zamówienia?”, a numer pojawił się w turze 3, model go nigdy nie widział. Dwa tanie rozwiązania. Wyciągnij trwałe fakty (imię, numer zamówienia, plan) z rozmowy we własnym kodzie i dopisz je do system promptu, gdzie okno nigdy ich nie odetnie. Albo dodaj podsumowanie, czyli następną opcję.

Opcja 2: podsumowanie starych tur#

Zamiast odrzucać stare tury, kompresujesz je. Co kilka tur wysyłasz do modelu tury, które właśnie wypadły z okna, plus bieżące podsumowanie, i prosisz o nowe, krótkie podsumowanie. Potem umieszczasz to podsumowanie w wiadomości systemowej.

python
def summarize(summary, old_messages):
    transcript = "\n".join(f"{m['role']}: {m['content']}" for m in old_messages)
    prompt = (
        f"Summary so far:\n{summary}\n\nNew turns:\n{transcript}\n\n"
        "Rewrite the summary in under 200 words. "
        "Keep names, numbers, decisions and open questions."
    )
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "user", "content": prompt}],
        max_tokens=400,
    )
    return resp.choices[0].message.content

def build_messages(history, summary, keep_pairs=4):
    system = history[0]["content"]
    if summary:
        system += "\n\nEarlier in this chat: " + summary
    recent = history[1:][-(keep_pairs * 2 + 1):]
    return [{"role": "system", "content": system}] + recent

Podsumowanie nie jest darmowe: to dodatkowe wywołanie modelu. Załóż podsumowanie o długości około 300 tokenów, odświeżane co 5 tur (9 razy w 50 turach), przy czym każde odświeżenie czyta około 1 600 tokenów (stare podsumowanie plus pięć tur plus instrukcja) i zapisuje 300. Żeby być po bezpiecznej stronie, licz podsumowanie w każdym żądaniu od tury 5 wzwyż (w rzeczywistości pojawia się po pierwszym odświeżeniu, więc to lekkie przeszacowanie): 400 + 300 + 4 × 250 + 60 = 1,760 tokenów wejściowych.

Sumy dla rozmowy: główne żądania 3,340 + 46 × 1,760 = 84,300 tokenów wejściowych, wywołania podsumowania 9 × 1,600 = 14,400 wejściowych i 9 × 300 = 2,700 wyjściowych. Łącznie 84,300 + 14,400 = 98,700 tokenów wejściowych i 9,500 + 2,700 = 12,200 wyjściowych.

Podsumowanie kosztuje nieco więcej niż samo okno, a w zamian model nadal wie, co się stało w turze 3.

Ile kosztują trzy konfiguracje#

Oto ta sama 50-turowa rozmowa na DeepSeek-V4-Flash, wyceniona na żywo na podstawie powyższych sum:

Jedna 50-turowa rozmowa na DeepSeek-V4-Flash
  • Pełna historia (329 250 wej., 9 500 wyj.)$0.0059
  • Okno plus podsumowanie (98 700 wej., 12 200 wyj.)$0.0027
  • Okno przesuwne, 4 tury (70 500 wej., 9 500 wyj.)$0.002

Ceny pochodzą z bieżącego cennika, więc liczby aktualizują się wraz z taryfą. Kolejność się nie zmieni: okno wysyła najmniej, podsumowanie jest pośrodku, pełna historia jest najdroższa.

Dla takiej rozmowy modelem CheapTokens na start jest DeepSeek-V4-Flash. Ma okno kontekstu 380K (50-turowa rozmowa mieści się nawet bez przycinania), do 32 768 tokenów wyjściowych na odpowiedź, jedną stałą cenę o każdej porze dnia i łącznie, licząc wejście i wyjście razem, jest tańszy niż OpenRouter. Identyfikator modelu to deepseek-ai/DeepSeek-V4-Flash-0731. Jeśli chcesz porównać modele w konfiguracji z oknem (średnio 1 410 tokenów wejściowych na żądanie, 190 wyjściowych, 50 żądań), oto bieżąca tabela:

Model Za żądanie 50 żądań OpenRouter, 50 żądań
GLM-5.3-Flash $0.000036 $0.0018 $0.0032
DeepSeek-V4-Flash $0.00004 $0.002 $0.0063
MiniMax-M2.7 $0.000099 $0.005 $0.0594

1410 tokenów wejściowych i 190 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.

GLM-5.3-Flash ma kontekst 390K, a MiniMax-M2.7 ma 180K, co wystarcza na przyciętą rozmowę. Aktualne ceny są na stronie cennika, a dokumentacja pokazuje, jak wysłać pierwsze żądanie.

Co wybrać#

Okno jest domyślnym wyborem: trzy linie kodu, bez dodatkowych wywołań, bez dodatkowego trybu awarii. Używaj go do botów wsparcia, korepetytorów i odgrywania ról, gdzie kilka ostatnich tur niesie rozmowę, a system prompt niesie zasady. Dodaj podsumowanie, gdy użytkownicy odwołują się do rzeczy powiedzianych dawno temu, jak w osobistym asystencie z jedną niekończącą się rozmową. Trzymaj okno na tyle małe, żeby model nadal widział bezpośredni kontekst, i na tyle duże, żeby zmieściła się pełna wymiana pytania i odpowiedzi. Ile w ogóle się mieści, to osobny limit, opisany w czym jest okno kontekstu.

Szybkie sprawdzenie

Użytkownik w turze 40 pyta o numer zamówienia podany w turze 3. Używasz okna 4 tur bez podsumowania. Co się dzieje?

Pokaż odpowiedź

Odpowiedź: Model go nie widzi, bo tura 3 została odcięta z żądania

API jest bezstanowe. Model widzi tylko to, co jest w żądaniu, więc fakty, których nadal potrzebujesz, muszą pozostać w system promptcie lub w podsumowaniu.