<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ivan Béthus</title>
    <description>The latest articles on DEV Community by Ivan Béthus (@ibethus).</description>
    <link>https://dev.to/ibethus</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1428348%2F28fd1d4c-5919-4afd-ab66-9f7d8cddeee6.png</url>
      <title>DEV Community: Ivan Béthus</title>
      <link>https://dev.to/ibethus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ibethus"/>
    <language>en</language>
    <item>
      <title>Koog : un framework agentique pour ne plus réinventer la boucle</title>
      <dc:creator>Ivan Béthus</dc:creator>
      <pubDate>Tue, 15 Sep 2026 09:22:50 +0000</pubDate>
      <link>https://dev.to/onepoint/koog-un-framework-agentique-pour-ne-plus-reinventer-la-boucle-4gpg</link>
      <guid>https://dev.to/onepoint/koog-un-framework-agentique-pour-ne-plus-reinventer-la-boucle-4gpg</guid>
      <description>&lt;p&gt;&lt;a href="https://blog.hot-coffee.dev/en/blog/koog/" rel="noopener noreferrer"&gt;Also in english 🇬🇧&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Construire un agent LLM "à la main", c'est amusant pendant deux heures. Mais, rapidement, émergent les vraies questions : comment gérer une conversation qui dépasse la fenêtre de contexte ? Comment structurer un workflow qui a plus de trois étapes ? Comment brancher ses propres outils sans réécrire un parseur de function-calling maison ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.koog.ai/" rel="noopener noreferrer"&gt;Koog&lt;/a&gt; est le framework agentique de JetBrains. Il est écrit en Kotlin et cible principalement la JVM, avec ses intégrations Spring Boot, Spring AI et Ktor. La version 1.0 est sortie en mai 2026, annoncée à &lt;a href="https://blog.jetbrains.com/ai/2026/05/koog-1-0-is-out-stable-core-better-interop-and-multiplatform-observability/" rel="noopener noreferrer"&gt;la keynote de KotlinConf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Découvrons ensemble si ce framework JVM tout neuf tient ses promesses !&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tous les exemples sont donnés en Kotlin.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Une prise en main étonnamment simple
&lt;/h2&gt;

&lt;p&gt;Le point d'entrée de Koog est un DSL Kotlin (avec, depuis mars 2026, une API Java). Pas de YAML tentaculaire : on déclare son agent, ses outils et sa stratégie directement en code typé. Le "hello world" d'un agent tient en quelques lignes :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;runBlocking&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ANTHROPIC_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The API key is not set."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;promptExecutor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MultiLLMPromptExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;AnthropicLLMClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="n"&gt;llmModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnthropicModels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Opus_4_1&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello! How can you help me?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Déclarer un outil personnalisé est tout aussi direct : une classe qui implémente &lt;code&gt;ToolSet&lt;/code&gt;, une méthode annotée &lt;code&gt;@Tool&lt;/code&gt;, des &lt;code&gt;@LLMDescription&lt;/code&gt; pour guider le modèle, et l'outil devient utilisable dès qu'on l'enregistre dans le &lt;code&gt;ToolRegistry&lt;/code&gt; de l'agent :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@LLMDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Tools for getting weather information"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyFirstToolSet&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ToolSet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Tool&lt;/span&gt;
    &lt;span class="nd"&gt;@LLMDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Get the current weather for a location"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getWeather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@LLMDescription&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The city and state/country"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"The weather in $location is sunny and 72°F"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;runBlocking&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;promptExecutor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;simpleOpenAIExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiToken&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;systemPrompt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Provide weather information for a given location."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;llmModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAIModels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GPT4o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;toolRegistry&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ToolRegistry&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MyFirstToolSet&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"What's the weather like in New York?"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Des graphes d'états sur-mesure
&lt;/h2&gt;

