Поделиться через


Клиентская библиотека Помощников Azure OpenAI для JavaScript версии 1.0.0-beta.5

Клиентская библиотека Помощников Azure OpenAI для JavaScript — это адаптация REST API OpenAI, которая обеспечивает идиоматический интерфейс и расширенную интеграцию с остальной частью экосистемы пакета SDK Azure. Он может подключаться к ресурсам Azure OpenAI или к конечной точке вывода OpenAI, отличной от Azure, что делает его отличным выбором даже для разработки OpenAI, отличной от Azure.

Основные ссылки:

Начало работы

Поддерживаемые в настоящее время среды

Предварительные требования

Если вы хотите использовать ресурс Azure OpenAI, у вас должна быть подписка Azure и доступ к Azure OpenAI. Это позволит создать ресурс Azure OpenAI и получить URL-адрес подключения, а также ключи API. Дополнительные сведения см. в статье Краткое руководство. Начало создания текста с помощью Службы Azure OpenAI.

Если вы хотите использовать клиентскую библиотеку JS Помощников Azure OpenAI для подключения к OpenAI, отличному от Azure, вам потребуется ключ API из учетной записи разработчика по адресу https://platform.openai.com/.

Установите пакет @azure/openai-assistants.

Установите клиентскую библиотеку Помощников Azure OpenAI для JavaScript с помощью npm:

npm install @azure/openai-assistants

Создание и проверка подлинности AssistantsClient

Чтобы настроить клиент для использования с Azure OpenAI, укажите допустимый URI конечной точки для ресурса Azure OpenAI вместе с соответствующими учетными данными ключа, учетными данными маркера или учетными данными удостоверений Azure, авторизованными для использования ресурса Azure OpenAI. Чтобы вместо этого настроить клиент для подключения к службе OpenAI, укажите ключ API на портале разработчика OpenAI.

Использование ключа API из Azure

Используйте портал Azure , чтобы перейти к ресурсу OpenAI и получить ключ API, или используйте приведенный ниже фрагмент кода Azure CLI :

Примечание: Иногда ключ API называется ключом подписки или ключом API подписки.

az cognitiveservices account keys list --resource-group <your-resource-group-name> --name <your-resource-name>

Основные понятия

Общие сведения о концепциях и связях, используемых с помощниками, см. в документации OpenAI по принципу работы помощников . Этот обзор внимательно соответствует примеру с обзором OpenAI , чтобы продемонстрировать основы создания, запуска и использования помощников и потоков.

Чтобы приступить к работе, создайте :AssistantsClient

const assistantsClient = new AssistantsClient("<endpoint>", new AzureKeyCredential("<azure_api_key>"));

С помощью клиента можно создать помощник. Помощник — это специализированный интерфейс для моделей OpenAI, который может вызывать средства, предоставляя при этом инструкции высокого уровня на протяжении всего времени существования помощник.

Код для создания помощник:

const assistant = await assistantsClient.createAssistant({
  model: "gpt-4-1106-preview",
  name: "JS Math Tutor",
  instructions: "You are a personal math tutor. Write and run code to answer math questions.",
  tools: [{ type: "code_interpreter" }]
});

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

Чтобы создать поток, выполните приведенные далее действия.

const assistantThread = await assistantsClient.createThread();

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

const question = "I need to solve the equation '3x + 11 = 14'. Can you help me?";
const messageResponse = await assistantsClient.createMessage(assistantThread.id, "user", question);

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

let runResponse = await assistantsClient.createRun(assistantThread.id, {
   assistantId: assistant.id,
   instructions: "Please address the user as Jane Doe. The user has a premium account." 
});

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

do {
  await new Promise((resolve) => setTimeout(resolve, 800));
  runResponse = await assistantsClient.getRun(assistantThread.id, runResponse.id);
} while (runResponse.status === "queued" || runResponse.status === "in_progress")

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

