Build in Public · LF-09
Uso del SDK de OpenAI para Gemini: de la petición de texto mínima a una migración reversible
Separa los límites de compatibilidad del SDK, la dirección del servicio y los modelos; valida las peticiones de texto no estuche, los errores y la facturación, y recupera los parámetros por tarea para evitar asumir una compatibilidad total.
Actualización del estado del producto (revisión hora de Pekín 2026-09-13): la API de texto genérico EveryInfra se retiró el 2026-09-12. Este documento conserva el SDK original, el baseURL y los ejemplos no estuche para comprender los clientes anteriores y los límites de retroceso, no como una guía de nueva integración. Las llamadas históricas conservan la compatibilidad con 410 ai_chat_retired; el procesamiento de datos compatible debe usar la limpieza de datos vinculada a tu propia fuente EveryData, un ámbito de clave independiente y una receta fija.
Al migrar una aplicación que ya usa el SDK de OpenAI, el esfuerzo que se suele subestimar no es cambiar la dirección, sino volver a confirmar qué comportamientos siguen vigentes. Que una petición devuelva texto con éxito solo indica que esta entrada obtuvo un resultado en este servicio; no demuestra de forma simultánea que el prompt anterior funcione igual, que el streaming esté disponible, que la llamada a herramientas sea correcta ni que el estado financiero posterior a una anomalía sea coherente.
Este artículo utiliza la entrada de texto no estuche de EveryInfra en Gemini para ofrecer un orden de migración que se puede verificar paso a paso: fija primero la configuración, valida la petición mínima, comprueba la respuesta y los errores, y finalmente restaura los parámetros de negocio y decide si amplías el uso. No es una promesa de compatibilidad general para trasladar todas las funciones de OpenAI a otro servicio.
Cuál capa es compatible
Distingue primero tres elementos: el SDK de OpenAI es una biblioteca cliente; la dirección del servicio determina el sistema que recibe realmente la petición; el ID del modelo debe pertenecer al catálogo que ofrece actualmente ese servicio. Usar el mismo paquete de npm no significa utilizar la misma clave, el mismo conjunto de nombres de modelos o el mismo contrato de servicio.
La documentación de la capa de compatibilidad de OpenAI con Google ofrece ejemplos para acceder al servicio Gemini de Google con el SDK de OpenAI. Este artículo utiliza la dirección y las credenciales de EveryInfra. Los modelos y funciones que aparecen en la documentación de Google no se convierten automáticamente en la lista disponible de EveryInfra; la autenticación y la facturación de ambos deben comprobarse por separado.
La documentación del SDK de TypeScript de OpenAI explica el modo de llamada de Chat Completions. El SDK también incluye otras API, pero que un cliente tenga un método no equivale a que la dirección de destino haya implementado la ruta correspondiente. En particular, no consideres que la migración ha finalizado al cambiar responses.create en proyectos antiguos, la subida de archivos, las tareas en segundo plano o la gestión de sesiones solo por sustituirlo por baseURL.
Fija la configuración primero para evitar cruces de credenciales y direcciones
Divide el entorno al menos en tres grupos: desarrollo, aceptación y producción; especifica en cada uno la dirección del servicio, la clave de ese servicio, el modelo, el tiempo de espera y las funciones permitidas. No cambies una variable de entorno global en un sitio y dejes que otros códigos que aún se conecten al servicio anterior arrastren por error las nuevas credenciales.
Este artículo fija la ruta base de EveryInfra como https://api.everyinfra.com/api/v1, que no es la dirección de la consola ni la ruta completa de /chat/completions. El SDK continuará concatenando los endpoints. Añadir /v1 una vez más o usar el endpoint completo como ruta base puede hacer que las peticiones se envíen a una ubicación incorrecta.
Conserva la clave únicamente en el entorno del servidor y no la incluyas en variables empaquetadas para el navegador, repositorios, capturas de pantalla o registros. No es necesario activar opciones que permitan exponer la clave en el navegador solo para ejecutar este documento. Utiliza también una lista blanca clara para los registros y no imprimas directamente todo el objeto de error del SDK ni las cabeceras de las peticiones.
El diseño de los registros se puede contrastar con la lista de exclusión de información sensible de OWASP: conserva el estado y los identificadores asociados necesarios para la localización, y excluye los tokens, los valores de sesión y la información personal innecesaria. Esto facilita mantener la consistencia en comparación con depender de que cada llamador elimine los campos sensibles de forma manual.
Comprueba los modelos primero con el catálogo público; este paso no requiere una clave de negocio:
set -o pipefail
curl -fsS --max-time 30 'https://api.everyinfra.com/api/v1/models' \
| jq -e '{
default_model,
models: [.data[].id]
} | if (.models | length) > 0
and (.default_model as $m | .models | index($m)) != null
then . else error("invalid model catalog") end'Tras seleccionar en el catálogo el ID que se ajuste a tus necesidades, configura de forma explícita EVERYINFRA_MODEL_ID. Si falla la lectura del catálogo, detén la aceptación y no vuelvas a un nombre anterior de forma silenciosa; los cambios en los valores predeterminados también deben evaluarse como una modificación de configuración en lugar de cambiar de modelo discretamente entre ejecuciones. El catálogo solo demuestra una declaración y no puede verificar si esta clave tiene autorización para llamar al modelo seleccionado.
Empieza por la petición de texto mínima no estuche
A continuación, necesitas el entorno de Node.js en el servidor y el paquete openai bloqueado por el proyecto. El código es una plantilla de llamada de negocio única; este artículo realiza comprobaciones sin conexión sobre él y no califica una respuesta sintética como un resultado en línea. No actualices las dependencias de todo el proyecto para ejecutar el ejemplo; registra primero la versión actual del SDK y el archivo de bloqueo.
import OpenAI from "openai";
const apiKey = process.env.EVERYINFRA_API_KEY?.trim();
const model = process.env.EVERYINFRA_MODEL_ID?.trim();
if (!apiKey || !model) throw new Error("Missing EveryInfra configuration");
const client = new OpenAI({
apiKey,
baseURL: "https://api.everyinfra.com/api/v1",
maxRetries: 0,
timeout: 120_000,
});
const { data, response: http } = await client.chat.completions.create({
model,
messages: [{ role: "user", content: "explica la idempotencia en una frase." }],
stream: false,
}).withResponse();
const choice = data.choices?.[0];
const text = choice?.message?.content;
if (typeof text !== "string" || !text.trim()) {
throw new Error("No usable text; inspect this attempt before retrying");
}
console.log({
httpStatus: http.status,
model: data.model,
finishReason: choice.finish_reason,
requestId: http.headers.get("x-request-id"),
textReceived: true,
});
// pasa el texto text entrégalo a la capa de negocio; no escribas por defecto el contenido generado completo en los registros。Los 120 segundos aquí son un presupuesto de espera del cliente para la demostración y no un límite de tiempo de respuesta del servicio ni una garantía de rendimiento. La aplicación también debe coordinar el tiempo de espera del proxy de entrada, el ejecutor de tareas y la interfaz de usuario. Si el cliente agota el tiempo de espera antes de recibir la información de finalización del servidor, se trata de un resultado desconocido que se debe comprobar y no de una determinación automática de que "no se ha ejecutado".
Desactiva los reintentos automáticos en la primera aceptación para observar una única llamada. El SDK de OpenAI incluye de serie mecanismos de reintento para determinados errores de conexión y del servicio; antes de restablecer los reintentos en producción, aclara primero los acuerdos del servicio de destino sobre peticiones duplicadas, cobros e idempotencia en lugar de limitarte a usar los valores predeterminados del SDK. Explicación de reintentos y tiempos de espera del SDK
Una vez superada la prueba no estuche, no cambies directamente a stream: true
La implementación actual de EveryInfra procesa las peticiones de chat sin streaming. Escribir stream: true en el código o que la capa de compatibilidad oficial de Google admita streaming no demuestra que esta dirección devuelva un flujo de eventos acorde con las expectativas del SDK. Este artículo mantiene explícitamente stream: false y evita conectar una interfaz de usuario en streaming a una ruta no aceptada.
Si tu negocio depende de la visualización palabra por palabra, señálalo primero como una condición de migración no cumplida. Cuando exista un contrato claro, comprueba por separado el tipo de respuesta, el orden de los eventos, las marcas de fin, la recuperación de interrupciones y el uso final. No utilices el éxito de un JSON normal para simular la aceptación del streaming ni dividas fragmentos de texto en el frontend para llamarlo streaming del servidor.
Confirma también por separado las llamadas a herramientas, las salidas estructuradas, las entradas multimodales, el control de razonamiento y otros parámetros opcionales. Que el tipo en el cliente permita un campo solo significa que se puede serializar; esto es muy diferente a que el servicio de destino comprenda dicho campo y lo ejecute según lo previsto.
La respuesta debe responder a tres preguntas de forma simultánea
Primero, si se obtiene contenido que cumpla los requisitos de negocio. Un texto no vacío aún puede desviarse del tema, incumplir el formato de salida o no finalizar por completo debido a restricciones de longitud u otros motivos. Conserva finish_reason, comprueba los criterios de finalización de la propia tarea y no equipares HTTP 200 con el éxito de la tarea del usuario.
Segundo, qué datos se pueden entregar de forma segura a los componentes posteriores. Al leer choices y usage, gestiona los valores ausentes y las diferencias de tipos; las operaciones de negocio que exigen JSON deben analizarlo y verificar su estructura por separado. No confíes en que la respuesta de un tercero en tiempo de ejecución coincida con la declaración estática solo porque la compilación de TypeScript haya tenido éxito.
Tercero, cuáles son el coste y el estado de esta petición. La información de facturación ampliada de EveryInfra no pertenece a los tipos genéricos de todos los SDK y debe validarse mediante la documentación del servicio; no completes los campos ausentes con ceros ni conviertas el uso de tokens directamente en un cargo del monedero. Guardar por separado la salida del modelo, el identificador de la petición y la vinculación contable permite explicar situaciones como "el contenido falla pero el HTTP tiene éxito". Documentación de API y facturación de EveryInfra
La documentación oficial del SDK indica que las propiedades de respuesta adicionales no se eliminan automáticamente por no estar escritas en los tipos estáticos. Cuando necesites estos campos, realiza comprobaciones en tiempo de ejecución en lugar de omitir la validación con as any; .withResponse() permite obtener tanto los datos analizados como la información HTTP, pero no puede inventar un ID de petición que el servicio no haya devuelto. Respuesta ampliada del SDK e información HTTP
Al definir un esquema en tiempo de ejecución para los campos ampliados, puedes consultar la guía de objetos de JSON Schema para describir por separado los tipos de valores obligatorios, opcionales y permitidos. Que la comprobación estructural sea exitosa no demuestra que el significado de la facturación o la conclusión del modelo sean correctos; la semántica de negocio debe validarse por separado.
Localiza los errores primero y decide después si procede reintentar
Los modelos desconocidos y los fallos del servicio no deben seguir la misma rama de procesamiento. En comparación con la línea base del código fuente implementado de 2026-09-04, en peticiones REST con mensajes completos como esta, identifica primero la clave de API y comprueba después el modelo; un modelo desconocido genera 422 unknown_model antes de cobrar. Las peticiones sin mensajes son rechazadas primero por la comprobación de entrada, por lo que este orden no se puede extrapolar a todas las combinaciones de errores. Esta es una comprobación del código fuente y no una observación de peticiones de autenticación reales en esta ronda.
Al recibir unknown_model, actualiza el catálogo y corrige la configuración; no repitas indefinidamente los intentos ante el mismo nombre de error ni aceptes automáticamente modelos candidatos similares, ya que cambiar de modelo puede alterar el comportamiento. 401 comprueba la dirección de destino y la clave; deriva la falta de permisos al responsable de permisos y la insuficiencia de saldo al responsable de cuentas; la aplicación no debe cambiar de clave por cuenta propia para sortear restricciones.
Las anomalías de red se dividen además en dos tipos: fallos en los que se constata que la petición no se completó, y tiempos de espera o cortes de conexión en los que se envió pero cuyo resultado final no se puede confirmar. El cliente por lo general no puede determinar si se ha realizado el cobro basándose únicamente en la clase de excepción. Guarda para cada intento el número de operación de negocio, la hora, el modelo real y el ID de petición disponible; comprueba este intento antes de decidir si lanzas una nueva petición.
Qué se puede verificar mediante comprobaciones sin conexión y qué no
Las pruebas sin conexión pueden sustituir fetch del SDK para comprobar la URL final, el método POST, la forma de la cabecera de autenticación y el cuerpo de la petición, y devolver después una respuesta sintética debidamente marcada. Esto resulta idóneo para detectar rutas duplicadas, errores tipográficos en los parámetros, suposiciones de análisis y problemas en las ramas de error, sin necesidad de enviar un prompt real ni consumir saldo de la cuenta.
La prueba de aislamiento anterior de este artículo con la versión fija 7.10.0 del paquete openai cubrió el texto, el uso y una simulación de 422; en esta ocasión se registran de nuevo de forma explícita la versión y el ámbito de prueba sin calificarlo de versión más reciente ni de certificación de compatibilidad del servicio. La nueva plantilla mínima también debe comprobar que la ausencia de configuración impide enviar peticiones, que una llamada única no reintenta automáticamente y que el contenido en blanco se conserva como un resultado pendiente de verificación.
El archivo de 2026-09-02 contiene además muestras de producción del SDK de Python. Estas podían admitir aquella petición de Python en su momento, pero no demuestran que la plantilla de TypeScript actual haya completado una integración real. En esta ronda no se han añadido llamadas de negocio de TS reales; la autenticación, la calidad del texto diario y los resultados contables siguen requiriendo la validación de muestras autorizadas.
Restaura los parámetros de negocio por muestra de tarea
Una vez superada la petición mínima, recupera una sola categoría de función por vez: primero el prompt real y el contexto, luego las restricciones de salida y, por último, las opciones que la aplicación realmente necesita y que el servicio declara admitir. Guarda una entrada reproducible mínima para poder contrastarla si surge un error, en lugar de trasladar todos los parámetros del proyecto antiguo de golpe.
Al crear muestras de tarea, incluye entradas correctas comunes, entradas vacías, contextos largos, preguntas propensas a ambigüedades y los formatos exigidos por el negocio. Evalúa si se completa la tarea, si el formato es analizable y si los hechos clave tienen fundamento; no utilices la coincidencia palabra por palabra como el único criterio de éxito de un modelo generativo. Cualquier porcentaje de calidad debe detallar las muestras y los criterios humanos, y no se puede extrapolar un rendimiento general a partir de unas pocas pruebas improvisadas.
Si una petición real tiene éxito pero la salida de negocio empeora, localiza primero si se debe al prompt, al modelo, al truncamiento de la entrada o a las reglas de análisis; no atribuyas todas las diferencias al SDK. Por el contrario, cuando ni siquiera el HTTP tenga éxito, investiga primero la ruta, la autenticación y el estado del servicio; ajustar los prompts normalmente no soluciona los problemas de conexión.
Haz que la migración sea reversible, pero no repitas automáticamente las acciones de negocio
La capa de llamadas de negocio puede conservar configuraciones explícitas de la dirección del servicio, el modelo y la versión, registrando qué grupo se utiliza en esta ocasión; guarda la configuración anterior aceptada antes de cambiar. El objetivo de retroceder es recuperar un estado controlable para las peticiones posteriores, no reenviar automáticamente a otro servicio cada petición cuyo resultado se desconoce.
Antes de ampliar el uso formalmente, confirma que se pueden revalidar una ruta de texto real autorizada, un conjunto de muestras de negocio, el manejo de errores y la vinculación contable. Si necesitas streaming o funciones de herramientas y todavía no hay pruebas de aceptación, manténlas en la lista de elementos no migrados. De este modo, "completar la migración" corresponderá a tareas y funciones concretas, en lugar de limitarse a cambiar tres líneas de configuración en el cliente.