Les agents de recherche approfondie itèrent à travers des boucles de recherche-lecture-calcul : interroger un sujet, extraire des données des résultats, raisonner sur les conclusions, puis rechercher à nouveau avec des requêtes affinées. La qualité de l'étape de recherche détermine si l'agent ancre son analyse dans des données réelles ou hallucine. Ce tutoriel intègre une recherche multi-plateforme dans un agent de recherche, lui donnant Google, Reddit et YouTube à chaque itération pour 0,005 $ par requête.
Prérequis
- Python 3.10+
- bibliothèque requests installée
- Une clé API Scavio de scavio.dev
- Une clé API OpenAI pour le raisonnement
Parcours
Étape 1: Construire la fonction de recherche multi-plateforme
Créer une recherche qui interroge plusieurs plateformes et fusionne les résultats pour le LLM.
import os, requests, json
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
OPENAI_KEY = os.environ['OPENAI_API_KEY']
SH = {'x-api-key': SCAVIO_KEY, 'Content-Type': 'application/json'}
def multi_search(query, platforms=None):
if platforms is None: platforms = ['google', 'reddit']
all_results = []
for platform in platforms:
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': query, 'platform': platform, 'country_code': 'us'})
for r in resp.json().get('organic_results', [])[:3]:
all_results.append({'platform': platform, 'title': r.get('title', ''),
'snippet': r.get('snippet', ''), 'url': r.get('link', '')})
return all_results
def format_context(results):
return '\n\n'.join(f"[{r['platform'].upper()}] {r['title']}\n{r['snippet']}" for r in results)Étape 2: Implémenter la boucle de recherche
L'agent décide quoi rechercher, analyse les résultats et détermine s'il faut continuer ou produire une sortie.
def llm_call(system, user):
resp = requests.post('https://api.openai.com/v1/chat/completions',
headers={'Authorization': f'Bearer {OPENAI_KEY}', 'Content-Type': 'application/json'},
json={'model': 'gpt-4o', 'temperature': 0,
'messages': [{'role': 'system', 'content': system}, {'role': 'user', 'content': user}]})
return resp.json()['choices'][0]['message']['content']
def research_loop(topic, max_iterations=5):
findings = []
search_count = 0
for i in range(max_iterations):
plan = json.loads(llm_call('Return JSON only.',
f'Topic: {topic}\nFindings: {json.dumps(findings[-3:])}\n'
f'Return: {{"query": "...", "platforms": [...], "done": bool}}'))
if plan.get('done'): break
results = multi_search(plan['query'], plan.get('platforms', ['google']))
search_count += len(plan.get('platforms', ['google']))
analysis = llm_call('Extract key facts.', f'Results:\n{format_context(results)}')
findings.append({'query': plan['query'], 'analysis': analysis})
print(f' [{i+1}] "{plan["query"]}" -> {len(results)} results')
return findings, search_countÉtape 3: Générer le rapport final
Synthétiser toutes les découvertes dans un rapport structuré avec des citations.
def generate_report(topic, findings, search_count):
text = '\n'.join(f"Query: {f['query']}\n{f['analysis']}" for f in findings)
report = llm_call('Write a structured report with key findings.', f'Topic: {topic}\n\n{text}')
print(f'\n{report[:500]}')
print(f'\nSearches: {search_count}, Cost: ${search_count * 0.005:.3f}')
return report
findings, count = research_loop('SERP API trends 2026')
generate_report('SERP API trends 2026', findings, count)Étape 4: Ajouter des contrôles budgétaires
Empêcher les coûts excessifs avec un plafond budgétaire strict.
def research_with_budget(topic, max_budget=0.50, max_iter=10):
findings, total_cost = [], 0.0
for i in range(max_iter):
remaining = int((max_budget - total_cost) / 0.005)
if remaining < 1:
print(f' Budget exhausted at ${total_cost:.3f}')
break
plan = json.loads(llm_call('Return JSON only.',
f'Topic: {topic}\nFindings: {json.dumps(findings[-3:])}\n'
f'Budget: {remaining} searches left\n'
f'Return: {{"query": "...", "platforms": [...], "done": bool}}'))
if plan.get('done'): break
platforms = plan.get('platforms', ['google'])[:remaining]
results = multi_search(plan['query'], platforms)
total_cost += len(platforms) * 0.005
analysis = llm_call('Extract key facts.', f'Results:\n{format_context(results)}')
findings.append({'query': plan['query'], 'analysis': analysis})
print(f' [{i+1}] ${total_cost:.3f} spent')
return findings, total_cost
research_with_budget('search API comparison', max_budget=0.25)Exemple Python
import os, requests, json
SK = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': SK, 'Content-Type': 'application/json'}
def search(query, platform='google'):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': query, 'platform': platform, 'country_code': 'us'}).json()
return [{'title': r['title'], 'snippet': r.get('snippet', '')}
for r in data.get('organic_results', [])[:3]]
def research(topic, queries):
for q in queries:
g = search(q)
r = search(q, 'reddit')
print(f'"{q}": {len(g)} Google + {len(r)} Reddit')
print(f'Cost: ${len(queries) * 2 * 0.005:.3f}')
research('AI search', ['best search api agents 2026', 'tavily alternatives reddit'])Exemple JavaScript
const SK = process.env.SCAVIO_API_KEY;
const SH = { 'x-api-key': SK, 'Content-Type': 'application/json' };
async function search(query, platform = 'google') {
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query, platform, country_code: 'us' })
}).then(r => r.json());
return (data.organic_results || []).slice(0, 3);
}
async function research(queries) {
for (const q of queries) {
const g = await search(q);
const r = await search(q, 'reddit');
console.log(`"${q}": ${g.length}G + ${r.length}R`);
}
console.log(`Cost: $${(queries.length * 2 * 0.005).toFixed(3)}`);
}
research(['best search api 2026', 'tavily alternatives']).catch(console.error);Sortie attendue
[1] "AI agent search API comparison 2026" -> 6 results
[2] "tavily vs scavio vs exa agents" -> 3 results
[3] "self-hosted search SearXNG agents" -> 6 results
[4] Research complete.
Searches: 5, Cost: $0.025