Overview
AI agents that depend on search tools for grounding fail silently when the search API degrades. Response times creep up, schemas change, or results go empty, and your agent starts hallucinating because it gets no web data. This workflow runs hourly, sends test queries to your search API, measures response latency against your SLA, validates the response schema matches what your agent expects, and alerts immediately when any check fails. Catch search tool degradation before your users notice the agent giving stale answers.
Trigger
Cron schedule (hourly)
Schedule
Hourly
Workflow Steps
Send test search call
Execute a known-good query against the Scavio search API. Use a query that should always return results.
Measure latency
Record the response time. Compare against your SLA threshold (e.g., under 2 seconds for P95).
Validate response schema
Check that the response contains expected fields: organic array, result count, AI overview. Flag missing or empty fields.
Check result quality
Verify that organic results are non-empty, URLs are valid, and snippets contain expected keywords.
Alert on failure
If any check fails, send an alert with the specific failure reason, timestamp, and raw response for debugging.
Python Implementation
import requests, os, json, time
from datetime import datetime
H = {"x-api-key": os.environ["SCAVIO_API_KEY"]}
# Test queries that should always return results
TEST_QUERIES = [
{"query": "python programming", "platform": "google", "min_results": 5},
{"query": "javascript tutorial", "platform": "google", "min_results": 5},
{"query": "best headphones 2026", "platform": "amazon", "min_results": 3},
]
SLA_LATENCY_MS = 2000 # 2 second SLA
def run_health_check(test):
"""Run a single health check against the search API."""
start = time.time()
try:
r = requests.post("https://api.scavio.dev/api/v1/search", headers=H,
json={"platform": test["platform"], "query": test["query"]},
timeout=10).json()
latency_ms = round((time.time() - start) * 1000)
except Exception as e:
return {"status": "ERROR", "query": test["query"], "error": str(e), "latency_ms": None}
organic = r.get("organic", [])
checks = {
"has_organic": len(organic) > 0,
"meets_min_results": len(organic) >= test["min_results"],
"has_titles": all(o.get("title") for o in organic[:3]),
"has_links": all(o.get("link") for o in organic[:3]),
"under_sla": latency_ms < SLA_LATENCY_MS,
}
all_passed = all(checks.values())
return {
"status": "OK" if all_passed else "DEGRADED",
"query": test["query"],
"platform": test["platform"],
"latency_ms": latency_ms,
"result_count": len(organic),
"checks": checks,
"checked_at": datetime.utcnow().isoformat()
}
results = []
for test in TEST_QUERIES:
result = run_health_check(test)
results.append(result)
print(f"[{result['status']}] {result['platform']}/{result['query']} | {result.get('latency_ms', 'N/A')}ms | {result.get('result_count', 0)} results")
if result["status"] != "OK":
failed = [k for k, v in result.get("checks", {}).items() if not v]
print(f" Failed checks: {', '.join(failed)}")
healthy = sum(1 for r in results if r["status"] == "OK")
print(f"\nHealth: {healthy}/{len(results)} checks passed")JavaScript Implementation
const H = {"x-api-key": process.env.SCAVIO_API_KEY, "Content-Type": "application/json"};
const TEST_QUERIES = [
{query: "python programming", platform: "google", minResults: 5},
{query: "javascript tutorial", platform: "google", minResults: 5},
{query: "best headphones 2026", platform: "amazon", minResults: 3},
];
const SLA_LATENCY_MS = 2000;
async function runHealthCheck(test) {
const start = Date.now();
try {
const r = await fetch("https://api.scavio.dev/api/v1/search", {
method: "POST", headers: H,
body: JSON.stringify({platform: test.platform, query: test.query})
}).then(r => r.json());
const latencyMs = Date.now() - start;
const organic = r.organic || [];
const checks = {
hasOrganic: organic.length > 0,
meetsMinResults: organic.length >= test.minResults,
hasTitles: organic.slice(0, 3).every(o => o.title),
hasLinks: organic.slice(0, 3).every(o => o.link),
underSla: latencyMs < SLA_LATENCY_MS,
};
const allPassed = Object.values(checks).every(Boolean);
return {
status: allPassed ? "OK" : "DEGRADED",
query: test.query, platform: test.platform,
latencyMs, resultCount: organic.length, checks,
checkedAt: new Date().toISOString()
};
} catch (e) {
return {status: "ERROR", query: test.query, error: e.message, latencyMs: null};
}
}
(async () => {
const results = [];
for (const test of TEST_QUERIES) {
const result = await runHealthCheck(test);
results.push(result);
console.log(`[${result.status}] ${result.platform}/${result.query} | ${result.latencyMs ?? "N/A"}ms | ${result.resultCount || 0} results`);
if (result.status !== "OK") {
const failed = Object.entries(result.checks || {}).filter(([,v]) => !v).map(([k]) => k);
console.log(` Failed: ${failed.join(", ")}`);
}
}
const healthy = results.filter(r => r.status === "OK").length;
console.log(`\nHealth: ${healthy}/${results.length} checks passed`);
})();Platforms Used
Web search with knowledge graph, PAA, and AI overviews
Amazon
Product search with prices, ratings, and reviews