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

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

Варианты использования вызова инструментов обычно делятся на несколько тем:

Предоставление LLM доступа к информации, с которой он не был обучен

  • Часто меняющаяся информация, например ежедневное меню ресторана или состояние запасов в магазине.
  • Информация, относящаяся к вашему домену приложения, например информация о продукте.

Обратите внимание на совпадение с генерацией с расширенным поиском (RAG), которая также позволяет LLM интегрировать фактическую информацию в свои генерации. RAG — более тяжелое решение, которое лучше всего подходит, когда у вас есть большой объем информации или когда информация, наиболее релевантная для подсказки, неоднозначна. С другой стороны, если получение информации, необходимой LLM, представляет собой простой вызов функции или поиск в базе данных, более подходящим будет вызов инструмента.

Введение степени детерминизма в рабочий процесс LLM

  • Выполнение вычислений, которые LLM не может выполнить самостоятельно.
  • Принуждение LLM генерировать дословный текст при определенных обстоятельствах, например, при ответе на вопрос об условиях обслуживания приложения.

Выполнение действия по инициативе LLM

  • Включение и выключение света в домашнем помощнике на базе LLM
  • Резервирование столиков в ресторанном агенте на базе LLM

Прежде чем начать

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

На этой странице обсуждается одна из расширенных функций абстракции модели Genkit и функции генерации(), поэтому, прежде чем углубляться в нее, вам следует ознакомиться с содержимым страницы «Генерация контента с помощью моделей ИИ» . Вы также должны быть знакомы с системой Genkit для определения схем ввода и вывода, которая обсуждается на странице «Потоки» .

Обзор вызова инструментов

На высоком уровне вот как выглядит типичное взаимодействие вызова инструмента с LLM:

  1. Вызывающее приложение отправляет LLM запрос, а также включает в запрос список инструментов, которые LLM может использовать для генерации ответа.
  2. LLM либо генерирует полный ответ, либо генерирует запрос на вызов инструмента в определенном формате.
  3. Если вызывающий абонент получает полный ответ, запрос выполняется и взаимодействие завершается; но если вызывающий объект получает вызов инструмента, он выполняет любую подходящую логику и отправляет новый запрос в LLM, содержащий исходное приглашение или его вариант, а также результат вызова инструмента.
  4. LLM обрабатывает новое приглашение, как на шаге 2.

Чтобы это работало, необходимо выполнить несколько требований:

  • Модель должна быть обучена отправлять запросы к инструментам, когда необходимо выполнить запрос. Большинство более крупных моделей, предоставляемых через веб-API, таких как Gemini и Claude, могут это сделать, но меньшие и более специализированные модели часто не могут. Genkit выдаст ошибку, если вы попытаетесь предоставить инструменты модели, которая ее не поддерживает.
  • Вызывающее приложение должно предоставить модели определения инструментов в ожидаемом формате.
  • Вызывающее приложение должно предложить модели сгенерировать запросы вызова инструмента в формате, ожидаемом приложением.

Вызов инструмента с помощью Genkit

Genkit предоставляет единый интерфейс для вызова инструментов с моделями, которые его поддерживают. Каждый плагин модели гарантирует соблюдение последних двух из вышеперечисленных критериев, а generate() автоматически выполняет цикл вызова инструмента, описанный ранее.

Поддержка модели

Поддержка вызова инструментов зависит от модели, API модели и плагина Genkit. Обратитесь к соответствующей документации, чтобы определить, будет ли поддерживаться вызов инструментов. Кроме того:

  • Genkit выдаст ошибку, если вы попытаетесь предоставить инструменты модели, которая ее не поддерживает.
  • Если плагин экспортирует ссылки на модели, свойство info.supports.tools укажет, поддерживает ли он вызов инструментов.

Определение инструментов

Используйте функцию defineTool() для записи определений инструментов:

const specialToolInputSchema = z.object({ meal: z.enum(["breakfast", "lunch", "dinner"]) });
const specialTool = defineTool(
  {
    name: "specialTool",
    description: "Retrieves today's special for the given meal",
    inputSchema: specialToolInputSchema,
    outputSchema: z.string(),
  },
  async ({ meal }): Promise<string> => {
    // Retrieve up-to-date information and return it. Here, we just return a
    // fixed value.
    return "Baked beans on toast";
  }
);

Синтаксис здесь выглядит так же, как синтаксис defineFlow() ; однако все четыре параметра name , description , inputSchema и outputSchema являются обязательными. При написании определения инструмента обратите особое внимание на формулировку и описательность этих параметров, поскольку они жизненно важны для LLM, чтобы эффективно использовать доступные инструменты.

Включение инструментов с вашими подсказками

После того, как вы определили свои инструменты, укажите их в параметре инструментов метода generate() :

const llmResponse = await generate({
  model: gemini15Flash,
  prompt,
  tools: [specialTool],
});

Вы можете сделать доступными несколько инструментов; LLM вызовет инструменты по мере необходимости для выполнения запроса.

Явная обработка вызовов инструментов

По умолчанию Genkit неоднократно вызывает LLM, пока каждый вызов инструмента не будет разрешен. Если вам нужен больший контроль над этим циклом вызова инструмента, например, для применения более сложной логики, установите для параметра returnToolRequests значение true . Теперь вы обязаны обеспечить выполнение всех запросов инструментов:

let generateOptions: GenerateOptions = {
  model: gemini15Flash,
  prompt,
  tools: [specialTool],
  returnToolRequests: true,
};
let llmResponse;
while (true) {
  llmResponse = await generate(generateOptions);
  const toolRequests = llmResponse.toolRequests();
  if (toolRequests.length < 1) {
    break;
  }
  const toolResponses: ToolResponsePart[] = await Promise.all(
    toolRequests.map(async (part) => {
      switch (part.toolRequest.name) {
        case "specialTool":
          return {
            toolResponse: {
              name: part.toolRequest.name,
              ref: part.toolRequest.ref,
              output: await specialTool(specialToolInputSchema.parse(part.toolRequest?.input)),
            },
          };
        default:
          throw Error('Tool not found');
        }
      }));
    generateOptions.history = llmResponse.toHistory();
    generateOptions.prompt = toolResponses;
}