&lt;p&gt;Koog ne se contente pas d'une boucle "prompt → outil → prompt". Il expose une véritable architecture en &lt;strong&gt;graphe de stratégie&lt;/strong&gt; (&lt;code&gt;AIAgentGraphStrategyBuilder&lt;/code&gt;), composée de trois briques :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;des &lt;strong&gt;nœuds&lt;/strong&gt;, qui encapsulent une étape de traitement (appel LLM, appel d'outil, compression d'historique, transformation de données...) ;&lt;/li&gt;
&lt;li&gt;des &lt;strong&gt;arêtes&lt;/strong&gt;, qui relient les nœuds et peuvent porter des conditions : on ne suit une arête que si telle condition est vraie ;&lt;/li&gt;
&lt;li&gt;des &lt;strong&gt;sous-graphes&lt;/strong&gt;, des unités de traitement autonomes avec leur propre contexte et leurs propres outils.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chaque nœud a un type d'entrée et un type de sortie, et la stratégie elle-même en a un aussi, ce qui fait que les erreurs de branchement se voient à la compilation plutôt qu'en production.&lt;/p&gt;

&lt;p&gt;Koog livre deux stratégies prêtes à l'emploi : &lt;code&gt;chatAgentStrategy&lt;/code&gt;, pour une interaction conversationnelle, et &lt;code&gt;reActStrategy&lt;/code&gt;, qui implémente le pattern ReAct en alternant phases de raisonnement et phases d'action, à une fréquence réglable via le paramètre &lt;code&gt;reasoningInterval&lt;/code&gt;. Mais ce ne sont que des points de départ. Dès que le cas d'usage sort du cadre (boucles de validation, branchements selon le résultat d'un outil, sous-agents spécialisés qui se relaient sur une tâche complexe), on redescend sur le graphe et on assemble ses propres nœuds. Voici par exemple une simple boucle d'appels d'outils, écrite à la main, qui tourne jusqu'à obtenir une réponse textuelle :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;calculatorAgentStrategy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"Simple calculator"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;sendInput&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;nodeLLMRequest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;executeTools&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;nodeExecuteTools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;sendToolResults&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;nodeLLMSendToolResults&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodeStart&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;sendInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendInput&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;nodeFinish&lt;/span&gt; &lt;span class="nf"&gt;onTextMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendInput&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;executeTools&lt;/span&gt; &lt;span class="nf"&gt;onToolCalls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executeTools&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;sendToolResults&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendToolResults&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;nodeFinish&lt;/span&gt; &lt;span class="nf"&gt;onTextMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendToolResults&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;executeTools&lt;/span&gt; &lt;span class="nf"&gt;onToolCalls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La seule contrainte : chaque &lt;code&gt;strategy { }&lt;/code&gt; doit avoir un chemin complet entre &lt;code&gt;nodeStart&lt;/code&gt; et &lt;code&gt;nodeFinish&lt;/code&gt;. Tout le reste, nœuds intermédiaires, boucles, branches, est à la carte.&lt;/p&gt;

&lt;h2&gt;
  
  
  La boucle agentique, et la compression automatique de l'historique
&lt;/h2&gt;

&lt;p&gt;Le cœur du sujet reste donc la boucle agentique : l'agent appelle le LLM, reçoit éventuellement des demandes d'appel d'outils, les exécute, réinjecte les résultats, et recommence jusqu'à obtenir une réponse finale. Koog gère cette boucle nativement, avec un mécanisme de retry configurable et de la persistance par checkpoints (qui restaure la machine à états complète de l'agent, pas seulement l'historique de messages).&lt;/p&gt;

&lt;p&gt;Reste le problème du contexte long. Une conversation agentique qui s'étale sur des dizaines d'itérations, appels d'outils compris, fait exploser le nombre de tokens envoyés à chaque requête. Koog propose une &lt;strong&gt;compression automatique de l'historique&lt;/strong&gt;, activable comme un nœud à part entière dans le graphe (&lt;code&gt;nodeLLMCompressHistory&lt;/code&gt; en Kotlin, &lt;code&gt;AIAgentNode.llmCompressHistory()&lt;/code&gt; côté Java), avec plusieurs stratégies prêtes à l'emploi :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;HistoryCompressionStrategy.WholeHistory&lt;/code&gt; (par défaut) : résume l'intégralité de la conversation en un seul message de synthèse.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;HistoryCompressionStrategy.FromLastNMessages(n)&lt;/code&gt; : ne compresse que les &lt;em&gt;n&lt;/em&gt; derniers messages.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;HistoryCompressionStrategy.Chunked(size)&lt;/code&gt; : découpe l'historique en segments de taille fixe et résume chaque segment indépendamment, pour garder à la fois le passé lointain et le présent récent.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FactRetrievalHistoryCompressionStrategy&lt;/code&gt; : extrait uniquement les faits pertinents par rapport à une liste de concepts que vous fournissez, plutôt qu'un résumé généraliste.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si aucune ne correspond à votre cas d'usage, rien n'empêche d'étendre &lt;code&gt;HistoryCompressionStrategy&lt;/code&gt; pour écrire la vôtre. De quoi faire tourner des agents longtemps sans que la facture de tokens (ni la latence) ne devienne ingérable.&lt;/p&gt;

