Réponse courte
Créez-le en six décisions : un objectif étroit, une courte liste d’outils, une boucle qui permet au modèle d’appeler ces outils par l’appel de fonctions, une mémoire pour ce qu’il a appris, des règles d’arrêt fermes et un journal de chaque étape. Mettez chacune par écrit avant de coder, et le programme lui-même devient court : l’agent de synthèse de recherche ci-dessous tient en environ soixante-dix lignes de Python.
Question de suivi Comment décider des outils qu’on lui donne?
Un agent d’IA est un programme dans lequel un modèle de langage décide de la prochaine étape vers un objectif, utilise un outil pour franchir cette étape, examine le résultat et décide de nouveau. L’idée vient de travaux de recherche comme l’article ReAct de 2022, qui a montré que laisser un modèle alterner entre raisonnement et actions, comme chercher une information, rendait ses réponses mieux ancrées dans les faits que le raisonnement seul.
La plupart des projets d’agents qui échouent le font à l’étape de la planification, pas dans le code. L’objectif est trop large, l’agent a trop d’outils, ou personne n’a décidé quand il devait s’arrêter. Ce guide passe donc d’abord par le plan, puis montre le code qui en découle.
Étape 1 : écrire un objectif en une phrase
Un bon objectif d’agent nomme l’entrée, la sortie et la limite. Le nôtre : À partir d’une question, trouver les documents pertinents dans un dossier local d’articles, les lire et rédiger un court résumé qui cite les fichiers utilisés, en le disant quand les documents ne répondent pas à la question. Il lit, mais n’écrit, n’envoie ni ne supprime jamais rien, ce qui rend la première version sûre.
Étape 2 : choisir le moins d’outils possible pour atteindre l’objectif
Un outil, ici, est une fonction de votre programme que le modèle peut vous demander d’exécuter. Notre agent en a besoin de deux : search_docs pour trouver les fichiers probables, et read_doc pour en lire un. Avec l’appel de fonctions d’OpenAI (function calling), vous décrivez chaque outil par un nom, une description en langage courant et ses paramètres en JSON Schema, un format standard pour décrire des données. Le modèle n’exécute jamais rien lui-même : il répond avec le nom d’une fonction et les arguments qu’il veut, et c’est votre code qui décide de l’exécuter ou non.
Étape 3 : écrire la boucle
À chaque passage, la conversation et la liste d’outils sont envoyées au modèle. Si la réponse contient des appels d’outils, votre code les exécute et ajoute chaque résultat sous forme de message avec le rôle tool. Si elle n’en contient aucun, le modèle a écrit sa réponse. Cette version utilise la bibliothèque Python openai (version 1.x) avec le paramètre tools, comme dans les exemples du livre de recettes (cookbook) d’OpenAI.
import json
from pathlib import Path
from openai import OpenAI
client = OpenAI() # lit OPENAI_API_KEY dans l’environnement
MODEL = "gpt-4o"
DOCS = Path("articles") # un dossier de fichiers .txt
LOG = Path("agent_log.jsonl")
def search_docs(query):
words = query.lower().split()
hits = []
for f in DOCS.glob("*.txt"):
text = f.read_text(encoding="utf-8").lower()
score = sum(text.count(w) for w in words)
if score:
hits.append((score, f.name))
hits.sort(reverse=True)
return json.dumps([name for _, name in hits[:5]])
def read_doc(name):
path = DOCS / Path(name).name # ne jamais sortir du dossier
if not path.exists():
return "Erreur : aucun document de ce nom."
return path.read_text(encoding="utf-8")[:6000]
TOOLS = [
{"type": "function", "function": {
"name": "search_docs",
"description": "Trouve les documents qui contiennent les mots de la requête. Renvoie jusqu’à 5 noms de fichiers.",
"parameters": {"type": "object",
"properties": {"query": {"type": "string", "description": "Quelques mots-clés"}},
"required": ["query"]}}},
{"type": "function", "function": {
"name": "read_doc",
"description": "Renvoie le texte d’un document (les 6 000 premiers caractères).",
"parameters": {"type": "object",
"properties": {"name": {"type": "string", "description": "Un nom de fichier fourni par search_docs"}},
"required": ["name"]}}},
]
FUNCTIONS = {"search_docs": search_docs, "read_doc": read_doc}
SYSTEM = ("Tu es un assistant de recherche. Réponds uniquement à partir des documents "
"que tu as lus avec read_doc, et cite leurs noms de fichiers entre crochets. "
"Si les documents ne répondent pas à la question, dis-le. "
"Tes résumés font moins de 200 mots.")
def log(entry):
with LOG.open("a", encoding="utf-8") as f:
f.write(json.dumps(entry) + "\n")
def run(question, max_steps=8, token_budget=40000):
messages = [{"role": "system", "content": SYSTEM},
{"role": "user", "content": question}]
used = 0
for step in range(1, max_steps + 1):
response = client.chat.completions.create(
model=MODEL, messages=messages, tools=TOOLS, temperature=0)
used += response.usage.total_tokens
msg = response.choices[0].message
messages.append(msg)
if not msg.tool_calls:
log({"step": step, "final": msg.content, "tokens": used})
return msg.content
for call in msg.tool_calls:
func = FUNCTIONS.get(call.function.name)
try:
args = json.loads(call.function.arguments)
result = func(**args) if func else "Erreur : outil inconnu."
except Exception as e:
args, result = call.function.arguments, f"Erreur : {e}"
log({"step": step, "tool": call.function.name, "args": args, "result": result[:200]})
messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
if used > token_budget:
return "Arrêt : budget de jetons atteint."
return "Arrêt : limite d’étapes atteinte."
print(run("Que disent nos articles sur les thermopompes en climat froid?"))
Étape 4 : décider de ce dont il se souvient
La liste messages est la mémoire à court terme de l’agent : tout ce qu’il a cherché et lu pendant cette exécution. Elle disparaît à la fin de l’exécution. Si vous voulez que l’agent se souvienne d’une exécution à l’autre, enregistrez quelque chose délibérément, par exemple en ajoutant chaque résumé final à un fichier que l’agent pourra consulter la fois suivante. Commencez sans mémoire à long terme; ajoutez-en une seulement quand vous en voyez le besoin.
Étape 5 : fixer des règles d’arrêt
Trois sont intégrées ci-dessus : une réponse finale met fin à l’exécution, max_steps plafonne le nombre de passages, et le budget de jetons plafonne le coût, puisque chaque appel renvoie toute la conversation. Ajoutez une limite de dépenses dans les paramètres de votre compte OpenAI comme dernier filet de sécurité.
Étape 6 : tout consigner
Le fichier agent_log.jsonl enregistre chaque appel d’outil, ses arguments et le début de son résultat, une ligne par événement. Quand le résumé est faux, le journal montre si le modèle a cherché les mauvais mots, sauté un fichier ou mal lu un document. C’est ainsi que vous améliorez les descriptions et le message système.
À essayer : placez cinq ou six fichiers texte sur un même sujet dans un dossier articles, lancez le script avec une question à laquelle ils répondent en partie, puis ouvrez agent_log.jsonl. Modifiez la description d’un outil, relancez le script et comparez les étapes choisies par le modèle.
Comment décider des outils qu’on lui donne?
Partez de l’objectif et dressez la liste des actions dont une personne consciencieuse aurait besoin pour l’atteindre, puis ne donnez à l’agent que celles-là. Chaque outil de plus est un choix de plus où le modèle peut se tromper, et une chose de plus à tester. Deux outils qui font chacun une tâche claire valent mieux qu’un seul outil avec de nombreuses options.
Classez les outils selon le risque. Les outils en lecture seule, comme chercher ou lire des fichiers, peuvent être appelés librement par l’agent sans danger. Les outils qui ont des conséquences, comme envoyer un courriel, publier, acheter ou supprimer, devraient faire une pause et demander à une personne de confirmer; c’est exactement le conseil qu’OpenAI a donné au lancement de l’appel de fonctions. Gardez aussi des paramètres étroits : read_doc ci-dessus n’accepte qu’un nom de fichier et retire tout chemin de dossier, si bien que le modèle ne peut pas s’aventurer hors du dossier que vous avez choisi.
Enfin, traitez ce que renvoient les outils comme non fiable. Un document ou une page Web peut contenir du texte qui tente de donner des consignes au modèle, un risque qu’OpenAI a aussi signalé. Des descriptions d’outils claires, un message système ferme et une approbation humaine pour tout ce qui est irréversible gardent l’agent concentré sur la seule tâche pour laquelle vous l’avez conçu.
Sources
- How to call functions with chat models (OpenAI Cookbook, commit a519708) — OpenAI (GitHub), 17 mai 2024
- Function calling and other API updates — OpenAI, 13 juin 2023
- ReAct: Synergizing Reasoning and Acting in Language Models — arXiv (Shunyu Yao and six co-authors), 6 octobre 2022