Comment utiliser Ollama pour le streaming des réponses et l'appel d'outils

Ce guide explique le streaming et l'appel d'outils en temps réel avec Ollama. Idéal pour des applis de chat interactives.

Louis Dupont

Louis Dupont

5 June 2025

Comment utiliser Ollama pour le streaming des réponses et l'appel d'outils

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 :

💡
Vous voulez un excellent outil de test d'API qui génère une documentation d'API magnifique ?

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 !
button

Premiers pas : ce dont vous aurez besoin

Pour suivre, vous aurez besoin de quelques éléments :

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 :

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 :

  1. Recevoir le texte initial du modèle (diffusé).
  2. Soudain, le flux peut indiquer qu'un appel d'outil est nécessaire.
  3. Votre application traite l'appel d'outil.
  4. 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... »).
  5. 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 :

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 :

É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 :

É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 :

Dans une véritable application, lorsque vous voyez un morceau tool_calls, votre code :

  1. Arrêterait le traitement du flux (ou le gérerait de manière asynchrone).
  2. Exécuterait la fonction/API get_current_weather réelle avec « Toronto » et « celsius ».
  3. Obtiendrait le résultat (par exemple, « 20 degrés Celsius »).
  4. Renvoyerait ce résultat à Ollama dans un nouveau message avec role: "tool".
  5. 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 :

  1. Importer ollama.
  2. 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.
  3. messages : Nous commençons la conversation avec la requête de l'utilisateur.
  4. ollama.chat(...) :
  1. Boucle à travers response_stream :
  1. Gestion de l'appel d'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 :

  1. Importer ollama.
  2. Objet addTool : Il s'agit du schéma JSON décrivant notre outil à Ollama.
  3. Fonction executeAddTwoNumbers : Notre fonction JavaScript réelle pour l'outil.
  4. Fonction asynchrone main :
  1. Gestion de l'appel d'outil : Similaire à Python, si toolToCallInfo est défini :

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.

Pourquoi est-ce mieux ?

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.

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
  }
}'

Explore more

Fathom-R1-14B : Modèle de raisonnement IA avancé d'Inde

Fathom-R1-14B : Modèle de raisonnement IA avancé d'Inde

L'IA en expansion rapide. Fathom-R1-14B (14,8 milliards de paramètres) excelle en raisonnement mathématique et général, conçu par Fractal AI Research.

5 June 2025

Mistral Code : L'assistant de codage le plus personnalisable basé sur l'IA pour les entreprises

Mistral Code : L'assistant de codage le plus personnalisable basé sur l'IA pour les entreprises

Découvrez Mistral Code, l'IA d'aide au code la plus personnalisable pour les entreprises.

5 June 2025

Comment Claude Code transforme le codage de l'IA en 2025

Comment Claude Code transforme le codage de l'IA en 2025

Découvrez Claude Code en 2025 : codage IA révolutionné. Fonctionnalités, démo, et pourquoi il gagne du terrain après Windsurf d'Anthropic. Indispensable !

5 June 2025

Pratiquez le Design-first d'API dans Apidog

Découvrez une manière plus simple de créer et utiliser des API