Cuando utiliza varias API de búsqueda, cada una tiene diferentes niveles de precios, créditos gratuitos y límites de tarifas. Un enrutador de costos selecciona automáticamente el proveedor más barato disponible para cada consulta, agotando primero los niveles gratuitos antes de gastar dinero. Este tutorial construye un enrutador en Scavio (250 gratis/mes, $0.005 después), Brave (crédito mensual gratuito de $5) y Tavily (1K gratis/mes). El enrutador rastrea el uso, respeta los límites de velocidad y retrocede con elegancia.
Requisitos previos
- Python 3.9+ instalado
- Claves API para al menos dos proveedores de búsqueda
- solicita biblioteca instalada
Guia paso a paso
Paso 1: Definir configuraciones de proveedor
Configure cada proveedor con su precio, nivel gratuito, límites de tarifas y formato de llamada API.
import os
providers = {
'scavio': {
'cost_per_query': 0.005,
'free_monthly': 250,
'rate_limit_per_sec': 10,
'api_key': os.environ.get('SCAVIO_API_KEY', ''),
'priority': 1, # lower = preferred
},
'brave': {
'cost_per_query': 0.005,
'free_monthly': 1000, # $5 free credit = 1K queries
'rate_limit_per_sec': 5,
'api_key': os.environ.get('BRAVE_API_KEY', ''),
'priority': 2,
},
'tavily': {
'cost_per_query': 0.03,
'free_monthly': 1000,
'rate_limit_per_sec': 5,
'api_key': os.environ.get('TAVILY_API_KEY', ''),
'priority': 3,
},
}
for name, p in providers.items():
status = 'configured' if p['api_key'] else 'no key'
print(f' {name}: ${p["cost_per_query"]}/query, {p["free_monthly"]} free/mo [{status}]')Paso 2: Construya el enrutador de costos con seguimiento de uso
El enrutador rastrea el uso mensual por proveedor, usa créditos gratuitos primero y luego dirige al proveedor pago más barato.
import time, requests
from datetime import datetime
class CostRouter:
def __init__(self, providers: dict):
self.providers = providers
self.usage = {name: 0 for name in providers}
self.month = datetime.now().month
self.last_call = {name: 0.0 for name in providers}
def _reset_if_new_month(self):
current_month = datetime.now().month
if current_month != self.month:
self.usage = {name: 0 for name in self.providers}
self.month = current_month
def _get_cost(self, name: str) -> float:
p = self.providers[name]
if self.usage[name] < p['free_monthly']:
return 0.0
return p['cost_per_query']
def _can_call(self, name: str) -> bool:
p = self.providers[name]
if not p['api_key']:
return False
elapsed = time.time() - self.last_call[name]
return elapsed >= (1.0 / p['rate_limit_per_sec'])
def select_provider(self) -> str:
self._reset_if_new_month()
available = [(name, self._get_cost(name), self.providers[name]['priority'])
for name in self.providers if self._can_call(name)]
if not available:
return list(self.providers.keys())[0] # fallback to first
# Sort by cost, then priority
available.sort(key=lambda x: (x[1], x[2]))
return available[0][0]
def search(self, query: str) -> dict:
provider = self.select_provider()
cost = self._get_cost(provider)
results = self._call_provider(provider, query)
self.usage[provider] += 1
self.last_call[provider] = time.time()
return {'results': results, 'provider': provider,
'cost': cost, 'usage': dict(self.usage)}Paso 3: Implementar llamadas API específicas del proveedor
Agregue la lógica de llamada API real para cada proveedor. El enrutador envía automáticamente al correcto.
def _call_provider(self, name: str, query: str) -> list:
p = self.providers[name]
try:
if name == 'scavio':
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': p['api_key'], 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us', 'num_results': 10},
timeout=10)
return [{'title': r['title'], 'link': r['link'], 'snippet': r.get('snippet', '')}
for r in resp.json().get('organic_results', [])]
elif name == 'brave':
resp = requests.get('https://api.search.brave.com/res/v1/web/search',
headers={'X-Subscription-Token': p['api_key']},
params={'q': query, 'count': 10}, timeout=10)
return [{'title': r['title'], 'link': r['url'], 'snippet': r.get('description', '')}
for r in resp.json().get('web', {}).get('results', [])]
elif name == 'tavily':
resp = requests.post('https://api.tavily.com/search',
json={'api_key': p['api_key'], 'query': query, 'max_results': 10},
timeout=10)
return [{'title': r.get('title', ''), 'link': r['url'], 'snippet': r.get('content', '')}
for r in resp.json().get('results', [])]
except Exception as e:
print(f'{name} failed: {e}')
return []
return []
# Initialize and test
router = CostRouter(providers)
result = router.search('best search API 2026')
print(f'Provider: {result["provider"]}, Cost: ${result["cost"]:.3f}')
print(f'Results: {len(result["results"])}')
print(f'Usage: {result["usage"]}')Ejemplo en Python
import requests, os, time
SCAVIO_KEY = os.environ.get('SCAVIO_API_KEY', '')
BRAVE_KEY = os.environ.get('BRAVE_API_KEY', '')
usage = {'scavio': 0, 'brave': 0}
def route_search(query):
# Use free credits first
if usage['scavio'] < 250 and SCAVIO_KEY:
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us', 'num_results': 10})
usage['scavio'] += 1
return {'results': resp.json().get('organic_results', []), 'provider': 'scavio', 'cost': 0}
if usage['brave'] < 1000 and BRAVE_KEY:
resp = requests.get('https://api.search.brave.com/res/v1/web/search',
headers={'X-Subscription-Token': BRAVE_KEY}, params={'q': query, 'count': 10})
usage['brave'] += 1
return {'results': resp.json().get('web', {}).get('results', []), 'provider': 'brave', 'cost': 0}
# Paid fallback
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us', 'num_results': 10})
usage['scavio'] += 1
return {'results': resp.json().get('organic_results', []), 'provider': 'scavio', 'cost': 0.005}
result = route_search('best search api 2026')
print(f'{result["provider"]}: {len(result["results"])} results, ${result["cost"]}')Ejemplo en JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
const BRAVE_KEY = process.env.BRAVE_API_KEY;
const usage = { scavio: 0, brave: 0 };
async function routeSearch(query) {
if (usage.scavio < 250 && SCAVIO_KEY) {
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: 'us', num_results: 10 })
});
usage.scavio++;
return { results: (await resp.json()).organic_results || [], provider: 'scavio', cost: 0 };
}
if (usage.brave < 1000 && BRAVE_KEY) {
const resp = await fetch(`https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=10`, {
headers: { 'X-Subscription-Token': BRAVE_KEY }
});
usage.brave++;
return { results: (await resp.json()).web?.results || [], provider: 'brave', cost: 0 };
}
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: 'us', num_results: 10 })
});
usage.scavio++;
return { results: (await resp.json()).organic_results || [], provider: 'scavio', cost: 0.005 };
}
routeSearch('best search api').then(r => console.log(`${r.provider}: ${r.results.length} results`));Salida esperada
scavio: $0.005/query, 250 free/mo [configured]
brave: $0.005/query, 1000 free/mo [configured]
tavily: $0.030/query, 1000 free/mo [no key]
Provider: scavio, Cost: $0.000
Results: 10
Usage: {'scavio': 1, 'brave': 0, 'tavily': 0}
First 250 queries: $0.00 (Scavio free)
Next 1000 queries: $0.00 (Brave free)
Remaining: $0.005/query (cheapest paid)