LeRobot documentation

Инструменты

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Инструменты

LeRobot поддерживает вызовы инструментов в политиках — сообщения ассистента могут формировать структурированные вызовы, например say(text="OK, starting now"), которые рантайм направляет в реальную реализацию (TTS, контроллер, логгер, …).

На этой странице рассматриваются:

  1. Место расположения каталога инструментов.
  2. Как конвейер аннотации формирует атомы вызовов инструментов.
  3. Как добавить собственный инструмент.

Где объявляются инструменты

Два слоя.

Каталог — список схем функций в стиле OpenAI — находится в meta/info.json["tools"] каждого набора данных. Пример:

{
  "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"]
        }
      }
    }
  ]
}

Прочитайте его через доступ к метаданным набора данных:

from lerobot.datasets.dataset_metadata import LeRobotDatasetMetadata

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

Если в файле info.json набора данных не объявлены инструменты, meta.tools возвращает DEFAULT_TOOLS из lerobot.datasets.language — на данный момент это список из одного элемента с канонической схемой say. Таким образом, наборы данных без аннотаций и потребители шаблонов чата продолжают работать без какой-либо конфигурации:

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

Реализации — исполняемый Python — будут находиться в src/lerobot/tools/, по одному файлу на инструмент. Диспетчер времени выполнения и каноническая реализация say (обёртка над pocket-tts от Kyutai) не входят в описанный здесь слой каталога; на данный момент этот слой содержит только хранилище схемы и константу DEFAULT_TOOLS по умолчанию.

Вызовы инструментов построчно

Каталог выше описывает то, что можно назвать. Фактический вызов — имя функции и значения аргументов — хранится построчно, в атомах ассистента в language_events:

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

Рецепты вставляют их в отрендеренные сообщения через 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,
      }

Целевым значением для обучения модели является один ход ассистента, содержащий как текст плана и вызов инструмента say. На этапе инференса рантайм парсит сгенерированный текст обратно в структурированные tool_calls и направляет их в соответствующую реализацию.

Как добавить собственный инструмент

Примечание: Шаги 2 и 3 ниже описывают слой времени выполнения (src/lerobot/tools/, протокол Tool, TOOL_REGISTRY, get_tools(meta)), который не входит в слой каталога, поставляемый на данный момент, — эти модули пока не существуют в дереве. Одного шага 1 достаточно, чтобы сделать инструмент видимым для шаблона чата через meta.tools, что позволяет модели научиться генерировать вызов; для выполнения вызова на этапе инференса требуется слой времени выполнения.

Три шага. Конкретный пример: инструмент record_observation, который политика может вызвать для получения дополнительного наблюдения вне обычного цикла управления.

Шаг 1 — объявление схемы

Добавьте запись в meta/info.json["tools"], отредактировав файл напрямую на диске до запуска конвейера аннотации (она будет сохранена).

{
  "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"]
        }
      }
    }
  ]
}

Схема точно следует конвенции вызова функций OpenAI, поэтому шаблон чата может рендерить её нативно.

Шаг 2 — реализация вызова

Создайте 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"

Размещение каждого инструмента в отдельном файле изолирует зависимости: record_observation может тянуть за собой pillow, а say — pocket-tts. Пользователи, устанавливающие только необходимые инструменты, избегают тяжёлых транзитивных зависимостей.

Шаг 3 — зарегистрируйте его

Добавьте в src/lerobot/tools/registry.py:

from .record_observation import RecordObservationTool

TOOL_REGISTRY["record_observation"] = RecordObservationTool

Всё. Во время выполнения get_tools(meta) находит каждую схему в meta.tools, создаёт экземпляр соответствующего зарегистрированного класса и возвращает словарь «имя → экземпляр», по которому диспетчер может маршрутизировать вызовы.

Если вы хотите использовать инструмент без написания реализации (например, только для форматирования шаблона чата во время обучения), достаточно выполнить только шаг 1 — модель всё равно научится генерировать вызов. Шаги 2 и 3 необходимы только для фактического выполнения вызова на этапе инференса.

Update on GitHub