Les LLM locaux exécutés avec Ollama ou llama.cpp n'ont pas accès à Internet par défaut. Lorsque les utilisateurs posent des questions sur l'actualité, les prix ou tout sujet sensible au temps, le modèle soit hallucine, soit refuse de répondre. Ajouter un outil de recherche Web résout ce problème. L'API Scavio agit comme un point de terminaison de recherche HTTP léger qui renvoie du JSON structuré, suffisamment petit pour tenir dans la fenêtre de contexte de n'importe quel modèle local. Ce tutoriel connecte un outil de recherche à un agent Ollama en utilisant Python, afin que le modèle puisse décider de manière autonome quand chercher et fonder ses réponses sur des données en direct. Pas besoin de LangChain ni de framework lourd.
Prérequis
- Ollama installé avec un modèle compatible outil (llama3.1, mistral, etc.)
- Python 3.10+
- Bibliothèque requests installée
- Une clé API Scavio depuis scavio.dev
Parcours
Étape 1: Définir le schéma de l'outil de recherche
Créez une définition d'outil qui indique au LLM ce que fait la fonction de recherche et les paramètres qu'elle accepte. Ollama utilise le format d'outil compatible OpenAI.
import os
import requests
import json
API_KEY = os.environ['SCAVIO_API_KEY']
SEARCH_TOOL = {
'type': 'function',
'function': {
'name': 'web_search',
'description': 'Search the web for current information. Use this when the user asks about recent events, prices, news, or anything you do not have up-to-date knowledge about.',
'parameters': {
'type': 'object',
'properties': {
'query': {'type': 'string', 'description': 'The search query'}
},
'required': ['query']
}
}
}Étape 2: Implémenter la fonction de recherche
La fonction appelle l'API Scavio et renvoie une chaîne condensée de résultats qui tient confortablement dans la fenêtre de contexte du modèle.
def web_search(query):
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us'})
results = resp.json().get('organic_results', [])[:5]
lines = []
for r in results:
lines.append(f"{r['title']}: {r.get('snippet', '')} ({r['link']})")
return '\n'.join(lines) if lines else 'No results found.'Étape 3: Exécuter la boucle de l'agent avec Ollama
Envoyez le message de l'utilisateur à Ollama avec la définition de l'outil. Si le modèle appelle l'outil, exécutez la recherche et renvoyez le résultat pour la réponse finale.
def chat_with_search(user_message, model='llama3.1'):
messages = [{'role': 'user', 'content': user_message}]
resp = requests.post('http://localhost:11434/api/chat', json={
'model': model, 'messages': messages, 'tools': [SEARCH_TOOL], 'stream': False
}).json()
msg = resp['message']
if msg.get('tool_calls'):
for tc in msg['tool_calls']:
if tc['function']['name'] == 'web_search':
args = tc['function']['arguments']
result = web_search(args['query'])
messages.append(msg)
messages.append({'role': 'tool', 'content': result})
final = requests.post('http://localhost:11434/api/chat', json={
'model': model, 'messages': messages, 'stream': False
}).json()
return final['message']['content']
return msg['content']Étape 4: Tester avec une question en temps réel
Demandez à l'agent quelque chose qu'il ne peut pas répondre uniquement à partir des données d'entraînement. Le modèle devrait appeler web_search et synthétiser les résultats.
answer = chat_with_search('What are the top trending Python libraries released in 2026?')
print(answer)Exemple Python
import os, requests, json
API_KEY = os.environ['SCAVIO_API_KEY']
SEARCH_TOOL = {
'type': 'function',
'function': {
'name': 'web_search',
'description': 'Search the web for current information.',
'parameters': {
'type': 'object',
'properties': {'query': {'type': 'string', 'description': 'Search query'}},
'required': ['query']
}
}
}
def web_search(query):
resp = requests.post('https://api.scavio.dev/api/v1/search',
headers={'x-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'query': query, 'country_code': 'us'})
results = resp.json().get('organic_results', [])[:5]
return '\n'.join(f"{r['title']}: {r.get('snippet', '')}" for r in results) or 'No results.'
def chat(user_msg, model='llama3.1'):
messages = [{'role': 'user', 'content': user_msg}]
resp = requests.post('http://localhost:11434/api/chat', json={
'model': model, 'messages': messages, 'tools': [SEARCH_TOOL], 'stream': False
}).json()
msg = resp['message']
if msg.get('tool_calls'):
for tc in msg['tool_calls']:
result = web_search(tc['function']['arguments']['query'])
messages.append(msg)
messages.append({'role': 'tool', 'content': result})
return requests.post('http://localhost:11434/api/chat', json={
'model': model, 'messages': messages, 'stream': False
}).json()['message']['content']
return msg['content']
print(chat('What Python libraries were released in 2026?'))Exemple JavaScript
const API_KEY = process.env.SCAVIO_API_KEY;
const SEARCH_TOOL = {
type: 'function',
function: {
name: 'web_search',
description: 'Search the web for current information.',
parameters: {
type: 'object',
properties: { query: { type: 'string', description: 'Search query' } },
required: ['query']
}
}
};
async function webSearch(query) {
const r = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST',
headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, country_code: 'us' })
}).then(r => r.json());
return (r.organic_results || []).slice(0, 5)
.map(r => `${r.title}: ${r.snippet || ''}`).join('\n') || 'No results.';
}
async function chat(userMsg, model = 'llama3.1') {
const messages = [{ role: 'user', content: userMsg }];
let resp = await fetch('http://localhost:11434/api/chat', {
method: 'POST',
body: JSON.stringify({ model, messages, tools: [SEARCH_TOOL], stream: false })
}).then(r => r.json());
if (resp.message.tool_calls) {
for (const tc of resp.message.tool_calls) {
const result = await webSearch(tc.function.arguments.query);
messages.push(resp.message, { role: 'tool', content: result });
}
resp = await fetch('http://localhost:11434/api/chat', {
method: 'POST',
body: JSON.stringify({ model, messages, stream: false })
}).then(r => r.json());
}
return resp.message.content;
}
chat('Latest AI news in 2026?').then(console.log).catch(console.error);Sortie attendue
User: What Python libraries were released in 2026?
[Agent calls web_search("new python libraries released 2026")]
[Search returns 5 results with titles and snippets]
Agent: Based on web search results, several notable Python libraries
launched in 2026 including... The agent synthesizes the search
results into a grounded, accurate answer.