Workflow

Local LLM Search Resilience Pipeline

Multi-provider search with automatic failover for local LLMs. Keep your AI agent online when one search provider fails.

Overview

Local LLM agents need web search but single-provider setups break when the API is down or rate-limited. This pipeline wraps Scavio as the primary search provider with configurable fallback logic: if the primary call fails or times out, it retries once, then falls back to a cached result or a secondary provider. Designed for on-demand use inside LangChain, LlamaIndex, or raw function-calling agents. Each search costs one credit ($0.005), and the failover adds zero cost unless you configure a paid secondary provider.

Trigger

On search request from local LLM agent

Schedule

On-demand

Workflow Steps

1

Receive Search Query

Accept the search query and optional parameters (platform, country) from the LLM agent.

2

Attempt Primary Search

Call Scavio search API with a 10-second timeout. Parse the response and check for valid results.

3

Retry on Failure

If the primary call fails or returns empty, retry once with exponential backoff.

4

Check Local Cache

If both attempts fail, check a local SQLite cache for a recent result for the same query.

5

Return Structured Results

Format the results into a standard schema the LLM agent can parse: title, snippet, URL, source.

Python Implementation

Python
import requests, os, json, time, sqlite3
from pathlib import Path

API_KEY = os.environ["SCAVIO_API_KEY"]
SH = {"x-api-key": API_KEY, "Content-Type": "application/json"}
CACHE_DB = "search_cache.db"

def init_cache():
    conn = sqlite3.connect(CACHE_DB)
    conn.execute("CREATE TABLE IF NOT EXISTS cache (query TEXT PRIMARY KEY, result TEXT, ts REAL)")
    conn.commit()
    return conn

def scavio_search(query: str, platform: str = "google", retries: int = 1) -> dict | None:
    for attempt in range(retries + 1):
        try:
            resp = requests.post(
                "https://api.scavio.dev/api/v1/search",
                headers=SH,
                json={"query": query, "platform": platform},
                timeout=10,
            )
            resp.raise_for_status()
            data = resp.json()
            if data.get("organic"):
                return data
        except Exception as e:
            print(f"Attempt {attempt + 1} failed: {e}")
            if attempt < retries:
                time.sleep(2 ** attempt)
    return None

def cached_search(conn: sqlite3.Connection, query: str, max_age: float = 86400) -> dict | None:
    row = conn.execute("SELECT result, ts FROM cache WHERE query = ?", (query,)).fetchone()
    if row and (time.time() - row[1]) < max_age:
        return json.loads(row[0])
    return None

def save_cache(conn: sqlite3.Connection, query: str, result: dict):
    conn.execute("INSERT OR REPLACE INTO cache VALUES (?, ?, ?)", (query, json.dumps(result), time.time()))
    conn.commit()

def resilient_search(query: str, platform: str = "google") -> list:
    conn = init_cache()
    result = scavio_search(query, platform, retries=1)
    if result:
        save_cache(conn, query, result)
    else:
        result = cached_search(conn, query)
        if result:
            print("Using cached result")
        else:
            return []
    return [
        {"title": r.get("title", ""), "snippet": r.get("snippet", ""), "url": r.get("url", ""), "source": platform}
        for r in result.get("organic", [])[:5]
    ]

results = resilient_search("best python web framework 2026")
for r in results:
    print(f"  {r['title']} - {r['url']}")

JavaScript Implementation

JavaScript
const SH = {'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json'};
const fs = await import('fs');

const CACHE_FILE = 'search_cache.json';
let cache = {};
try { cache = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8')); } catch {}

async function scavioSearch(query, platform='google', retries=1) {
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      const r = await fetch('https://api.scavio.dev/api/v1/search', {method:'POST', headers:SH, body:JSON.stringify({query, platform}), signal:AbortSignal.timeout(10000)});
      const data = await r.json();
      if (data.organic && data.organic.length > 0) return data;
    } catch (e) {
      console.log('Attempt '+(attempt+1)+' failed: '+e.message);
      if (attempt < retries) await new Promise(r => setTimeout(r, 2**attempt * 1000));
    }
  }
  return null;
}

function cachedSearch(query, maxAge=86400) {
  const entry = cache[query];
  if (entry && (Date.now()/1000 - entry.ts) < maxAge) return entry.result;
  return null;
}

function saveCache(query, result) {
  cache[query] = {result, ts: Date.now()/1000};
  fs.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
}

async function resilientSearch(query, platform='google') {
  let result = await scavioSearch(query, platform, 1);
  if (result) {
    saveCache(query, result);
  } else {
    result = cachedSearch(query);
    if (result) console.log('Using cached result');
    else return [];
  }
  return (result.organic || []).slice(0,5).map(r => ({title:r.title||'', snippet:r.snippet||'', url:r.url||'', source:platform}));
}

const results = await resilientSearch('best python web framework 2026');
results.forEach(r => console.log('  '+r.title+' - '+r.url));

Platforms Used

Google

Web search with knowledge graph, PAA, and AI overviews

Frequently Asked Questions

Local LLM agents need web search but single-provider setups break when the API is down or rate-limited. This pipeline wraps Scavio as the primary search provider with configurable fallback logic: if the primary call fails or times out, it retries once, then falls back to a cached result or a secondary provider. Designed for on-demand use inside LangChain, LlamaIndex, or raw function-calling agents. Each search costs one credit ($0.005), and the failover adds zero cost unless you configure a paid secondary provider.

This workflow uses a on search request from local llm agent. On-demand.

This workflow uses the following Scavio platforms: google. Each platform is called via the same unified API endpoint.

Yes. Scavio's free tier includes 250 credits per month with no credit card required. That is enough to test and validate this workflow before scaling it.

Local LLM Search Resilience Pipeline

Multi-provider search with automatic failover for local LLMs. Keep your AI agent online when one search provider fails.