Agent search failures are the most common reason AI agents produce wrong or incomplete answers. The failure modes are predictable: API key misconfiguration, malformed queries, empty result parsing, timeout on slow networks, and rate limiting. This tutorial provides a systematic debugging checklist and reusable diagnostic functions you can drop into any agent. Each test uses the Scavio API endpoint but the patterns apply to any search backend.
Prerequisites
- Python 3.9+ installed
- requests library installed
- A Scavio API key from scavio.dev
- An agent with search tool integration to debug
Walkthrough
Step 1: Test API connectivity and auth
The first thing to check is whether your API key works and the endpoint is reachable. This function runs a minimal health check.
import requests, os
def test_api_health(api_key: str = None) -> dict:
key = api_key or os.environ.get('SCAVIO_API_KEY', '')
if not key:
return {'status': 'FAIL', 'error': 'No API key found'}
try:
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': key, 'Content-Type': 'application/json'},
json={'query': 'test', 'country_code': 'us'},
timeout=10)
return {'status': 'OK' if resp.status_code == 200 else 'FAIL',
'http_code': resp.status_code,
'has_results': bool(resp.json().get('organic_results'))}
except requests.exceptions.Timeout:
return {'status': 'FAIL', 'error': 'Timeout after 10s'}
except Exception as e:
return {'status': 'FAIL', 'error': str(e)}
print(test_api_health())Step 2: Diagnose empty results
If the API returns 200 but no results, the query may be too specific, malformed, or in a locale with no coverage. Test with progressively simpler queries.
def diagnose_empty_results(original_query: str) -> dict:
api_key = os.environ['SCAVIO_API_KEY']
test_queries = [
original_query,
' '.join(original_query.split()[:3]), # first 3 words
'python programming', # known good query
]
results = {}
for q in test_queries:
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': api_key, 'Content-Type': 'application/json'},
json={'query': q, 'country_code': 'us'})
count = len(resp.json().get('organic_results', []))
results[q] = count
return results
diag = diagnose_empty_results('xylophone quantum blockchain synergy 2026')
for query, count in diag.items():
status = 'OK' if count > 0 else 'EMPTY'
print(f'[{status}] "{query}" -> {count} results')Step 3: Add structured logging to the search tool
Wrap your search function with logging so you can trace every call, its latency, result count, and any errors.
import time, logging
logging.basicConfig(level=logging.INFO)
log = logging.getLogger('agent_search')
def logged_search(query: str, country: str = 'us') -> dict:
start = time.time()
log.info(f'Searching: "{query}" country={country}')
try:
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': os.environ['SCAVIO_API_KEY'],
'Content-Type': 'application/json'},
json={'query': query, 'country_code': country},
timeout=15)
elapsed = time.time() - start
data = resp.json()
count = len(data.get('organic_results', []))
log.info(f'Result: {resp.status_code}, {count} results, {elapsed:.2f}s')
return data
except Exception as e:
elapsed = time.time() - start
log.error(f'Failed after {elapsed:.2f}s: {e}')
return {'organic_results': [], 'error': str(e)}Step 4: Build a retry wrapper with exponential backoff
Transient failures (network blips, rate limits) are best handled with retries. Use exponential backoff to avoid hammering the API.
def search_with_retry(query: str, max_retries: int = 3) -> dict:
for attempt in range(max_retries):
try:
data = logged_search(query)
if data.get('organic_results'):
return data
if attempt < max_retries - 1:
wait = 2 ** attempt
log.warning(f'Empty results, retrying in {wait}s...')
time.sleep(wait)
except Exception as e:
if attempt < max_retries - 1:
wait = 2 ** attempt
log.warning(f'Error: {e}, retrying in {wait}s...')
time.sleep(wait)
else:
raise
return {'organic_results': [], 'error': 'All retries exhausted'}Step 5: Run the full diagnostic suite
Combine all checks into a single diagnostic function that reports the health of your agent's search integration.
def full_diagnostic() -> None:
print('=== Agent Search Diagnostic ===')
# 1. API Health
health = test_api_health()
print(f'1. API Health: {health["status"]}')
if health['status'] != 'OK':
print(f' Error: {health.get("error", health.get("http_code"))}')
return
# 2. Result quality
data = logged_search('best crm software 2026')
results = data.get('organic_results', [])
print(f'2. Result quality: {len(results)} results')
if results:
print(f' Top result: {results[0]["title"]}')
# 3. Retry behavior
retry_data = search_with_retry('obscure test query 12345')
print(f'3. Retry test: {len(retry_data.get("organic_results", []))} results')
print('=== Diagnostic complete ===')
full_diagnostic()Python Example
import os, time, requests, logging
logging.basicConfig(level=logging.INFO)
log = logging.getLogger('debug')
API_KEY = os.environ['SCAVIO_API_KEY']
def search(query: str) -> dict:
start = time.time()
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us'}, timeout=15)
elapsed = time.time() - start
data = resp.json()
count = len(data.get('organic_results', []))
log.info(f'"{query}" -> {count} results in {elapsed:.2f}s')
return data
def main():
# Health check
health = search('test')
print(f'Health: {"OK" if health.get("organic_results") else "FAIL"}')
# Real query
data = search('best crm 2026')
for r in data.get('organic_results', [])[:3]:
print(f' #{r["position"]} {r["title"]}')
if __name__ == '__main__':
main()JavaScript Example
const API_KEY = process.env.SCAVIO_API_KEY;
async function search(query) {
const start = Date.now();
const resp = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: 'us' })
});
const data = await resp.json();
const ms = Date.now() - start;
console.log(`"${query}" -> ${(data.organic_results || []).length} results in ${ms}ms`);
return data;
}
async function main() {
const health = await search('test');
console.log(`Health: ${health.organic_results?.length ? 'OK' : 'FAIL'}`);
const data = await search('best crm 2026');
(data.organic_results || []).slice(0, 3).forEach(r => {
console.log(` #${r.position} ${r.title}`);
});
}
main().catch(console.error);Expected Output
=== Agent Search Diagnostic ===
1. API Health: OK
INFO:agent_search:Searching: "best crm software 2026" country=us
INFO:agent_search:Result: 200, 10 results, 0.87s
2. Result quality: 10 results
Top result: Best CRM Software for Small Business (2026)
3. Retry test: 0 results
=== Diagnostic complete ===