&lt;p&gt;Voici à quoi ça ressemble une fois branché sur un graphe de stratégie, avec une compression déclenchée conditionnellement après l'exécution d'un outil :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Helper maison, pas une API du framework : à vous de définir le seuil&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;suspend&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;AIAgentContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;historyIsTooLong&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readSession&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;strategy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"execute-with-history-compression"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;callLLM&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;nodeLLMRequest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;executeTool&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;nodeExecuteTools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;sendToolResult&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;nodeLLMSendToolResults&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;compressHistory&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;nodeLLMCompressHistory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ReceivedToolResults&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodeStart&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;callLLM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callLLM&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;nodeFinish&lt;/span&gt; &lt;span class="nf"&gt;onTextMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callLLM&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;executeTool&lt;/span&gt; &lt;span class="nf"&gt;onToolCalls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executeTool&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;compressHistory&lt;/span&gt; &lt;span class="nf"&gt;onCondition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;historyIsTooLong&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compressHistory&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;sendToolResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executeTool&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;sendToolResult&lt;/span&gt; &lt;span class="nf"&gt;onCondition&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;historyIsTooLong&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendToolResult&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;executeTool&lt;/span&gt; &lt;span class="nf"&gt;onToolCalls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sendToolResult&lt;/span&gt; &lt;span class="n"&gt;forwardTo&lt;/span&gt; &lt;span class="n"&gt;nodeFinish&lt;/span&gt; &lt;span class="nf"&gt;onTextMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ce qui donne, visuellement :&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;stateDiagram-v2
    [*] --&amp;gt; AppelLLM
    AppelLLM --&amp;gt; [*] : réponse textuelle
    AppelLLM --&amp;gt; ExecutionOutils : appels d'outils
    ExecutionOutils --&amp;gt; CompressionHistorique : historique trop long
    ExecutionOutils --&amp;gt; EnvoiResultats : historique OK
    CompressionHistorique --&amp;gt; EnvoiResultats
    EnvoiResultats --&amp;gt; ExecutionOutils : nouveaux appels d'outils
    EnvoiResultats --&amp;gt; [*] : réponse textuelle&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  GOAP : planification algorithmique
&lt;/h2&gt;

&lt;p&gt;Koog sait aussi faire du &lt;strong&gt;GOAP&lt;/strong&gt; (&lt;em&gt;Goal-Oriented Action Planning&lt;/em&gt;), une technique popularisée par le jeu vidéo (l'exemple le plus connu étant peut-être l'IA des soldats de &lt;a href="https://www.gamedeveloper.com/design/building-the-ai-of-f-e-a-r-with-goal-oriented-action-planning" rel="noopener noreferrer"&gt;F.E.A.R.&lt;/a&gt; en 2005) et qui se révèle efficace pour organiser le comportement d'un agent.&lt;/p&gt;

