Dale a un agente de IA búsqueda web en vivo con un límite de gasto estricto

Un agente que puede buscar en la web también puede entrar en bucle. Cómo conectar la búsqueda para que el presupuesto lo imponga la API, no la esperanza.

Dar a un modelo una herramienta de búsqueda son cuatro líneas de código. Darle una herramienta de búsqueda que no pueda costarte 4.000 $ de la noche a la mañana requiere un poco más de cuidado.

El modo de fallo es concreto: un agente que reintenta sobre resultados vacíos, o que descompone una sola pregunta en cuarenta subconsultas, o que se queda atrapado en un bucle de planificar-buscar-replanificar. Nada de esto parece un bug mientras sucede. Parece un agente trabajando duro.

No confíes en el prompt para el presupuesto

“Usa como máximo 5 búsquedas” en un system prompt es una preferencia, no un límite. Se degrada en contextos largos, queda anulado por un plan convincente y desaparece del todo en cuanto el agente recibe una pregunta realmente difícil.

Los límites de gasto van en tres sitios con los que el modelo no puede discutir.

Nivel 1: un saldo de créditos que el modelo no puede superar

El límite más externo debería ser la propia clave. Una clave con un saldo de créditos finito no puede gastar más de ese saldo, decida lo que decida el agente. En FastAF el saldo vive en la cuenta y cada solicitud reserva su coste antes de empezar el trabajo, así que un bucle descontrolado choca con 402 insufficient_credits y se detiene.

El saldo pertenece a la cuenta, y todas las claves de esa cuenta tiran de él. Las claves sirven para revocar el acceso (una por despliegue, así una clave filtrada se corta sola), no para repartir el dinero: si un proyecto secundario no debe poder vaciar el presupuesto de tu pipeline de producción, dale su propia cuenta con su propio saldo, recargado de forma deliberada.

Nivel 2: un presupuesto por ejecución en el wrapper de la herramienta

Dentro de una sola ejecución, cuenta lo que gastas y niégate a seguir. Cada respuesta lleva su coste en una cabecera, así que la contabilidad es exacta, no estimada:

import requests

class SearchBudget:
    cost = 5  # credits per search

    def __init__(self, api_key, max_credits=100):
        self.api_key = api_key
        self.max_credits = max_credits
        self.spent = 0

    def search(self, query, country="us"):
        if self.spent + self.cost > self.max_credits:
            # Se devuelve al modelo como resultado normal de la tool, no como
            # excepción: el agente debe poder razonar sobre quedarse sin presupuesto.
            return {"error": "presupuesto de búsqueda agotado para esta ejecución"}

        response = requests.get(
            "https://api.fastaf.co/v1/serp",
            params={"query": query, "country": country},
            headers={"Authorization": f"Bearer {self.api_key}"},
            timeout=60,
        )

        if response.status_code == 402:
            return {"error": "sin créditos"}
        if response.status_code != 200:
            return {"error": response.json().get("error", {}).get("code", "search_failed")}

        self.spent += int(response.headers.get("X-FastAF-Credits-Used", 5))
        data = response.json()
        return {
            "results": [
                {"title": r["title"], "link": r["link"], "snippet": r.get("snippet")}
                for r in data.get("organic_results", [])[:5]
            ],
            "credits_remaining": self.max_credits - self.spent,
        }

La comprobación es spent + cost > max_credits, no solo spent: con un presupuesto de 6, comprobar solo spent dejaría pasar una segunda búsqueda de 5 créditos, 10 en total.

Dos detalles importan más de lo que parece. Primero, el agotamiento se devuelve como resultado de la tool en vez de lanzarse como excepción, así el agente puede adaptarse y responder con lo que tiene en vez de hacer fallar la ejecución. Segundo, decirle al modelo cuánto presupuesto le queda cambia su comportamiento de forma medible: los agentes que pueden ver un presupuesto que se reduce priorizan sus consultas.

Nivel 3: recorta lo que vuelve al contexto

Una respuesta SERP en bruto es grande, y meterla entera en el contexto cuesta más en tokens de lo que cuesta la búsqueda en créditos. Devolver los cinco primeros resultados con título, enlace y snippet suele ser suficiente para que el modelo decida qué leer entero, y mantiene el bucle barato.

Por eso también conviene que “buscar” y “traer la página” sean dos tools separadas: deja que el modelo busque barato y luego paga por la página completa solo para los dos o tres enlaces que de verdad quiere.

Nivel 4: limita la concurrencia

Si tu agente lanza subconsultas en paralelo, limita el fan-out al nivel de concurrencia de tu plan o por debajo. Por encima obtienes respuestas 429 con una cabecera Retry-After, que un bucle de reintento ingenuo convierte en una ráfaga de solicitudes duplicadas. Respeta la cabecera y mantén el pool de workers pequeño.

Hacia dónde va esto

Hoy la forma limpia de montar esto es una llamada REST con una clave de alcance limitado y un presupuesto que impones en el wrapper, que es lo que hace el código de arriba. La otra vía es que el propio agente pague por llamada, sin cuenta alguna. FastAF ya admite x402 en todos los endpoints REST, a 0,001 USDC por crédito en Base: una búsqueda de Google cuesta 0,005 $ y solo se cobra si la llamada sale bien (MPP no está soportado). El tope pasa a ser el saldo del wallet, mientras que con volumen los créditos prepagados siguen siendo más baratos. La documentación de x402 muestra el flujo completo.

La documentación tiene la lista completa de endpoints y la semántica de errores, y los precios tienen el coste en créditos de cada llamada para que puedas dimensionar bien un presupuesto por ejecución.