Construire une recherche organisée pour les agents IA consiste à envelopper une API de recherche avec filtrage, réordonnancement et compression afin que l'agent reçoive uniquement des résultats de haute qualité au lieu du bruit brut du SERP. Les résultats de recherche bruts gaspillent des tokens sur des publicités, des domaines non pertinents et des extraits verbeux qui diluent le raisonnement de l'agent. Ce tutoriel construit un middleware Python qui se place entre votre agent et l'API de recherche Scavio, appliquant des listes d'autorisation de domaines, un score de pertinence et une troncature des extraits pour réduire l'utilisation de tokens de 70% tout en améliorant la qualité des réponses.
Prérequis
- Python 3.8+
- bibliothèque requests installée
- Clé API Scavio depuis scavio.dev
- Compréhension de base du comptage de tokens (tiktoken optionnel)
Parcours
Étape 1: Définir les filtres de domaine et les règles de qualité
Créer des listes d'autorisation et des listes de blocage pour les domaines, ainsi que des règles pour filtrer les résultats de faible qualité comme les forums sans réponses ou les contenus payants.
BLOCKED_DOMAINS = [
'pinterest.com', 'quora.com', 'facebook.com',
'instagram.com', 'tiktok.com', 'twitter.com',
]
TRUSTED_DOMAINS = [
'docs.python.org', 'developer.mozilla.org', 'github.com',
'stackoverflow.com', 'arxiv.org', 'huggingface.co',
]
def domain_score(url):
domain = url.split('/')[2] if url else ''
if any(b in domain for b in BLOCKED_DOMAINS):
return -10
if any(t in domain for t in TRUSTED_DOMAINS):
return 5
return 0Étape 2: Construire l'enveloppe de recherche avec compression
Créer une fonction qui appelle Scavio, filtre les résultats, note la pertinence et compresse les extraits selon un budget de tokens.
import requests, os
H = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
def curated_search(query, max_results=5, max_snippet_chars=200):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=H, json={'query': query, 'country_code': 'us'}).json()
results = data.get('organic_results', [])
scored = []
for r in results:
ds = domain_score(r.get('link', ''))
if ds < 0:
continue
snippet = (r.get('snippet') or '')[:max_snippet_chars]
scored.append({
'title': r.get('title', ''),
'url': r.get('link', ''),
'snippet': snippet,
'score': ds + r.get('position', 10) * -0.5
})
scored.sort(key=lambda x: x['score'], reverse=True)
return scored[:max_results]Étape 3: Ajouter un réordonnancement par pertinence
Noter les résultats par chevauchement de mots-clés avec la requête originale pour placer les résultats les plus pertinents en haut.
def relevance_score(query, result):
query_terms = set(query.lower().split())
text = f"{result['title']} {result['snippet']}".lower()
matches = sum(1 for t in query_terms if t in text)
return matches / max(len(query_terms), 1)
def curated_search_v2(query, max_results=5, max_snippet_chars=200):
raw = curated_search(query, max_results=15, max_snippet_chars=max_snippet_chars)
for r in raw:
r['score'] += relevance_score(query, r) * 3
raw.sort(key=lambda x: x['score'], reverse=True)
return raw[:max_results]Étape 4: Mesurer les économies de tokens
Comparer les comptes de tokens entre les résultats bruts et organisés pour vérifier le taux de compression.
def estimate_tokens(text):
return len(text.split()) * 1.3 # rough estimate
def compare_token_usage(query):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=H, json={'query': query, 'country_code': 'us'}).json()
raw_text = str(data.get('organic_results', []))
raw_tokens = estimate_tokens(raw_text)
curated = curated_search_v2(query)
curated_text = str(curated)
curated_tokens = estimate_tokens(curated_text)
savings = (1 - curated_tokens / raw_tokens) * 100
print(f'Raw: ~{int(raw_tokens)} tokens')
print(f'Curated: ~{int(curated_tokens)} tokens')
print(f'Savings: {savings:.0f}%')
compare_token_usage('how to deploy FastAPI to production')Exemple Python
import os, requests
H = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
BLOCKED = ['pinterest.com', 'quora.com', 'facebook.com']
TRUSTED = ['docs.python.org', 'developer.mozilla.org', 'github.com', 'stackoverflow.com']
def curated_search(query, max_results=5, max_chars=200):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=H, json={'query': query, 'country_code': 'us'}).json()
results = []
query_terms = set(query.lower().split())
for r in data.get('organic_results', []):
domain = r.get('link', '').split('/')[2] if r.get('link') else ''
if any(b in domain for b in BLOCKED):
continue
snippet = (r.get('snippet') or '')[:max_chars]
text = f"{r.get('title', '')} {snippet}".lower()
relevance = sum(1 for t in query_terms if t in text) / max(len(query_terms), 1)
trust = 5 if any(t in domain for t in TRUSTED) else 0
results.append({
'title': r.get('title', ''),
'url': r.get('link', ''),
'snippet': snippet,
'score': trust + relevance * 3
})
results.sort(key=lambda x: x['score'], reverse=True)
return results[:max_results]
for r in curated_search('FastAPI deployment best practices 2026'):
print(f"[{r['score']:.1f}] {r['title']}")
print(f" {r['url']}")Exemple JavaScript
const H = {'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json'};
const BLOCKED = ['pinterest.com', 'quora.com', 'facebook.com'];
const TRUSTED = ['docs.python.org', 'developer.mozilla.org', 'github.com', 'stackoverflow.com'];
async function curatedSearch(query, maxResults = 5, maxChars = 200) {
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: H,
body: JSON.stringify({query, country_code: 'us'})
}).then(r => r.json());
const queryTerms = new Set(query.toLowerCase().split(' '));
const results = (data.organic_results || []).map(r => {
const domain = (r.link || '').split('/')[2] || '';
if (BLOCKED.some(b => domain.includes(b))) return null;
const snippet = (r.snippet || '').slice(0, maxChars);
const text = \`\${r.title || ''} \${snippet}\`.toLowerCase();
const relevance = [...queryTerms].filter(t => text.includes(t)).length / queryTerms.size;
const trust = TRUSTED.some(t => domain.includes(t)) ? 5 : 0;
return {title: r.title, url: r.link, snippet, score: trust + relevance * 3};
}).filter(Boolean).sort((a, b) => b.score - a.score).slice(0, maxResults);
return results;
}
curatedSearch('FastAPI deployment best practices 2026').then(results => {
results.forEach(r => console.log(\`[\${r.score.toFixed(1)}] \${r.title}\`));
});Sortie attendue
[8.0] FastAPI Deployment Guide - Official Docs
https://docs.python.org/fastapi-deploy
[5.5] Deploy FastAPI on AWS Lambda in 2026
https://github.com/example/fastapi-lambda
[3.0] Production FastAPI Checklist
https://example.com/fastapi-prod