1 points par GN⁺ 4 시간 전 | 1 commentaires | Partager sur WhatsApp
  • Pour les agents qui doivent traiter de façon fiable des tâches complexes, ce dont on a besoin n’est pas d’une chaîne de prompts plus sophistiquée, mais d’un flux de contrôle déterministe encodé dans le logiciel
  • Si vous dépendez dans vos prompts d’expressions comme MANDATORY ou DO NOT SKIP, c’est que vous avez atteint les limites du prompting
  • Imaginez un langage de programmation dans lequel les phrases se comportent comme des suggestions et les fonctions hallucinent tout en renvoyant « Success » : à mesure que la complexité augmente, le raisonnement devient impossible et la fiabilité s’effondre
  • Le logiciel évolue grâce à une composabilité récursive fondée sur des bibliothèques, des modules et des fonctions, et permet un raisonnement local parce qu’il offre un comportement prévisible
  • Les chaînes de prompts sont utiles pour des tâches étroites, mais elles n’ont pas les mêmes propriétés, car elles sont non déterministes, faiblement spécifiées et difficiles à vérifier

La structure nécessaire à la fiabilité des agents

  • Pour garantir la fiabilité, il faut sortir la logique des explications en langage naturel pour la déplacer dans le runtime
  • La structure requise est un échafaudage déterministe qui traite le LLM non pas comme l’ensemble du système, mais comme un composant parmi d’autres
  • Cet échafaudage doit inclure des transitions d’état explicites et des points de contrôle de validation
  • L’orchestration déterministe seule ne suffit pas ; dans un système qui peut échouer silencieusement, une détection agressive des erreurs est nécessaire
  • Sans validation programmatique, les options se réduisent à trois
    • Surveillant (Babysitter)

      • Une personne doit rester dans la boucle pour intercepter les erreurs avant qu’elles ne se propagent
    • Auditeur (Auditor)

      • Il faut vérifier minutieusement l’ensemble du résultat une fois l’exécution terminée
    • Prière (Prayer)

      • On finit par dépendre d’une acceptation du résultat au ressenti

