# Le daemon Ollama doit tourner (souvent déjà lancé en service)
ollama serve
# Un modèle qui supporte les outils
ollama pull qwen3.5:4b
# La librairie Python officielle
pip install -U ollama
import ollama
def get_meteo(ville: str, unite: str = "celsius") -> str:
"""Renvoie la météo actuelle pour une ville donnée.
Args:
ville: Nom de la ville (ex : Lyon).
unite: Unité de température, celsius ou fahrenheit.
"""
# Ici, un vrai appel à une API météo. On simule le retour.
return f"21 degrés, ciel dégagé à {ville} ({unite})."
reponse = ollama.chat(
model="qwen3.5:4b",
messages=[{"role": "user", "content": "Quel temps fait-il à Lyon ?"}],
tools=[get_meteo], # la lib introspecte signature + docstring
)
# Le modèle n'a pas répondu en texte : il demande un outil
for appel in reponse.message.tool_calls or []:
print(appel.function.name) # -> get_meteo
print(appel.function.arguments) # -> {'ville': 'Lyon'}
import ollama
def get_meteo(ville: str, unite: str = "celsius") -> str:
"""Météo actuelle d'une ville."""
return f"21 degrés, ciel dégagé à {ville}."
# Registre nom -> fonction réelle
OUTILS = {"get_meteo": get_meteo}
messages = [{"role": "user", "content": "Météo à Lyon puis à Marseille ?"}]
while True:
reponse = ollama.chat(model="qwen3.5:4b", messages=messages, tools=[get_meteo])
messages.append(reponse.message) # on garde la demande dans l'historique
if not reponse.message.tool_calls:
# Plus d'outil demandé : c'est la réponse finale
print(reponse.message.content)
break
for appel in reponse.message.tool_calls:
fonction = OUTILS.get(appel.function.name)
if fonction is None:
resultat = f"Erreur : outil inconnu '{appel.function.name}'"
else:
resultat = fonction(**appel.function.arguments)
messages.append({
"role": "tool",
"tool_name": appel.function.name,
"content": str(resultat),
})
import ollama
flux = ollama.chat(
model="qwen3.5:4b",
messages=[{"role": "user", "content": "Météo à Nice ?"}],
tools=[get_meteo],
stream=True,
)
for morceau in flux:
# Le texte arrive token par token
if morceau.message.content:
print(morceau.message.content, end="", flush=True)
# Les appels d'outils arrivent aussi dans le flux
for appel in morceau.message.tool_calls or []:
print("\n[outil]", appel.function.name, appel.function.arguments)