Depender de un único proveedor de búsqueda significa que su agente falla cuando ese proveedor tiene tiempo de inactividad, límites de tarifas o cobertura deficiente para un tipo de consulta específico. Este tutorial crea un agente de búsqueda multimotor que se conecta en cascada a través de proveedores (Scavio, Brave, SearXNG) y selecciona el mejor conjunto de resultados. El agente prueba primero con el proveedor más barato y recurre a alternativas sólo cuando es necesario, manteniendo los costos al mínimo.
Requisitos previos
- Python 3.9+ instalado
- solicita biblioteca instalada
- Una clave API de Scavio de scavio.dev
- Opcional: Clave API Brave como respaldo
Guia paso a paso
Paso 1: Definir la cascada del motor de búsqueda
Configure varios proveedores de búsqueda en orden de prioridad. Cada uno tiene una función de búsqueda, un costo y un umbral de calidad para aceptar resultados.
import requests, os, time
SCAVIO_KEY = os.environ.get('SCAVIO_API_KEY', '')
BRAVE_KEY = os.environ.get('BRAVE_API_KEY', '')
def search_scavio(query: str, count: int = 10) -> list:
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': count},
timeout=10)
if resp.status_code != 200:
return []
return [{'title': r['title'], 'link': r['link'], 'snippet': r.get('snippet', '')}
for r in resp.json().get('organic_results', [])]
def search_brave(query: str, count: int = 10) -> list:
if not BRAVE_KEY:
return []
resp = requests.get('https://api.search.brave.com/res/v1/web/search',
headers={'X-Subscription-Token': BRAVE_KEY},
params={'q': query, 'count': count}, timeout=10)
if resp.status_code != 200:
return []
return [{'title': r['title'], 'link': r['url'], 'snippet': r.get('description', '')}
for r in resp.json().get('web', {}).get('results', [])]
ENGINES = [
{'name': 'scavio', 'fn': search_scavio, 'cost': 0.005, 'min_results': 3},
{'name': 'brave', 'fn': search_brave, 'cost': 0.005, 'min_results': 3},
]
print(f'Configured {len(ENGINES)} search engines in cascade')
for e in ENGINES:
print(f' {e["name"]}: ${e["cost"]}/query, min {e["min_results"]} results')Paso 2: Cree la función de búsqueda en cascada
Pruebe cada motor en orden. Aceptar los resultados si cumplen con el umbral de calidad. Realice un seguimiento de qué motor tuvo éxito y el costo total.
def cascade_search(query: str, count: int = 10) -> dict:
"""Search with cascading fallback across engines."""
attempts = []
for engine in ENGINES:
start = time.time()
try:
results = engine['fn'](query, count)
latency = int((time.time() - start) * 1000)
attempts.append({
'engine': engine['name'], 'results': len(results),
'latency_ms': latency, 'cost': engine['cost']
})
if len(results) >= engine['min_results']:
total_cost = sum(a['cost'] for a in attempts)
return {
'results': results,
'engine': engine['name'],
'attempts': attempts,
'total_cost': total_cost
}
except Exception as e:
attempts.append({
'engine': engine['name'], 'error': str(e),
'cost': engine['cost']
})
# All engines failed or returned poor results
total_cost = sum(a['cost'] for a in attempts)
best = max(attempts, key=lambda a: a.get('results', 0))
return {
'results': [],
'engine': 'none',
'attempts': attempts,
'total_cost': total_cost,
'note': 'All engines returned insufficient results'
}
result = cascade_search('best python web framework 2026')
print(f'Engine: {result["engine"]}')
print(f'Results: {len(result["results"])}')
print(f'Cost: ${result["total_cost"]:.3f}')
for a in result['attempts']:
print(f' {a["engine"]}: {a.get("results", "error")} results, {a.get("latency_ms", "N/A")}ms')Paso 3: Agregar selección de motor inteligente según el tipo de consulta
Enrute diferentes tipos de consultas al mejor motor. Las consultas técnicas pueden funcionar mejor en un motor, mientras que las consultas de noticias funcionan mejor en otro.
def smart_search(query: str, count: int = 10) -> dict:
"""Route query to best engine based on query type."""
query_lower = query.lower()
# Classify query type
if any(w in query_lower for w in ['news', 'latest', 'today', 'just', 'announced']):
query_type = 'news'
elif any(w in query_lower for w in ['site:', 'filetype:', 'inurl:']):
query_type = 'advanced'
elif any(w in query_lower for w in ['how to', 'tutorial', 'guide', 'example']):
query_type = 'tutorial'
else:
query_type = 'general'
# Reorder engines based on query type
# For most queries, default cascade works fine
# For advanced queries, Scavio handles operators better
result = cascade_search(query, count)
result['query_type'] = query_type
return result
# Test different query types
test_queries = [
'latest AI news today',
'site:github.com python search api',
'how to build a search agent',
]
for q in test_queries:
r = smart_search(q)
print(f'[{r["query_type"]}] {q[:40]} -> {r["engine"]} ({len(r["results"])} results, ${r["total_cost"]:.3f})')Ejemplo en Python
import requests, os, time
SCAVIO_KEY = os.environ.get('SCAVIO_API_KEY', '')
BRAVE_KEY = os.environ.get('BRAVE_API_KEY', '')
def search(query, count=10):
# Try Scavio first
try:
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': count}, timeout=10)
results = resp.json().get('organic_results', [])
if len(results) >= 3:
return {'results': results, 'engine': 'scavio', 'cost': 0.005}
except Exception:
pass
# Fallback to Brave
if BRAVE_KEY:
try:
resp = requests.get('https://api.search.brave.com/res/v1/web/search',
headers={'X-Subscription-Token': BRAVE_KEY},
params={'q': query, 'count': count}, timeout=10)
results = resp.json().get('web', {}).get('results', [])
return {'results': results, 'engine': 'brave', 'cost': 0.010}
except Exception:
pass
return {'results': [], 'engine': 'none', 'cost': 0}
r = search('python web framework 2026')
print(f'{r["engine"]}: {len(r["results"])} results, ${r["cost"]}')Ejemplo en JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
const BRAVE_KEY = process.env.BRAVE_API_KEY;
async function search(query, count = 10) {
try {
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: count })
});
const results = (await resp.json()).organic_results || [];
if (results.length >= 3) return { results, engine: 'scavio', cost: 0.005 };
} catch {}
if (BRAVE_KEY) {
try {
const resp = await fetch(`https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=${count}`, {
headers: { 'X-Subscription-Token': BRAVE_KEY }
});
const results = (await resp.json()).web?.results || [];
return { results, engine: 'brave', cost: 0.01 };
} catch {}
}
return { results: [], engine: 'none', cost: 0 };
}
search('python framework 2026').then(r => console.log(`${r.engine}: ${r.results.length} results`));Salida esperada
Configured 2 search engines in cascade
scavio: $0.005/query, min 3 results
brave: $0.005/query, min 3 results
Engine: scavio
Results: 10
Cost: $0.005
scavio: 10 results, 245ms
[news] latest AI news today -> scavio (10 results, $0.005)
[advanced] site:github.com python search api -> scavio (8 results, $0.005)
[tutorial] how to build a search agent -> scavio (10 results, $0.005)