ScavioScavio
ProductPricingDocs
Sign InGet Started
  1. Home
  2. Tutorials
  3. How to Build a Search Fallback Stack for Local LLMs
Tutorial

How to Build a Search Fallback Stack for Local LLMs

Build a multi-provider search fallback for local LLMs. Try Scavio first, fall back to Brave, then Tavily. Never lose search grounding due to a single outage.

Get Free API KeyAPI Docs

Relying on a single search provider for your local LLM is a single point of failure. When that provider goes down or hits rate limits, your agent loses web grounding entirely. This tutorial builds a search fallback stack that tries Scavio first ($0.005/query), falls back to Brave Search ($0.005/query), then Tavily ($0.008/credit) if both are unavailable. The stack normalizes responses into a common format so your LLM sees consistent data regardless of which provider responded.

Prerequisites

  • Python 3.9+ installed
  • requests library installed
  • API keys for Scavio, Brave Search, and Tavily
  • A local LLM setup (Ollama, llama.cpp, or vLLM)

Walkthrough

Step 1: Define the provider interface

Create a common interface that each search provider implements. All providers return the same normalized result format.

Python
import os, requests, time
from typing import Optional

SCAVIO_KEY = os.environ.get('SCAVIO_API_KEY', '')
BRAVE_KEY = os.environ.get('BRAVE_API_KEY', '')
TAVILY_KEY = os.environ.get('TAVILY_API_KEY', '')

def normalize_result(title: str, url: str, snippet: str, source: str) -> dict:
    return {'title': title, 'url': url, 'snippet': snippet, 'source': source}

Step 2: Implement each search provider

Write a search function for each provider that returns normalized results. Each function handles its own errors and returns None on failure.

Python
def search_scavio(query: str, num: int = 5) -> Optional[list]:
    try:
        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': num}, timeout=10)
        resp.raise_for_status()
        return [normalize_result(r['title'], r['link'], r.get('snippet', ''), 'scavio')
                for r in resp.json().get('organic_results', [])]
    except Exception as e:
        print(f'Scavio failed: {e}')
        return None

def search_brave(query: str, num: int = 5) -> Optional[list]:
    try:
        resp = requests.get('https://api.search.brave.com/res/v1/web/search',
            headers={'X-Subscription-Token': BRAVE_KEY, 'Accept': 'application/json'},
            params={'q': query, 'count': num}, timeout=10)
        resp.raise_for_status()
        return [normalize_result(r['title'], r['url'], r.get('description', ''), 'brave')
                for r in resp.json().get('web', {}).get('results', [])]
    except Exception as e:
        print(f'Brave failed: {e}')
        return None

def search_tavily(query: str, num: int = 5) -> Optional[list]:
    try:
        resp = requests.post('https://api.tavily.com/search',
            json={'api_key': TAVILY_KEY, 'query': query, 'max_results': num}, timeout=10)
        resp.raise_for_status()
        return [normalize_result(r['title'], r['url'], r.get('content', ''), 'tavily')
                for r in resp.json().get('results', [])]
    except Exception as e:
        print(f'Tavily failed: {e}')
        return None

Step 3: Build the fallback stack

Chain providers in priority order. The first provider to return results wins. Log which provider served the request.

Python
PROVIDERS = [
    ('scavio', search_scavio, 0.005),
    ('brave', search_brave, 0.005),
    ('tavily', search_tavily, 0.008),
]

def search_with_fallback(query: str, num: int = 5) -> dict:
    for name, fn, cost in PROVIDERS:
        results = fn(query, num)
        if results is not None:
            return {'results': results, 'provider': name, 'cost': cost, 'query': query}
    return {'results': [], 'provider': 'none', 'cost': 0, 'query': query}

# Test the fallback
result = search_with_fallback('best python web frameworks 2026')
print(f'Provider: {result["provider"]} (${result["cost"]}/query)')
for r in result['results'][:3]:
    print(f'  {r["title"]}')
    print(f'  {r["url"]}')

Step 4: Integrate with your local LLM

Use the fallback search as a tool for your local LLM. The LLM never needs to know which provider responded.

Python
def format_for_llm(search_result: dict) -> str:
    lines = [f'Web search results for: {search_result["query"]}\n']
    for i, r in enumerate(search_result['results'], 1):
        lines.append(f'[{i}] {r["title"]}')
        lines.append(f'    URL: {r["url"]}')
        lines.append(f'    {r["snippet"]}')
        lines.append('')
    return '\n'.join(lines)