const runMessages = await assistantsClient.listMessages(assistantThread.id);
for (const runMessageDatum of runMessages.data) {
  for (const item of runMessageDatum.content) {
    if (item.type === "text") {
      console.log(item.text.value);
    } else if (item.type === "image_file") {
      console.log(item.imageFile.fileId);
    }
  }
}

Пример выходных данных из этой последовательности:

2023-11-14 20:21:23 -  assistant: The solution to the equation \(3x + 11 = 14\) is \(x = 1\).
2023-11-14 20:21:18 -       user: I need to solve the equation `3x + 11 = 14`. Can you help me?

Работа с файлами для извлечения

На файлы можно отправлять, а затем ссылаться помощники или сообщения. Во-первых, используйте универсальный API отправки с целью "помощников", чтобы сделать идентификатор файла доступным:

const filename = "<path_to_text_file>";
await fs.writeFile(filename, "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457.", "utf8");
const uint8array = await fs.readFile(filename);
const uploadAssistantFile = await assistantsClient.uploadFile(uint8array, "assistants", { filename });

После отправки идентификатор файла можно предоставить помощник после создания. Обратите внимание, что идентификаторы файлов будут использоваться только в том случае, если включено соответствующее средство, например Интерпретатор кода или Извлечение.

const fileAssistant = await assistantsClient.createAssistant({
  model: "gpt-4-1106-preview",
  name: "JS SDK Test Assistant - Retrieval",
  instructions: "You are a helpful assistant that can help fetch data from files you know about.",
  tools: [{ type: "retrieval" }],
  fileIds: [ uploadAssistantFile.id ]
});

Если сопоставление идентификатора файла и включено поддерживаемое средство, помощник сможет использовать связанные данные при выполнении потоков.

Использование средств функций и параллельных вызовов функций

Как описано в документации OpenAI для средств помощник, средства, которые ссылаются на возможности, определяемые вызывающим абонентом, как функции, можно предоставить помощник, чтобы позволить ему динамически разрешать и устранять неоднозначности во время выполнения.

Здесь приведен простой помощник, который "знает, как" с помощью функций, предоставляемых вызывающим:

  1. Получение избранного города пользователя
  2. Получение псевдонима для заданного города
  3. Получение текущей погоды (при необходимости с единицей температуры) в городе

Для этого начните с определения используемых функций. Фактические реализации здесь являются лишь репрезентативными заглушками.

// Example of a function that defines no parameters
const getFavoriteCity = () => "Atlanta, GA";
const getUserFavoriteCityTool = { 
  type: "function",
  function: {
    name: "getUserFavoriteCity",
    description: "Gets the user's favorite city.",
    parameters: {
      type: "object",
      properties: {}
    }
  }
}; 

// Example of a function with a single required parameter
const getCityNickname = (city) => { 
  switch (city) { 
    case "Atlanta, GA": 
      return "The ATL"; 
    case "Seattle, WA": 
      return "The Emerald City"; 
    case "Los Angeles, CA":
      return "LA"; 
    default: 
      return "Unknown"; 
  }
};

const getCityNicknameTool = { 
  type: "function",
  function: {
    name: "getCityNickname",
    description: "Gets the nickname for a city, e.g. 'LA' for 'Los Angeles, CA'.",
    parameters: { 
      type: "object",
      properties: { 
        city: {
          type: "string",
          description: "The city and state, e.g. San Francisco, CA"
        } 
      }
    }
  }
};

// Example of a function with one required and one optional, enum parameter
const getWeatherAtLocation = (location, temperatureUnit = "f") => {
  switch (location) { 
    case "Atlanta, GA": 
      return temperatureUnit === "f" ? "84f" : "26c"; 
    case "Seattle, WA": 
      return temperatureUnit === "f" ? "70f" : "21c"; 
    case "Los Angeles, CA":
      return temperatureUnit === "f" ? "90f" : "28c"; 
    default: 
      return "Unknown"; 
  }
};

