Transmisión de contabilidad de tokens en una puerta de enlace API de IA: uso final, cancelaciones y respuestas parciales
La transmisión mejora la latencia percibida, pero puede interrumpir el análisis y la facturación del uso de la IA si la puerta de enlace solo transfiere bytes. A continuación se muestra un patrón práctico de máquina de estados para capturar el uso final, transmisiones abortadas, errores del proveedor y respuestas parciales.
La transmisión de respuestas de LLM es fácil de representar y difícil de facturar correctamente. Si una puerta de enlace API AI reenvía eventos enviados por el servidor al cliente pero trata los primeros fragmentos como el registro de uso, los análisis de los inquilinos se desviarán. La deriva suele aparecer en disputas como: "el usuario solo vio la mitad de la respuesta", "el proveedor facturó más de lo que muestra nuestro panel", "la cuota se liberó demasiado pronto" o "un tiempo de espera produjo tokens pero no una línea de factura".
La raíz del problema es que las llamadas transmitidas no son un solo evento. Son una secuencia: solicitud aceptada, flujo ascendente abierto, bytes entregados, uso final informado, proveedor detenido, cliente desconectado, tiempo de espera agotado y facturación liquidada. Una puerta de enlace confiable debe modelar esos estados explícitamente en lugar de asumir que una respuesta HTTP completa es la única ruta exitosa.
El modo de fracaso: el streaming oculta los límites contables
Las finalizaciones no transmitidas generalmente devuelven un objeto de respuesta con metadatos de uso. Una puerta de enlace puede normalizar ese uso, escribir una fila del libro mayor, actualizar la cuota y emitir análisis en una sola pasada.
El streaming cambia los límites. La experiencia del usuario es incremental, pero la verdad de la facturación puede llegar al final, en un evento final específico del proveedor, en un delta acumulativo, a través de una respuesta SDK agregada o más tarde a través de las API de informes del proveedor. Si el cliente se desconecta antes del evento de uso final, es posible que la puerta de enlace haya entregado solo una parte de la respuesta mientras que el proveedor aún generó y facturó más tokens.
Hecho: OpenAI documenta que las personas que llaman por streaming y desean datos de uso deben configurar stream_options con include_usage. OpenAI también proporciona puntos finales de uso y costos a nivel de organización, aunque señala que es posible que el uso y los costos no siempre se concilien perfectamente para fines financieros.
Dato: La transmisión antrópica utiliza eventos enviados por el servidor, como message_start, content_block_delta, message_delta y message_stop. Su información de uso de message_delta es acumulativa, por lo que una puerta de enlace no debe sumar cada delta de uso.
Hecho: Las API de transmisión de estilo Gemini y Vertex pueden exponer fragmentos incrementales, mientras que los SDK también pueden proporcionar un objeto de respuesta agregado. Para las puertas de enlace, esa ruta agregada puede ser una mejor fuente para el uso completo que los fragmentos visibles por sí solos.
Utilice una máquina de estado de flujo, no un indicador de éxito booleano
Una solicitud transmitida debe tener un registro de uso duradero antes de que comience la llamada ascendente. Ese registro debería pasar por estados explícitos. Un mínimo práctico es:
aceptado: la puerta de enlace autenticó la clave, atribuyó el inquilino y creó una fila del libro mayor abierta.first_byte_sent: al menos un evento de salida llegó al cliente descendente.provider_completed: el proveedor ascendente emitió una señal de parada normal u objeto de respuesta completa.client_aborted: el socket descendente se cerró antes de que se completara la puerta de enlace normal.provider_error: el proveedor ascendente devolvió un error después de que comenzara la transmisión o antes de que llegara el uso final.gateway_timeout: la puerta de enlace aplicó su presupuesto de latencia y finalizó la solicitud.resuelto: la puerta de enlace convirtió el uso en costo de inquilino y consumo de cuota.conciliado: el uso posterior del proveedor o los datos de costos confirmaron o ajustaron la fila.
Este modelo evita un error de análisis común: marcar cada secuencia que produjo texto como "exitosa y exacta". Un flujo puede ser útil para el usuario, incompleto del proveedor, estimado para facturación y pendiente de conciliación al mismo tiempo.
Campos de libro mayor recomendados
Mantenga la fila de tiempo de solicitud pequeña pero explícita:
{ "request_id": "gw_req_...", "tenant_id": "tenant_123", "api_key_id": "key_456", "proveedor": "openai|antrópico|géminis|...", "provider_request_id": nulo, "modelo": "id-modelo-proveedor", "estado": "aceptado", "corriente": verdadero, "tokens_entrada": nulo, "output_tokens_billed": nulo, "output_tokens_delivered_estimate": 0, "proveedor_usage_source": nulo, "billing_status": "pendiente_reconciliación", "client_abort_at": nulo, "provider_completed_at": nulo, "asentado_en": nulo, "error_class": nulo }
La separación importante es output_tokens_billed versus output_tokens_delivered_estimate. A los usuarios les importa lo que llegó a su aplicación. A Finanzas le importa lo que facturó el proveedor. Esos números pueden diferir después de desconexiones, flujos de llamadas de herramientas, tokens de razonamiento ocultos, tokens almacenados en caché, paradas de seguridad o tiempos de espera de puerta de enlace.
Reglas de captura específicas del proveedor
Una API compatible con OpenAI neutral para el proveedor es útil para los desarrolladores de aplicaciones, pero el adaptador de puerta de enlace aún necesita reglas de contabilidad específicas del proveedor.
Transmisión compatible con OpenAI
Para rutas OpenAI, exponga una opción de puerta de enlace que permita generar informes de uso ascendentes cuando sea compatible. Un patrón común es aceptar un valor predeterminado a nivel de puerta de enlace, como por ejemplo:
{ "corriente": verdadero, "opciones_transmisión": { "include_usage": verdadero } }
Si la persona que llama en sentido descendente lo omite, la puerta de enlace puede decidir si lo inyecta en las rutas en las que hacerlo sea compatible. Documente este comportamiento porque algunos clientes esperan una compatibilidad de cables exacta y es posible que algunos modelos o versiones anteriores no admitan el uso final de la misma manera.
Recomendación: no liquidar los costos del inquilino desde las primeras partes. Mantenga abierta la fila del libro mayor hasta que se capture el evento de uso final, la respuesta del proveedor finalice sin uso o la transmisión ingrese una ruta de error o cancelación.
Transmisión antrópica
El uso acumulativo de Anthropic requiere una regla diferente. Si una puerta de enlace ve tres eventos message_delta con recuentos de tokens de salida de 10, 25 y 40, el recuento de salida es 40, no 75.
let lastUsage = null;
para esperar (evento constante de anthropicStream) {
if (evento.tipo === "mensaje_delta" && evento.uso) {
if (últimoUso && event.usage.output_tokens <últimoUsage.output_tokens) {
emit("cumulative_usage_regressed", requestId);
}
últimoUso = evento.uso;
}
forwardToClient(evento);
}
liquidarFromLatestCumulativeUsage(últimoUso);
Recomendación: registre el último valor de uso acumulado y emita un evento de observabilidad si retrocede. Una regresión puede indicar errores del analizador, eventos duplicados, cambios de proveedor o transmisiones mixtas.
Transmisión estilo Géminis y Vertex
Gemini admite fragmentos de transmisión para reducir la latencia percibida. En los SDK de estilo Vertex, la transmisión puede exponer tanto una transmisión asíncrona como un objeto de respuesta agregada. Una puerta de enlace debe conservar esa ruta agregada cuando esté disponible.
const streamingResult = await model.generateContentStream(solicitud);
para await (fragmento constante de streamingResult.stream) {
forwardChunk(trozo);
countDeliveredBytesOrText(fragmento);
}
const agregado = espera streamingResult.response;
liquidarFromAggregatedUsage(agregado);
Recomendación: evite crear toda la contabilidad a partir de fragmentos visibles si el SDK proporciona un registro de respuesta completo. Los fragmentos sirven para la latencia. El objeto final suele ser mejor para la facturación y el análisis.
Manejar las desconexiones de clientes como eventos contables de primera clase
Las desconexiones de clientes provocan que muchas puertas de enlace pierdan dinero o cobren de más a sus clientes. Se cierra una pestaña del navegador, se cae una red móvil o una aplicación cancela una solicitud. La puerta de enlace detecta que el socket descendente está cerrado, pero es posible que el proveedor ascendente aún esté generando.
La puerta de enlace debe tomar una decisión política explícita:
- Cancelar el flujo ascendente inmediatamente: reduce el desperdicio de generación y el costo del proveedor, pero puede interrumpir los flujos de trabajo cuando el backend todavía necesita el resultado después de que la interfaz de usuario se desconecta.
- Continuar en segundo plano: puede conservar el trabajo para los consumidores del lado del servidor, pero es posible que el usuario no vea todos los tokens generados y facturados.
- Comportamiento dependiente de la ruta: cancelar para chat interactivo, continuar para flujos de trabajo similares a trabajos y hacer que la configuración sea visible para los inquilinos.
Un valor predeterminado práctico para la transmisión interactiva es cancelar la transmisión ascendente cuando el cliente descendente se desconecta y luego marcar la fila del libro mayor como client_aborted. Si el uso final llega durante la cancelación, liquide a partir de ese uso autorizado. De lo contrario, marque la fila estimated o pending_reconciliation en lugar de fingir que es exacta.
downstream.on("cerrar", async () => { si (! proveedorCompleted) { libro mayor.markClientAborted(requestId); aguardar aguas arriba.abort().catch(() => { ledger.emit("upstream_cancel_failed", requestId); }); } });
Recomendación: exponer etiquetas de facturación transparentes como final, provider_reconciled, estimated, waived o pending_reconciliation. Esto es más defendible que mostrar cada llamada transmitida como inmediatamente exacta.
Cuotas impuestas durante una transmisión
La facturación precisa generalmente depende del uso del proveedor final, pero el cumplimiento de la cuota no siempre puede esperar hasta el final. A un inquilino con un presupuesto estricto no se le debe permitir transmitir indefinidamente porque el uso exacto no está disponible en pleno proceso.
Utilice dos mecanismos juntos:
- Reserva de verificación previa: reserve un máximo estimado según el modelo, los tokens máximos solicitados, la política del inquilino y el saldo actual.
- Comprobaciones de presión de transmisión: estima la producción entregada durante la transmisión y deténgala si la solicitud cruza un límite de seguridad configurado.
Este es un mecanismo de control, no la factura final. Los proveedores pueden contar los tokens almacenados en caché, los tokens de razonamiento, los tokens multimodales o los tokens ocultos de manera diferente al estimador de una puerta de enlace.
Compensación: las estimaciones en tiempo real ayudan a hacer cumplir los presupuestos, pero pueden diferir de los tokens facturados por el proveedor. La liquidación final debe utilizar el uso de proveedores autorizados cuando esté disponible, y la conciliación debe ajustar las estimaciones más adelante.
Eventos de observabilidad que detectan errores contables
Los errores de facturación de streaming son más fáciles de depurar cuando la puerta de enlace emite eventos específicos en lugar de solo registros de solicitudes genéricos. Añade eventos como:
final_usage_missing: la transmisión finalizó sin uso autorizado.cumulative_usage_regressed: el recuento de tokens acumulados se movió hacia atrás.stream_ended_ without_stop_event: no se observó ningún marcador de parada de proveedor normal.aborted_after_provider_completion: el proveedor se completó, pero el cliente descendente se cerró antes de que la puerta de enlace terminara de reenviar.settled_from_estimate: el libro mayor de inquilinos utilizó una estimación porque el uso final no estaba disponible.reconciliation_adjusted_usage: los informes del proveedor cambiaron posteriormente la fila.
Hecho: Las convenciones semánticas de OpenTelemetry GenAI recomiendan utilizar la información de uso devuelta por el proveedor para transmitir respuestas cuando esté disponible, y advierten contra la presentación de informes de métricas de uso si los recuentos de tokens no se pueden obtener de manera eficiente o precisa.
Para los análisis de uso de IA, esto significa que los paneles deben respaldar los niveles de confianza. Un gráfico que combine valores finales, estimados y conciliados sin etiquetas puede parecer limpio, pero inducir a error a los equipos de finanzas y soporte.
Pruebas de conformidad para la contabilidad de streaming
No confíe en las pruebas manuales con un mensaje de chat de ruta feliz. Cada adaptador de proveedor debe tener pruebas de conformidad para los casos que rompen los libros mayores:
- Transmisión normal: llega el uso final, se observa el evento de detención, el libro mayor se establece como
final. - Flujo de llamadas de herramientas: los deltas de llamadas de herramientas se reenvían, se captura el uso y los metadatos estructurados no dañan el recuento de tokens.
- Parada de seguridad o rechazo: el proveedor se detiene antes de tiempo, el uso aún se establece correctamente.
- Desconexión forzada del cliente: el flujo descendente se cierra después de una salida parcial; upstream se cancela o continúa según la política.
- Ascendente 5xx después de la salida parcial: la puerta de enlace registra la entrega parcial y no marca la solicitud como un éxito limpio.
- Tiempo de espera de la puerta de enlace antes del uso final: la fila pasa a ser estimada o pendiente de conciliación.
- Evento final faltante: el adaptador emite
final_usage_missingy evita etiquetas de facturación exactas.
Estas pruebas deben afirmar las transiciones de estado, los campos del libro mayor, los eventos de observabilidad emitidos y el comportamiento posterior. La compatibilidad de flujo byte por byte no es suficiente; los efectos secundarios contables son parte del contrato.
Lista de verificación de implementación práctica
- Cree la fila del libro mayor de uso antes de enviar la solicitud ascendente.
- Almacenar inquilino, clave, usuario, modelo, ruta, proveedor e identificadores de solicitud en el momento de la solicitud.
- Habilite los informes de uso final del proveedor cuando sea compatible, como
stream_options.include_usagecompatible con OpenAI. - Para proveedores acumulativos, almacene el valor de uso más reciente en lugar de sumar eventos.
- Conservar los objetos de respuesta agregados cuando los SDK los proporcionen.
- Realice un seguimiento de la producción entregada por separado del uso facturado por el proveedor.
- Al desconectarse, cancele el flujo ascendente de acuerdo con la política de ruta y marque
client_aborted. - Utilice estados de facturación transparentes: final, estimado, pendiente de conciliación, proveedor conciliado o exento.
- Emitir eventos de observabilidad específicos de la contabilidad.
- Conciliar más adelante el uso del proveedor o los informes de costos cuando estén disponibles, preservando al mismo tiempo la atribución del inquilino en el momento de la solicitud.
Qué mostrar a los inquilinos
Los inquilinos no necesitan todos los eventos internos, pero sí necesitan etiquetas honestas. Una tabla de uso útil podría mostrar:
- Estado: final, estimado o conciliado.
- Resultado de la solicitud: completada, cliente cancelado, error del proveedor o tiempo de espera de la puerta de enlace.
- Salida entregada: texto aproximado o bytes enviados al cliente.
- Tokens facturados: uso normalizado por el proveedor utilizado para calcular el costo.
- Ajuste: cualquier delta de conciliación posterior.
Este diseño reduce la ambigüedad de soporte. Si un usuario vio solo una parte de una respuesta, el panel puede explicar si el proveedor ya la había completado, si la puerta de enlace canceló la respuesta y si el cargo es final o estimado.
Recomendaciones versus predicciones
Recomendaciones: trate las solicitudes transmitidas como máquinas de estado, espere el uso final autorizado antes de la liquidación exacta, separe la salida entregada del uso facturado y etiquete las filas estimadas de manera honesta. Los adaptadores de proveedores deben codificar la semántica de uso específica del proveedor en lugar de aplanar cada flujo en un proxy de bytes genérico.
Predicción: la contabilidad de streaming será más importante a medida que los modelos expongan más trabajo oculto: tokens de razonamiento, descuentos de tokens almacenados en caché, procesamiento multimodal, seguimientos de uso de herramientas y paradas de seguridad. Las puertas de enlace que ya separan el uso facturado por el proveedor de la salida visible para el cliente se adaptarán más fácilmente que las puertas de enlace que solo cuentan el texto transmitido.
Conclusión procesable
Si su puerta de enlace admite streaming, audite una ruta hoy: fuerce la desconexión de un cliente después de los primeros fragmentos e inspeccione la fila del libro mayor. Si dice "éxito" con recuentos de tokens exactos, probablemente sus análisis estén mintiendo.
La solución es no abandonar el streaming. Mantenga la experiencia de usuario rápida, pero haga que los estados contables explícitos de finalización de transmisión, cancelación, errores de proveedor, falta de uso final y conciliación. Esto les brinda a los equipos de productos resultados receptivos, costos defendibles a los equipos de finanzas y a los equipos de soporte evidencia suficiente para explicar respuestas parciales sin adivinar.