&lt;p&gt;Contrairement à un planificateur "LLM-based" qui demande au modèle de générer lui-même la séquence d'actions, un agent GOAP la &lt;strong&gt;découvre algorithmiquement&lt;/strong&gt;. En pratique, on déclare :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;un &lt;strong&gt;état&lt;/strong&gt;, sous forme de data class, qui représente les propriétés pertinentes du monde de l'agent ;&lt;/li&gt;
&lt;li&gt;des &lt;strong&gt;actions&lt;/strong&gt;, chacune avec une précondition (ce qui doit être vrai pour pouvoir l'exécuter), un coût, et une &lt;em&gt;belief&lt;/em&gt; : la prédiction optimiste de l'état résultant, utilisée uniquement pendant la phase de planification ;&lt;/li&gt;
&lt;li&gt;des &lt;strong&gt;buts&lt;/strong&gt;, avec leur condition de complétion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Le planificateur part de l'objectif : la recherche &lt;a href="https://fr.wikipedia.org/wiki/Algorithme_A*" rel="noopener noreferrer"&gt;A*&lt;/a&gt; remonte la chaîne des préconditions, de l'action qui satisfait le but jusqu'à celle qu'on peut exécuter immédiatement, en minimisant le coût total du chemin obtenu. C'est cette recherche à rebours qui rend l'algorithme efficace. La distinction entre la &lt;em&gt;belief&lt;/em&gt; et le résultat réel est importante : le plan est construit sur ces prédictions, mais c'est bien l'exécution effective de chaque action qui met à jour l'état courant, celui depuis lequel le planificateur repart à l'étape suivante. Si une action échoue ou produit un résultat inattendu, l'agent le constate et replanifie. Cette approche est intéressante lorsque plusieurs chemins mènent à l'objectif, ou quand les conditions changent en cours de route.&lt;/p&gt;

&lt;p&gt;Un exemple pour un agent de rédaction de contenu, qui doit passer par un plan (rédiger, relire, publier) sans qu'on lui impose l'ordre en dur. Pour que le planificateur ait un vrai choix à faire (et pas une simple chaîne linéaire), on lui donne deux façons d'obtenir un plan : le générer via le LLM, ou réutiliser un plan déjà fourni par l'appelant :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;ContentState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;providedOutline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;hasOutline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;hasDraft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;hasReview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isPublished&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;GoapAgentState&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;agentInput&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;topic&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;provideOutput&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;draft&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;planner&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;goap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"content-planner"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;ContentState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Use provided outline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;precondition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasOutline&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;providedOutline&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;belief&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasOutline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;providedOutline&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasOutline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;providedOutline&lt;/span&gt;&lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Create outline"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;precondition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasOutline&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;belief&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasOutline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outline&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Outline"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* appel LLM pour générer le plan */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Write draft"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;precondition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasOutline&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasDraft&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;belief&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasDraft&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Draft"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* appel LLM pour rédiger le brouillon */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Review content"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;precondition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasDraft&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasReview&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;belief&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hasReview&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* appel LLM pour relire */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Publish"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;precondition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hasReview&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isPublished&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;belief&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isPublished&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isPublished&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Published article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Complete and publish the article"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;condition&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isPublished&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Le planner n'est pas un agent : on l'emballe dans une stratégie&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;promptExecutor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AIAgentPlannerStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"content-agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;planner&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;llmModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAIModels&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GPT4o&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aucune de ces actions ne dit explicitement "fais A puis B puis C" : c'est le planificateur qui, à partir des préconditions et de l'objectif final (&lt;code&gt;isPublished == true&lt;/code&gt;), reconstruit lui-même l'ordre d'exécution. Et selon que &lt;code&gt;providedOutline&lt;/code&gt; est renseigné ou non, il retient "Use provided outline" (coût 0.1, aucun appel LLM) plutôt que "Create outline" (coût 1.0) : deux chemins différents vers le même objectif, sans une ligne de branchement écrite à la main.&lt;/p&gt;

&lt;p&gt;Reste une question cruciale : que se passe-t-il si le planificateur ne converge jamais, par exemple parce que deux actions s'annulent mutuellement en boucle (l'une remet l'état dans la configuration que l'autre vient de défaire) ? Côté Koog, le seul garde-fou documenté est générique à tous les agents : le paramètre &lt;code&gt;maxAgentIterations&lt;/code&gt; de l'&lt;code&gt;AIAgentConfig&lt;/code&gt;, qui plafonne le nombre total d'itérations, planification comprise. Rien d'aussi ciblé qu'un vrai &lt;em&gt;stuck handler&lt;/em&gt; dédié au planificateur pour l'instant. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;À comparer avec le fonctionnement du framework &lt;a href="https://hub.embabel.com/" rel="noopener noreferrer"&gt;Embabel&lt;/a&gt;, qui, lui, expose une interface &lt;code&gt;StuckHandler&lt;/code&gt; pour traiter explicitement l'état "bloqué", ainsi qu'un &lt;code&gt;Budget&lt;/code&gt; (nombre d'actions, coût, tokens) branché sur son &lt;code&gt;EarlyTerminationPolicy&lt;/code&gt; pour couper court aux boucles. Un point à surveiller si vous comptez vous appuyer sur GOAP en production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Deux détails pratiques : les planificateurs vivent dans un module à part (&lt;code&gt;agents:agents-planners&lt;/code&gt;, à ajouter explicitement à vos dépendances), et cette partie de Koog est encore estampillée beta. L'API peut bouger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools, MCP et A2A : un agent ne travaille jamais seul
&lt;/h2&gt;

