Customer support bots that rely on static knowledge bases hallucinate outdated product details, pricing, and policy information. Adding a live search step before generating responses ensures the bot answers with current data from your own website. This tutorial adds search grounding to an existing support bot using Scavio's Google endpoint with site-restricted queries.
Prerequisites
- An existing support bot or chatbot framework
- Python 3.8+ or Node.js 18+
- A Scavio API key from scavio.dev
- Your company's domain name
Walkthrough
Step 1: Define the site-restricted search function
Search your own website for the answer before asking the LLM to generate one.
import requests, os
H = {'x-api-key': os.environ['SCAVIO_API_KEY']}
MY_SITE = 'yourcompany.com'
def search_own_site(question: str) -> list:
resp = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
json={'platform': 'google', 'query': f'site:{MY_SITE} {question}'}, timeout=10)
return [{'title': r['title'], 'snippet': r['snippet'], 'url': r['link']}
for r in resp.json().get('organic', [])[:3]]Step 2: Add confidence-based routing
If internal search returns good results, use them. Otherwise, search the open web.
def grounded_search(question: str) -> dict:
internal = search_own_site(question)
if internal:
return {'source': 'internal', 'results': internal}
# Fallback to open web search
resp = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
json={'platform': 'google', 'query': question}, timeout=10)
web_results = [{'title': r['title'], 'snippet': r['snippet'], 'url': r['link']}
for r in resp.json().get('organic', [])[:3]]
return {'source': 'web', 'results': web_results}Step 3: Inject search context into the support prompt
Format the search results as context for the LLM to reference when answering.
def build_support_prompt(question: str, context: dict) -> str:
source_type = 'our website' if context['source'] == 'internal' else 'the web'
ctx_text = '\n'.join(f"- {r['title']}: {r['snippet']}" for r in context['results'])
return f"""You are a customer support agent. Answer the question using ONLY the context below.
If the context does not contain the answer, say you need to transfer to a human agent.
Context (from {source_type}):
{ctx_text}
Customer question: {question}
Answer:"""Step 4: Add human handoff trigger
Route to a human when search returns no results or the question is sensitive.
SENSITIVE_TOPICS = ['refund', 'cancel', 'lawsuit', 'legal', 'complaint']
def should_handoff(question: str, context: dict) -> bool:
if not context['results']:
return True
if any(topic in question.lower() for topic in SENSITIVE_TOPICS):
return True
return False
def handle_question(question: str) -> str:
context = grounded_search(question)
if should_handoff(question, context):
return 'Let me connect you with a team member who can help with this.'
prompt = build_support_prompt(question, context)
# Call your LLM here with the grounded prompt
return promptPython Example
import requests, os
H = {'x-api-key': os.environ['SCAVIO_API_KEY']}
def ground_answer(question, site='yourcompany.com'):
data = requests.post('https://api.scavio.dev/api/v1/search', headers=H,
json={'platform': 'google', 'query': f'site:{site} {question}'}, timeout=10).json()
return [r['snippet'] for r in data.get('organic', [])[:3]]JavaScript Example
async function groundAnswer(question, site = 'yourcompany.com') {
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: {'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json'},
body: JSON.stringify({platform: 'google', query: `site:${site} ${question}`})
}).then(r => r.json());
return (data.organic || []).slice(0, 3).map(r => r.snippet);
}Expected Output
A support bot with live search grounding that answers from your own website first, falls back to web search, and hands off to humans for sensitive or unanswerable questions.