DeepSeek models offer strong reasoning capabilities but lack built-in web search access. When users ask about current events, pricing, or recent releases, DeepSeek will either refuse to answer or hallucinate outdated information. Search grounding solves this by fetching relevant SERP data and injecting it into the prompt context before DeepSeek generates its response. This tutorial shows how to add search grounding to any DeepSeek-based agent using the Scavio API at $0.005 per search.
Prerequisites
- Python 3.9+ installed
- openai library installed (DeepSeek uses OpenAI-compatible API)
- requests library installed
- A DeepSeek API key and a Scavio API key
Walkthrough
Step 1: Set up the DeepSeek client
DeepSeek uses an OpenAI-compatible API, so you use the OpenAI Python library with a custom base URL. Set up both the DeepSeek and search clients.
from openai import OpenAI
import requests, os
# DeepSeek client
deepseek = OpenAI(
api_key=os.environ['DEEPSEEK_API_KEY'],
base_url='https://api.deepseek.com'
)
# Search client
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
def web_search(query: str, max_results: int = 5) -> str:
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'})
results = resp.json().get('organic_results', [])[:max_results]
return '\n\n'.join(
f'Source: {r["link"]}\nTitle: {r["title"]}\n{r.get("snippet", "")}'
for r in results
)
print('DeepSeek + Search grounding ready')Step 2: Detect when grounding is needed
Not every query needs search. Build a classifier that decides based on query content whether to search or let DeepSeek answer from its training data.
def needs_grounding(user_message: str) -> bool:
grounding_signals = [
'latest', 'current', 'today', 'now', '2025', '2026',
'price', 'cost', 'how much', 'release', 'version',
'news', 'update', 'recent', 'best', 'top', 'compare'
]
message_lower = user_message.lower()
return any(signal in message_lower for signal in grounding_signals)
# Test:
for q in ['explain quantum computing', 'best Python IDE 2026', 'what is recursion']:
print(f'Ground: {needs_grounding(q):5} | {q}')Step 3: Build the grounded DeepSeek chat function
Create the main function that optionally searches, builds the context, and calls DeepSeek with grounded or ungrounded prompts.
def ask_deepseek(user_message: str, ground: bool = None) -> str:
should_ground = ground if ground is not None else needs_grounding(user_message)
messages = []
if should_ground:
search_context = web_search(user_message)
system_prompt = f"""You are a helpful assistant with access to current web search results.
Use the search results below to provide accurate, up-to-date answers.
Cite sources with URLs when referencing specific facts.
If the search results do not contain relevant information, say so.
Search Results:
{search_context}"""
messages.append({'role': 'system', 'content': system_prompt})
else:
messages.append({'role': 'system',
'content': 'You are a helpful assistant. Answer from your knowledge.'})
messages.append({'role': 'user', 'content': user_message})
response = deepseek.chat.completions.create(
model='deepseek-chat',
messages=messages,
max_tokens=1000,
temperature=0.7
)
return response.choices[0].message.content
# Test grounded query:
answer = ask_deepseek('What are the top Python web frameworks in 2026?')
print(answer)Step 4: Add multi-turn conversation support
For conversations, maintain message history and only ground when the current turn needs it. Previous grounding context is already in the history.
class GroundedDeepSeek:
def __init__(self):
self.history = []
self.search_count = 0
def chat(self, user_message: str) -> str:
self.history.append({'role': 'user', 'content': user_message})
if needs_grounding(user_message):
context = web_search(user_message)
self.search_count += 1
system = f'Use these search results:\n{context}'
messages = [{'role': 'system', 'content': system}] + self.history
else:
messages = self.history.copy()
response = deepseek.chat.completions.create(
model='deepseek-chat',
messages=messages,
max_tokens=1000
)
answer = response.choices[0].message.content
self.history.append({'role': 'assistant', 'content': answer})
return answer
def cost_so_far(self) -> str:
return f'{self.search_count} searches = ${self.search_count * 0.005:.3f}'
agent = GroundedDeepSeek()
print(agent.chat('What is the latest DeepSeek model?'))
print(f'Search cost: {agent.cost_so_far()}')Python Example
from openai import OpenAI
import os, requests
deepseek = OpenAI(api_key=os.environ['DEEPSEEK_API_KEY'], base_url='https://api.deepseek.com')
SCAVIO_KEY = os.environ['SCAVIO_API_KEY']
def search(query, k=5):
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'})
return '\n'.join(f'{r["title"]}: {r.get("snippet", "")}'
for r in resp.json().get('organic_results', [])[:k])
def ask(question):
ctx = search(question)
resp = deepseek.chat.completions.create(
model='deepseek-chat',
messages=[
{'role': 'system', 'content': f'Use search results:\n{ctx}'},
{'role': 'user', 'content': question}
], max_tokens=500)
return resp.choices[0].message.content
print(ask('Best Python web frameworks 2026'))JavaScript Example
import OpenAI from 'openai';
const deepseek = new OpenAI({
apiKey: process.env.DEEPSEEK_API_KEY,
baseURL: 'https://api.deepseek.com'
});
const SCAVIO_KEY = process.env.SCAVIO_API_KEY;
async function search(query) {
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' })
});
const data = await resp.json();
return (data.organic_results || []).slice(0, 5)
.map(r => `${r.title}: ${r.snippet || ''}`).join('\n');
}
async function ask(question) {
const ctx = await search(question);
const resp = await deepseek.chat.completions.create({
model: 'deepseek-chat',
messages: [
{ role: 'system', content: `Search results:\n${ctx}` },
{ role: 'user', content: question }
], max_tokens: 500
});
console.log(resp.choices[0].message.content);
}
ask('Best Python frameworks 2026');Expected Output
Ground: False | explain quantum computing
Ground: True | best Python IDE 2026
Ground: False | what is recursion
Based on current search results, the top Python web frameworks in 2026 are:
1. FastAPI - async-first, ideal for APIs (Source: https://...)
2. Django - full-featured with built-in admin (Source: https://...)
3. Flask - lightweight and flexible (Source: https://...)
Search cost: 1 searches = $0.005