Planifier puis exécuter : un patron de sécurité et ce qu'il interdit
Ce que garantit un plan figé avant toute lecture de contenu non fiable, ce qu'il ne garantit pas sur les arguments, et les fonctionnalités auxquelles il faut renoncer pour en bénéficier.
Par Elias Varen7 min de lectureMembres
Dans une boucle d'agent ordinaire, le modèle choisit sa prochaine action après avoir lu le résultat de la précédente. C'est ce qui le rend utile, et c'est aussi la faille, car si le résultat contient un texte écrit par un attaquant, ce texte participe au choix de l'action suivante. Le contenu non fiable tient le volant.
Le patron « planifier puis exécuter » retire le volant. Le modèle établit la liste complète des actions à partir de la seule demande de l'utilisateur, avant d'avoir lu quoi que ce soit d'extérieur, puis un exécutant déroule le plan. Les résultats d'outils circulent comme des données d'une étape à l'autre, sans jamais ajouter, retirer ni réordonner une étape.
Parmi les défenses contre l'injection, celle-ci est l'une des rares à donner une garantie structurelle au lieu d'une probabilité. Elle se paie en utilité, et plus cher que les schémas ne le laissent croire.
L'intégrité du flot de contrôle
La propriété obtenue est une intégrité du flot de contrôle. La séquence des appels d'outils est décidée dans un contexte qui ne contient que du texte fiable, le prompt système et la demande de l'utilisateur. Aucune injection placée dans un document, un ticket ou une page web ne peut faire apparaître un appel qui n'était pas prévu.
Boucle réactive Planifier puis exécuter
demande ──► modèle ──► outil A demande ──► planificateur ──► plan [A, B, C]
▲ │ │
└──────────┘ exécutant ◄─────────┘
(le résultat de A A ─► B ─► C
choisit la suite) (les résultats sont des valeurs,
jamais des instructions)Le plan est un objet que le code valide avant exécution, et le modèle ne se contente pas de relire un texte. Chez nous, il a cette forme :
final readonly class Etape
{
/** @param array<string, Litteral|Reference> $arguments */
public function __construct(
public string $outil,
public array $arguments,
public string $resultat, // nom de variable, ex. "$ticket"
) {}
}
final readonly class Plan
{
/** @param list<Etape> $etapes */
public function __construct(public array $etapes) {}
}Un argument est soit un Litteral fixé à la planification, soit une Reference vers le résultat d'une étape antérieure. L'exécutant est un programme ordinaire qui parcourt les étapes, résout les références et appelle les outils, sans contenir de modèle. Ce détail compte, parce qu'un exécutant qui « interprète » un résultat pour savoir quoi faire reconstruit la boucle réactive.
À lire ensuite
Toute la rubrique IAIA
Identité des agents : qui agit, au nom de qui ?
Pourquoi un agent doté d'un compte de service large devient un adjoint confus, et comment faire porter à chaque appel d'outil l'autorité de l'utilisateur, réduite à la tâche, avec un journal qui nomme les deux.
7 minMembres
IA
Mode automatique : classer les actions au lieu de demander
Pourquoi la demande de permission systématique ne protège plus au bout d'une heure, ce qu'un classifieur d'actions rattrape et ce qu'il laisse passer, et comment décider quelles actions lui confier.
8 minMembres
IA
Workflow ou agent : le coût de l'autonomie
Ce que vous payez quand vous laissez le modèle choisir l'étape suivante, comment chaque option casse, et la règle pour décider où l'autonomie est justifiée.
7 minLecture libre