&lt;p&gt;Un agent, même bien conçu, ne vaut que par les outils qu'il peut actionner. Koog embarque nativement un système de &lt;strong&gt;tools&lt;/strong&gt; avec un registre typé (nom, description, schéma d'entrée) et la possibilité de déclarer ses propres outils métier en quelques lignes.&lt;/p&gt;

&lt;p&gt;Le support du &lt;a href="https://modelcontextprotocol.io/docs/2026-07-28/getting-started/intro" rel="noopener noreferrer"&gt;Model Context Protocol (MCP)&lt;/a&gt; est inclus de base, via &lt;code&gt;McpToolRegistryProvider&lt;/code&gt; : Koog se connecte à un serveur MCP en stdio (&lt;code&gt;defaultStdioTransport&lt;/code&gt;) ou en SSE (&lt;code&gt;defaultSseTransport&lt;/code&gt;), y découvre dynamiquement les outils disponibles, les transforme en outils Koog et les enregistre dans le tool registry de l'agent. Que ce serveur expose Google Maps, Playwright ou votre propre outillage interne, le code appelant ne change pas.&lt;/p&gt;

&lt;p&gt;Pour les architectures multi-agents, Koog implémente le protocole &lt;a href="https://a2a-protocol.org/latest/" rel="noopener noreferrer"&gt;A2A (Agent-to-Agent)&lt;/a&gt; en version 0.3.0, côté client comme côté serveur. On peut donc exposer un agent Koog comme serveur A2A consommable par n'importe quel agent compatible, ou faire dialoguer un agent Koog avec des agents tiers respectant le protocole.&lt;/p&gt;

&lt;h2&gt;
  
  
  Les intégrations : Spring Boot, Spring AI, Ktor
&lt;/h2&gt;

&lt;p&gt;Koog est pensé pour s'intégrer dans votre écosystème JVM avec le moins de friction possible :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Spring Boot&lt;/strong&gt; a son starter dédié, &lt;code&gt;koog-spring-boot-starter&lt;/code&gt;. Il permet d'auto-configurer des &lt;code&gt;PromptExecutor&lt;/code&gt; à partir de vos properties (&lt;code&gt;openAIExecutor&lt;/code&gt;, &lt;code&gt;anthropicExecutor&lt;/code&gt;, &lt;code&gt;googleExecutor&lt;/code&gt;, &lt;code&gt;ollamaExecutor&lt;/code&gt;, &lt;code&gt;multiLLMPromptExecutor&lt;/code&gt;...).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spring AI&lt;/strong&gt; bénéficie d'une intégration plus large, avec quatre starters indépendants : &lt;code&gt;koog-spring-ai-starter-model-chat&lt;/code&gt; (adapte un &lt;code&gt;ChatModel&lt;/code&gt; Spring AI en &lt;code&gt;LLMClient&lt;/code&gt; Koog), &lt;code&gt;-model-embedding&lt;/code&gt; (un &lt;code&gt;EmbeddingModel&lt;/code&gt; en &lt;code&gt;LLMEmbeddingProvider&lt;/code&gt;), &lt;code&gt;-chat-memory&lt;/code&gt; (un &lt;code&gt;ChatMemoryRepository&lt;/code&gt; en &lt;code&gt;ChatHistoryProvider&lt;/code&gt;) et &lt;code&gt;-vector-store&lt;/code&gt; (un &lt;code&gt;VectorStore&lt;/code&gt; en &lt;code&gt;KoogVectorStore&lt;/code&gt;). La répartition des rôles est claire : Spring AI couvre l'accès au modèle, la mémoire de chat et le stockage vectoriel pour le RAG, Koog ajoute par-dessus l'orchestration, les stratégies multi-étapes et la résilience. Un point à connaître : même quand le modèle passe par Spring AI, c'est Koog qui exécute les outils. Spring AI ne reçoit que les définitions et les schémas, avec &lt;code&gt;internalToolExecutionEnabled&lt;/code&gt; forcé à &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ktor&lt;/strong&gt; dispose également d'un plugin dédié, pour les backends qui préfèrent rester sur l'écosystème Kotlin natif plutôt que Spring.&lt;/li&gt;
&lt;li&gt;Côté fournisseurs LLM, la liste est large : OpenAI, Anthropic, Google, DeepSeek, Mistral, Alibaba, AWS Bedrock, Ollama pour les modèles locaux. Et on peut basculer une conversation vers un autre modèle en cours de route, avec un jeu d'outils différent, sans perdre l'historique.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;L'observabilité n'est pas en reste, puisque Koog s'appuie sur OpenTelemetry, avec des intégrations clefs en main pour Langfuse, W&amp;amp;B Weave et Datadog.&lt;/p&gt;

