Bygg ett Responses API-kompatibilitetslager i en AI API-gateway
En Responses API-gateway är inte bara en Chat Completions-proxy med en ny rutt. Bevara svarsobjekt, status, verktygsanrop, strömmar, resonemangskontinuitet, användningstillskrivning och nedgraderingsbeteende med ett förstklassigt kompatibilitetslager.
Implementera inte /v1/responses genom att översätta varje begäran till /v1/chat/completions och hoppas att formen är tillräckligt nära. Den adaptern kan returnera text, men den kan tyst tappa de delar som utvecklarna bryr sig om: svarsobjekt, server-side-tillstånd, verktygsanrop, resonemangskontinuitet, strömningslivscykelhändelser, annulleringssemantik och användningstillskrivning på objektnivå.
Det praktiska målet är ett kompatibilitetslager som behandlar Responses API som ett rikare protokoll. Behåll stöd för chattavslutningar för befintliga klienter, men bygg Responses som sin egen gateway-yta med sin egen tillståndsmodell, strömnormaliserare, verktygsanropsreskontra, kapacitetsmatris och reservregler.
Vad är fakta, vad är policy och vad är förutsägelse?
Fakta: OpenAI beskriver Responses API som förenande funktioner som tidigare var uppdelade på chattavslut och assistenter, inklusive stöd för verktyg som webbsökning, filsökning och datoranvändning. API:et exponerar fält som previous_response_id, streaming, verktygsval och inbyggda verktyg. SDK-dokumentation visar att previous_response_id kan ge konversationskontinuitet, medan tidigare instruktioner inte automatiskt förs vidare och måste skickas om när de fortfarande borde gälla. OpenAI:s strömningsreferens inkluderar distinkta responslivscykel- och utdatahändelser snarare än bara tokendelta.
Rekommendationer: En gateway bör bevara denna semantik snarare än att förenkla den som standard. Den bör avvisa eller uttryckligen nedgradera förfrågningar när en målleverantör inte kan stödja det nödvändiga beteendet.
Förutsägelse: Fler agentarbetsbelastningar kommer att bero på svarsobjektstruktur, verktygsexekveringsspår och tillståndskontext. Gateways som modellerar dessa koncept nu kommer att vara lättare att utöka än gateways som behandlar Responses som en kosmetisk slutpunkt.
Definiera ett separat kompatibilitetskontrakt för svar
Det första implementeringsmisstaget är att anta att OpenAI-kompatibel innebär ett universellt begäran- och svarsschema. I praktiken bör /v1/chat/completions och /v1/responses vara separata kompatibilitetskontrakt.
Behåll ett delat lager för autentisering, fakturering, kvot och routing, men separera protokolllagret:
- Chattslutföranden visas: meddelanden, val, delta, verktygsanrop i chattformat, äldre klientbeteende.
- Svars yta: indataobjekt, utdataobjekt, svars-ID:n, tidigare svarsreferenser, rikare verktygshändelser, livscykelflödeshändelser, resonemangsrelaterade fält och slutligt svarstillstånd.
Denna uppdelning är viktig för överensstämmelsetester. En leverantörsadapter som klarar chatttest kan fortfarande misslyckas med svarstester eftersom den inte kan bevara previous_response_id, artikelbeställning, avslagsstruktur, värdverktygets metadata eller strömmande händelsenamn.
Ett minimalt kompatibilitetskontrakt bör svara:
- Vilka begärandefält accepteras, avvisas, omvandlas eller ignoreras?
- Vilka svarsobjekttyper bevaras?
- Vilka verktygstyper stöds per leverantör och modell?
- Kan leverantören behålla konversationsstatus, eller måste gatewayen behålla det?
- Vad händer när
store=falsebegärs? - Vilka strömningsevenemang garanteras?
- Hur registreras avbokningar, timeout och partiell användning?
Om du redan har en AI API-gateway, behandla Responses-stödet som en protokollexpansion, inte ett ruttalias.
Använd en kanonisk svarsobjektmodell
Responses API returnerar mer än ett assistentmeddelande. Det kan representera olika utdata och händelser. Din gateway behöver en intern kanonisk modell innan den mappas till någon leverantör.
Ett praktiskt internt objektschema kan börja så här:
{
"gateway_response_id": "gw_resp_...",
"provider_response_id": "resp_...",
"tenant_id": "ten_123",
"key_id": "key_456",
"model_alias": "agent-default",
"provider": "openai",
"objekt": [
{
"item_id": "item_1",
"type": "text",
"role": "assistent",
"content": [{ "type": "output_text", "text": "..." }],
"status": "avslutad"
},
{
"item_id": "item_2",
"type": "funktionssamtal",
"call_id": "call_abc",
"name": "lookup_order",
"arguments_json": "{\"order_id\":\"123\"}",
"status": "avslutad"
}
],
"användning": {
"input_tokens": 0,
"output_tokens": 0,
"reasoning_tokens": null,
"verktygsenheter": []
},
"status": "avslutad"
}
Inkludera artikeltyper redan innan varje leverantör kan producera dem. Användbara kategorier inkluderar:
- Textutdata
- Avvisningar
- Funktionsanrop
- Funktionsutdata som skickats in av ansökan
- Resoneringssammanfattningar eller resonemangsrelaterad metadata där tillgänglig
- Filreferenser
- Webbsökning, filsökning, datoranvändning eller andra värdbaserade verktygshändelser
- Slutlig användning och faktureringsmetadata
Poängen är inte att exponera ett proprietärt schema för användarna. Poängen är att förhindra att gatewayen kastar bort information innan den kan granska, fakturera, streama, spela upp igen eller omvandla den.
Skapa en gatewayägd statsbok
previous_response_id är det fält som mest avslöjar skillnaden mellan tillståndslös chattproxy och Responses-kompatibilitet. Om en klient hänvisar till ett tidigare svar måste gatewayen veta vad det ID betyder, om hyresgästen får använda det och om leverantören kan fortsätta från det.
Skapa en delstatsbok som anges av hyresgästen och svars-ID:
{
"gateway_response_id": "gw_resp_789",
"provider_response_id": "resp_provider_789",
"previous_gateway_response_id": "gw_resp_456",
"tenant_id": "ten_123",
"user_id": "user_999",
"key_id": "key_456",
"model": "gpt-...",
"provider": "openai",
"store_mode": "leverantör|gateway|ingen",
"retention_policy": "standard|noll_retention|custom_30d",
"instructions_hash": "sha256:...",
"tool_policy_id": "tools_readonly_v3",
"created_at": "...",
"expires_at": "...",
"deleted_at": null
}
Viktig regel: emulera inte automatiskt previous_response_id genom att spela upp hela chatthistoriken såvida inte hyresgästen uttryckligen har tillåtit detta bevarande- och kostnadsbeteende. Omspelning kan öka tokenkostnaden, ändra sekretessställning och ändra modellens beteende. Det är säkrare att returnera ett tydligt funktionsfel än att tyst skicka lagrat konversationsinnehåll som programmet inte förväntade sig att du skulle behålla eller återanvända.
Tillståndshanteringslägen
- Leverantörstillstånd: Uppströmsleverantören lagrar tillräckligt med sammanhang, och gatewayen mappar gatewaysvars-ID:n till leverantörssvars-ID:n.
- Gatewaytillstånd: Gatewayen lagrar nödvändiga tidigare objekt och rekonstruerar sammanhanget när det tillåts.
- Ingen status: Begäran använder
store=falseeller så förbjuder hyresgästpolicyn lagring.previous_response_idbör avvisas såvida inte leverantören kan uppfylla begäran utan gatewayretention och policyn tillåter det.
Kom också ihåg att tidigare instruktioner kan behöva skickas om av klienten när de ska fortsätta tillämpa. Gatewayen bör inte hitta på dolda instruktioner för att kompensera såvida inte det beteendet är en del av en explicit hyresgästpolicy.
Validera verktyg innan utskick
Svar gör verktygsanvändningen mer central. Ett kompatibilitetslager bör hantera två breda kategorier:
- Applikationsverktyg: Funktionsdefinitioner som tillhandahålls av klienten, exekveras utanför modellleverantören, med utdata som skickas tillbaka till API:et.
- Verktyg för värdleverantörer: Webbsökning, filsökning, datoranvändning, kodexekvering, jordning eller liknande verktyg som körs av leverantören eller gateway-kontrollerad infrastruktur.
Ved ingång, validera verktygsscheman före routning:
- Avvisa ogiltigt JSON-schema tidigt.
- Tvinga fram maximal schemastorlek och kapslingsdjup.
- Kontrollera verktygsnamn för leverantörskompatibilitet.
- Tillämpa omfattningar för klient, nyckel, användare och miljö.
- Kräv godkännandegrindar för verktyg som skriver data, spenderar pengar, kommer åt känsliga system eller ringer externa kontakter.
Kräv ett stabilt samtals-ID för att anropa applikationsfunktioner. Modellen avger ett funktionsanrop med call_id; applikationen skickar verktygsutgången som hänvisar till detta ID; gatewayen registrerar båda i samma spår. Utan den anslutningsnyckeln blir granskningsloggar och återförsök tvetydiga.
För värdbaserade verktyg, reservera budget innan utskick och reglera kostnaden efteråt. Värdbaserade verktyg kan lägga till avgifter utanför ordinarie tokenredovisning, så anslut verktygsreskontran till unified AI API-fakturering istället för att dölja dessa kostnader i en generisk modellanropssumma.
Normalisera streaming som händelser, inte tokentext
En chatproxy kan ofta komma undan med att vidarebefordra tokendelta. En Responses-gateway kan inte. Strömmen har livscykelbetydelse: ett svar kan starta, utdataobjekt kan starta och slutföras, text kan komma in i delta, verktygsanrop kan sammanställas stegvis, användning kan komma i slutet eller under strömmen, och svaret kan misslyckas eller avbrytas.
Definiera ett gateway-händelseschema och mappa sedan varje leverantörsström till det:
händelse: response_started
data: { "response_id": "gw_resp_123", "status": "pågår" }
händelse: output_item_starteddata: { "item_id": "item_1", "type": "text" }
händelse: text_delta
data: { "item_id": "item_1", "delta": "Hej" }
händelse: tool_call_delta
data: { "item_id": "item_2", "call_id": "call_abc", "arguments_delta": "{\"order" }
händelse: usage_delta
data: { "output_tokens": 12 }
händelse: avslutad
data: { "response_id": "gw_resp_123", "usage": { ... } }
Rekommenderade normaliserade händelser:
svar_startadoutput_item_startedoutput_item_completedtext_deltarefusal_deltatool_call_deltatool_result_receivedusage_deltaslutförtavbrutenmisslyckades
När klienten kopplar från, sprid avbokning uppströms om leverantören stöder det. Registrera delsvarstillståndet åt båda hållen. Om leverantören senare returnerar slutanvändning genom en fördröjd återuppringning eller slutlig del, stäm av redovisningen. Streamingkompatibilitet handlar lika mycket om redovisning och livscykel som om latens.
Skapa en leverantörskapacitetsmatris
Multi-modell routing är användbart endast när gatewayen förstår vad som säkert kan dirigeras. Lägg till svarsspecifika funktioner i din modellkatalog:
{
"model_alias": "agent-default",
"rutter": [
{
"provider": "openai",
"model": "...",
"supports_responses": sant,
"supports_previous_response_id": sant,
"supports_store_false": sant,
"supports_builtin_web_search": sant,
"supports_function_calling": sant,
"supports_stream_lifecycle_events": sant,
"supports_reasoning_context_continuity": sant,
"max_tool_schema_bytes": 65536
},
{
"provider": "provider_b",
"model": "...",
"supports_responses": false,
"chat_adapter_available": sant,
"loss_profile": ["no_previous_response_id", "no_hosted_tools", "flattened_stream"]
}
]
}
Tillbakagång bör vara förlustmedveten. Om begäran kräver inbyggd webbsökning och reservleverantören inte kan utföra det, svara inte tyst utan sökning. Om begäran beror på bevarat resonemangskontext och reservvägen inte kan bevara den, returnera ett kapacitetsfel eller ett nedgraderingssvar som klienten uttryckligen valde.
Ett användbart alternativ för begäran är:
{
"model": "agent-default",
"input": "...",
"fallback_policy": {
"allow_lossy": false,
"allowed_losses": []
}
}
För mindre känsliga användningsfall kan hyresgäster tillåta specifika nedgraderingar med förlust:
{
"fallback_policy": {
"allow_lossy": sant,
"allowed_losses": ["flatened_stream", "no_reasoning_summary"]
}
}
Gatewayen bör logga reservbeslutet åt båda hållen. Det gör senare felsökning möjlig när en agent beter sig annorlunda efter ett leverantörsavbrott eller modellomdirigering.
Attributanvändning på svars- och objektnivå
Svarsanrop kan kosta mer än motsvarande chattslutföranden eftersom de kan innefatta verktygskörning, längre sammanhang, resonemangstokens, filsökning, webbsökning eller upprepade instruktioner. Ett enda samlat antal token räcker inte för en dashboard för AI API-användningsanalys.
Registrera användning på två nivåer:
- Svarsnivå: hyresgäst, nyckel, användare, modell, leverantör, latens, slutlig status, indatatoken, utdatatoken, resonemangstoken där rapporterad, total kostnad och reservväg.
- Artikel-/verktygsnivå: verktygsnamn, samtals-ID, värdbaserade verktygsenheter, fil-ID:n, antal sökfrågor om tillgängligt, verktygslatens, verktygskostnad och godkännandepolicyresultat.
Detta låter utvecklare svara på konkreta frågor:
- Ökade kostnaderna på grund av längre tillstånd, resonemang, verktygsanrop eller reserv?
- Vilken klient eller API-nyckel genererar värdbaserade verktygsavgifter?
- Vilket svar misslyckades efter ett verktygsanrop men före slutlig text?
- Vilka avbrutna strömmar har fortfarande uppströmsanvändning?
Hantera nollretention och radering som förstklassigt beteende
Serversidans tillstånd är användbart, men det ändrar gatewayens lagringskrav. Bygg in policy i protokolllagret istället för att behandla det som en loggningsinställning.
För varje svarsbegäran löser du:
- Behållningspolicy för hyresgäster
- Inställning för
butikpå begäran på nivå - Kompatibilitet med leverantörsbevarande
- Om gatewayuppspelning är tillåten
- Om verktygsingångar och -utgångar kan lagras
- Utgångs- och raderingsbeteende för svarstillstånd
Om lagring är inaktiverat kan gatewayen fortfarande behålla minimal operativ metadata: tidsstämplar, ID:n, status, antal token, kostnader och policybeslut. Undvik att lagra råa uppmaningar, fullständiga verktygsutdata eller rekonstruerad historik om inte policyn tillåter det.
Konformitetsfixturer att lägga till före lansering
Lita inte på happy-path manuella tester. Lägg till fixturer som verifierar protokollbeteende över direkta OpenAI-rutter, leverantörsanpassade rutter och reservscenarier.
Minsta testuppsättning
- Grundläggande svar: textobjekt returneras med stabilt svars-ID och användning.
- Multi-turn state: andra begäran referenser
previous_response_id; gateway validerar hyresgästernas ägande och tillståndsläge. - Upprepade instruktioner: verifiera att utelämnade instruktioner inte uppfanns i tysthet av gatewayen.
- Funktionssamtal tur och retur: modellen avger samtals-ID; ansökan lämnar output; slutligt svar förenar båda posterna.
- Värdverktygspolicy: obehörigt inbyggt verktyg blockeras innan det skickas.
- Strömmande ordning: svarsstart, artikelstart, deltas, objekts slutförande, användning och slutförande sänds ut i giltig ordning.
- Strömavbrytning: Klientfrånkoppling utlöser uppströmsavstängning där det stöds och registrerar partiell användning.
- Tillbaka avslag: leverantör utan krav Svarssemantik returnerar kapacitetsfel.
- Förlustad reservopt-in: begäran med tillåtna förluster får en explicit nedgraderingsmarkör.
- Läge för nollretention: tillståndsuppspelning och lagring av meddelanden på gatewaysidan är blockerade.
Rekommenderad lanseringssekvens
- Exponera en betarutt. Lägg till
/v1/responsesutan att ändra befintligt chattbeteende. - Implementera pass-through först för leverantörer med inbyggt svarsstöd. Bevara ID:n, objekt, strömmar, användning och fel.
- Lägg till huvudboken. Kartlägg gateway-ID:n till leverantörs-ID:n och upprätthåll hyresgästernas ägande.
- Lägg till kanoniska objekt. Lagra objektmetadata som behövs för granskning, fakturering och återuppbyggnad av strömmen.
- Lägg till verktygsstyrning. Validera scheman, upprätthålla omfattningar och registrera verktygssamtal.
- Lägg till strömningsnormalisering. Konvertera leverantörsspecifika strömmar till gatewaylivscykelhändelser.
- Lägg till kapacitetsmedveten routing. Tillåt endast säkra reservalternativ som standard.
- Lägg till analyser och faktureringsavräkning. Ange token, resonemang och verktygsanvändning separat.
- Publicera anteckningar om kompatibilitet. Berätta för utvecklare vilka fält som är inbyggda, emulerade, stöds inte eller förlorar.
Aktiv slutsats
Ett Responses API-kompatibilitetslager bör bevara protokollets betydelse, inte bara returnera rimlig text. Bygg den kring fem hållbara objekt: en kanonisk svarsobjektmodell, en konversationsstatusbok, en verktygsanropsreskontra, en normaliserare för streaminghändelser och en leverantörskapacitetsmatris.
Den säkraste standarden är strikt kompatibilitet: om en rutt inte kan bibehålla erforderligt tillstånd, verktyg, resonemangskontext, strömningshändelser eller lagringsbeteende, returnera ett tydligt funktionsfel. Lägg till en förlustfri reserv när utvecklarna förstår vad som kommer att tas bort. Det tillvägagångssättet kan kännas mindre bekvämt än automatisk utjämning, men det förhindrar det värsta felläget: en applikation som verkar kompatibel samtidigt som den tyst förlorar den semantik som gjorde att den använde Responses API i första hand.