Cursos de IA

Usar la API de un modelo en tu producto: primeros pasos

Conseguir que una llamada a un modelo devuelva una respuesta toma diez minutos. Lograr que esa llamada se comporte bien cuando hay mil usuarios, la red falla y el modelo devuelve algo inesperado lleva bastante más. Esta nota repasa lo que conviene resolver antes de mostrarle la función a un cliente.

La credencial vive en el servidor

Los proveedores te dan una credencial secreta para autenticar las llamadas, y cada llamada se factura contra ella. Si la ponés en el código de un frontend, en una app móvil o en un repositorio público, cualquiera puede extraerla y gastar a tu nombre.

La regla es simple: el navegador o la app llaman a tu backend, y tu backend llama al modelo. La credencial se lee de una variable de entorno o de un gestor de secretos, nunca de un archivo versionado. Tu backend, además, es el lugar donde podés limitar cuántas consultas hace cada usuario, registrar el uso y recortar lo que se envía. Si alguna vez se filtra la credencial, revocala y generá otra de inmediato.

Timeouts y reintentos

Una llamada a un modelo puede tardar varios segundos, y a veces mucho más. Si tu servidor espera indefinidamente, un pico de lentitud te deja sin conexiones libres. Definí siempre un timeout explícito, pensado según lo que tolera tu experiencia de usuario.

Los errores pasajeros (límite de uso alcanzado, servicio sobrecargado, corte de red) se resuelven reintentando, pero no de golpe: si cien procesos reintentan al mismo tiempo, empeoran lo que intentan arreglar. La técnica habitual es la espera creciente con un poco de azar:

import random
import time

def con_reintentos(llamada, intentos=4, espera_base=1.0):
    for intento in range(intentos):
        try:
            return llamada()
        except (TimeoutError, ConnectionError):
            if intento == intentos - 1:
                raise
            time.sleep(espera_base * 2 ** intento + random.random())

Esperá uno, dos, cuatro segundos más una fracción aleatoria. Reintentá solo errores que tengan sentido reintentar: una petición mal formada o una credencial inválida van a fallar igual la cuarta vez. Y si la operación tiene efectos (cobrar, enviar un correo), pensá antes qué pasa si se ejecuta dos veces.

Streaming para respuestas largas

Un modelo genera su respuesta de a poco. Si esperás a tenerla completa para mostrarla, el usuario mira una pantalla vacía durante varios segundos. Muchas APIs ofrecen streaming: te mandan los fragmentos a medida que se producen, y tu interfaz los va mostrando. La sensación de velocidad mejora mucho aunque el tiempo total sea el mismo.

El streaming complica algunas cosas. Una respuesta cortada a la mitad por un error es más difícil de manejar, y si necesitás validar el resultado completo (por ejemplo, un JSON), tenés que esperar el final. Usalo para texto que lee una persona, y no para salidas que va a procesar otro programa.

Salidas estructuradas y validación

Cuando tu código consume la respuesta, pedí un formato fijo, y después no confíes en que lo cumplió. Los modelos a veces agregan texto antes del JSON, omiten un campo o inventan un valor fuera de la lista permitida.

import json

CATEGORIAS = {"factura", "acceso", "consulta", "reclamo"}

def leer_respuesta(texto):
    try:
        datos = json.loads(texto)
    except json.JSONDecodeError:
        return None
    if not isinstance(datos, dict):
        return None
    if datos.get("categoria") not in CATEGORIAS:
        return None
    if not isinstance(datos.get("urgente"), bool):
        return None
    return datos

Si la validación falla, tenés opciones: reintentar una vez con la misma entrada, caer a un valor por defecto seguro o derivar el caso a una persona. Lo que no corresponde es dejar pasar el dato dudoso hacia el resto del sistema.

No confiar a ciegas en la salida

La respuesta del modelo es una entrada más, igual que lo que escribe un usuario en un formulario. Si la vas a mostrar en una página web, escapala como cualquier texto externo. Si la vas a usar para armar una consulta a la base de datos o ejecutar un comando, tratala con el mismo recelo: jamás concatenes esa salida en una sentencia SQL ni la pases a un intérprete de comandos. Y si el modelo ve texto de terceros (correos, páginas web), ese texto puede contener instrucciones disfrazadas que intenten desviarlo, así que limitá lo que el modelo puede hacer por su cuenta.

Para cerrar el circuito

Registrá cada llamada con su duración, su cantidad de tokens y si falló. Con eso detectás rápido cuándo sube el gasto o cuándo un cambio de prompt empeoró los resultados. Ponele además un tope mensual de gasto en tu cuenta si el proveedor lo permite, porque un bucle mal escrito puede salir caro antes de que lo notes.