Una búsqueda más barata no ayuda si los resultados son malos. Este tutorial crea un punto de referencia automatizado que califica la calidad de los resultados de la API de búsqueda utilizando métricas de relevancia y calcula una relación calidad por dólar. Prueba las mismas consultas en varios proveedores y obtiene una comparación clasificada. El punto de referencia utiliza superposición de palabras clave, heurísticas de autoridad de dominio y puntuación de frescura; no se necesita un juez de LLM.
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 consultas de referencia con los resultados esperados
Cree un conjunto de consultas de prueba en el que sepa cómo son los buenos resultados. Incluya los principales dominios esperados y los términos clave que deberían aparecer.
benchmark_queries = [
{
'query': 'python asyncio tutorial 2026',
'expected_domains': ['docs.python.org', 'realpython.com', 'stackoverflow.com'],
'expected_terms': ['asyncio', 'await', 'coroutine', 'event loop'],
},
{
'query': 'next.js app router server components',
'expected_domains': ['nextjs.org', 'vercel.com', 'react.dev'],
'expected_terms': ['server components', 'app router', 'next.js'],
},
{
'query': 'best CRM software small business 2026',
'expected_domains': ['forbes.com', 'g2.com', 'capterra.com'],
'expected_terms': ['CRM', 'pricing', 'small business', 'features'],
},
{
'query': 'docker compose networking tutorial',
'expected_domains': ['docs.docker.com', 'stackoverflow.com'],
'expected_terms': ['docker', 'compose', 'network', 'bridge'],
},
{
'query': 'react useEffect cleanup function',
'expected_domains': ['react.dev', 'stackoverflow.com', 'kentcdodds.com'],
'expected_terms': ['useEffect', 'cleanup', 'unmount', 'return'],
},
]
print(f'{len(benchmark_queries)} benchmark queries defined')Paso 2: Construir la función de puntuación de calidad
Califique cada conjunto de resultados según la coincidencia de dominio, la cobertura de términos, el recuento de resultados y la calidad del fragmento. Devuelve una puntuación de calidad de 0 a 100.
def score_results(results: list, expected_domains: list, expected_terms: list) -> dict:
if not results:
return {'total': 0, 'domain_score': 0, 'term_score': 0, 'count_score': 0}
# Domain match score (0-40 points)
result_domains = [r.get('link', '').split('/')[2] if '/' in r.get('link', '') else ''
for r in results[:10]]
domain_hits = sum(1 for ed in expected_domains
if any(ed in rd for rd in result_domains))
domain_score = min(domain_hits / max(len(expected_domains), 1) * 40, 40)
# Term coverage score (0-40 points)
all_text = ' '.join(r.get('title', '') + ' ' + r.get('snippet', '')
for r in results[:10]).lower()
term_hits = sum(1 for t in expected_terms if t.lower() in all_text)
term_score = min(term_hits / max(len(expected_terms), 1) * 40, 40)
# Result count score (0-20 points)
count_score = min(len(results) / 10 * 20, 20)
total = round(domain_score + term_score + count_score, 1)
return {'total': total, 'domain_score': round(domain_score, 1),
'term_score': round(term_score, 1), 'count_score': round(count_score, 1)}
print('Quality scorer ready')Paso 3: Ejecute puntos de referencia entre proveedores y calcule la calidad por dólar
Ejecute cada consulta de referencia con cada proveedor, califique los resultados y calcule la relación calidad por dólar.
import requests, os, time
SCAVIO_KEY = os.environ.get('SCAVIO_API_KEY', '')
def search_scavio(query):
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})
return [{'title': r['title'], 'link': r['link'], 'snippet': r.get('snippet', '')}
for r in resp.json().get('organic_results', [])]
PRICES = {'scavio': 0.005}
def run_benchmark():
results = {}
for provider in PRICES:
scores = []
for bq in benchmark_queries:
search_results = search_scavio(bq['query'])
score = score_results(search_results, bq['expected_domains'], bq['expected_terms'])
scores.append(score['total'])
time.sleep(0.3)
avg_score = sum(scores) / len(scores)
price = PRICES[provider]
qpd = avg_score / (price * 1000) if price > 0 else avg_score # quality per $1
results[provider] = {'avg_quality': round(avg_score, 1),
'price_per_1k': price * 1000,
'quality_per_dollar': round(qpd, 1)}
print(f'{"Provider":<15} {"Quality":>8} {"$/1K":>8} {"Q/$":>8}')
print('-' * 42)
for name, r in sorted(results.items(), key=lambda x: -x[1]['quality_per_dollar']):
print(f'{name:<15} {r["avg_quality"]:>7.1f} {r["price_per_1k"]:>7.2f} {r["quality_per_dollar"]:>7.1f}')
return results
run_benchmark()Ejemplo en Python
import requests, os, time
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
def search(query):
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})
return resp.json().get('organic_results', [])
def score(results, terms):
text = ' '.join(r.get('snippet', '') for r in results).lower()
hits = sum(1 for t in terms if t.lower() in text)
return hits / len(terms) * 100 if terms else 0
queries = [('python asyncio', ['asyncio', 'await', 'coroutine']),
('react hooks', ['useState', 'useEffect', 'hook'])]
for q, terms in queries:
results = search(q)
s = score(results, terms)
print(f'{q}: quality={s:.0f}/100, cost=$0.005')Ejemplo en JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
async function search(query) {
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 })
});
return (await resp.json()).organic_results || [];
}
function score(results, terms) {
const text = results.map(r => r.snippet || '').join(' ').toLowerCase();
const hits = terms.filter(t => text.includes(t.toLowerCase())).length;
return (hits / terms.length) * 100;
}
const results = await search('python asyncio tutorial');
console.log(`Quality: ${score(results, ['asyncio', 'await', 'coroutine']).toFixed(0)}/100`);Salida esperada
5 benchmark queries defined
Quality scorer ready
Provider Quality $/1K Q/$
------------------------------------------
scavio 78.4 5.00 15.7
Interpretation: 15.7 quality points per dollar spent
Higher Q/$ = better value for money