result = search_with_fallback('latest AI frameworks 2026')
formatted = format_for_llm(result)
print(formatted)
print(f'\n--- Served by: {result["provider"]} at ${result["cost"]}/query ---')

Python Example

Python
import os, requests
from typing import Optional

SCAVIO_KEY = os.environ.get('SCAVIO_API_KEY', '')
BRAVE_KEY = os.environ.get('BRAVE_API_KEY', '')

def search_scavio(query, num=5):
    try:
        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': num}, timeout=10)
        resp.raise_for_status()
        return [{'title': r['title'], 'url': r['link'], 'snippet': r.get('snippet', '')}
                for r in resp.json().get('organic_results', [])]
    except: return None

def search_brave(query, num=5):
    try:
        resp = requests.get('https://api.search.brave.com/res/v1/web/search',
            headers={'X-Subscription-Token': BRAVE_KEY},
            params={'q': query, 'count': num}, timeout=10)
        resp.raise_for_status()
        return [{'title': r['title'], 'url': r['url'], 'snippet': r.get('description', '')}
                for r in resp.json().get('web', {}).get('results', [])]
    except: return None

def search(query):
    for name, fn in [('scavio', search_scavio), ('brave', search_brave)]:
        results = fn(query)
        if results:
            print(f'Served by {name}')
            return results
    return []

for r in search('python web frameworks 2026')[:3]:
    print(f'  {r["title"]}')

JavaScript Example

JavaScript
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
const BRAVE_KEY = process.env.BRAVE_API_KEY;

async function searchScavio(query) {
  try {
    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: 5 })
    });
    const data = await resp.json();
    return (data.organic_results || []).map(r => ({ title: r.title, url: r.link, snippet: r.snippet || '' }));
  } catch { return null; }
}

async function searchBrave(query) {
  try {
    const resp = await fetch(`https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=5`, {
      headers: { 'X-Subscription-Token': BRAVE_KEY, Accept: 'application/json' }
    });
    const data = await resp.json();
    return (data.web?.results || []).map(r => ({ title: r.title, url: r.url, snippet: r.description || '' }));
  } catch { return null; }
}

async function search(query) {
  for (const [name, fn] of [['scavio', searchScavio], ['brave', searchBrave]]) {
    const results = await fn(query);
    if (results) { console.log(`Served by ${name}`); return results; }
  }
  return [];
}

search('AI frameworks 2026').then(r => r.slice(0, 3).forEach(x => console.log(x.title)));

Expected Output

JSON
Provider: scavio ($0.005/query)
  FastAPI 1.0: The Modern Python Web Framework
  https://fastapi.tiangolo.com/release-notes/
  Django 6.0 Features and Migration Guide
  https://docs.djangoproject.com/en/6.0/

--- Served by: scavio at $0.005/query ---

Related Tutorials

  • How to Add Search to Ollama After Google CSE Shutdown
  • How to Connect Scavio MCP to Local LLMs

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

Python 3.9+ installed. requests library installed. API keys for Scavio, Brave Search, and Tavily. A local LLM setup (Ollama, llama.cpp, or vLLM). A Scavio API key gives you 50 free credits on signup.

Yes. The free tier includes 50 credits on signup, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses the raw REST API, but you can adapt to your framework of choice.

Related Resources

Use Case

MCP Search Gateway for Multi-Agent Systems

Read more
Best Of

Best Personal Knowledge Base Tools for Local LLMs in May 2026

Read more
Best Of

Best Agent Search Fallback Architectures (2026)

Read more
Solution

Pi Agent Search Provider Switching

Read more
Solution

Migrate from Brave Search API to Scavio for Better Coverage

Read more
Use Case

Hermes v0.12 Search API Fallback Layer

Read more

Start Building

Build a multi-provider search fallback for local LLMs. Try Scavio first, fall back to Brave, then Tavily. Never lose search grounding due to a single outage.

Get Free API KeyRead the Docs
ScavioScavio

Real-time search API for AI agents. Search every platform, not just Google.

Product

  • Features
  • Pricing
  • Dashboard
  • Affiliates

Developers

  • Documentation
  • API Reference
  • Quickstart
  • MCP Integration
  • Python SDK

Alternatives

  • Tavily Alternative
  • SerpAPI Alternative
  • Firecrawl Alternative
  • Exa Alternative

Tools

  • JSON Formatter
  • cURL to Code
  • Token Counter
  • All Tools

© 2026 Scavio. All rights reserved.

Featured on TAAFT
Terms of ServicePrivacy Policy