Черновики

Глава 2.2: Руководство по инструкциям

В этом документе объясняются ключевые концепции и механизмы системы инструкций, показанные на примерах. Мы расскажем, как обрабатываются переключения контекста, как инструкции можно составлять подобно макросам, и как данные передаются между шагами.

Переключение контекста с помощью сред выполнения

Понимание суффиксов контекста

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

  • Базовое имя (например, IdentifyParticipants): Выполняется в контексте LLM по умолчанию
  • Суффикс _Activity (например, FetchAvailability_Activity): Выполняется на сервере
  • Суффикс _User (например, ConfirmInvitation_User): Требует взаимодействия с пользователем

Эти суффиксы служат наглядными сигналами в коде, показывая, где будет происходить выполнение, и помогают системе направлять операции в соответствующую среду.

// Операция LLM (по умолчанию)
const participants = IdentifyParticipants(prompt);

// Операция LLM для подготовки параметров
const availabilityParams = FetchAvailability(participants);

// Операция на сервере
const availabilityData = FetchAvailability_Activity(availabilityParams);

// Взаимодействие с пользователем
const approval = ConfirmInvitation_User(invitation);

Контейнеры контекста

В плоском представлении мы явно группируем операции по их контексту выполнения:

Process(
  // Операции LLM
  LLM_Context({
    participants: IdentifyParticipants(prompt),
    availabilityParams: FetchAvailability({ participants }),
  }),

  // Операции на сервере
  Server_Context({
    availabilityData: FetchAvailability_Activity({ availabilityParams }),
  })

  // Другие контексты...
);

Такая структура создает четкое разделение задач, гарантируя, что операции выполняются в своих средах, при этом сохраняя поток данных между ними.

Композиция инструкций и макросы

Инструкции можно комбинировать как миксины, когда одна инструкция «оборачивает» или расширяет другую. Это достигается с помощью композиции JSON Schema.

Слияние схем

Когда инструкции комбинируются, их схемы сливаются в соответствии с семантикой allOf из JSON Schema. Это сохраняет структуру и требования обеих схем, объединяя их в единый, целостный интерфейс.

Ключевая идея в том, что JSON Schema сохраняет порядок свойств, что и позволяет реализовать поведение, похожее на миксины:

{
  "properties": {
    "_considerations": { "type": "string" },
    "default": true, // Это заполнитель, который будет заменен
    "_feedback": { "type": "string" }
  }
}

Когда эта схема объединяется с другой, свойство default действует как слот, который заменяется свойствами другой схемы. Это создает шаблон-обертку, где миксин может вставлять свои свойства до и после свойств оборачиваемой схемы.

Создание инструкций-миксинов

Introspect_Mixin демонстрирует этот шаблон:

{
  "title": "Introspection_Mixin",
  "properties": {
    "_considerations": {
      "type": "string",
      "description": "Перед выполнением действия проанализируйте запрос и выделите ключевые моменты."
    },
    "default": true, // Заполнитель для оборачиваемой схемы
    "_feedback": {
      "type": "string",
      "description": "После завершения действия предоставьте обратную связь о принятых решениях."
    }
  }
}

При применении к другой инструкции, он добавляет когнитивные шаги до и после основной задачи:

Introspect_Mixin({
  default: {
    identifyParticipants: IdentifyParticipants(prompt),
    fetchAvailability: FetchAvailability({ participants }),
  },
});

Такая композиция создает новую схему, которая направляет LLM:

  1. Обдумать важные моменты перед действием
  2. Выполнить основные операции
  3. Проанализировать результаты после выполнения

Поток данных между инструкциями

Неявная передача параметров

Инструкции могут неявно передавать данные между шагами через свои описания и понимание контекста моделью LLM. Это показано в примерах, где информация об участниках передается от identifyParticipants к fetchAvailability.

fetchAvailability: {
  organizerEmail: 'alice@example.com', // Повторно используется из identifyParticipants
  attendeeEmail: 'bob@example.com',    // Повторно используется из identifyParticipants
  timeRange: { /* ... */ }
}

Описание в схеме явно указывает на повторное использование данных. Фактическая структура схемы использует allOf для объединения ссылки на базовую схему с дополнительными инструкциями:

"fetchAvailability": {
  "allOf": [
    { "$ref": "aug:processes/schedule-meeting:1#fetchAvailability" },
    { "description": "Получает данные о доступности в календаре для определенных участников, повторно используя их email из шага идентификации для проверки расписаний" }
  ]
}

Этот шаблон позволяет нам:

  1. Ссылаться на базовую функциональность и структуру из определения процесса
  2. Расширять ее контекстными инструкциями для конкретного случая использования
  3. Направлять LLM, как повторно использовать данные между шагами, не требуя явного объявления параметров

Явные ссылки

Для более сложных зависимостей инструкции могут использовать явные ссылки, чтобы объявить, от каких предыдущих шагов они зависят:

"findCommonSlot": {
  "references": [
    "LLM_1.identifyParticipants",
    "SERVER_1.fetchAvailabilityOutput"
  ]
}

Эти ссылки служат нескольким целям:

  1. Они четко документируют зависимости данных
  2. Они помогают LLM понять, какие данные использовать
  3. Они помогают системе убедиться, что данные, на которые есть ссылки, доступны в нужный момент

Создание экземпляра и выполнение процесса

Прототипы процессов

Процессы определяются как «вайбы» (vibes) — многоразовые прототипы, на основе которых можно создавать экземпляры:

aug:processes/schedule-meeting:1

Эти прототипы определяют полную структуру процесса, включая все шаги, контексты и зависимости данных.

Запуск процесса

Экземпляр процесса создается, когда «сосуд» (vessel) завершает свой первый шаг:

StartProcess({
  name: 'ScheduleMeeting',
  LLM_1: {
    // Данные первого шага...
  },
});

Это создает новый экземпляр процесса, который будет хранить свое состояние на протяжении всего жизненного цикла.

Продолжение процесса

После запуска процесс автоматически продолжается по определенным шагам. Каждый шаг имеет доступ к данным, необходимым ему от предыдущих шагов. «Сосуд» (vessel) переносит состояние процесса, обеспечивая непрерывность при переключении контекстов.

Рекомендации по разработке инструкций

  1. Используйте понятные соглашения об именах для переключения контекста (базовое имя, _Activity, _User)
  2. Проектируйте модульные инструкции, которые можно комбинировать и повторно использовать
  3. Используйте описания для управления потоком данных между шагами
  4. Явно документируйте ссылки для сложных зависимостей
  5. Создавайте макроинструкции для общих шаблонов, таких как интроспекция, валидация или обработка ошибок
  6. Начинайте с минимальной точки входа, необходимой для запуска процесса

Следуя этим практикам, вы сможете создавать инструкции, которые будут одновременно мощными и гибкими. Это позволит реализовывать сложные рабочие процессы, охватывающие несколько сред выполнения, при этом сохраняя четкий поток данных и зависимости.