&lt;h2&gt;
  
  
  NB : Kotlin first, mais Java n'est pas en reste
&lt;/h2&gt;

&lt;p&gt;Deux points de vigilance avant de foncer tête baissée :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Koog reste un framework &lt;strong&gt;Kotlin-first&lt;/strong&gt;. Le support Java est arrivé en mars 2026, avec une API fluide en builder et l'accès aux fonctionnalités cœur. Cependant, les nouveautés continuent d'arriver côté Kotlin en premier. Si vous êtes en pur Java, vérifiez au cas par cas dans la documentation que la fonctionnalité qui vous intéresse est bien portée.&lt;/li&gt;
&lt;li&gt;Depuis la 1.0, Koog sépare explicitement ses modules en deux flux : &lt;strong&gt;stable&lt;/strong&gt;, sur lequel les APIs ne cassent pas sans cycle de dépréciation, et &lt;strong&gt;beta&lt;/strong&gt;, où elles peuvent changer. C'est plutôt une bonne nouvelle, mais ça veut aussi dire qu'une partie de ce qui rend Koog intéressant, GOAP en tête, est du côté beta. À arbitrer avant de tout miser dessus en production.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Koog coche une case rare : un framework agentique pensé pour la JVM, qui ne sacrifie ni l'ergonomie (DSL Kotlin, builders Java) ni la puissance (graphes d'états sur-mesure, GOAP, MCP, A2A), tout en s'intégrant proprement dans les stacks Spring Boot et Spring AI déjà en place. Si vous devez faire cohabiter des agents LLM avec un backend Java ou Kotlin existant plutôt que de monter une stack Python en parallèle, ça vaut clairement le détour.&lt;/p&gt;

&lt;p&gt;Son concurrent direct pour la JVM est &lt;a href="https://hub.embabel.com/" rel="noopener noreferrer"&gt;Embabel&lt;/a&gt;, que je vous conseille de suivre de près également !&lt;/p&gt;

&lt;p&gt;La documentation officielle est disponible sur &lt;a href="https://docs.koog.ai/" rel="noopener noreferrer"&gt;docs.koog.ai&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>koog</category>
      <category>kotlin</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>BreizhCamp2024 : à l'ouest toute !</title>
      <dc:creator>Ivan Béthus</dc:creator>
      <pubDate>Thu, 11 Jul 2024 14:15:27 +0000</pubDate>
      <link>https://dev.to/onepoint/breizhcamp2024-a-louest-toute--4mm2</link>
      <guid>https://dev.to/onepoint/breizhcamp2024-a-louest-toute--4mm2</guid>
      <description>&lt;p&gt;Nous sommes de nouveau sur la route avec quelques membres des équipes onepoint pour le rendez-vous breton des développeurs en tout genre : le BreizhCamp. &lt;br&gt;
Créé en 2011 à l’initiative du BreizhJUG, le BreizhCamp propose de faire se rencontrer les communautés du développement et de l’expertise, avec un contenu à la carte sur plus de 100 thèmes présentés. &lt;/p&gt;