const getWeatherAtLocationTool = { 
  type: "function",
  function: {
    name: "getWeatherAtLocation",
    description: "Gets the current weather at a provided location.",
    parameters: { 
      type: "object",
      properties: { 
        location: {
          type: "string",
          description: "The city and state, e.g. San Francisco, CA"
        },
        temperatureUnit: {
          type: "string",
          enum: ["f", "c"],
        }
      },
      required: ["location"]
    }
  }
};

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

  const weatherAssistant = await assistantsClient.createAssistant({
  // note: parallel function calling is only supported with newer models like gpt-4-1106-preview
  model: "gpt-4-1106-preview",
  name: "JS SDK Test Assistant - Weather",
  instructions: `You are a weather bot. Use the provided functions to help answer questions.
    Customize your responses to the user's preferences as much as possible and use friendly
    nicknames for cities whenever possible.
  `,
  tools: [getUserFavoriteCityTool, getCityNicknameTool, getWeatherAtLocationTool]
});

Если помощник вызывает средства, вызывающий код должен разрешить ToolCall экземпляры в совпадающие ToolOutputSubmission экземпляры. Для удобства здесь извлекается базовый пример:

const getResolvedToolOutput = (toolCall) => {
  const toolOutput = { toolCallId: toolCall.id };

  if (toolCall["function"]) {
    const functionCall = toolCall["function"];
    const functionName = functionCall.name;
    const functionArgs = JSON.parse(functionCall["arguments"] ?? {});

    switch (functionName) {
      case "getUserFavoriteCity":
        toolOutput.output = getFavoriteCity();
        break;
      case "getCityNickname":
        toolOutput.output = getCityNickname(functionArgs["city"]);
        break;
      case "getWeatherAtLocation":
        toolOutput.output = getWeatherAtLocation(functionArgs.location, functionArgs.temperatureUnit);
        break;
      default:
        toolOutput.output = `Unknown function: ${functionName}`;
        break;
    }
  }
  return toolOutput;
};

Для обработки входных данных пользователя, таких как "Какая погода сейчас в моем любимом городе?", опрос ответа на завершение должен быть дополнен RunStatus проверка для RequiresAction или, в данном случае, наличие RequiredAction свойства в запуске. Затем коллекция должна быть отправлена ToolOutputSubmissions в запуск с помощью SubmitRunToolOutputs метода , чтобы выполнение можно было продолжить:

const question = "What's the weather like right now in my favorite city?";
let runResponse = await assistantsClient.createThreadAndRun({ 
  assistantId: weatherAssistant.id, 
  thread: { messages: [{ role: "user", content: question }] },
  tools: [getUserFavoriteCityTool, getCityNicknameTool, getWeatherAtLocationTool]
});

do {
  await new Promise((resolve) => setTimeout(resolve, 500));
  runResponse = await assistantsClient.getRun(runResponse.threadId, runResponse.id);
  
  if (runResponse.status === "requires_action" && runResponse.requiredAction.type === "submit_tool_outputs") {
    const toolOutputs = [];

    for (const toolCall of runResponse.requiredAction.submitToolOutputs.toolCalls) {
      toolOutputs.push(getResolvedToolOutput(toolCall));
    }
    runResponse = await assistantsClient.submitToolOutputsToRun(runResponse.threadId, runResponse.id, toolOutputs);
  }
} while (runResponse.status === "queued" || runResponse.status === "in_progress")

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

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

Устранение неполадок

Ведение журнала

Включение ведения журнала может помочь выявить полезные сведения о сбоях. Чтобы просмотреть журнал HTTP-запросов и ответов, задайте для переменной среды AZURE_LOG_LEVEL значение info. Кроме того, ведение журнала можно включить во время выполнения, вызвав setLogLevel в @azure/logger:

const { setLogLevel } = require("@azure/logger");

setLogLevel("info");

Более подробные инструкции по включению журналов см. в документации по пакету @azure и средства ведения журнала.