1 commentaires

 
GN⁺ 4 시간 전
Commentaires Hacker News
  • D’accord à 1000 %. J’ai de plus en plus de mal à croire au refrain d’Anthropic qui répète sans cesse : « concevez en vous basant sur les performances des modèles futurs, ils vont bientôt s’améliorer ».
    J’avais créé un agent QA qui passait en revue 200 fichiers Markdown d’exigences dans une session navigateur, et c’était un bon système qui avait nettement amélioré l’efficacité de l’équipe. Mais dès qu’on confiait au modèle un flux de contrôle de haut niveau du genre « regarde les fichiers d’exigences dans ce répertoire et, pour chaque fichier, crée une tâche à faire pour vérifier si l’application satisfait ces exigences », tout s’effondrait à partir d’une trentaine de fichiers.
    Il sautait des fichiers, ou testait trois fois certains groupes de fichiers, transformant une tâche de 3 minutes en tâche de 10 minutes, ou encore retestait sans raison les 4 fichiers précédents à cause d’une erreur sur un seul fichier. Sur Opus 4.6 et GPT 5.4, et même d’après un rapide essai sur Opus 4.7 et GPT 5.5, les capacités d’orchestration de workflow restaient incohérentes.
    Au final, j’ai construit autour du modèle un harnais déterministe très simple : appel du modèle pour chaque cas de test, stockage des résultats dans un tableau, puis écriture dans un fichier. La fiabilité du système s’est alors énormément améliorée. Mais les plateformes d’agents managées comme Cursor Cloud Agents ou Anthropic semblent trop obsédées par l’idée que « l’agent doit tout exécuter » pour voir l’intérêt d’ajouter un peu de déterminisme aux bons endroits.

    • Avant, je pensais qu’ils poussaient les gens vers des workflows uniquement basés sur des prompts parce qu’ils pouvaient facturer les tokens mais pas le scaffolding créé par les utilisateurs. Maintenant, j’ai plutôt l’impression qu’ils ont peur du fait qu’il faut quelqu’un pour concevoir et implémenter ce scaffolding.
      Ça refroidit les discours selon lesquels cette technologie remplacerait des personnes entières, des workflows entiers ou des projets entiers. Je pense qu’elle peut énormément augmenter la productivité et avoir des effets désastreux sur le marché de l’emploi des développeurs et sur les salaires, mais la version actuelle de cette technologie ne me semble pas capable d’aller jusqu’au niveau qu’ils prétendent. S’ils l’avaient positionnée comme « un outil très utile qui réduit une bonne partie des corvées d’une équipe de développement humaine », les développeurs en voudraient, mais les dirigeants beaucoup moins, et les investisseurs ne l’auraient probablement pas toléré.
      En outre, les étapes finement et fortement contrôlées se prêtent bien mieux à l’intégration de modèles plus petits, moins chers et spécialisés qu’à de gros modèles capables d’écrire en un instant cinq tomes de fanfiction CSI.
    • Ça vient peut-être de la façon même dont les benchmarks évaluent les modèles.
      Certains benchmarks ne laissent-ils pas faire plusieurs essais sur un même problème, puis ignorent-ils le taux d’échec pour ne retenir qu’un résultat dès qu’une seule tentative réussit ?
    • D’accord. La seule manière de rendre ces systèmes fiables, c’est de découper le problème en petits morceaux. Même les vérifications de cohérence interne ne font au final que montrer que les LLM sont bien moins cohérents qu’on ne l’espérait.
    • Les performances se sont nettement améliorées après avoir combiné apply_patch avec check_compilation et run_unit_tests. L’outil s’appelle toujours apply_patch, mais désormais, si le patch réussit, il renvoie aussi des informations supplémentaires sur le build et les tests.
      Le taux de réussite de l’agent est passé d’environ 80 % à quelque chose qui, jusqu’ici, paraît presque déterministe. Je n’ai même plus besoin d’expliquer dans le prompt le processus de compilation et de tests unitaires : il suffit de l’exécuter avec certaines dépendances et de renvoyer le résultat.
      J’ai aussi l’impression de m’éloigner de la mode du moment. J’utilise depuis longtemps des tokens prépayés et des harnais personnalisés, et ça marche tout simplement bien. On peut ignorer la plupart des actualités. Sur des problèmes explicitement ciblés, les outils de type Copilot ne servent plus à rien, et sur certaines codebases, alors qu’on utilise pourtant le même modèle basé sur GPT 5.4, la différence de performance est d’un tout autre ordre de grandeur.
    • Le secret, c’est de « compiler » ce prompt d’orchestration. Si on transforme le prompt en code, ce code peut ensuite exécuter l’agent, exécuter du code, ou les deux, ce qui résout le problème de déterminisme.
      Tout le monde passe à côté de ce schéma dans les skills. Si on place du code à côté de SKILL.md, on peut garantir certains comportements, mais bizarrement tout le monde est accro au prompt engineering. Pas besoin de créer une CLI ; un simple skill.py contenant le travail suffit. On peut même ajouter un helper qui appelle claude -p.
  • Ce serait drôle si, dans quelques années, les gens utilisaient encore les LLM, mais uniquement via un vocabulaire et une grammaire contrôlés qu’il faut de toute façon apprendre. Un peu comme quand tout le monde est passé à NoSQL il y a 15 ans, avant de recréer presque immédiatement des schémas dans du JSON.

  • Une partie du problème vient peut-être du fait qu’on applique mal les LLM dès le départ. Comme cela a été dit ailleurs, le prompt de l’agent devrait peut-être être : écris du code qui effectue la tâche de la manière la plus reproductible, vérifiable et déterministe possible.
    La validation de la sortie de l’agent devrait aussi en faire partie. L’objectif global est de retirer le LLM des tâches qui peuvent être gérées plus efficacement, et souvent plus correctement, par un programme.

    • Entièrement d’accord. Il faut utiliser un outil non déterministe correct à 90 % pour créer un outil déterministe correct à 100 %. L’une des phrases clés que je mets toujours dans mes prompts est : « si tu rencontres un cas limite ambigu, demande-moi ».
      Brancher directement une IA en production pour qu’elle fasse des choses via des appels API, c’est une mauvaise idée. À mon avis, dans une application, le seul rôle que l’IA devrait avoir, c’est lire, classer, ce genre de choses. En gros remplacer le « R » des anciennes applis CRUD.
      Utiliser ce même endpoint « R » basé sur l’IA pour préremplir automatiquement des formulaires de « C », « U » ou « D » selon le prompt, pourquoi pas ; mais il ne faut pas modifier quoi que ce soit pour un client avant validation humaine. Une appli CRUD reste une appli CRUD et le restera, sauf qu’elle dispose maintenant d’un endpoint « R » très intelligent qui propose de l’autocomplétion de formulaire ou des suggestions d’action pour les clients, les outils internes, les pipelines Jenkins, etc. Elle peut suggérer des actions, mais pas les exécuter directement.
    • Dans la plupart des organisations, le flux semble évoluer de llm -> prompt -> result, vers llm -> prompt + prompt encoded as skill -> result, puis llm -> prompt + deterministic code encoded as skill -> result.
      Faire générer du code par prompt au début peut raccourcir le chemin vers du code déterministe, mais cela revient toujours à mettre du code déterministe à l’intérieur d’un wrapper non déterministe. Pour réussir des tâches longues, il faut souvent une couche de déterminisme qui manque encore.
      Il faut placer du code déterministe hors de la frontière non déterministe, via une boucle d’agent ou un framework. On obtient alors quelque chose comme flux d’agent déterministe -> prise de décision non déterministe -> outils déterministes, où le jugement non déterministe s’insère entre des couches de déterminisme. Dans mes expérimentations, c’était un schéma très puissant, et il devient encore plus fort quand l’agent crée lui-même du déterminisme avec des outils comme auto-researcher.
    • Nous avons eu exactement la même expérience. Au début, on donnait à l’agent une liste d’outils capables de manipuler des structures de données d’une certaine manière, mais cette approche était assez fragile.
      Maintenant, on utilise un petit langage spécifique au domaine et un outil unique, et l’agent fournit en entrée un script écrit dans ce langage. Ça permet de gérer des cas d’usage plus dynamiques, et la moindre syntaxe invalide est facilement détectée par le parseur puis renvoyée à l’agent.
    • Le problème, c’est que les programmes rencontrent souvent des cas limites qui nécessitent une interprétation, et à ce moment-là on veut confier ce cas limite au LLM ; puis, de fil en aiguille, on finit par vouloir lui confier aussi toute la boucle et les appels d’outils.
    • C’est exactement comme ça que j’ai procédé sur mon dernier projet, quand j’ai automatisé la génération d’une bibliothèque d’interface entre un serveur qui contrôle du matériel et une appli mobile.
      L’équipe en charge du contrôle matériel fournissait les spécifications sous forme de documents et de feuilles de calcul, et l’équipe mobile codait ensuite la bibliothèque d’interface à partir de ça, puis la validait face au serveur. J’ai converti la documentation en TSV et j’en ai envoyé une partie à Claude pour lui faire écrire un parseur TSV capable de préserver les subtilités de spécifications rédigées par des humains.
      Il a fallu plus de 150 itérations pour gérer tous les cas limites et générer les résultats intermédiaires en JSON. Ensuite, Claude m’a aidé à écrire un générateur de code qui ajoute du code de glue personnalisé au-dessus d’Apollo afin de produire le code consommé par l’appli mobile.
      Tout ce pipeline tourne dans Github Actions, et Claude n’est appelé que lorsque le validateur de bibliothèque échoue. En cas d’échec, un fichier md est inclus dans la requête pour lui demander d’identifier ce qui n’a pas fonctionné, de proposer une solution et de créer une PR. Ensuite, un humain relit, corrige et fusionne. Le coût total en crédits jusqu’ici est resté inférieur à 350 $.
  • Je suis d’accord avec l’idée générale, mais je pense qu’il faut changer la conclusion. Quand on atteint les limites du prompt, il faut cesser d’essayer de faire exécuter la tâche par un LLM au moment de l’exécution, et utiliser le LLM pour écrire le logiciel qui exécutera la tâche.
    Le rôle du LLM à l’exécution sera généralement réduit à aider l’utilisateur à choisir des entrées conformes à un système logiciel qui, lui, embarque des règles métier strictes.

    • J’ai eu quelques semaines de marge au travail, donc j’ai essayé d’introduire des agents dans des processus métier comme la prise de notes, le suivi des tâches ou la gestion documentaire, et cela correspond exactement à mon expérience.
      La première semaine, les prompts grossissaient sans cesse et les performances baissaient. La deuxième semaine, je me suis concentré sur la définition précise d’objets comme des notes, des tâches, des projets ou des personnes, puis sur la définition de méthodes bien spécifiées opérant sur ces objets. Comme tu le soulignes, la surface de l’agent se réduit à une couche de traduction qui transforme le langage naturel en commandes et arguments passant par un validateur d’entrée.
    • Si on voulait vraiment boucler la boucle avec un system prompt, ce serait : « cherche toutes les opportunités d’automatisation susceptibles de te rendre inutile. Si on te pose une question à laquelle du code peut répondre, écris et exécute du code pour obtenir le résultat, puis réponds. »
      Un tel LLM aurait peut-être mieux réussi le test strawberry.
    • Sur ce forum aussi, certains ont soutenu que l’avenir du logiciel réside dans des programmes générés et adaptés à l’exécution grâce à l’IA générative. Je ne sais pas combien de temps il reste avant d’en arriver là.
    • J’ai vu des cas où le modèle restait coincé dans une manière particulière de résoudre un problème, et avait besoin d’un petit coup de pouce pour changer d’approche. Par exemple, pour gérer le hotplug/unplug de flux audio, il bricolait toutes sortes de réglages de services système alors qu’en réalité il suffisait d’écrire quelques dizaines de lignes de Python.
      J’ai fait en sorte que Claude écrive lui-même quelques scripts shell pour gérer des cas courants de mon workflow, comme l’exécution des tests. Maintenant, au lieu de tourner en rond pendant 30 minutes, il exécute ces outils et termine la configuration.
      Chaque fois qu’il me demande l’autorisation d’exécuter une ligne shell ou Python ponctuelle et bizarre pour faire quelque chose, ça me fait me demander si je ne devrais pas plutôt lui faire utiliser un outil pouvant être approuvé automatiquement.
  • C’est pour ça qu’on parle souvent d’« IA de nouvelle génération ». Cela ne veut pas dire seulement LLM. Les LLM sont assez formidables et, même sans progrès fondamentaux supplémentaires, je pense qu’ils continueront à produire de la valeur en étant utilisés et optimisés de manières plus intéressantes.
    Mais sur certains points, il semble qu’il faille, sous une forme ou une autre, des améliorations fondamentales de nouvelle génération. Le fait qu’un LLM transforme un « ne fais jamais X » en quelque chose de flou, puis au bout de nombreuses étapes finisse par le comprendre comme « s’il te plaît fais X », paraît très proche du fonctionnement même du système. C’est facile à oublier dans l’excitation des débuts où l’on découvre encore ce qu’on peut faire, mais les LLM ne sont pas tout ce que l’on recherche dans l’IA.
    Il faut une architecture capable de traiter « ne fais jamais X » comme un humain le ferait. Il faut aussi une architecture avec une hiérarchie de mémoire comparable à celle des humains, plutôt qu’une simple « fenêtre de contexte ». Deux personnes qui parleraient assez longtemps avec une même IA finiraient ainsi, même si c’était la même IA au départ, avec deux IA réellement différentes et pas seulement avec des fenêtres de contexte différentes.
    Bien sûr, personne ne sait à quoi cela ressemblera. Mais il n’y a pas non plus de raison de penser que les LLM sont la réponse finale à l’IA.

    • À mon avis, il faut une vraie mémoire. La mémoire actuelle ressemble plutôt, au sens large, à un système de post-it que l’IA s’écrit à elle-même puis relit à chaque fois, pas à un système intégré permettant réellement l’apprentissage et un déclenchement plus souple.
    • Il y a un exemple intéressant ici : https://www.youtube.com/watch?v=kYkIdXwW2AE&t=315s
  • En tant que quelqu’un qui a fait tout le tour prompt enforcement → flux déterministe → prompt enforcement, je ne suis pas d’accord.
    Si « ne saute rien » échoue, c’est parce que l’agent a trop à faire et que d’autres éléments du contexte détournent son attention de cette instruction.
    Mais personne n’a dit que l’agent chargé d’appliquer les contraintes devait être le même que celui qui construit. On peut coder une part de logique de décision intelligente dans un flux de contrôle déterministe, mais si on le rend trop rigide ça fonctionne mal, et si on le rend trop complexe, il devient alors moins coûteux en mise en place et en maintenance d’utiliser directement un agent.
    En pratique, il faut trois types d’agents : un superviseur qui gère la boucle et déclenche ce qu’il faut quand un problème survient, un orchestrateur qui délègue aux bons agents et applique les garde-fous là où c’est nécessaire, et des workers qui exécutent les unités de travail.

    • Oui, il suffit juste d’ajouter encore plus d’agents.
  • À mes yeux, tous les harnais se trompent sur cet aspect, et certains se trompent gravement.
    Par exemple, les slash commands sont une mauvaise fonctionnalité. On ne devrait pas avoir à attendre que le chatbot finisse un tour pour vérifier l’état de la fenêtre de contexte ou l’argent dépensé pendant la session. Le contrôle devrait être orthogonal à la boucle de chat.
    Des choses qui n’ont absolument rien à voir avec le contrôle des entrées et sorties d’un générateur de texte se retrouvent mêlées au comportement du chat juste parce que « c’est du chat, alors faisons-le se comporter comme un bot IRC ».
    Il existe aujourd’hui énormément d’agents LLM, mais presque aucun ne sépare correctement le contrôle, la boucle d’agent et la couche de présentation. Quelques-uns ont au moins un mode headless, et c’est déjà ça.

    • Je vois ce que tu veux dire, mais construire réellement l’architecture que tu proposes est bien plus difficile. Pourquoi ne pas la construire toi-même et viser un recrutement dans une grande entreprise ?
    • Dans codex CLI, /status fonctionne bien même au milieu d’un tour.
      Ce n’est pas le cas ailleurs.
    • J’utilise l’application desktop Codex. Dans l’interface graphique, on voit l’indicateur de contexte et les statistiques d’utilisation.
      C’est aussi plus pratique pour naviguer entre les conversations et voir les mises à jour. J’utilise parfois Claude Code ou opencode dans le terminal, mais l’expérience est bien moins bonne qu’avec l’application desktop Codex.
  • La phrase « imagine un langage de programmation où les phrases sont des suggestions et où une fonction hallucine avant de renvoyer “Success”. Le raisonnement devient impossible et la fiabilité s’effondre à mesure que la complexité augmente » relève essentiellement de la programmation déclarative.
    La plupart de la programmation traditionnelle est impérative, ce qui est familier aux développeurs : on donne un ensemble précis d’instructions et on s’attend à ce qu’elles soient suivies comme écrites. Les agents sont bien plus proches du déclaratif que de l’impératif : on leur donne un résultat, et ils travaillent pour l’obtenir.
    Bien sûr, dans un système déclaratif comme SQL, le résultat est généralement très cohérent et bien défini, mais cela reste une affaire de confiance envers le moteur interne quant à la manière de le produire. Penser aux agents comme à du déclaratif m’a beaucoup plus aidé que d’essayer de concevoir des systèmes de « contrôle » à la Rube Goldberg. Si le résultat n’est pas bon, on le valide, on signale que c’est faux, puis on réessaie ou on adopte une autre approche.
    Si on a vraiment besoin d’impératif, on peut écrire de manière impérative. Ou demander à l’agent de le faire. Ça ressemble ici à une tentative d’utiliser un outil qui n’est pas adapté à la tâche.

    • J’ai l’impression que c’est encore un cran plus abstrait que le déclaratif. On pourrait appeler ça de la programmation narrative ? Bien sûr, on peut aussi débattre de savoir si le mot « programmation » convient encore.
      Ça peut ressembler à du déclaratif, mais seulement à l’intérieur d’une illusion. En réalité, on ne décrit pas un objectif à une IA pour qu’elle l’interprète ; on a un document narratif dans lequel un personnage représentant l’humain parle à un personnage représentant l’ordinateur, et nous, dans le monde réel, espérons qu’un LLM recolle derrière cela une histoire plus cohérente pour en extraire quelque chose d’utile.
      Ce n’est pas juste une distinction académique. Savoir qu’il y a une histoire aide à mieux modéliser la relation entre entrées et sorties et à élaborer des stratégies. Par exemple, cela aide à comprendre des risques comme l’injection de prompt et donne aussi des indications sur les données d’entraînement à inclure ou à exclure.
    • J’ai aussi pensé au déclaratif, mais plutôt à PROLOG qu’à SQL. Le genre qui a un vrai flux de contrôle et de vraies capacités d’inférence.
      On retrouve alors des problèmes similaires à ceux des LLM : échecs silencieux, répétitions et contradictions si on n’est pas extrêmement prudent. Au fond, c’est peut-être le même problème d’hypothèse du monde clos. Avec les LLM, cela se manifeste par des hallucinations plutôt que par l’aveu d’une absence de connaissance.
    • D’accord. Mais on peut aussi parler de manière impérative à un agent. Même si on lui dit « voici des étapes précises, suis-les », il peut quand même tout rater. Ce qu’on cherche, ce n’est pas l’impératif, c’est le déterminisme.
      Et comme tu le dis, si on donne à un LLM non déterministe une consigne déclarative du type « amène-moi à cet état final », il a encore plus de chances de dérailler.
    • Le caractère déclaratif de SQL repose sur des mathématiques, en l’occurrence l’algèbre relationnelle, ce qui fait qu’il renvoie le même résultat à chaque fois. Le fait de renvoyer ce résultat dans le même temps à chaque requête dépend, lui, des index et de la taille de la base de données.
      Mais la requête elle-même ne change pas comme le ferait un LLM.
  • Je réfléchis beaucoup à ce problème. On peut aussi le relier à la question de la spécialisation. Plus un modèle devient spécialisé, plus il semble perdre en capacités de base ; peut-être qu’en visant un tout petit peu d’abstraction, on peut obtenir le meilleur des deux mondes.
    C’est un exemple assez spécifique, mais ça mérite réflexion.
    Résumé podcast en 20 minutes : https://pub-6333550e348d4a5abe6f40ae47d2925c.r2.dev/EP008.ht...
    Article : https://arxiv.org/abs/2605.00225

  • On le voyait déjà à l’époque d’Auto-GPT en 2023. Les gens laissaient GPT « conduire », alors que dans la plupart des cas, ce qu’il fallait vraiment, c’était dix lignes de Python et peut-être quelques appels à llm().
    L’alternative consistait à faire tourner ces dix lignes de Python de la manière la plus chère, la plus lente et la moins fiable possible. Cela dit, c’était populaire.
    Par exemple, la plupart utilisaient des agents pour faire de la recherche sur internet. Ils tournaient pendant des heures avant de se disperser ou d’oublier ce qu’ils faisaient au départ.
    À l’inverse, avec import duckduckgo et import llm, on peut écrire en dix lignes un code qui fait la même chose en 20 secondes, qui s’exécute réellement de façon déterministe, et qui coûte 50 fois moins cher.
    Les modèles actuels sont bien meilleurs, et ils se sont suffisamment améliorés pour qu’Auto-GPT soit désormais réaliste. Mais exécuter un flux de contrôle mal spécifié de la manière la plus coûteuse possible reste une mauvaise idée.