&lt;p&gt;En plus des nombreux sujets présentés par nos collègues, nous avons préparé avec @dlucas un petit top 3 de nos conférences préférées. À vos lunettes, il y a de la bonne lecture !&lt;/p&gt;
&lt;h2&gt;
  
  
  Du code source à l'exécutable : plongée dans les entrailles de la compilation en Rust par &lt;a href="https://www.linkedin.com/in/sihaedouard/" rel="noopener noreferrer"&gt;Édouard Siha&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Comment le compilateur Rust fait-il pour assurer le respect de la notion d'emprunt ? Pourquoi est-il capable de générer facilement des binaires spécialisés pour une plateforme d'exécution différente de celle de la plateforme de compilation ? Quel genre d'optimisations surprenantes est-il capable de réaliser ? Quelles caractéristiques le différencie des compilateurs utilisés pour le C ? Pour le Java ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si ces questionnements vous intéressent, la conférence d'Édouard Siha est un incontournable. Il rentre en détail dans les étapes de la compilation en Rust, en faisant une analogie assez pédagogique avec les profondeurs marines. Un &lt;em&gt;deep dive&lt;/em&gt; très intéressant pour renforcer sa compréhension du Rust et de manière générale des différentes étapes de création d'un binaire exécutable.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/gjQlZuStWeQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  MongoDB en scale-up : comment sortir d’un enfer monolithique par &lt;a href="https://x.com/horgix" rel="noopener noreferrer"&gt;Alexis Chotard&lt;/a&gt; et &lt;a href="https://www.linkedin.com/in/caroline-becker-1396957/" rel="noopener noreferrer"&gt;Caroline Becker&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Ce talk, c'est l'histoire d'une scale-up spécialisée dans la gestion de fiches de paie : PayFit. Le 15 mars 2023, leur cluster MongoDB s'écroule, alors qu'il contient 95% des données utilisateur et il est vital au fonctionnement de l'application.&lt;/p&gt;

&lt;p&gt;A travers cette conférence, on découvre comment de mauvais choix d'architecture ou une croissance organique et (trop) rapide ont pu mener à une situation aussi critique. Heureusement, Alexis et Caroline nous expliquent également comment ils ont réussi à réparer leur application, entre stabilisation technique, détricotage du modèle de données, ou encore élimination de &lt;em&gt;single point of failure&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Si on ne doit retenir qu'une chose de ce retour d'expérience, c'est qu'un modèle de donnée doit coller au métier et que la duplication doit être maitrisée. Ici, le principal problème était lié à des données redondantes et stockées en grande quantité, qui ont fini par saturer la base NoSQL... &lt;/p&gt;

&lt;h2&gt;
  
  
  RetEx : Optimisation du temps de démarrage d'une application Java Spring par &lt;a href="https://www.linkedin.com/in/daria-hervieux/" rel="noopener noreferrer"&gt;Daria Hervieux&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Daria Hervieux nous explique comment elle et son équipe ont étudié plusieurs manières de réduire le temps de démarrage d'une application Spring pour atteindre un taux de disponibilité de l'application à 99,9%&lt;/p&gt;

&lt;p&gt;Elle nous livre donc les résultats des trois expérimentations effectuées :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Class Data Sharing (CDS) : cette technique permet de réduire le temps de démarrage et l'empreinte mémoire des JVM en mettant en cache les métadonnées de classes dans un fichier d'archive afin qu'elles puissent être rapidement préchargées dans une JVM nouvellement lancée.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Spring Ahead-of-Time (AOT) : sans aller jusqu'à la création d'image native, Daria nous explique qu'ils ont utilisé la technique de compilation AOT qui permet de pré-compiler le bytecode en code natif avant le démarrage de l'application. Le tout, s'exécutant sur une JVM traditionnelle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CRaC (Coordinated Restore at Checkpoint) : cette technique repose sur le principe d'effectuer un checkpoint de l'état de l'application à un moment donné, puis de le restaurer à partir de ce checkpoint lors du redémarrage de l'application. Cela permettant notamment d'avoir les hotspots de l'application déjà chargés en mémoire.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Daria conclut par un tableau comparatif en termes de gain, inconvénients, taille de livrable... Pas de spoil ! Nous vous laissons découvrir le résultat de son étude dans le replay (quand il sera disponible) !&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Git update-refs in a nutshell</title>
      <dc:creator>Ivan Béthus</dc:creator>
      <pubDate>Thu, 23 May 2024 17:26:37 +0000</pubDate>
      <link>https://dev.to/onepoint/git-update-refs-in-a-nutshell-574c</link>
      <guid>https://dev.to/onepoint/git-update-refs-in-a-nutshell-574c</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Original article on my &lt;a href="https://blog.hot-coffee.dev/blog/git_update_refs/" rel="noopener noreferrer"&gt;blog&lt;/a&gt; (🇫🇷)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When working on a versioned project, it is relatively common to end up with a "stack" of branches. What could be more frustrating than having to rebase all the other branches on top of the first one when updating it? This process becomes even more tedious when the number of branches is high or when they are regularly modified.&lt;/p&gt;

