Rozliczanie tokenów strumieniowych w bramie API AI: ostateczne wykorzystanie, anulowanie i częściowe odpowiedzi
Przesyłanie strumieniowe poprawia postrzegane opóźnienia, ale może zakłócić analizę wykorzystania sztucznej inteligencji i rozliczenia, jeśli brama przesyła tylko bajty proxy. Oto praktyczny wzorzec maszyny stanu do przechwytywania końcowego użycia, przerwanych strumieni, błędów dostawcy i częściowych odpowiedzi.
Odpowiedzi LLM przesyłane strumieniowo są łatwe do proxy i trudne do prawidłowego wystawienia rachunku. Jeśli bramka AI API przekazuje zdarzenia wysyłane przez serwer do klienta, ale traktuje pierwsze fragmenty jako rekord użycia, analityka dzierżawy będzie się wahać. Odchylenie zwykle pojawia się w przypadku sporów, takich jak: „użytkownik zobaczył tylko połowę odpowiedzi”, „dostawca naliczył wyższą opłatę, niż pokazuje nasz panel”, „przydział został zwolniony zbyt wcześnie” lub „przekroczenie limitu czasu wygenerowało tokeny, ale nie było wiersza faktury”.
Główny problem polega na tym, że połączenia przesyłane strumieniowo nie są jednym wydarzeniem. Są to następujące sekwencje: żądanie przyjęte, otwarty strumień nadrzędny, dostarczone bajty, raport końcowego użycia, zatrzymanie dostawcy, odłączenie klienta, przekroczenie limitu czasu bramy i uregulowanie płatności. Niezawodna brama powinna jawnie modelować te stany, zamiast zakładać, że ukończona odpowiedź HTTP jest jedyną pomyślną ścieżką.
Tryb awarii: przesyłanie strumieniowe ukrywa granicę rozliczeń
Zakończenia inne niż przesyłane strumieniowo zwykle zwracają jeden obiekt odpowiedzi z metadanymi użycia. Brama może normalizować to użycie, zapisywać wiersze księgi, aktualizować limity i emitować analizy w jednym przebiegu.
Streaming zmienia granice. Doświadczenie użytkownika ma charakter przyrostowy, ale prawda o rozliczeniach może zostać ujawniona na końcu, w zdarzeniu końcowym specyficznym dla dostawcy, w formie skumulowanej delty, poprzez zagregowaną odpowiedź SDK lub później za pośrednictwem interfejsów API raportowania dostawcy. Jeśli klient rozłączy się przed końcowym zdarzeniem użycia, brama mogła dostarczyć tylko część odpowiedzi, podczas gdy dostawca nadal wygenerował i obciążył większą liczbę tokenów.
Fakt: OpenAI dokumentuje, że rozmówcy przesyłający strumieniowo, którzy chcą danych o użyciu, powinni ustawić stream_options za pomocą include_usage. OpenAI podaje także punkty końcowe dotyczące wykorzystania i kosztów na poziomie organizacji, pamiętając jednak, że wykorzystanie i koszty nie zawsze mogą idealnie się zgadzać z powodów finansowych.
Fakt: Anthropic przesyłanie strumieniowe wykorzystuje zdarzenia wysyłane przez serwer, takie jak message_start, content_block_delta, message_delta i message_stop. Informacje message_delta o użyciu mają charakter zbiorczy, więc brama nie może sumować poszczególnych różnic użycia.
Fakt: Gemini i interfejsy API przesyłania strumieniowego w stylu Vertex mogą udostępniać przyrostowe fragmenty, podczas gdy zestawy SDK mogą również udostępniać zagregowany obiekt odpowiedzi. W przypadku bram ta zagregowana ścieżka może być lepszym źródłem pełnego wykorzystania niż same widoczne fragmenty.
Użyj maszyny stanu strumienia, a nie logicznej flagi sukcesu
Żądanie przesyłane strumieniowo powinno mieć trwały zapis użycia przed rozpoczęciem wywołania nadrzędnego. Ten rekord powinien przechodzić przez jawne stany. Praktyczne minimum to:
accepted: brama uwierzytelniła klucz, przypisała dzierżawcę i utworzyła otwarty wiersz księgi.first_byte_sent: co najmniej jedno zdarzenie wyjściowe dotarło do klienta dalszego.provider_completed: dostawca wyższego szczebla wyemitował normalny sygnał stopu lub zakończył obiekt odpowiedzi.client_aborted: gniazdo downstream zostało zamknięte przed normalnym zakończeniem działania bramy.provider_error: dostawca wyższego szczebla zwrócił błąd po rozpoczęciu transmisji lub przed ostatecznym użyciem.gateway_timeout: brama wymusiła budżet opóźnienia i zakończyła żądanie.settled: brama przekonwertowała użycie na koszt dzierżawy i wykorzystanie przydziału.reconciled: późniejsze dane dotyczące wykorzystania lub kosztów dostawcy potwierdziły lub skorygowały wiersz.
Ten model zapobiega typowemu błędowi analitycznemu: oznaczaniu każdego strumienia, który wygenerował tekst, jako „udanego i dokładnego”. Strumień może być przydatny dla użytkownika, niekompletny od dostawcy, szacowany pod kątem rozliczeń i jednocześnie oczekujący na uzgodnienie.
Zalecane pola księgi
Trzymaj wiersz czasu żądania mały, ale wyraźny:
{
"request_id": "gw_req_...",
"tenant_id": "tenant_123",
"api_key_id": "key_456",
"provider": "openai|anthropic|gemini|...",
"provider_request_id": null,
"model": "provider-model-id",
"state": "accepted",
"stream": true,
"input_tokens": null,
"output_tokens_billed": null,
"output_tokens_delivered_estimate": 0,
"provider_usage_source": null,
"billing_status": "pending_reconciliation",
"client_abort_at": null,
"provider_completed_at": null,
"settled_at": null,
"error_class": null
}
Ważna separacja to output_tokens_billed i output_tokens_delivered_estimate. Użytkownikom zależy na tym, co dotarło do ich aplikacji. Finanse dbają o to, co naliczył dostawca. Liczby te mogą się różnić po rozłączeniach, strumieniach wywołań narzędzi, ukrytych tokenach rozumowania, tokenach w pamięci podręcznej, przystankach bezpieczeństwa lub przekroczeniu limitu czasu bramy.
Reguły przechwytywania specyficzne dla dostawcy
Neutralny dla dostawcy OpenAIkompatybilny API jest przydatny dla twórców aplikacji, ale adapter bramy nadal wymaga reguł rozliczania specyficznych dla dostawcy.
OpenAIkompatybilne przesyłanie strumieniowe
W przypadku tras OpenAI udostępnij opcję bramy, która umożliwia raportowanie wykorzystania nadrzędnego, jeśli jest to obsługiwane. Typowym wzorcem jest akceptowanie wartości domyślnych na poziomie bramy, takich jak:
{
"stream": true,
"stream_options": {
"include_usage": true
}
}
Jeśli obiekt wywołujący na dalszym etapie go pominie, brama może zdecydować, czy wstrzyknąć go dla tras, gdzie jest to zgodne. Udokumentuj to zachowanie, ponieważ niektórzy klienci oczekują dokładnej kompatybilności przewodów, a niektóre modele lub starsze modele mogą nie obsługiwać końcowego zastosowania w ten sam sposób.
Zalecenie: nie rozliczaj kosztów najemcy z wczesnych fragmentów. Pozostaw wiersz księgi otwarty do czasu, aż zostanie przechwycone końcowe zdarzenie użycia, odpowiedź dostawcy zakończy się bez użycia lub strumień wejdzie w błąd lub ścieżkę anulowania.
Anthropic transmisja strumieniowa
Łączne użycieAnthropic wymaga innej reguły. Jeśli brama widzi trzy zdarzenia message_delta z liczbą tokenów wyjściowych 10, 25 i 40, liczba wyjściowa wynosi 40, a nie 75.
let latestUsage = null;
for await (const event of anthropicStream) {
if (event.type === "message_delta" && event.usage) {
if (latestUsage && event.usage.output_tokens < latestUsage.output_tokens) {
emit("cumulative_usage_regressed", requestId);
}
latestUsage = event.usage;
}
forwardToClient(event);
}
settleFromLatestCumulativeUsage(latestUsage);
Zalecenie: zapisz najnowszą skumulowaną wartość użycia i wyemituj zdarzenie obserwowalności, jeśli ulegnie regresji. Regresja może wskazywać błędy analizatora składni, zduplikowane zdarzenia, zmiany dostawcy lub strumienie mieszane.
Gemini i przesyłanie strumieniowe w stylu Vertex
Gemini obsługuje strumieniowe przesyłanie fragmentów w celu zmniejszenia postrzeganych opóźnień. W zestawach SDK w stylu Vertex przesyłanie strumieniowe może udostępniać zarówno strumień asynchroniczny, jak i zagregowany obiekt odpowiedzi. Brama powinna zachować tę zagregowaną ścieżkę, jeśli jest dostępna.
const streamingResult = await model.generateContentStream(request);
for await (const chunk of streamingResult.stream) {
forwardChunk(chunk);
countDeliveredBytesOrText(chunk);
}
const aggregated = await streamingResult.response;
settleFromAggregatedUsage(aggregated);
Zalecenie: unikaj budowania całego rozliczania z widocznych fragmentów, jeśli SDK daje kompletny rekord odpowiedzi. Kawałki służą do opóźnienia. Ostateczny obiekt jest często lepszy pod względem rozliczeń i analiz.
Traktuj rozłączenia klientów jako pierwszorzędne zdarzenia księgowe
Rozłączanie klientów ma miejsce wtedy, gdy wiele bramek traci pieniądze lub obciąża klientów nadmiernymi kosztami. Karta przeglądarki zamyka się, sieć komórkowa przestaje działać lub aplikacja anuluje żądanie. Brama zauważa zamknięcie gniazda odbiorczego, ale dostawca nadrzędny może nadal generować.
Brama powinna wyraźnie wybierać zasady:
- Natychmiast anuluj przesyłanie danych: zmniejsza straty związane z generowaniem i kosztami dostawcy, ale może przerwać przepływy pracy, w których backend nadal potrzebuje wyniku po rozłączeniu interfejsu użytkownika.
- Kontynuuj przesyłanie danych w tle: może zachować pracę klientów po stronie serwera, ale użytkownik może nie widzieć wszystkich wygenerowanych i rozliczonych tokenów.
- Zachowanie zależne od trasy: anuluj dla czatu interaktywnego, kontynuuj dla przepływów pracy przypominających pracę i udostępnij ustawienie jako widoczne dla najemców.
Praktycznym rozwiązaniem domyślnym w przypadku interaktywnego przesyłania strumieniowego jest anulowanie przesyłania danych w górę, gdy klient podrzędny rozłączy się, a następnie oznaczenie wiersza księgi jako client_aborted. Jeśli ostateczne wykorzystanie nastąpi w trakcie anulowania, rozlicz się na podstawie tego autorytatywnego wykorzystania. Jeśli nie, zaznacz wiersz estimated lub pending_reconciliation, zamiast udawać, że jest dokładny.
downstream.on("close", async () => {
if (!providerCompleted) {
ledger.markClientAborted(requestId);
await upstream.abort().catch(() => {
ledger.emit("upstream_cancel_failed", requestId);
});
}
});
Zalecenie: eksponuj przejrzyste etykiety rozliczeniowe, takie jak final, provider_reconciled, estimated, waived lub pending_reconciliation. Można to lepiej obronić niż pokazywanie, że każde przesyłane strumieniowo połączenie jest bezpośrednio dokładne.
Egzekwowanie limitów podczas transmisji
Dokładne rozliczenia zwykle zależą od końcowego wykorzystania usług przez dostawcę, ale egzekwowanie limitów nie zawsze może czekać do końca. Najemca z ograniczonym budżetem nie powinien mieć możliwości strumieniowego przesyłania strumieniowego w nieskończoność, ponieważ dokładne informacje o wykorzystaniu nie są dostępne w trakcie transmisji.
Użyj dwóch mechanizmów jednocześnie:
- Rezerwacja przed lotem: zarezerwuj szacunkową kwotę maksymalną na podstawie modelu, żądanej maksymalnej liczby tokenów, zasad najemcy i bieżącego salda.
- Kontrola ciśnienia przesyłania strumieniowego: oszacuj dostarczony wynik podczas strumienia i zatrzymaj, jeśli żądanie przekroczy skonfigurowaną granicę bezpieczeństwa.
To jest mechanizm kontrolny, a nie ostateczny rachunek. Dostawcy mogą liczyć tokeny przechowywane w pamięci podręcznej, tokeny wnioskowania, tokeny multimodalne lub tokeny ukryte w inny sposób niż estymator bramy.
Kompromis: szacunki w czasie rzeczywistym pomagają egzekwować budżety, ale mogą odbiegać od tokenów rozliczanych przez dostawcę. Ostateczne rozliczenie powinno uwzględniać dane wiarygodnego dostawcy, jeśli jest dostępne, a podczas uzgadniania należy skorygować szacunki później.
Zdarzenia obserwowalne, które wychwytują błędy księgowe
Błędy rozliczeń podczas przesyłania strumieniowego są łatwiejsze do debugowania, gdy brama emituje ukierunkowane zdarzenia, a nie tylko ogólne dzienniki żądań. Dodaj zdarzenia takie jak:
final_usage_missing: strumień zakończył się bez autorytatywnego użycia.cumulative_usage_regressed: skumulowana liczba tokenów została przesunięta do tyłu.stream_ended_without_stop_event: nie zaobserwowano normalnego znacznika zatrzymania dostawcy.aborted_after_provider_completion: dostawca zakończył działalność, ale klient podrzędny został zamknięty, zanim brama zakończyła przekazywanie.settled_from_estimate: księga najemców użyła szacunków, ponieważ ostateczne wykorzystanie było niedostępne.reconciliation_adjusted_usage: raport dostawcy zmienił później ten wiersz.
Fakt: Konwencje semantyczne OpenTelemetry GenAI zalecają używanie informacji o użytkowaniu zwracanych przez dostawcę do przesyłania strumieniowego odpowiedzi, jeśli są dostępne, i ostrzegają przed raportowaniem metryk użycia, jeśli nie można wydajnie i dokładnie uzyskać liczby tokenów.
W przypadku analityki wykorzystania sztucznej inteligencji oznacza to, że pulpity nawigacyjne powinny obsługiwać poziomy ufności. Wykres zawierający wartości ostateczne, szacunkowe i uzgodnione bez etykiet może wyglądać czysto, ale wprowadzać w błąd zespoły finansowe i wsparcie.
Testy zgodności dotyczące rozliczania strumieniowego
Nie polegaj na ręcznych testach za pomocą komunikatu na czacie Happy Path. Każdy adapter dostawcy powinien mieć testy zgodności dla przypadków, które łamią księgi:
- Normalny strumień: nadchodzi końcowe wykorzystanie, zaobserwowano zdarzenie zatrzymujące, księga zostaje uznana za
final. - Strumień wywołań narzędzi: delta wywołań narzędzi jest przekazywana dalej, rejestrowane jest użycie, uporządkowane metadane nie zakłócają zliczania tokenów.
- Zatrzymanie ze względów bezpieczeństwa lub odmowa: dostawca zatrzymuje się wcześniej, wykorzystanie nadal jest ustalane prawidłowo.
- Wymuszone odłączenie klienta: downstream zostaje zamknięty po częściowym wyjściu; przesyłanie strumieniowe zostało anulowane lub kontynuowane zgodnie z zasadami.
- Przesłanie 5xx po częściowym wyjściu: brama rejestruje częściowe dostarczenie i nie oznacza żądania jako całkowicie zakończonego sukcesem.
- Upłynął limit czasu bramy przed ostatecznym użyciem: wiersz jest szacunkowy lub oczekuje na uzgodnienie.
- Brakujące zdarzenie końcowe: adapter emituje
final_usage_missingi unika dokładnych etykiet rozliczeniowych.
Testy te powinny potwierdzać przejścia stanów, pola księgi, wyemitowane zdarzenia obserwowalności i dalsze zachowanie. Zgodność strumienia bajt po bajcie nie wystarczy; księgowe skutki uboczne są częścią umowy.
Praktyczna lista kontrolna wdrożenia
- Utwórz wiersz księgi użytkowania przed wysłaniem żądania nadrzędnego.
- Przechowuj najemcę, klucz, użytkownika, model, trasę, dostawcę i identyfikatory żądań w momencie żądania.
- Włącz raportowanie końcowego wykorzystania przez dostawcę, jeśli jest obsługiwane, na przykład OpenAI-kompatybilny
stream_options.include_usage. - W przypadku dostawców zbiorczych przechowuj najnowszą wartość użycia zamiast sumować zdarzenia.
- Zachowaj zagregowane obiekty odpowiedzi, gdy udostępniają je pakiety SDK.
- Śledź dostarczone dane wyjściowe niezależnie od wykorzystania naliczanego przez dostawcę.
- Po rozłączeniu anuluj przepływ dalej zgodnie z zasadami trasy i zaznacz
client_aborted. - Używaj przejrzystych statusów rozliczeń: ostateczny, szacunkowy, oczekujący na uzgodnienie, dostawca uzgodniony lub zniesiony.
- Emituj zdarzenia obserwowalne specyficzne dla księgowości.
- Uzgodnij później z raportami dotyczącymi wykorzystania dostawcy lub kosztami, jeśli są dostępne, zachowując przypisanie dzierżawcy w czasie żądania.
Co pokazać najemcom
Najemcy nie potrzebują każdego wydarzenia wewnętrznego, ale potrzebują uczciwych etykiet. Przydatna tabela użycia może zawierać:
- Stan: ostateczny, szacunkowy lub uzgodniony.
- Wynik żądania: ukończony, klient przerwany, błąd dostawcy lub przekroczono limit czasu bramy.
- Dostarczone dane wyjściowe: przybliżony tekst lub bajty wysłane do klienta.
- Tokeny płatne: użycie znormalizowane przez dostawcę stosowane w celu określenia kosztów.
- Korekta: jakakolwiek późniejsza delta uzgodnienia.
Taki projekt zmniejsza niejednoznaczność obsługi. Jeśli użytkownik zobaczył tylko część odpowiedzi, pulpit nawigacyjny może wyjaśnić, czy dostawca już zakończył współpracę, czy bramka została anulowana wcześniej i czy opłata jest ostateczna czy szacunkowa.
Zalecenia a prognozy
Zalecenia: traktuj żądania przesyłane strumieniowo jak maszyny stanu, poczekaj na wiarygodne ostateczne wykorzystanie przed dokładnym rozliczeniem, oddziel dostarczone dane wyjściowe od naliczonego użycia i uczciwie oznacz szacunkowe wiersze. Adaptery dostawców powinny kodować semantykę użycia specyficzną dla dostawcy, a nie spłaszczać każdy strumień do ogólnego bajtowego serwera proxy.
Przewidywanie: księgowanie strumieniowe stanie się ważniejsze, w miarę jak modele ujawniają więcej ukrytej pracy: tokeny wnioskowania, rabaty w postaci tokenów w pamięci podręcznej, przetwarzanie multimodalne, ślady użycia narzędzi i przystanki bezpieczeństwa. Bramy, które już oddzielają wykorzystanie rozliczane przez dostawcę od wyników widocznych dla klienta, dostosują się łatwiej niż bramy, które zliczają tylko przesyłany strumieniowo tekst.
Wniosek, który można zastosować
Jeśli Twoja brama obsługuje przesyłanie strumieniowe, przeprowadź dziś audyt jednej ścieżki: wymuś rozłączenie klienta po kilku pierwszych fragmentach i sprawdź wiersz księgi. Jeśli jest napisane „sukces” z dokładnie wyglądającą liczbą tokenów, Twoje analizy prawdopodobnie kłamią.
Poprawką nie jest rezygnacja z przesyłania strumieniowego. Zachowaj wygodę użytkownika, ale wyraźnie zaznacz stany rozliczeniowe dotyczące zakończenia strumienia, anulowania, błędów dostawcy, braku końcowego użycia i uzgodnienia. Daje to zespołom odpowiedzialnym za produkt elastyczne wyniki, zespołom finansowym możliwe do obrony koszty, a zespołom wsparcia wystarczające dowody, aby wyjaśnić częściowe odpowiedzi bez zgadywania.