Delen via


Azure OpenAI Assistants-clientbibliotheek voor JavaScript - versie 1.0.0-beta.5

De Azure OpenAI Assistants-clientbibliotheek voor JavaScript is een aanpassing van de REST API's van OpenAI die een idiomatische interface en uitgebreide integratie met de rest van het Azure SDK-ecosysteem biedt. Het kan verbinding maken met Azure OpenAI-resources of met het niet-Azure OpenAI-deductieeindpunt, waardoor het een uitstekende keuze is voor zelfs niet-Azure OpenAI-ontwikkeling.

Belangrijke koppelingen:

Aan de slag

Momenteel ondersteunde omgevingen

Vereisten

Als u een Azure OpenAI-resource wilt gebruiken, moet u een Azure-abonnement en Azure OpenAI-toegang hebben. Hiermee kunt u een Azure OpenAI-resource maken en zowel een verbindings-URL als API-sleutels ophalen. Zie Quickstart: Aan de slag met het genereren van tekst met behulp van Azure OpenAI Service voor meer informatie.

Als u de JS-clientbibliotheek van Azure OpenAI Assistants wilt gebruiken om verbinding te maken met niet-Azure OpenAI, hebt u een API-sleutel nodig van een ontwikkelaarsaccount op https://platform.openai.com/.

Installeer het pakket @azure/openai-assistants

Installeer de Azure OpenAI Assistants-clientbibliotheek voor JavaScript met npm:

npm install @azure/openai-assistants

Een maken en verifiëren AssistantsClient

Als u een client wilt configureren voor gebruik met Azure OpenAI, geeft u een geldige eindpunt-URI op voor een Azure OpenAI-resource, samen met een bijbehorende sleutelreferentie, tokenreferentie of Azure-identiteitsreferentie die is geautoriseerd voor het gebruik van de Azure OpenAI-resource. Als u in plaats daarvan de client wilt configureren om verbinding te maken met de service van OpenAI, geeft u een API-sleutel op vanuit de ontwikkelaarsportal van OpenAI.

Een API-sleutel van Azure gebruiken

Gebruik de Azure-portal om naar uw OpenAI-resource te bladeren en een API-sleutel op te halen, of gebruik het onderstaande Azure CLI-fragment :

Opmerking: Soms wordt de API-sleutel een 'abonnementssleutel' of 'abonnements-API-sleutel' genoemd.

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

Belangrijkste concepten

Zie de documentatie 'hoe assistenten werken' van OpenAI voor een overzicht van de concepten en relaties die worden gebruikt met assistenten. Dit overzicht volgt het overzichtsvoorbeeld van OpenAI om de basisbeginselen van het maken, uitvoeren en gebruiken van assistenten en threads te demonstreren.

Als u aan de slag wilt gaan, maakt u een AssistantsClient:

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

Met een client kan vervolgens een assistent worden gemaakt. Een assistent is een speciaal gebouwde interface voor OpenAI-modellen die Hulpprogramma's kunnen aanroepen terwijl instructies op hoog niveau mogelijk zijn gedurende de levensduur van de assistent.

De code voor het maken van een assistent:

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" }]
});

Een gesprekssessie tussen een assistent en een gebruiker wordt een thread genoemd. Threads slaan Berichten op en verwerken automatisch afkapping om inhoud in de context van een model te passen.

Een thread maken:

const assistantThread = await assistantsClient.createThread();

Bericht vertegenwoordigt een bericht dat is gemaakt door een assistent of een gebruiker. Berichten kunnen tekst, afbeeldingen en andere bestanden bevatten. Berichten worden opgeslagen als een lijst in de thread. Als er een thread is gemaakt, kunnen er berichten op worden gemaakt:

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

Een Run vertegenwoordigt een aanroep van een assistent op een thread. De Assistent gebruikt de configuratie en berichten van de thread om taken uit te voeren door modellen en hulpprogramma's aan te roepen. Als onderdeel van een Uitvoering voegt de Assistent Berichten toe aan de thread. Er kan vervolgens een uitvoering worden gestart die de thread evalueert op een assistent:

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