&lt;p&gt;Git version 2.38&lt;sup id="fnref1"&gt;1&lt;/sup&gt; introduces a solution to this problem: the &lt;code&gt;update-refs&lt;/code&gt; rebase option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack?
&lt;/h2&gt;

&lt;p&gt;Branch stacking is a way to break down important features, allowing for smaller pull requests. In the example below, three branches dependent on each other have been created, allowing "my feature" to be divided into three distinct blocks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The assumption here is that when each of these branches is individually merged into the &lt;code&gt;main&lt;/code&gt; branch, the code will still be functional, as it has been appropriately divided.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpiry3zxu4evdyso0lhec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpiry3zxu4evdyso0lhec.png" alt="initial state"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's say a small typo was made in the commit of the &lt;code&gt;my-feature-v1&lt;/code&gt; branch. A second commit needs to be added to fix the issue, resulting in the following history:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjqbz34lpnugl662flmi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjqbz34lpnugl662flmi.png" alt="after commit"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this situation, the only solution to update &lt;code&gt;my-feature-v2&lt;/code&gt; and &lt;code&gt;my-feature-v3&lt;/code&gt; is to checkout and rebase v2 on v1, then v3 on v2.&lt;/p&gt;

&lt;p&gt;This cumbersome process is remedied by the &lt;code&gt;update-refs&lt;/code&gt; rebase option.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  update-refs
&lt;/h3&gt;

&lt;p&gt;The goal of this option is to automatically update the &lt;em&gt;n&lt;/em&gt; branches on which the branch being rebased depends.&lt;/p&gt;

&lt;p&gt;Thus, in our case, we can simply checkout our &lt;code&gt;my-feature-v3&lt;/code&gt; branch and run the command &lt;code&gt;git rebase my-feature-v1 --update-refs&lt;/code&gt;. With this option, Git updates not only the v3 branch but also the v2 branch to preserve the history. The result of this operation is as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpopxq76ba40elbnxdfov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpopxq76ba40elbnxdfov.png" alt="after rebase update-refs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In practice:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84doy3uaerh4o9mgnb59.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84doy3uaerh4o9mgnb59.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the Remote Repository
&lt;/h3&gt;

&lt;p&gt;Even if the branches being manipulated have already been pushed to the remote repository, it is possible to update all of them in a single command: &lt;code&gt;git push --force-with-lease origin my-feature-v1 my-feature-v2 my-feature-v3&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here, a specific &lt;code&gt;force push&lt;/code&gt; is used to preserve the remote history&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Global Activation
&lt;/h3&gt;

&lt;p&gt;Why not always use the &lt;code&gt;update-refs&lt;/code&gt; option during a rebase? The Git team asked themselves the same question and decided to include this possibility in the configuration. Thus, &lt;code&gt;git config --global rebase.updateRefs true&lt;/code&gt; activates the option globally for each of your rebases.&lt;/p&gt;

&lt;h3&gt;
  
  
  In Summary
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git rebase {my-branch} --update-refs&lt;/code&gt; updates a branch and all its dependencies&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git push --force-with-lease origin my-branch-1 my-branch-2 my-branch-n&lt;/code&gt; pushes the update of these branches to the remote repository&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy &lt;em&gt;rebasing&lt;/em&gt;!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;The release note is available &lt;a href="https://github.blog/2022-10-03-highlights-from-git-2-38/#rebase-dependent-branches-with-update-refs" rel="noopener noreferrer"&gt;here&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;See the &lt;a href="https://delicious-insights.com/en/posts/git-push-with-lease/" rel="noopener noreferrer"&gt;use case&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>git</category>
      <category>rebase</category>
      <category>versioncontrol</category>
    </item>
  </channel>
</rss>
