LeRobot documentation

Outils

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Outils

LeRobot prend en charge les appels d’outils dans les politiques — les messages de l’assistant peuvent émettre des invocations structurées comme say(text="OK, starting now") que le runtime achemine vers une implémentation réelle (TTS, contrôleur, journal, …).

Cette page couvre :

  1. L’emplacement du catalogue d’outils.
  2. Comment le pipeline d'annotation produit des atomes d'appel d'outils.
  3. Comment ajouter votre propre outil.

Lieu de déclaration des outils

Deux couches.

Le catalogue — une liste de schémas de fonctions au format OpenAI — se trouve dans meta/info.json["tools"] de chaque jeu de données. Exemple :

{
  "features": { "...": "..." },
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "say",
        "description": "Speak a short utterance to the user via the TTS executor.",
        "parameters": {
          "type": "object",
          "properties": {
            "text": {
              "type": "string",
              "description": "The verbatim text to speak."
            }
          },
          "required": ["text"]
        }
      }
    }
  ]
}

Lisez-le via l'accesseur de métadonnées du jeu de données :

from lerobot.datasets.dataset_metadata import LeRobotDatasetMetadata

meta = LeRobotDatasetMetadata(repo_id="pepijn/super_poulain_final_annotations")
tools = meta.tools     # list[dict] — OpenAI tool schemas

Si le fichier info.json du jeu de données ne déclare aucun outil, meta.tools renvoie DEFAULT_TOOLS depuis lerobot.datasets.language — actuellement une liste à une seule entrée contenant le schéma canonique say. Ainsi, les jeux de données non annotés et les consommateurs de modèles de discussion continuent de fonctionner sans aucune configuration :

prompt_str = tokenizer.apply_chat_template(
    sample["messages"],
    tools=meta.tools,                 # works either way
    add_generation_prompt=False,
    tokenize=False,
)

Les implémentations — du Python exécutable — seront placées sous src/lerobot/tools/, un fichier par outil. Le dispatcheur d’exécution et l’implémentation canonique de say (qui encapsule pocket-tts de Kyutai) ne font pas partie de la couche de catalogue décrite ici ; à l’heure actuelle, cette couche ne fournit que le stockage du schéma et la constante de repli DEFAULT_TOOLS.

Invocations d'outils par ligne

Le catalogue ci-dessus décrit ce qui peut être appelé. L'appel réel — le nom de la fonction ainsi que les valeurs des arguments — est stocké par ligne, sur les atomes assistant dans language_events :

{
  "role": "assistant",
  "content": null,
  "style": null,
  "timestamp": 12.4,
  "camera": null,
  "tool_calls": [
    { "type": "function",
      "function": { "name": "say", "arguments": { "text": "On it." } } }
  ]
}

Les recettes intègrent ces éléments dans les messages rendus via tool_calls_from :

user_interjection_response:
  bindings:
    speech: "emitted_at(t, role=assistant, tool_name=say)"
  messages:
    - { role: user, content: "${task}", stream: high_level }
    - {
        role: assistant,
        content: "${current_plan}",
        stream: high_level,
        target: true,
        tool_calls_from: speech,
      }

La cible d’entraînement du modèle est un tour d’assistant qui contient à la fois le texte du plan et l’appel d’outil say. Lors de l’inférence, le runtime analyse le texte généré pour le reconvertir en tool_calls structurés et les achemine vers l’implémentation correspondante.

Comment ajouter votre propre outil

Remarque : Les étapes 2 et 3 ci-dessous décrivent la couche d'exécution (src/lerobot/tools/, le protocole Tool, TOOL_REGISTRY, get_tools(meta)) qui ne fait pas partie de la couche de catalogue livrée aujourd'hui — ces modules n'existent pas encore dans l'arborescence. L'étape 1 seule suffit pour rendre l'outil visible par le modèle de chat via meta.tools afin que le modèle puisse apprendre à générer l'appel ; l'exécution de l'appel lors de l'inférence nécessite la couche d'exécution.

Trois étapes. Exemple concret : un outil record_observation que la politique peut appeler pour capturer une observation supplémentaire en dehors de la boucle de contrôle régulière.

Étape 1 — déclarer le schéma

Ajoutez une entrée sous meta/info.json["tools"] en modifiant le fichier directement sur le disque avant d’exécuter le pipeline d’annotation (elle sera conservée).

{
  "tools": [
    { "type": "function", "function": { "name": "say", "...": "..." } },
    {
      "type": "function",
      "function": {
        "name": "record_observation",
        "description": "Capture a high-resolution still image for the user.",
        "parameters": {
          "type": "object",
          "properties": {
            "label": {
              "type": "string",
              "description": "Short label for the saved image."
            }
          },
          "required": ["label"]
        }
      }
    }
  ]
}

Le schéma suit exactement la convention d’appel de fonctions d’OpenAI, de sorte que le modèle de conversation peut le rendre nativement.

Étape 2 — implémenter l'appel

Créer src/lerobot/tools/record_observation.py :

from .base import Tool
from typing import Any

RECORD_OBSERVATION_SCHEMA: dict[str, Any] = { "...": "..." }   # mirrors the JSON above


class RecordObservationTool:
    name = "record_observation"
    schema = RECORD_OBSERVATION_SCHEMA

    def __init__(self, schema: dict | None = None, output_dir: str = "."):
        self.output_dir = output_dir

    def call(self, arguments: dict) -> str:
        label = arguments["label"]
        # ... save the latest camera frame to <output_dir>/<label>.png ...
        return f"saved {label}.png"

Un fichier par outil permet d’isoler les dépendances — record_observation peut exiger pillow, tandis que say exige pocket-tts. Les utilisateurs qui n’installent que les outils dont ils ont besoin évitent ainsi les dépendances transitives lourdes.

Étape 3 — l'enregistrer

Ajouter à src/lerobot/tools/registry.py :

from .record_observation import RecordObservationTool

TOOL_REGISTRY["record_observation"] = RecordObservationTool

C’est tout. À l’exécution, get_tools(meta) recherche chaque schéma dans meta.tools, instancie la classe enregistrée correspondante et renvoie un dictionnaire nom → instance dans lequel le dispatcher peut acheminer les appels.

Si vous souhaitez utiliser un outil sans écrire d’implémentation (par exemple uniquement pour le formatage du chat-template lors de l’entraînement), l’étape 1 suffit — le modèle apprend toujours à générer l’appel. Les étapes 2 et 3 ne sont nécessaires que pour réellement exécuter l’appel lors de l’inférence.

Update on GitHub