> ## Content Index
> Fetch the complete content index at: https://www.sfeir.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Donner un corps à un agent IA : quand un LLM commence à interagir avec le monde réel
- URL: https://www.sfeir.dev/donner-un-corps-a-un-agent-ia-quand-un-llm-commence-a-interagir-avec-le-monde-reel/
- Published: 2026-09-02T14:38:39.000Z
- Updated: 2026-09-02T14:38:39.000Z
- Description: On nous avait promis Skynet, nous avons eu la fenêtre de contexte. Et si on donnait enfin un corps aux LLM ? Premier objectif : faire clignoter une LED.
- Author: Jean-Edouard Reuglewicz
- Tags: agents IA, Journal du Hard, JournalduHard, arduino

Vous les voyez partout.

Il devient presque impossible d’ouvrir LinkedIn sans tomber sur un nouvel article annonçant la prochaine révolution : les agents IA sont arrivés, les LLM ont changé la donne, et l’intelligence artificielle serait sur le point de transformer profondément notre manière de travailler.

En parallèle, un autre domaine connaît un regain d’intérêt spectaculaire : la [robotique](https://www.sfeir.dev/ia/walt-disney-100ans-ia-vs-humain/). Les entreprises spécialisées dans les [robots humanoïdes](https://www.sfeir.dev/le-journal-du-hardware-nao-le-petit-prince-de-la-robotique/) multiplient les démonstrations et promettent déjà un futur où des robots domestiques pourraient assister les humains dans leur quotidien.

Un futur qui réveille deux imaginaires opposés.

D’un côté, le rêve des robots assistants d’Isaac Asimov, capables d’aider l’humanité et de vivre à nos côtés.

De l’autre, la crainte du soulèvement des machines, popularisée par Terminator et son fameux Skynet.

Mais pour l’instant, force est de constater que les robots humanoïdes ne sont pas encore dans nos salons, et que les machines n’ont pas remplacé les humains.

La grande révolution annoncée ressemble parfois davantage à une révolution logicielle qu’à une invasion de robots.

Aujourd’hui, [les usages les plus répandus des IA génératives](https://www.sfeir.dev/tag/ia-generative/) sont encore des [outils](https://www.sfeir.dev/ia/quest-ce-que-le-sdlc-definition-phases-et-metamorphose-a-lere-de-lia/) à demander une recette de cookies, résumer des documents ou accélérer la production de code.

Comme le résume avec humour une formule attribuée à Peter Thiel :

> « On nous avait promis Skynet, nous avons eu la fenêtre de contexte. »

Et même si les formes de vie carbonées que nous sommes n’ont toujours pas eu à défendre leur survie face aux nouvelles formes de vie issues du silicium, il n’est peut-être pas trop tard pour préparer l’avenir.  
Après tout, chaque grande révolution commence par une première expérimentation.  
Alors commençons modestement : donnons à un agent IA la capacité d’interagir physiquement avec le monde.  
Pas de bras robotisé complexe. Pas de robot humanoïde autonome. Pas encore.  
Simplement une carte Arduino, une LED, un port USB et un [LLM](https://www.sfeir.dev/llm-vs-modele-fondation-quelles-differences-dans-lunivers-de-lia-generative/).

Un premier pas vers des agents capables non seulement de réfléchir, mais aussi d’agir.

Comme le colibri de la fable de Pierre Rabhi:

> « Je fais ma part. »

---

# Le principe : un agent IA qui contrôle une LED

L’idée est volontairement simple.

Une carte [Arduino](https://www.sfeir.dev/le-journal-du-hardware-arduino-faire-du-hard-naura-jamais-ete-aussi-easy/) est connectée à l’ordinateur via un port USB.

Une interface en ligne de commande permet ensuite de communiquer avec un agent basé sur un LLM.

Selon la demande de l’utilisateur, l’agent décide d’une action et utilise un outil (`tool`) pour envoyer une commande à l’Arduino.

La LED devient alors une forme primitive de sortie physique.

Trois comportements sont possibles :

- une réponse positive déclenche un clignotement ;
- une réponse négative déclenche deux clignotements ;
- un résultat numérique déclenche autant de clignotements que la valeur obtenue.

```
Question : 2 + 2

Réponse de l’agent :
NUMBER:4

Action physique :
La LED clignote 4 fois.
```

Ce montage est évidemment très limité, mais il contient déjà les éléments fondamentaux d’un système agentique :

1. un modèle capable de raisonner ;
2. des outils permettant d’agir ;
3. un environnement extérieur avec lequel interagir.

Le montage est extrêmement simple:

![](https://storage.ghost.io/c/0b/31/0b31478e-a66a-46f1-8c34-d44388e21192/content/images/2026/08/image-5.png)

arduino blink led

# Architecture du projet

La structure du projet est volontairement simple :

```
Main Function
│
├── prompt.py
├── tools.py
└── requirements.txt
```

Le fichier `requirements.txt` contient les dépendances nécessaires :

- `pyserial` pour communiquer avec l’Arduino ;
- [langchain](https://www.sfeir.dev/ia/kesaco-langchain/) pour créer l’agent ;
- `langchain-google-genai` pour utiliser Gemini ;
- `python-dotenv` pour charger les variables d’environnement ;
- `pydantic` pour structurer les données.

---

# Donner une mission à l’agent avec un prompt

Avant de pouvoir agir, l’agent doit savoir ce qu’on attend de lui.

Le [prompt](https://www.sfeir.dev/ia/comment-bien-prompter-une-ia-4-strategies-dexperts-en-genai/) dans prompt.py est:

```python
PROMPT = """
    You are an Arduino interaction assistant.
    You control an Arduino connected through a serial port.
    Your job:
    1. For yes/no questions:
       - Determine the answer.
       - If the answer is YES, call the arduino_tool with:
            command="YES"
       - If the answer is NO, call the arduino_tool with:
            command="NO"
    2. For mathematical expressions:
       - Calculate the result.
       - If the result is a positive integer between 1 and 20,
         call the arduino_tool with:
            command="NUMBER:<result>"
    3. Never explain the answer before sending the Arduino command.
       Always use the Arduino tool when a physical output is requested.
    Examples:
    User:
    "Is Paris the capital of France?"
    Reasoning:
    The answer is YES.
    Tool call:
    arduino_tool(command="YES")
    User:
    "Is 10 greater than 100?"
    Reasoning:
    The answer is NO.
    Tool call:
    arduino_tool(command="NO")
    User:
    "What is 2+2?"
    Reasoning:
    Result is 4.
    Tool call:
    arduino_tool(command="NUMBER:4")
    If the calculation result is too large or not an integer,
    explain that it cannot be represented by blinking.
    """
```

Le point important ici est que le LLM ne contrôle pas directement l’Arduino. Il ne manipule pas le port USB.  
Il prend simplement une décision et appelle un outil capable d’effectuer l’action.  
C’est exactement le principe d’un agent : un modèle de raisonnement auquel on donne des capacités.

---

# Les tools : donner des mains à l’agent

Un agent sans outil reste limité à du texte. [Les tools](https://www.sfeir.dev/ia/skills-vs-tools-la-difference-fondamentale-dans-un-agent-ia/) sont ce qui lui permet d’interagir avec le monde.  
Dans notre cas, il n’existe qu’un seul outil :

```python
 from langchain.tools import tool
import serial
import time

SERIAL_PORT = "/dev/cu.usbserial-14110" #change it for your own serial port 
BAUD_RATE = 9600

def get_serial():
    return serial.Serial(
        SERIAL_PORT,
        BAUD_RATE,
        timeout=2
    )

@tool
def arduino_tool(command: str) -> dict:
    """
    Send a command to an Arduino.
    Commands:
    YES
    NO
    NUMBER:x
    Example:
    arduino_tool("YES")
    arduino_tool("NUMBER:4")
    """

    try:
        ser = get_serial()
        time.sleep(2)  # wait for Arduino reset
        message = command.strip().upper()
        ser.write((message + "\n").encode())
        ser.close()
        return {"success": True,"command_sent": message}
    except Exception as e:
        return {"success": False,"error": str(e)}
```

Le fonctionnement est simple :

1. l’agent choisit une commande ;
2. LangChain appelle le tool ;
3. le tool ouvre une connexion série ;
4. l’Arduino reçoit une instruction.

L’agent vient de gagner une capacité physique.

---

# Création de l’agent avec Gemini

Le modèle utilisé ici est [Gemini](https://www.sfeir.dev/ia/definition-gemini/) :

```python
from dotenv import load_dotenv
from pydantic import BaseModel

from langchain.agents import create_agent
from langchain_google_genai import ChatGoogleGenerativeAI

from tools import arduino_tool
from prompt import PROMPT

def pick_action(query: str):
    query = (query)
    response = ask_agent(query)
    print(response)

# --------------------------------------------------
# Environment
# --------------------------------------------------

load_dotenv()

# --------------------------------------------------
# Structured Output
# --------------------------------------------------

class ArduinoCommand(BaseModel):
    command: str

# --------------------------------------------------
# Model
# --------------------------------------------------

llm = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash",
)

# --------------------------------------------------
# Agent
# --------------------------------------------------

agent = create_agent(
    model=llm,
    tools=[arduino_tool],
    system_prompt=PROMPT,
)

# --------------------------------------------------
# Agent runner
# --------------------------------------------------

def ask_agent(question: str):
    response = agent.invoke(
        {
            "messages": [
                {
                    "role": "user",
                    "content": question,
                }
            ]
        }
    )
    return response

if __name__ == "__main__":
    print("what is your request ?")
    query = input()
    pick_action(query.lower())
```

L’agent possède maintenant :

- un cerveau : le LLM ;
- une mission : le prompt système ;
- une capacité d’action : `arduino_tool`.

Enfin, il faut également flasher le code arduino sur la carte:

```c
const int LED_PIN = 13;

void blinkLED(int count)
{
  for(int i = 0; i < count; i++)
  {
    digitalWrite(LED_PIN, HIGH);
    delay(300);

    digitalWrite(LED_PIN, LOW);
    delay(300);
  }
}

void setup()
{
  pinMode(
    LED_PIN,
    OUTPUT
  );
  Serial.begin(9600);
}

void loop()
{
  if(Serial.available())
  {
    String command = Serial.readStringUntil('\n');
    command.trim();
    if(command == "YES")
    {
      blinkLED(1);
    }
    else if(command == "NO")
    {
      blinkLED(2);
    }
    else if(command.startsWith("NUMBER:"))
    {
      String value =
        command.substring(7);
      int number =
        value.toInt();
      if(number > 0 && number <= 20)
      {
        blinkLED(number);
      }
    }
  }
}
```

L’Arduino ne connaît rien du LLM.  
Il ne sait pas ce qu’est Gemini, LangChain ou un agent.  
Il reçoit simplement des commandes et les transforme en actions physiques.

---

# Premier test : l’agent agit réellement

Lancement du programme :

```bash
what is your request ?
2+2
{'messages': [HumanMessage(content='2+2', additional_kwargs={}, response_metadata={}, id='2e75dcfb-806c-4be0-b875-0dc1d5cb4c8a'), AIMessage(content='', additional_kwargs={'function_call': {'name': 'arduino_tool', 'arguments': '{"command": "NUMBER:4"}'}, '__gemini_function_call_thought_signatures__': {'166332b6-702f-476a-8214-31b61b76ae39': 'Ct8BARFNMg+WqOIMZnjH33KfIHZcZy9RDexMsvA3Yu6aAe5PMROWJzwWQEnsiFQczULnN4bLr4M1lIQiWiWkGsGO5aVrnNsUsCaSinZAPQD0eUw8QnyQLuLQAjbbgUsZ0VpE2WcoVX6U0Y11DPmlgHJzrm8dUdLMuAh0vP2NqlJQaiPTcD0R632K3PTmIiGCMoHddobbpPzl+ZN1EBR7B/v+3FRKcwUj1p74SkqpfbCsvxn/nXSiLrpszRNHQUIqlOSEztzDZ2Zl9g0XiCgSVFFy7kbSFXNyzXvhStQM+uboYg=='}}, response_metadata={'finish_reason': 'STOP', 'model_name': 'gemini-2.5-flash', 'safety_ratings': [], 'model_provider': 'google_genai'}, id='lc_run--019fd705-1b42-77b2-9c33-55355c832743-0', tool_calls=[{'name': 'arduino_tool', 'args': {'command': 'NUMBER:4'}, 'id': '166332b6-702f-476a-8214-31b61b76ae39', 'type': 'tool_call'}], invalid_tool_calls=[], usage_metadata={'input_tokens': 405, 'output_tokens': 75, 'total_tokens': 480, 'input_token_details': {'cache_read': 0}, 'output_token_details': {'reasoning': 58}}), ToolMessage(content='{"success": true, "command_sent": "NUMBER:4"}', name='arduino_tool', id='7f59680c-f04f-4f75-8c85-b8884f268700', tool_call_id='166332b6-702f-476a-8214-31b61b76ae39'), AIMessage(content='', additional_kwargs={}, response_metadata={'finish_reason': 'STOP', 'model_name': 'gemini-2.5-flash', 'safety_ratings': [], 'model_provider': 'google_genai'}, id='lc_run--019fd705-67ee-7bf3-9a3b-a6d833cb46a7-0', tool_calls=[], invalid_tool_calls=[], usage_metadata={'input_tokens': 446, 'output_tokens': 0, 'total_tokens': 446, 'input_token_details': {'cache_read': 0}})]}

```

Le tool transmet cette commande à l’Arduino.

Résultat :  
La LED clignote quatre fois.  
Pour la première fois, une décision prise par un modèle de langage produit une conséquence physique dans le monde réel.

---

# Un premier pas vers des agents incarnés

Soyons réalistes : ce montage est très loin d’un robot autonome capable de naviguer dans une maison ou de prendre des décisions complexes.  
Nous sommes encore très loin de Skynet.  
Mais il illustre une idée fondamentale : la prochaine étape des agents IA ne sera probablement pas uniquement de mieux répondre à des questions.  
Ce sera leur capacité à agir.  
Un LLM connecté à des outils devient capable d’utiliser des APIs, manipuler des fichiers, contrôler des logiciels… et potentiellement interagir avec des objets physiques.

Aujourd’hui, une LED. Demain, peut-être un capteur, un moteur, un robot. Le soulèvement des machines peut attendre.  
Pour l’instant, la machine apprend simplement à allumer une lumière.  
Et c’est déjà un début.  
Le terminator est encore loin, mais il s'agit d'un premier pas pour permettre à un agent d'interagir physiquement avec le monde extérieur.