Exercices Projets guidés Function calling : le LLM choisit l'outil
🎉

Bravo!

Débutant 🧠 Fondamentaux 10 XP 0 personnes ont réussi

Function calling : le LLM choisit l'outil

Maintenant que tu sais definir des outils, passons a la partie magique : le LLM decide tout seul quel outil utiliser. Quand un utilisateur demande "Quel temps fait-il a Paris ?", le modele ne cherche pas a inventer une reponse. Il regarde sa liste d'outils, voit qu'il y a un outil "rechercher_meteo", et decide de l'appeler avec le parametre "Paris".

En pratique, tu envoies ta question a l'API OpenAI avec la liste des schemas d'outils. La reponse peut contenir un champ tool_calls au lieu d'un message texte. Ce champ te dit quel outil appeler et avec quels arguments (en JSON).

Voici le flux complet :

1. Tu envoies la question + les schemas d'outils
2. Le LLM renvoie un tool_call (nom de l'outil + arguments JSON)
3. Tu executes l'outil avec les bons arguments
4. Tu renvoies le resultat au LLM
5. Le LLM formule sa reponse finale

Pour simuler ce mecanisme sans API, on va travailler avec des dictionnaires. Un tool_call ressemble a ca :

{
"id": "call_abc123",
"type": "function",
"function": {
"name": "rechercher_web",
"arguments": '{"query": "meteo Paris"}'
}
}

Remarque que les arguments sont une chaine JSON, pas un dictionnaire. Il faut les parser avec json.loads().

Ecris une fonction executer_tool_call(tool_call, boite_a_outils) qui prend un dictionnaire tool_call et un dictionnaire boite_a_outils (comme celui de l'exercice precedent). Elle doit extraire le nom de la fonction, parser les arguments JSON, appeler la bonne fonction, et renvoyer un dictionnaire avec le resultat.

La fonction renvoie :

{"tool_call_id": "...", "name": "...", "result": "..."}

Si le nom de l'outil n'existe pas dans la boite, renvoie un dict avec "error" au lieu de "result".

Exemple :

def chercher(query): return f"Resultats pour {query}"
boite = {"rechercher_web": chercher}

tc = {
"id": "call_1",
"type": "function",
"function": {"name": "rechercher_web", "arguments": '{"query": "Python"}'}
}
executer_tool_call(tc, boite)
renvoie {"tool_call_id": "call_1", "name": "rechercher_web", "result": "Resultats pour Python"}

Tests (4/5)

Execution basique d'un tool call
import json
def chercher(query): return f"Resultats pour {query}"
boite = {"rechercher_web": chercher}
tc = {"id": "call_1", "type": "function", "function": {"name": "rechercher_web", "arguments": json.dumps({"query": "Python"})}}
r = executer_tool_call(tc, boite)
assert r["tool_call_id"] == "call_1"
assert r["name"] == "rechercher_web"
assert "Python" in r["result"]
Outil avec plusieurs arguments
import json
def additionner(a, b): return a + b
boite = {"additionner": additionner}
tc = {"id": "call_2", "type": "function", "function": {"name": "additionner", "arguments": json.dumps({"a": 3, "b": 7})}}
r = executer_tool_call(tc, boite)
assert "10" in r["result"], f"3 + 7 devrait donner 10, obtenu {r['result']}"
Outil inconnu renvoie une erreur
import json
boite = {"chercher": lambda q: "ok"}
tc = {"id": "call_3", "type": "function", "function": {"name": "outil_inexistant", "arguments": "{}"}}
r = executer_tool_call(tc, boite)
assert "error" in r, "Un outil inconnu doit renvoyer une cle 'error'"
assert "result" not in r, "Un outil inconnu ne doit pas avoir de cle 'result'"
L'id du tool call est preserve
import json
def echo(msg): return msg
boite = {"echo": echo}
tc = {"id": "call_xyz_789", "type": "function", "function": {"name": "echo", "arguments": json.dumps({"msg": "test"})}}
r = executer_tool_call(tc, boite)
assert r["tool_call_id"] == "call_xyz_789", "L'id du tool call doit etre copie dans tool_call_id"

+ 0 tests cachés

Indices (3 disponibles)

solution.py