Deep research agents iterate through search-read-compute loops: query a topic, extract data from results, reason over findings, then search again with refined queries. The quality of the search step determines whether the agent grounds its analysis in real data or hallucinates. This tutorial wires multi-platform search into a research agent, giving it Google, Reddit, and YouTube in each iteration at $0.005 per query.
Prerequisites
- Python 3.10+
- requests library installed
- A Scavio API key from scavio.dev
- An OpenAI API key for reasoning
Walkthrough
Step 1: Build the multi-platform search function
Create a search that queries multiple platforms and merges results for the 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)Step 2: Implement the research loop
The agent decides what to search, analyzes results, and determines whether to continue or produce output.
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_countStep 3: Generate the final report
Synthesize all findings into a structured report with 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)Step 4: Add budget controls
Prevent runaway costs with a hard budget cap.
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)Python Example
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'])JavaScript Example
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);Expected Output
[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