Grounding an LLM with live SERP data means fetching current search results for a factual claim before generating a response, then injecting the extracted facts into the prompt as context. This prevents price, date, and availability hallucinations.
Prerequisites
- Python 3.9+
- Scavio API key
- openai or anthropic SDK
Walkthrough
Step 1: Search SERP for the factual claim
Before prompting the LLM, run a targeted search to retrieve current facts.
import requests
API_KEY = "your-scavio-api-key"
def fetch_grounding_context(claim_query: str, num_results: int = 5) -> str:
r = requests.post(
"https://api.scavio.dev/api/v1/search",
json={"query": claim_query, "num_results": num_results},
headers={"x-api-key": API_KEY},
timeout=15
)
r.raise_for_status()
results = r.json().get("organic_results", [])
lines = []
for i, res in enumerate(results, 1):
lines.append(f"{i}. {res.get('title')}\n {res.get('snippet')}\n Source: {res.get('link')}")
return "\n\n".join(lines)Step 2: Inject grounding context into the prompt
Prepend the SERP snippets as a [CONTEXT] block so the LLM uses them instead of training data.
def build_grounded_prompt(user_question: str, grounding_context: str) -> str:
return f"""[CONTEXT - Retrieved {__import__('datetime').date.today()}]
{grounding_context}
[INSTRUCTIONS]
Answer the question below using ONLY the context above. If the context does not contain the answer, say "I don't have current data on this."
Do not use information from your training data for prices, dates, or availability.
[QUESTION]
{user_question}"""
context = fetch_grounding_context("GPT-4o API pricing 2026")
prompt = build_grounded_prompt("What is the current price of GPT-4o per million tokens?", context)
print(prompt[:500])Step 3: Call the LLM with the grounded prompt
Pass the grounded prompt to any LLM. The model's response is constrained to the injected facts.
import anthropic
client = anthropic.Anthropic(api_key="your-anthropic-key")
def grounded_answer(question: str, search_query: str = None) -> str:
query = search_query or question
context = fetch_grounding_context(query)
prompt = build_grounded_prompt(question, context)
message = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=512,
messages=[{"role": "user", "content": prompt}]
)
return message.content[0].text
answer = grounded_answer(
"What does GPT-4o cost per million input tokens?",
"GPT-4o API pricing per million tokens 2026"
)
print(answer)Python Example
import requests
import anthropic
from datetime import date
SCAVIO_KEY = "your-scavio-api-key"
ANTHROPIC_KEY = "your-anthropic-key"
def fetch_serp_context(query: str, n: int = 5) -> str:
r = requests.post(
"https://api.scavio.dev/api/v1/search",
json={"query": query, "num_results": n},
headers={"x-api-key": SCAVIO_KEY},
timeout=15
)
r.raise_for_status()
results = r.json().get("organic_results", [])
return "\n\n".join(
f"{i}. {r.get('title')}\n {r.get('snippet')}\n {r.get('link')}"
for i, r in enumerate(results, 1)
)
def grounded_answer(question: str, search_query: str | None = None) -> dict:
query = search_query or question
context = fetch_serp_context(query)
prompt = f"""[CONTEXT - {date.today()}]\n{context}\n\n[INSTRUCTIONS]\nAnswer using ONLY the context above. For prices, dates, or availability, cite the source number.\n\n[QUESTION]\n{question}"""
client = anthropic.Anthropic(api_key=ANTHROPIC_KEY)
msg = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=512,
messages=[{"role": "user", "content": prompt}]
)
return {"answer": msg.content[0].text, "context_used": context}
if __name__ == "__main__":
result = grounded_answer(
"How much does Firecrawl cost per month?",
"Firecrawl pricing 2026"
)
print(result["answer"])JavaScript Example
const SCAVIO_KEY = 'your-scavio-api-key';
const ANTHROPIC_KEY = 'your-anthropic-key';
async function fetchSerpContext(query, n = 5) {
const res = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-api-key': SCAVIO_KEY },
body: JSON.stringify({ query, num_results: n })
});
const data = await res.json();
return (data.organic_results ?? [])
.map((r, i) => `${i+1}. ${r.title}\n ${r.snippet}\n ${r.link}`)
.join('\n\n');
}
async function groundedAnswer(question, searchQuery) {
const context = await fetchSerpContext(searchQuery ?? question);
const prompt = `[CONTEXT - ${new Date().toISOString().slice(0,10)}]\n${context}\n\n[QUESTION]\n${question}`;
const res = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': ANTHROPIC_KEY,
'anthropic-version': '2023-06-01'
},
body: JSON.stringify({
model: 'claude-sonnet-4-6',
max_tokens: 512,
messages: [{ role: 'user', content: prompt }]
})
});
const msg = await res.json();
return msg.content[0].text;
}
const answer = await groundedAnswer('How much does Firecrawl cost per month?', 'Firecrawl pricing 2026');
console.log(answer);Expected Output
Based on the search results (source 2), Firecrawl offers:
- Free tier: 1,000 credits
- Starter: $16/month for 5,000 credits
- Scale: $83/month for 100,000 credits (annual billing)
These prices reflect annual billing rates as of 2026.