Zodra de uitvoering is gestart, moet deze worden polled totdat deze een terminalstatus bereikt:

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

Ervan uitgaande dat de uitvoering is voltooid, bevat het weergeven van berichten van de thread die is uitgevoerd nu nieuwe informatie die is toegevoegd door de assistent:

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);
    }
  }
}

Voorbeelduitvoer van deze reeks:

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?

Werken met bestanden voor ophalen

Bestanden kunnen worden geüpload en vervolgens worden verwezen door assistenten of berichten. Gebruik eerst de gegeneraliseerde upload-API met als doel 'assistenten' om een bestands-id beschikbaar te maken:

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 });

Na het uploaden kan de bestands-id worden opgegeven aan een assistent bij het maken. Houd er rekening mee dat bestands-id's alleen worden gebruikt als een geschikt hulpprogramma, zoals Code Interpreter of Ophalen, is ingeschakeld.

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 ]
});

Als een bestandskoppelings-id is gekoppeld en een ondersteund hulpprogramma is ingeschakeld, kunnen de assistent vervolgens de bijbehorende gegevens gebruiken bij het uitvoeren van threads.

Functiehulpprogramma's en parallelle functie-aanroepen gebruiken

Zoals beschreven in de openAI-documentatie voor assistent hulpprogramma's, kunnen hulpprogramma's die verwijzen naar door de oproeper gedefinieerde mogelijkheden als functies, worden geleverd aan een assistent zodat deze dynamisch kan worden opgelost en ondubbelzinnig kan worden uitgevoerd tijdens een uitvoering.

Hier ziet u een eenvoudige assistent die 'weet hoe dat moet', via functies van de aanroeper:

  1. De favoriete stad van de gebruiker ophalen
  2. Een bijnaam voor een bepaalde stad krijgen
  3. Het actuele weer ophalen, eventueel met een temperatuureenheid, in een stad

Om dit te doen, definieert u eerst de functies die u wilt gebruiken. De daadwerkelijke implementaties hier zijn slechts representatieve stubs.

// 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"]
    }
  }
};

Nu de functies zijn gedefinieerd in de juiste hulpprogramma's, kan er een assistent worden gemaakt waarvoor deze hulpprogramma's zijn ingeschakeld:

  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]
});

Als de assistent hulpprogramma's aanroept, moet de aanroepende code exemplaren omzetten ToolCall in overeenkomende ToolOutputSubmission exemplaren. Voor het gemak wordt hier een eenvoudig voorbeeld opgehaald:

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;
};

Als u gebruikersinvoer wilt verwerken zoals 'hoe is het weer op dit moment in mijn favoriete stad?', moet het peilen van het antwoord voor voltooiing worden aangevuld met een RunStatus controle RequiresAction op of, in dit geval, de aanwezigheid van de RequiredAction eigenschap op de run. Vervolgens moet de verzameling van ToolOutputSubmissions worden verzonden naar de uitvoering via de SubmitRunToolOutputs methode, zodat de uitvoering kan worden voortgezet:

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")

Houd er rekening mee dat bij het gebruik van ondersteunde modellen de assistent kan vragen om verschillende functies parallel aan te roepen. Oudere modellen kunnen slechts één functie tegelijk aanroepen.

Zodra alle benodigde functieaanroepen zijn opgelost, wordt de uitvoering normaal uitgevoerd en bevatten de voltooide berichten op de thread modeluitvoer, aangevuld met de opgegeven uitvoer van het functiehulpprogramma.

Problemen oplossen

Logboekregistratie

Het inschakelen van logboekregistratie kan helpen bij het ontdekken van nuttige informatie over fouten. Als u een logboek met HTTP-aanvragen en -antwoorden wilt zien, stelt u de AZURE_LOG_LEVEL omgevingsvariabele in op info. U kunt logboekregistratie ook tijdens runtime inschakelen door aan te roepen setLogLevel in de @azure/logger:

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

setLogLevel("info");

Voor meer gedetailleerde instructies over het inschakelen van logboeken kunt u de @azure-/loggerpakketdocumenten bekijken.