Zbuduj warstwę zgodności interfejsu API odpowiedzi w bramie interfejsu API AI
Brama interfejsu API odpowiedzi to nie tylko serwer proxy zakończenia czatu z nową trasą. Zachowaj elementy odpowiedzi, stan, wywołania narzędzi, strumienie, ciągłość rozumowania, przypisanie użycia i zachowanie przy przejściu na starszą wersję dzięki pierwszorzędnej warstwie kompatybilności.
Nie implementuj /v1/responses, tłumacząc każde żądanie na /v1/chat/completions i mając nadzieję, że kształt jest wystarczająco zbliżony. Ten adapter może zwracać tekst, ale może po cichu utracić elementy, na których zależy programistom: elementy odpowiedzi, stan po stronie serwera, wywołania narzędzi, ciągłość wnioskowania, zdarzenia cyklu życia strumienia, semantykę anulowania i przypisanie użycia na poziomie elementu.
Praktycznym celem jest warstwa zgodności, która traktuje interfejs API Responses jako bogatszy protokół. Zachowaj obsługę uzupełnień czatu dla istniejących klientów, ale zbuduj odpowiedzi jako własną powierzchnię bramy z własnym modelem stanu, normalizatorem strumienia, księgą wywołań narzędzi, macierzą możliwości i regułami awaryjnymi.
Co to są fakty, co to polityka, a co prognozy?
Fakty: OpenAI opisuje interfejs API Responses jako ujednolicające możliwości, które wcześniej były podzielone między funkcje uzupełniania czatu i asystentów, w tym obsługę takich narzędzi, jak wyszukiwanie w Internecie, wyszukiwanie plików i korzystanie z komputera. Interfejs API udostępnia pola, takie jak previous_response_id, przesyłanie strumieniowe, wybór narzędzi i narzędzia wbudowane. Dokumentacja SDK pokazuje, że previous_response_id może zapewnić ciągłość konwersacji, podczas gdy poprzednie instrukcje nie są automatycznie przenoszone i muszą zostać przesłane ponownie, gdy powinny nadal obowiązywać. Odniesienie do przesyłania strumieniowego OpenAI obejmuje odrębny cykl życia odpowiedzi i zdarzenia wyjściowe, a nie tylko różnice tokenów.
Zalecenia: brama powinna zachować tę semantykę, a nie domyślnie ją spłaszczać. Powinien odrzucać lub wyraźnie obniżać żądania, gdy docelowy dostawca nie może obsłużyć wymaganego zachowania.
Przewidywanie: więcej obciążeń agentów będzie zależeć od struktury elementów odpowiedzi, śladów wykonania narzędzia i kontekstu wnioskowania stanowego. Bramy modelujące te koncepcje będą teraz łatwiejsze do rozbudowy niż bramy traktujące Odpowiedzi jako kosmetyczny punkt końcowy.
Określ oddzielną umowę dotyczącą zgodności dla Odpowiedzi
Pierwszym błędem wdrożeniowym jest założenie, że kompatybilność z OpenAI oznacza jeden uniwersalny schemat żądań i odpowiedzi. W praktyce /v1/chat/completions i /v1/responses powinny stanowić oddzielne umowy dotyczące zgodności.
Zachowaj wspólną warstwę uwierzytelniania, rozliczeń, przydziałów i routingu, ale oddziel warstwę protokołu:
- Powierzchnia Uzupełnienia czatu: wiadomości, wybory, różnice, wywołania narzędzi w formacie czatu, starsze zachowania klientów.
- Powierzchnia odpowiedzi: elementy wejściowe, elementy wyjściowe, identyfikatory odpowiedzi, odniesienia do poprzednich odpowiedzi, bogatsze zdarzenia narzędzi, zdarzenia strumienia cyklu życia, pola związane z rozumowaniem i końcowy stan odpowiedzi.
Ten podział ma znaczenie dla testów zgodności. Adapter dostawcy, który przejdzie testy na czacie, może nadal nie przejść testów Odpowiedzi, ponieważ nie jest w stanie zachować previous_response_id, kolejności elementów, struktury odmów, metadanych hostowanego narzędzia ani nazw zdarzeń przesyłania strumieniowego.
Umowa o minimalnej kompatybilności powinna odpowiadać:
- Które pola żądania są akceptowane, odrzucane, przekształcane lub ignorowane?
- Jakie typy elementów odpowiedzi są zachowywane?
- Jakie typy narzędzi są obsługiwane w zależności od dostawcy i modelu?
- Czy dostawca może utrzymać stan konwersacji, czy musi go utrzymywać brama?
- Co się stanie, gdy zostanie zażądane
store=false? - Jakie zdarzenia strumieniowe są gwarantowane?
- W jaki sposób rejestrowane jest anulowanie, przekroczenie limitu czasu i częściowe wykorzystanie?
Jeśli masz już bramę AI API, traktuj obsługę odpowiedzi jako rozszerzenie protokołu, a nie alias trasy.
Użyj kanonicznego modelu pozycji odpowiedzi
Interfejs API Responses zwraca więcej niż jedną wiadomość asystenta. Może reprezentować różne elementy wyjściowe i zdarzenia. Twoja brama potrzebuje wewnętrznego modelu kanonicznego, zanim zostanie zmapowana do dowolnego dostawcy.
Praktyczny schemat elementów wewnętrznych może zacząć się w ten sposób:
{ "gateway_response_id": "gw_resp_...", "provider_response_id": "resp_...", "ident_dzierżawcy": "dziesięć_123", "key_id": "key_456", "model_alias": "domyślny agent", "dostawca": "openai", „przedmioty”: [ { "item_id": "element_1", "typ": "tekst", "rola": "asystent", „treść”: [{ „typ”: „tekst_wyjściowy”, „tekst”: „…” }], „status”: „zakończony” }, { "item_id": "item_2", "typ": "wywołanie_funkcji", "call_id": "call_abc", "nazwa": "kolejność_wyszukiwania", "arguments_json": "{\"order_id\":\"123\"}", „status”: „zakończony” } ], „wykorzystanie”: { „tokeny_wejściowe”: 0, „tokeny_wyjściowe”: 0, „reasoning_tokens”: null, "jednostki_narzędzi": [] }, „status”: „zakończony”
Uwzględnij typy produktów, zanim każdy dostawca będzie mógł je wyprodukować. Przydatne kategorie obejmują:
- Wyprowadzanie tekstu
- Odmowy
- Wywołania funkcji
- Wyniki funkcji przesłane przez aplikację
- Podsumowania lub metadane związane z rozumowaniem, jeśli są dostępne
- Odniesienia do plików
- Wyszukiwanie w Internecie, wyszukiwanie plików, korzystanie z komputera lub inne zdarzenia hostowanych narzędzi
- Metadane dotyczące końcowego wykorzystania i rozliczeń
Nie chodzi o to, aby udostępniać użytkownikom zastrzeżony schemat. Chodzi o to, aby brama nie wyrzucała informacji, zanim będzie mogła je sprawdzić, rozliczyć, przesłać strumieniowo, odtworzyć lub przekształcić.
Utwórz księgę stanową należącą do bramy
previous_response_id to pole, które najlepiej ukazuje różnicę między bezstanowym proxy czatu a zgodnością z odpowiedziami. Jeśli klient odwołuje się do poprzedniej odpowiedzi, brama musi wiedzieć, co oznacza ten identyfikator, czy dzierżawca może z niego korzystać i czy dostawca może z niego kontynuować.
Utwórz księgę stanu z kluczem według najemcy i identyfikatora odpowiedzi:
{ "gateway_response_id": "gw_resp_789", "provider_response_id": "resp_provider_789", "previous_gateway_response_id": "gw_resp_456", "ident_dzierżawcy": "dziesięć_123", "user_id": "użytkownik_999", "key_id": "key_456", "model": "gpt-...", "dostawca": "openai", "store_mode": "dostawca|brama|brak", "retention_policy": "standard|zero_retention|custom_30d", "instructions_hash": "sha256:...", "tool_policy_id": "tools_readonly_v3", "created_at": "...", "expires_at": "...", „usunięte_at”: null
Ważna zasada: nie emuluj automatycznie previous_response_id, odtwarzając pełną historię czatów, chyba że najemca wyraźnie zezwolił na takie zachowanie i koszty. Powtórka może zwiększyć koszt tokena, zmienić poziom prywatności i zmienić zachowanie modelu. Bezpieczniej jest zwrócić wyraźny błąd możliwości, niż dyskretnie wysłać zapisaną treść konwersacji, której aplikacja nie spodziewała się zachować lub ponownie wykorzystać.
Tryby obsługi stanów
- Stan dostawcy: Dostawca nadrzędny przechowuje wystarczającą ilość kontekstu, a brama mapuje identyfikatory odpowiedzi bramy na identyfikatory odpowiedzi dostawcy.
- Stan bramy: brama przechowuje niezbędne elementy wcześniejsze i rekonstruuje kontekst, jeśli jest to dozwolone.
- Brak stanu: żądanie używa
store=falselub zasady dzierżawy zabraniają przechowywania.previous_response_idpowinien zostać odrzucony, chyba że dostawca może spełnić żądanie bez zatrzymywania bramy i pozwalają na to zasady.
Pamiętaj również, że może zaistnieć potrzeba ponownego przesłania przez klienta poprzednich instrukcji, gdy będą one nadal obowiązywać. Brama nie powinna wymyślać ukrytych instrukcji w celu rekompensaty, chyba że takie zachowanie jest częścią wyraźnych zasad najemcy.
Weryfikuj narzędzia przed wysyłką
Dzięki Responses korzystanie z narzędzi jest bardziej centralne. Warstwa zgodności powinna obsługiwać dwie szerokie kategorie:
- Narzędzia aplikacji: definicje funkcji dostarczone przez klienta, wykonywane poza dostawcą modelu, a wyniki przesyłane z powrotem do interfejsu API.
- Narzędzia dostawcy hostowanego: wyszukiwanie w Internecie, wyszukiwanie plików, korzystanie z komputera, wykonywanie kodu, uziemianie lub podobne narzędzia wykonywane przez dostawcę lub infrastrukturę kontrolowaną przez bramę.
Przy wejściu sprawdź schematy narzędzi przed routingiem:
- Odrzuć wcześniej nieprawidłowy schemat JSON.
- Wymuś maksymalny rozmiar schematu i głębokość zagnieżdżenia.
- Sprawdź nazwy narzędzi pod kątem zgodności dostawców.
- Zastosuj zakresy dzierżawy, klucza, użytkownika i środowiska.
- Wymagaj bramek zatwierdzających w przypadku narzędzi, które zapisują dane, wydają pieniądze, uzyskują dostęp do wrażliwych systemów lub dzwonią do zewnętrznych łączników.
Do wywoływania funkcji aplikacji wymagany jest stabilny identyfikator połączenia. Model emituje wywołanie funkcji z call_id; aplikacja przesyła dane wyjściowe narzędzia odwołujące się do tego identyfikatora; brama rejestruje oba w tym samym śladzie. Bez tego klucza łączenia dzienniki kontroli i ponowne próby stają się niejednoznaczne.
W przypadku narzędzi hostowanych zarezerwuj budżet przed wysyłką i rozlicz koszty później. Hostowane narzędzia mogą dodawać opłaty poza zwykłym rozliczaniem tokenów, więc połącz księgę narzędzi z ujednoliconymi rozliczeniami interfejsu API AI, zamiast ukrywać te koszty w ogólnej sumie wywołań modelowych.
Normalizuj przesyłanie strumieniowe jako zdarzenia, a nie tekst tokena
Proxy czatu często może uniknąć delt tokenów przekazywania. Brama odpowiedzi nie może. Strumień ma znaczenie w cyklu życia: może rozpocząć się odpowiedź, elementy wyjściowe mogą się rozpocząć i zakończyć, tekst może pojawić się w postaci delt, wywołania narzędzi mogą być łączone przyrostowo, użycie może nastąpić na końcu lub w trakcie strumienia, a odpowiedź może zakończyć się niepowodzeniem lub zostać anulowana.
Zdefiniuj schemat zdarzenia bramy, a następnie zamapuj na niego strumień każdego dostawcy:
zdarzenie: odpowiedź_rozpoczęta
dane: { "response_id": "gw_resp_123", "status": "w toku" }
zdarzenie: element_wyjściowy_rozpoczętydane: { "item_id": "item_1", "type": "text" }
zdarzenie: tekst_delta
dane: { "item_id": "item_1", "delta": "Witam" }
zdarzenie:tool_call_delta
dane: { "item_id": "item_2", "call_id": "call_abc", "arguments_delta": "{\"zamówienie" }
zdarzenie: use_delta
dane: { "tokeny_wyjściowe": 12 }
wydarzenie: zakończone
dane: { "response_id": "gw_resp_123", "usage": { ... }
Zalecane zdarzenia znormalizowane:
response_startedoutput_item_startedoutput_item_completedtext_deltaodmowa_deltatool_call_deltaotrzymano wynik_narzędziausage_deltaukończonoanulowanynie powiodło się
Gdy klient się rozłączy, propaguj anulowanie w górę łańcucha dostaw, jeśli dostawca to obsługuje. Zapisz stan częściowej odpowiedzi w dowolny sposób. Jeśli dostawca później zwróci ostateczne wykorzystanie w drodze opóźnionego wywołania zwrotnego lub ostatniej części, należy uzgodnić księgę. Zgodność przesyłania strumieniowego dotyczy zarówno rozliczania i cyklu życia, jak i opóźnień.
Utwórz matrycę możliwości dostawcy
Routing wielomodelowy jest przydatny tylko wtedy, gdy brama rozumie, co można bezpiecznie trasować. Dodaj funkcje specyficzne dla Responses do swojego katalogu modeli:
{ "model_alias": "domyślny agent", „trasy”: [ { "dostawca": "openai", "model": "...", „supports_responses”: prawda, „supports_previous_response_id”: prawda, „supports_store_false”: prawda, „supports_builtin_web_search”: prawda, „supports_function_calling”: prawda, „supports_stream_lifecycle_events”: prawda, „supports_reasoning_context_continuity”: prawda, „max_tool_schema_bytes”: 65536 }, { "dostawca": "dostawca_b", "model": "...", „supports_responses”: fałsz, „chat_adapter_available”: prawda, „loss_profile”: [„no_previous_response_id”, „no_hosted_tools”, „flattened_stream”] } ]
Rezerwacja powinna uwzględniać straty. Jeśli żądanie wymaga wbudowanej wyszukiwarki internetowej, a dostawca zastępczy nie może go wykonać, nie odpowiadaj w trybie cichym bez wyszukiwania. Jeśli żądanie zależy od zachowanego kontekstu rozumowania i trasa rezerwowa nie może go zachować, zwróć błąd możliwości lub odpowiedź na obniżenie wersji, na którą klient wyraźnie wyraził zgodę.
Przydatną opcją żądania jest:
{ "model": "domyślny agent", "wejście": "...", „polityka_awaryjna”: { „allow_lossy”: fałsz, „allowed_losses”: [] }
W przypadku mniej wrażliwych przypadków użycia dzierżawcy mogą zezwolić na określone straty na niższą wersję:
{ „polityka_awaryjna”: { „allow_lossy”: prawda, „allowed_losses”: [„spłaszczony_strumień”, „no_reasoning_summary”] }
Brama powinna tak czy inaczej zarejestrować decyzję awaryjną. Dzięki temu możliwe jest późniejsze debugowanie, gdy agent zachowuje się inaczej po awarii dostawcy lub przekierowaniu modelu.
Wykorzystanie atrybutu na poziomie odpowiedzi i elementu
Połączenia w odpowiedziach mogą kosztować więcej niż równoważne zakończenia czatu, ponieważ mogą obejmować wykonanie narzędzia, dłuższy kontekst, tokeny rozumowania, wyszukiwanie plików, wyszukiwanie w Internecie lub powtarzane instrukcje. Pojedyncza zagregowana liczba tokenów nie wystarczy dla panelu analitycznego wykorzystania interfejsu API AI.
Rekorduj wykorzystanie na dwóch poziomach:
- Poziom odpowiedzi: dzierżawca, klucz, użytkownik, model, dostawca, opóźnienie, stan końcowy, tokeny wejściowe, tokeny wyjściowe, tokeny wnioskowania, jeśli zostały zgłoszone, całkowity koszt i trasa awaryjna.
- Poziom elementu/narzędzia: nazwa narzędzia, identyfikator wywołania, hostowane jednostki narzędzi, identyfikatory plików, liczba wyszukiwanych zapytań, jeśli są dostępne, opóźnienie narzędzia, koszt narzędzia i wynik zasad zatwierdzania.
Dzięki temu programiści mogą odpowiedzieć na konkretne pytania:
- Czy koszt wzrósł z powodu dłuższego stanu, wysiłku w zakresie rozumowania, wywołań narzędzi lub awarii?
- Który dzierżawca lub klucz API generuje opłaty za narzędzia hostowane?
- Która odpowiedź nie powiodła się po wywołaniu narzędzia, ale przed ostatecznym tekstem?
- Które anulowane transmisje nadal wiązały się z dodatkowym obciążeniem?
Zachowuj zera i usuwaj je jako zachowanie najwyższej klasy
Stan po stronie serwera jest pomocny, ale zmienia obowiązki przechowywania bramy. Wbuduj zasady w warstwę protokołu, zamiast traktować je jako ustawienie rejestrowania.
W przypadku każdego żądania Odpowiedzi rozwiąż:
- Zasady przechowywania najemców
- Preferencje
storena poziomie żądania - Zgodność przechowywania dostawców
- Czy dozwolone jest odtwarzanie przez bramę
- Czy można przechowywać dane wejściowe i wyjściowe narzędzia
- Zachowanie związane z wygaśnięciem i usunięciem stanu odpowiedzi
Jeśli przechowywanie jest wyłączone, brama może nadal przechowywać minimalne metadane operacyjne: znaczniki czasu, identyfikatory, stan, liczbę tokenów, koszty i decyzje dotyczące zasad. Unikaj przechowywania surowych podpowiedzi, pełnych wyników narzędzi lub zrekonstruowanej historii, chyba że pozwalają na to zasady.
Osprzęt zgodny z wymaganiami, który należy dodać przed uruchomieniem
Nie polegaj na ręcznych testach Happy-path. Dodaj urządzenia weryfikujące zachowanie protokołu na bezpośrednich trasach OpenAI, trasach dostosowanych przez dostawcę i scenariuszach awaryjnych.
Minimalny zestaw testowy
- Odpowiedź podstawowa: zwracany jest element tekstowy ze stabilnym identyfikatorem odpowiedzi i użyciem.
- Stan wieloobrotowy: drugie żądanie odwołuje się do
previous_response_id; brama sprawdza własność dzierżawy i tryb stanu. - Powtarzane instrukcje: sprawdź, czy pominięte instrukcje nie zostały po cichu wymyślone przez bramę.
- Wywołanie funkcji w obie strony: model emituje identyfikator wywołania; aplikacja przesyła dane wyjściowe; ostateczna odpowiedź łączy oba rekordy.
- Zasady dotyczące narzędzi hostowanych: nieautoryzowane wbudowane narzędzie jest blokowane przed wysłaniem.
- Kolejność przesyłania strumieniowego: początek odpowiedzi, początek elementu, różnice, zakończenie elementu, użycie i zakończenie są emitowane w prawidłowej kolejności.
- Anulowanie strumienia: rozłączenie klienta powoduje anulowanie transmisji nadrzędnej, jeśli jest to obsługiwane, i rejestruje częściowe wykorzystanie.
- Odrzucenie zastępcze: dostawca bez wymaganej semantyki odpowiedzi zwraca błąd możliwości.
- Zgoda na rezerwę stratną: żądanie z dozwolonymi stratami otrzymuje wyraźny znacznik obniżenia wersji.
- Tryb zerowego przechowywania: odtwarzanie stanu i zachowywanie monitów po stronie bramy są blokowane.
Zalecana sekwencja wdrażania
- Udostępnij trasę wersji beta. Dodaj
/v1/responsesbez zmiany istniejącego zachowania na czacie. - Wdrażaj najpierw przekazywanie dla dostawców z natywną obsługą odpowiedzi. Zachowaj identyfikatory, elementy, strumienie, użycie i błędy.
- Dodaj księgę stanu. Mapuj identyfikatory bram na identyfikatory dostawców i egzekwuj własność dzierżawy.
- Dodaj elementy kanoniczne. Metadane elementów przechowywania potrzebne do audytu, rozliczeń i rekonstrukcji strumienia.
- Dodaj zarządzanie narzędziami. Sprawdź poprawność schematów, egzekwuj zakresy i rejestruj połączenia wywołań narzędzi.
- Dodaj normalizację przesyłania strumieniowego. Konwertuj strumienie specyficzne dla dostawcy na zdarzenia cyklu życia bramy.
- Dodaj routing uwzględniający możliwości. Domyślnie zezwalaj tylko na bezpieczne połączenia awaryjne.
- Dodaj statystyki i rozliczenia. Oddzielnie przypisuj token atrybutu, uzasadnienie i użycie narzędzia.
- Opublikuj uwagi dotyczące zgodności. Poinformuj programistów, które pola są natywne, emulowane, nieobsługiwane lub stratne.
Wniosek, który można zastosować
Warstwa zgodności interfejsu API odpowiedzi powinna zachować znaczenie protokołu, a nie tylko zwracać wiarygodny tekst. Zbuduj go wokół pięciu trwałych obiektów: kanonicznego modelu pozycji odpowiedzi, księgi stanów konwersacji, księgi wywołań narzędzi, normalizatora zdarzeń przesyłania strumieniowego i macierzy możliwości dostawcy.
Najbezpieczniejszym ustawieniem domyślnym jest ścisła zgodność: jeśli trasa nie może zachować wymaganego stanu, narzędzi, kontekstu rozumowania, zdarzeń strumieniowych lub zachowania związanego z przechowywaniem, zwróć wyraźny błąd możliwości. Dodaj opcjonalną stratną rezerwę rezerwową tylko wtedy, gdy programiści zrozumieją, co zostanie porzucone. Takie podejście może wydawać się mniej wygodne niż automatyczne spłaszczanie, ale zapobiega najgorszemu trybowi awarii: aplikacji, która wydaje się zgodna, a jednocześnie cicho traci semantykę, która sprawiła, że w ogóle korzystała z interfejsu API Responses.