Ce guide vous expliquera comment utiliser l'une des nouvelles fonctionnalités puissantes d'Ollama : la possibilité de diffuser des réponses et d'appeler des outils (comme des fonctions ou des API) en temps réel. Il s'agit d'une révolution pour la création d'applications de chat qui semblent vivantes et peuvent interagir avec le monde qui les entoure.
Ce que vous apprendrez dans ce tutoriel :
- Ce que signifient la diffusion de réponses et l'appel d'outils dans Ollama.
- Pourquoi cette combinaison est super utile pour vos projets d'IA.
- Instructions étape par étape pour mettre en œuvre cela en utilisant :
- cURL (pour des tests rapides et un accès universel)
- Python (pour les applications backend)
- JavaScript (pour les applications web et Node.js)
- Un aperçu de la façon dont Ollama gère intelligemment ces fonctionnalités.
- Conseils pour obtenir les meilleures performances.
Vous voulez une plateforme intégrée, tout-en-un, pour que votre équipe de développeurs travaille ensemble avec une productivité maximale ?
Apidog répond à toutes vos demandes et remplace Postman à un prix beaucoup plus abordable !
Premiers pas : ce dont vous aurez besoin
Pour suivre, vous aurez besoin de quelques éléments :
- Ollama installé : Assurez-vous d'avoir la dernière version d'Ollama en cours d'exécution sur votre système. Sinon, rendez-vous sur le site officiel d'Ollama pour le télécharger et l'installer.
- Connaissances de base de la ligne de commande : Pour les exemples cURL.
- Environnement Python (pour la section Python) : Python 3.x installé, ainsi que
pip
pour la gestion des packages. - Environnement Node.js (pour la section JavaScript) : Node.js et
npm
installés. - Compréhension de JSON : Ollama utilise JSON pour structurer les données et les appels d'outils.
Comprendre les idées clés : diffusion et appels d'outils
Décomposons ce que nous entendons par « diffusion de réponses » et « appel d'outils ».
Qu'est-ce que la diffusion de réponses ?
Imaginez que vous discutez avec une IA. Au lieu d'attendre qu'elle réfléchisse et tape l'intégralité de sa réponse avant de voir quoi que ce soit, la diffusion signifie que l'IA vous envoie sa réponse morceau par morceau, mot par mot, au fur et à mesure qu'elle la génère. Cela rend l'interaction beaucoup plus rapide et plus naturelle, comme une vraie conversation.
Avec Ollama, lorsque vous activez la diffusion ("stream": true
), vous obtenez ces mises à jour incrémentielles.
Comment fonctionne l'appel d'outils ?
L'appel d'outils permet à vos modèles d'IA de faire plus que simplement générer du texte. Vous pouvez définir des « outils » – qui sont essentiellement des fonctions ou des API externes – que l'IA peut décider d'utiliser pour obtenir des informations ou effectuer des actions.
Par exemple, un outil pourrait être :
get_current_weather(location)
: Récupère la météo actuelle.calculate_sum(number1, number2)
: Effectue un calcul.search_web(query)
: Obtient des informations sur Internet.
Vous décrivez ces outils à Ollama, et lorsque l'IA détermine que l'utilisation d'un outil aiderait à répondre à la requête de l'utilisateur, elle signale son intention d'appeler cet outil avec des arguments spécifiques. Votre application exécute ensuite l'outil et peut renvoyer les résultats à l'IA pour continuer la conversation.
Pourquoi combiner la diffusion avec l'appel d'outils ?
La grande mise à niveau d'Ollama est qu'il peut désormais gérer l'appel d'outils tout en diffusant des réponses. Cela signifie que votre application peut :
- Recevoir le texte initial du modèle (diffusé).
- Soudain, le flux peut indiquer qu'un appel d'outil est nécessaire.
- Votre application traite l'appel d'outil.
- Pendant ce temps, le modèle peut même diffuser plus de texte (par exemple, « D'accord, je vais vous donner la météo... »).
- Une fois que votre application obtient le résultat de l'outil, vous pouvez le renvoyer au modèle, et il continuera à diffuser sa réponse, désormais informée par la sortie de l'outil.
Cela crée des applications d'IA très réactives et performantes.
Quels modèles prennent en charge ces fonctionnalités ?
Ollama a activé cela pour plusieurs modèles populaires, notamment :
- Qwen 3
- Devstral
- Qwen2.5 et Qwen2.5-coder
- Llama 3.1
- Llama 4
- ...et d'autres sont continuellement ajoutés !
Comment effectuer votre premier appel d'outil de diffusion avec cURL
cURL est un excellent moyen de tester rapidement l'API d'Ollama. Demandons la météo à Toronto.
Étape 1 : conceptualisation de votre outil
Notre outil sera get_current_weather
. Il a besoin de :
location
(chaîne) : par exemple, « Toronto »format
(chaîne) : par exemple, « celsius » ou « fahrenheit »
Étape 2 : construction de la commande cURL
Ouvrez votre terminal et préparez la commande suivante. Nous allons la décomposer :
curl <http://localhost:11434/api/chat> -d '{
"model": "qwen3",
"messages": [
{
"role": "user",
"content": "What is the weather today in Toronto?"
}
],
"stream": true,
"tools": [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The location to get the weather for, e.g. San Francisco, CA"
},
"format": {
"type": "string",
"description": "The format to return the weather in, e.g. \\\\\\\\'celsius\\\\\\\\' or \\\\\\\\'fahrenheit\\\\\\\\'",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location", "format"]
}
}
}
]
}'
Décomposition :
curl <http://localhost:11434/api/chat
: La commande et le point de terminaison de l'API de chat d'Ollama.d '{...}'
: Envoie les données JSON dans le corps de la requête."model": "qwen3"
: Spécifie le modèle d'IA à utiliser."messages": [...]
: L'historique de la conversation. Ici, juste la question de l'utilisateur."stream": true
: C'est la clé ! Il indique à Ollama de diffuser la réponse."tools": [...]
: Un tableau où nous définissons les outils disponibles pour le modèle."type": "function"
: Spécifie le type d'outil."function": {...}
: Décrit la fonction."name": "get_current_weather"
: Le nom de l'outil."description": "..."
: Aide le modèle à comprendre ce que fait l'outil."parameters": {...}
: Définit les arguments que l'outil accepte (en utilisant le schéma JSON).
Étape 3 : exécuter et observer la sortie
Appuyez sur Entrée. Vous verrez une série d'objets JSON apparaître les uns après les autres. C'est le flux !
Extraits d'exemples du flux :
{
"model": "qwen3", "created_at": "...",
"message": { "role": "assistant", "content": "Okay, " }, "done": false
}
{
"model": "qwen3", "created_at": "...",
"message": { "role": "assistant", "content": "I will " }, "done": false
}
{
"model": "qwen3", "created_at": "...",
"message": { "role": "assistant", "content": "try to get that for you." }, "done": false
}
(Le modèle peut afficher des jetons de « réflexion » comme <think>...celsius...</think>
en fonction de son processus interne, ceux-ci font également partie du flux)
Ensuite, de manière critique, vous pourriez voir quelque chose comme ceci :
{
"model": "qwen3",
"created_at": "2025-05-27T22:54:58.100509Z",
"message": {
"role": "assistant",
"content": "", // Content might be empty when a tool call is made
"tool_calls": [
{
"function": {
"name": "get_current_weather",
"arguments": { // The arguments the model decided on!
"format": "celsius",
"location": "Toronto"
}
}
}
]
},
"done": false // Still not done, awaiting tool result
}
Ce qu'il faut remarquer :
- Chaque morceau est un objet JSON.
"done": false
signifie que le flux est en cours. Le dernier morceau aura"done": true
.- L'objet
"message"
contient : "role": "assistant"
"content"
: La partie texte du flux."tool_calls"
: Un tableau qui apparaît lorsque le modèle souhaite utiliser un outil. Il comprend lename
de l'outil et lesarguments
sur lesquels il a décidé.
Dans une véritable application, lorsque vous voyez un morceau tool_calls
, votre code :
- Arrêterait le traitement du flux (ou le gérerait de manière asynchrone).
- Exécuterait la fonction/API
get_current_weather
réelle avec « Toronto » et « celsius ». - Obtiendrait le résultat (par exemple, « 20 degrés Celsius »).
- Renvoyerait ce résultat à Ollama dans un nouveau message avec
role: "tool"
. - Le modèle utilisera ensuite ces informations pour continuer à générer sa réponse, également diffusée.
Comment diffuser des appels d'outils en utilisant Python
Implémentons une idée similaire en Python en utilisant la bibliothèque officielle d'Ollama.
Étape 1 : installation de la bibliothèque Python Ollama
Si vous ne l'avez pas déjà fait, installez ou mettez à niveau la bibliothèque :
pip install -U ollama
Étape 2 : définition de votre outil et codage en Python
Le SDK Python d'Ollama vous permet intelligemment de passer des fonctions Python directement en tant qu'outils. Il inspecte la signature de la fonction et la chaîne de documentation pour créer le schéma pour l'IA.
Créons un exemple d'outil mathématique simple (l'entrée utilise add_two_numbers
mais l'exemple de sortie montre subtract_two_numbers
appelé par le modèle. Nous nous en tiendrons à add_two_numbers
fourni pour la définition et laisserons le modèle décider quoi faire en fonction de l'invite.)
import ollama
# Define the python function that can be used as a tool
def add_two_numbers(a: int, b: int) -> int:
"""
Add two numbers.
Args:
a (int): The first number as an int.
b (int): The second number as an int.
Returns:
int: The sum of the two numbers.
"""
print(f"--- Tool 'add_two_numbers' called with a={a}, b={b} ---")
return a + b
# --- Main conversation logic ---
messages = [{'role': 'user', 'content': 'What is three plus one?'}]
# Or, for the subtraction example in the original output:
# messages = [{'role': 'user', 'content': 'what is three minus one?'}]
print(f"User: {messages[0]['content']}")
# Make the chat request with streaming and the tool
# Note: ChatResponse type hint might be ollama.ChatResponse or similar depending on library version
response_stream = ollama.chat(
model='qwen3', # Or another capable model
messages=messages,
tools=[
{ # You can also define the tool explicitly if needed, or pass the function directly
'type': 'function',
'function': {
'name': 'add_two_numbers', # Must match the Python function name if you want it to be called directly by your code later
'description': 'Add two integer numbers together.',
'parameters': {
'type': 'object',
'properties': {
'a': {'type': 'integer', 'description': 'The first number'},
'b': {'type': 'integer', 'description': 'The second number'}
},
'required': ['a', 'b']
}
}
}
# Simpler way for Python: pass the function directly if the library supports easy schema generation from it
# tools=[add_two_numbers] # The SDK can often create the schema from this
],
stream=True
)
print("Assistant (streaming):")
full_response_content = ""
tool_call_info = None
for chunk in response_stream:
# Print the streamed content part
if chunk['message']['content']:
print(chunk['message']['content'], end='', flush=True)
full_response_content += chunk['message']['content']
# Check for tool calls in the chunk
if 'tool_calls' in chunk['message'] and chunk['message']['tool_calls']:
tool_call_info = chunk['message']['tool_calls'][0] # Assuming one tool call for simplicity
print(f"\\\\n--- Detected Tool Call: {tool_call_info['function']['name']} ---")
break # Stop processing stream for now, handle tool call
if chunk.get('done'):
print("\\\\n--- Stream finished ---")
if not tool_call_info:
print("No tool call was made.")
# --- If a tool call was detected, handle it ---
if tool_call_info:
tool_name = tool_call_info['function']['name']
tool_args = tool_call_info['function']['arguments']
print(f"Arguments for the tool: {tool_args}")
# Here, you'd actually call your Python tool function
if tool_name == "add_two_numbers":
# For safety, ensure arguments are of correct type if necessary
try:
arg_a = int(tool_args.get('a'))
arg_b = int(tool_args.get('b'))
tool_result = add_two_numbers(a=arg_a, b=arg_b)
print(f"--- Tool execution result: {tool_result} ---")
# Now, send this result back to Ollama to continue the conversation
messages.append({'role': 'assistant', 'content': full_response_content, 'tool_calls': [tool_call_info]})
messages.append({
'role': 'tool',
'content': str(tool_result), # Result must be a string
'tool_call_id': tool_call_info.get('id', '') # If your library/model provides a tool_call_id
})
print("\\\\n--- Sending tool result back to model ---")
follow_up_response_stream = ollama.chat(
model='qwen3',
messages=messages,
stream=True
# No tools needed here unless you expect another tool call
)
print("Assistant (after tool call):")
for follow_up_chunk in follow_up_response_stream:
if follow_up_chunk['message']['content']:
print(follow_up_chunk['message']['content'], end='', flush=True)
if follow_up_chunk.get('done'):
print("\\\\n--- Follow-up stream finished ---")
break
except ValueError:
print("Error: Could not parse tool arguments as integers.")
except Exception as e:
print(f"An error occurred during tool execution or follow-up: {e}")
else:
print(f"Error: Unknown tool '{tool_name}' requested by the model.")
Explication du code Python :
- Importer
ollama
. - Fonction
add_two_numbers
: C'est notre outil. La chaîne de documentation et les indications de type aident Ollama à comprendre son objectif et ses paramètres. messages
: Nous commençons la conversation avec la requête de l'utilisateur.ollama.chat(...)
:
model
,messages
,stream=True
sont similaires à cURL.tools=[...]
: Nous fournissons la définition de l'outil. Le SDK Python est assez flexible ; vous pouvez passer directement l'objet fonction (par exemple,tools=[add_two_numbers]
) s'il peut déduire le schéma, ou le définir explicitement comme indiqué.
- Boucle à travers
response_stream
:
chunk['message']['content']
: C'est le texte diffusé. Nous l'imprimons immédiatement.chunk['message']['tool_calls']
: Si cette clé existe et contient du contenu, l'IA souhaite utiliser un outil. Nous stockons cestool_call_info
et interrompons la boucle pour le gérer.
- Gestion de l'appel d'outil :
- Nous extrayons le
tool_name
et lestool_args
. - Nous appelons notre fonction Python réelle (
add_two_numbers
) avec ces arguments. - Fondamentalement : Nous ajoutons ensuite la réponse partielle de l'assistant (qui a conduit à l'appel d'outil) et un nouveau message avec
role: "tool"
et lecontent
comme le résultat sous forme de chaîne de notre fonction à la listemessages
. - Nous effectuons un autre appel
ollama.chat
avec ces messages mis à jour pour obtenir la réponse finale de l'IA basée sur la sortie de l'outil.
Flux de sortie attendu : Vous verrez la question initiale de l'utilisateur, puis la réponse de l'assistant en cours de diffusion. S'il décide d'appeler add_two_numbers
(ou subtract_two_numbers
comme dans l'exemple de sortie d'origine si l'invite était pour la soustraction), vous verrez le message « Appel d'outil détecté », les arguments, le résultat de votre fonction Python, puis l'assistant poursuivant sa réponse en utilisant ce résultat.
(L'exemple de sortie d'origine montrait :
<think>
Okay, the user is asking ...
</think>
[ToolCall(function=Function(name='subtract_two_numbers', arguments={'a': 3, 'b': 1}))]
Cela indique le processus de « réflexion » interne de l'IA, puis l'objet d'appel d'outil structuré que le SDK Python fournit.)
Comment diffuser des appels d'outils en utilisant JavaScript (Node.js)
Maintenant, faisons de même avec JavaScript, généralement pour un backend Node.js ou une application web.
Étape 1 : installation de la bibliothèque JavaScript Ollama
Dans le répertoire de votre projet, exécutez :
npm i ollama
Étape 2 : définition du schéma d'outil et codage en JavaScript
En JavaScript, vous définissez généralement le schéma d'outil sous forme d'objet JSON.
import ollama from 'ollama';
// Describe the tool schema (e.g., for adding two numbers)
const addTool = {
type: 'function',
function: {
name: 'addTwoNumbers',
description: 'Add two numbers together',
parameters: {
type: 'object',
required: ['a', 'b'],
properties: {
a: { type: 'number', description: 'The first number' },
b: { type: 'number', description: 'The second number' }
}
}
}
};
// Your actual JavaScript function that implements the tool
function executeAddTwoNumbers(a, b) {
console.log(`--- Tool 'addTwoNumbers' called with a=${a}, b=${b} ---`);
return a + b;
}
async function main() {
const messages = [{ role: 'user', content: 'What is 2 plus 3?' }];
console.log('User:', messages[0].content);
console.log('Assistant (streaming):');
let assistantResponseContent = "";
let toolToCallInfo = null;
try {
const responseStream = await ollama.chat({
model: 'qwen3', // Or another capable model
messages: messages,
tools: [addTool],
stream: true
});
for await (const chunk of responseStream) {
if (chunk.message.content) {
process.stdout.write(chunk.message.content);
assistantResponseContent += chunk.message.content;
}
if (chunk.message.tool_calls && chunk.message.tool_calls.length > 0) {
toolToCallInfo = chunk.message.tool_calls[0]; // Assuming one tool call
process.stdout.write(`\\\\n--- Detected Tool Call: ${toolToCallInfo.function.name} ---\\\\n`);
break; // Stop processing stream to handle tool call
}
if (chunk.done) {
process.stdout.write('\\\\n--- Stream finished ---\\\\n');
if (!toolToCallInfo) {
console.log("No tool call was made.");
}
break;
}
}
// --- If a tool call was detected, handle it ---
if (toolToCallInfo) {
const toolName = toolToCallInfo.function.name;
const toolArgs = toolToCallInfo.function.arguments;
console.log(`Arguments for the tool:`, toolArgs);
let toolResult;
if (toolName === 'addTwoNumbers') {
toolResult = executeAddTwoNumbers(toolArgs.a, toolArgs.b);
console.log(`--- Tool execution result: ${toolResult} ---`);
// Append assistant's partial message and the tool message
messages.push({
role: 'assistant',
content: assistantResponseContent, // Include content leading up to tool call
tool_calls: [toolToCallInfo]
});
messages.push({
role: 'tool',
content: toolResult.toString(), // Result must be a string
// tool_call_id: toolToCallInfo.id // If available and needed
});
console.log("\\\\n--- Sending tool result back to model ---");
const followUpStream = await ollama.chat({
model: 'qwen3',
messages: messages,
stream: true
});
console.log("Assistant (after tool call):");
for await (const followUpChunk of followUpStream) {
if (followUpChunk.message.content) {
process.stdout.write(followUpChunk.message.content);
}
if (followUpChunk.done) {
process.stdout.write('\\\\n--- Follow-up stream finished ---\\\\n');
break;
}
}
} else {
console.error(`Error: Unknown tool '${toolName}' requested.`);
}
}
} catch (error) {
console.error('Error during Ollama chat:', error);
}
}
main().catch(console.error);
Explication du code JavaScript :
- Importer
ollama
. - Objet
addTool
: Il s'agit du schéma JSON décrivant notre outil à Ollama. - Fonction
executeAddTwoNumbers
: Notre fonction JavaScript réelle pour l'outil. - Fonction asynchrone
main
:
- Le tableau
messages
démarre la conversation. await ollama.chat({...})
: Effectue l'appel.tools: [addTool]
: Transmet notre schéma d'outil.stream: true
: Active la diffusion.for await (const chunk of responseStream)
: Cette boucle traite chaque morceau diffusé.chunk.message.content
: Partie texte du flux.chunk.message.tool_calls
: S'il est présent, l'IA souhaite utiliser un outil. Nous stockonstoolToCallInfo
.
- Gestion de l'appel d'outil : Similaire à Python, si
toolToCallInfo
est défini :
- Extraire le nom et les arguments.
- Appeler
executeAddTwoNumbers()
. - Ajouter le message de l'assistant (qui incluait la demande d'appel d'outil) et un nouveau message
role: "tool"
avec le résultat au tableaumessages
. - Effectuer un autre appel
ollama.chat
avec les messages mis à jour pour obtenir la réponse finale.
Flux de sortie attendu (similaire aux exemples cURL et Python) : Vous verrez la question de l'utilisateur, puis la réponse de l'assistant en cours de diffusion. Lorsqu'il décide d'appeler addTwoNumbers
, il affichera les informations d'appel d'outil, le résultat de votre fonction JavaScript, puis continuera à diffuser la réponse de l'IA basée sur ce résultat.
L'exemple de sortie d'origine pour JS ressemblait à :
Question: What is 2 plus 3?
<think>
Okay, the user is asking...
</think>
Tool call: {
function: {
name: "addTwoNumbers",
arguments: { a: 2, b: 3 },
},
}
Comment Ollama gère l'analyse des outils pendant la diffusion
Vous vous demandez peut-être comment Ollama parvient à diffuser du texte et à identifier les appels d'outils aussi facilement. Il utilise un nouveau analyseur incrémentiel intelligent.
- Ancienne méthode : De nombreux systèmes devaient attendre la totalité de la réponse de l'IA, puis l'analyser pour les appels d'outils (généralement formatés en JSON). Cela bloquait la diffusion car un appel d'outil pouvait apparaître n'importe où.
- Nouvelle méthode d'Ollama :
- L'analyseur examine le modèle spécifique de chaque modèle pour comprendre comment il signale un appel d'outil (par exemple, des jetons spéciaux ou des préfixes).
- Cela permet à Ollama d'identifier les appels d'outils « incrémentiellement » au fur et à mesure que les données sont diffusées, en les séparant du contenu textuel normal.
- Il est suffisamment intelligent pour gérer les modèles qui n'ont pas été explicitement formés avec des préfixes d'outils, mais qui parviennent toujours à produire des structures d'appel d'outils valides. Il peut même revenir à la recherche de structures de type JSON si nécessaire, mais intelligemment, afin de ne pas simplement saisir n'importe quel JSON.
Pourquoi est-ce mieux ?
- Véritable diffusion : Vous obtenez du texte immédiatement, et les appels d'outils sont identifiés à la volée.
- Précision : Il est plus efficace pour éviter les faux positifs (par exemple, si l'IA parle d'un appel d'outil qu'elle a effectué précédemment, le nouvel analyseur est moins susceptible de le déclencher à nouveau par erreur).
Conseil : améliorer les performances avec la fenêtre contextuelle
Pour les interactions plus complexes, en particulier avec l'appel d'outils, la taille de la « fenêtre contextuelle » utilisée par le modèle peut avoir son importance. Une fenêtre contextuelle plus grande signifie que le modèle se souvient de davantage de la conversation en cours.
- Protocole de contexte du modèle (MCP) : Les améliorations d'Ollama fonctionnent bien avec MCP.
num_ctx
: Vous pouvez souvent suggérer une taille de fenêtre contextuelle. Par exemple, 32 000 (32k
) jetons ou plus peuvent améliorer les performances d'appel d'outils et la qualité des résultats.- Compromis : Les fenêtres contextuelles plus grandes utilisent plus de mémoire.
Exemple : définition de la fenêtre contextuelle avec cURL (Utilisez un modèle qui prend en charge des contextes plus grands, comme llama3.1
ou llama4
comme suggéré dans le matériel d'origine - bien que l'exemple utilise llama3.2
)
curl -X POST "<http://localhost:11434/api/chat>" -d '{
"model": "llama3.1",
"messages": [
{
"role": "user",
"content": "why is the sky blue?"
}
],
"options": {
"num_ctx": 32000
}
}'