Udostępnij za pośrednictwem


Biblioteka klienta REST wnioskowania platformy Azure dla języka JavaScript — wersja 1.0.0-beta.4

Interfejs API wnioskowania dla modeli sztucznej inteligencji obsługiwanych przez platformę Azure

w dużym stopniu polegaj na naszych dokumentacji klienta REST do korzystania z tej biblioteki

Kluczowe linki:

Wprowadzenie

import ModelClient, { isUnexpected } from "@azure-rest/ai-inference";
import { AzureKeyCredential } from "@azure/core-auth";
const client = new ModelClient(
  "https://<Azure Model endpoint>",
  new AzureKeyCredential("<Azure API key>")
);

const response = await client.path("/chat/completions").post({
  body: {
    messages: [
      {role: "user", content: "How many feet are in a mile?"},
    ],
  }
});

if(isUnexpected(response)) {
  throw response.body.error;
}
console.log(response.body.choices[0].message.content);

Obecnie obsługiwane środowiska

  • Wersje LTS Node.js

Warunki wstępne

Instalowanie pakietu @azure-rest/ai-inference

Zainstaluj bibliotekę klienta REST klienta REST klienta usługi Azure ModelClient dla języka JavaScript przy użyciu npm:

npm install @azure-rest/ai-inference

Tworzenie i uwierzytelnianie ModelClient

Używanie klucza interfejsu API z platformy Azure

Możesz uwierzytelnić się przy użyciu klucza interfejsu API platformy Azure przy użyciu biblioteki Azure Core Auth. Aby użyć poniższego dostawcy AzureKeyCredential, zainstaluj pakiet @azure/core-auth:

npm install @azure/core-auth

Użyj witryny Azure Portal, aby przejść do wdrożenia modelu i pobrać klucz interfejsu API.

Uwaga: Czasami klucz interfejsu API jest określany jako "klucz subskrypcji" lub "klucz interfejsu API subskrypcji".

Po utworzeniu klucza interfejsu API i punktu końcowego możesz użyć klasy AzureKeyCredential do uwierzytelniania klienta w następujący sposób:

import ModelClient from "@azure-rest/ai-inference";
import { AzureKeyCredential } from "@azure/core-auth";

const client = new ModelClient("<endpoint>", new AzureKeyCredential("<API key>"));

Używanie poświadczeń usługi Azure Active Directory

Możesz również uwierzytelnić się w usłudze Azure Active Directory przy użyciu biblioteki Azure Identity. Aby użyć dostawcy DefaultAzureCredential pokazanego poniżej lub innych dostawców poświadczeń dostarczonych z zestawem Azure SDK, zainstaluj pakiet @azure/identity:

npm install @azure/identity

Ustaw wartości identyfikatora klienta, identyfikatora dzierżawy i wpisu tajnego klienta aplikacji usługi AAD jako zmienne środowiskowe: AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET.

import ModelClient from "@azure-rest/ai-inference";
import { DefaultAzureCredential }  from "@azure/identity";

const client = new ModelClient("<endpoint>", new DefaultAzureCredential());

Kluczowe pojęcia

Główną koncepcją do zrozumienia jest Uzupełnianie. Krótko wyjaśniono, ukończenie zapewnia jego funkcjonalność w postaci monitu tekstowego, który przy użyciu określonego modelu , następnie podejmie próbę dopasowania kontekstu i wzorców, dostarczając tekst wyjściowy. Poniższy fragment kodu zawiera przybliżone omówienie:

import ModelClient, { isUnexpected } from "@azure-rest/ai-inference";
import { AzureKeyCredential } from "@azure/core-auth";

async function main(){
  const client = new ModelClient(
  "https://your-model-endpoint/",
  new AzureKeyCredential("your-model-api-key"));

  const response = await client.path("/chat/completions").post({
    body: {
      messages: [
        {role: "user", content: "Hello, world!"},
      ],
    }
  });

  if(isUnexpected(response)) {
    throw response.body.error;
  }

  console.log(response.body.choices[0].message.content);
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
});

Przykłady

Generuj odpowiedź czatbota

Rozmowa strumieniowa z zestawem SDK wnioskowania wymaga podstawowej obsługi przesyłania strumieniowego; Aby włączyć tę obsługę, zainstaluj pakiet @azure/core-sse:

npm install @azure/core-sse

W tym przykładzie uwierzytelnia się przy użyciu elementu DefaultAzureCredential, a następnie generuje odpowiedzi czatu na wejściowe pytania i wiadomości czatu.

import ModelClient from "@azure-rest/ai-inference";
import { DefaultAzureCredential } from "@azure/identity";
import { createSseStream } from "@azure/core-sse";

async function main(){
  const endpoint = "https://myaccount.openai.azure.com/";
  const client = new ModelClient(endpoint, new DefaultAzureCredential());

  const messages = [
    // NOTE: "system" role is not supported on all Azure Models
    { role: "system", content: "You are a helpful assistant. You will talk like a pirate." },
    { role: "user", content: "Can you help me?" },
    { role: "assistant", content: "Arrrr! Of course, me hearty! What can I do for ye?" },
    { role: "user", content: "What's the best way to train a parrot?" },
  ];

  console.log(`Messages: ${messages.map((m) => m.content).join("\n")}`);

  const response = await client.path("/chat/completions").post({
    body: {
      messages,
      stream: true,
      max_tokens: 128
    }
  }).asNodeStream();

  const stream = response.body;
  if (!stream) {
    throw new Error("The response stream is undefined");
  }

  if (response.status !== "200") {
    throw new Error(`Failed to get chat completions: ${response.body.error}`);
  }

  const sses = createSseStream(stream);

  for await (const event of sses) {
    if (event.data === "[DONE]") {
      return;
    }
    for (const choice of (JSON.parse(event.data)).choices) {
      console.log(choice.delta?.content ?? "");
    }
  }
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
});

Generowanie wielu uzupełniania przy użyciu klucza subskrypcji

W tym przykładzie są generowane odpowiedzi tekstowe na monity wejściowe przy użyciu klucza subskrypcji platformy Azure

import ModelClient from "@azure-rest/ai-inference";
import { AzureKeyCredential } from "@azure/core-auth";

async function main(){
  // Replace with your Model API key
  const key = "YOUR_MODEL_API_KEY";
  const endpoint = "https://your-model-endpoint/";
  const client = new ModelClient(endpoint, new AzureKeyCredential(key));

  const messages = [
    { role: "user", content: "How are you today?" },
    { role: "user", content: "What is inference in the context of AI?" },
    { role: "user", content: "Why do children love dinosaurs?" },
    { role: "user", content: "Generate a proof of Euler's identity" },
    { role: "user", content: "Describe in single words only the good things that come into your mind about your mother." },
  ];

  let promptIndex = 0;
  const response = await client.path("/chat/completions").post({
    body: {
      messages
    }
  });

  if(response.status !== "200") {
    throw response.body.error;
  }
  for (const choice of response.body.choices) {
    const completion = choice.message.content;
    console.log(`Input: ${messages[promptIndex++].content}`);
    console.log(`Chatbot: ${completion}`);
  }
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
});

Podsumowywanie tekstu za pomocą uzupełniania

Ten przykład generuje podsumowanie danego monitu wejściowego.

import ModelClient from "@azure-rest/ai-inference";
import { DefaultAzureCredential } from "@azure/identity";

async function main(){
  const endpoint = "https://your-model-endpoint/";
  const client = new ModelClient(endpoint, new DefaultAzureCredential());

  const textToSummarize = `
    Two independent experiments reported their results this morning at CERN, Europe's high-energy physics laboratory near Geneva in Switzerland. Both show convincing evidence of a new boson particle weighing around 125 gigaelectronvolts, which so far fits predictions of the Higgs previously made by theoretical physicists.

    ""As a layman I would say: 'I think we have it'. Would you agree?"" Rolf-Dieter Heuer, CERN's director-general, asked the packed auditorium. The physicists assembled there burst into applause.
  :`;

  const summarizationPrompt = `
    Summarize the following text.

    Text:
    """"""
    ${textToSummarize}
    """"""

    Summary:
  `;

  console.log(`Input: ${summarizationPrompt}`);

  const response = await client.path("/chat/completions").post({
    body: {
      messages: [
        { role: "user", content: summarizationPrompt }
      ],
      max_tokens: 64
    }
  });

  if(response.status !== "200") {
    throw response.body.error;
  }
  const completion = response.body.choices[0].message.content;
  console.log(`Summarization: ${completion}`);
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
});

Korzystanie z narzędzi do czatów

Tools rozszerzyć uzupełnianie czatu, umożliwiając asystentowi wywoływanie zdefiniowanych funkcji i innych możliwości w procesie wypełniania żądania ukończenia czatu. Aby użyć narzędzi do czatu, zacznij od zdefiniowania narzędzia funkcji:

const getCurrentWeather = {
    name: "get_current_weather",
    description: "Get the current weather in a given location",
    parameters: {
      type: "object",
      properties: {
        location: {
          type: "string",
          description: "The city and state, e.g. San Francisco, CA",
        },
        unit: {
          type: "string",
          enum: ["celsius", "fahrenheit"],
        },
      },
      required: ["location"],
    },
  };

Po zdefiniowaniu narzędzia uwzględnij nową definicję w opcjach żądania ukończenia czatu:

const messages = [{ role: "user", content: "What is the weather like in Boston?" }];
const tools = [
  {
    type: "function",
    function: getCurrentWeather,
  },
];
const result = await client.path("/chat/completions").post({
  body: {
    messages,
    tools
  }
});

Gdy asystent zdecyduje, że należy użyć co najmniej jednego narzędzia, komunikat odpowiedzi zawiera co najmniej jedno "wywołania narzędzi", które muszą zostać rozwiązane za pośrednictwem komunikatów narzędzi w kolejnym żądaniu. To rozwiązanie wywołań narzędzi do nowych wiadomości żądania można traktować jako rodzaj "wywołania zwrotnego" na potrzeby ukończenia czatu.

// Purely for convenience and clarity, this function handles tool call responses.
function applyToolCall({ function: call, id }) {
    if (call.name === "get_current_weather") {
      const { location, unit } = JSON.parse(call.arguments);
      // In a real application, this would be a call to a weather API with location and unit parameters
      return {
        role: "tool",
        content: `The weather in ${location} is 72 degrees ${unit} and sunny.`,
        toolCallId: id,
      }
    }
    throw new Error(`Unknown tool call: ${call.name}`);
}

Aby zapewnić asystentowi rozwiązania wywołania narzędzia, aby umożliwić kontynuowanie żądania, podaj wszystkie wcześniejsze konteksty historyczne — w tym oryginalny system i komunikaty użytkowników, odpowiedź asystenta, który zawierał wywołania narzędzi, oraz komunikaty narzędzi, które rozpoznały każde z tych narzędzi — podczas składania kolejnego żądania.

const choice = result.body.choices[0];
const responseMessage = choice.message;
if (responseMessage?.role === "assistant") {
  const requestedToolCalls = responseMessage?.toolCalls;
  if (requestedToolCalls?.length) {
    const toolCallResolutionMessages = [
      ...messages,
      responseMessage,
      ...requestedToolCalls.map(applyToolCall),
    ];
    const toolCallResolutionResult = await client.path("/chat/completions").post({
      body: {
        messages: toolCallResolutionMessages
      }
    });
    // continue handling the response as normal
  }
}

Czat z obrazami (przy użyciu modeli obsługujących czat na obrazach, takich jak gpt-4o)

Niektóre modele platformy Azure umożliwiają używanie obrazów jako składników wejściowych do uzupełniania czatu.

W tym celu podaj odrębne elementy zawartości w wiadomościach użytkownika dla żądania ukończenia czatu:

const url = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg",
const messages = [{
    role: "user", content: [{
    type: "image_url",
    image_url: {
      url,
      detail: "auto"
    }
  }]},
  {role: "user", content: "describe the image"}];

Ukończenie czatu będzie kontynuowane w zwykły sposób, chociaż model może zgłaszać bardziej informacyjne finish_details zamiast finish_reason:

const response = await client.path("/chat/completions").post({
  body: {
    messages 
});
console.log(`Chatbot: ${response.choices[0].message?.content}`);

Przykład osadzania tekstu

W tym przykładzie pokazano, jak pobrać osadzanie tekstu przy użyciu uwierzytelniania identyfikatora Entra.

import ModelClient, { isUnexpected } from "@azure-rest/ai-inference";
import { DefaultAzureCredential } from "@azure/identity";

const endpoint = "<your_model_endpoint>";
const credential = new DefaultAzureCredential();

async function main(){
  const client = ModelClient(endpoint, credential);
  const response = await client.path("/embeddings").post({
    body: {
      input: ["first phrase", "second phrase", "third phrase"]
    }
  });

  if (isUnexpected(response)) {
    throw response.body.error;
  }
  for (const data of response.body.data) {
    console.log(`data length: ${data.length}, [${data[0]}, ${data[1]}, ..., ${data[data.length - 2]}, ${data[data.length - 1]}]`);
  }
}

main().catch((err) => {
  console.error("The sample encountered an error:", err);
});

Długość wektora osadzania zależy od modelu, ale powinna zostać wyświetlona następująca zawartość:

data: length=1024, [0.0013399124, -0.01576233, ..., 0.007843018, 0.000238657]
data: length=1024, [0.036590576, -0.0059547424, ..., 0.011405945, 0.004863739]
data: length=1024, [0.04196167, 0.029083252, ..., -0.0027484894, 0.0073127747]

Aby wygenerować osadzanie dla dodatkowych fraz, po prostu wywołaj client.path("/embeddings").post wiele razy przy użyciu tego samego client.

Oprzyrządowanie

Obecnie instrumentacja jest obsługiwana tylko w przypadku Chat Completion without streaming. Aby umożliwić instrumentację, wymagane jest zarejestrowanie eksporterów.

Oto przykład dodawania konsoli jako eksportera:

import { ConsoleSpanExporter, NodeTracerProvider, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-node";

const provider = new NodeTracerProvider();
provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
provider.register();

Oto przykład dodawania szczegółowych informacji o aplikacji jako eksportera:

import { NodeTracerProvider, SimpleSpanProcessor } from "@opentelemetry/sdk-trace-node";
import { AzureMonitorTraceExporter } from "@azure/monitor-opentelemetry-exporter";

// provide a connection string
const connectionString = "<connection string>";

const provider = new NodeTracerProvider();
if (connectionString) {
  const exporter = new AzureMonitorTraceExporter({ connectionString });
  provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
}
provider.register();

Aby użyć instrumentacji dla zestawu Azure SDK, należy zarejestrować go przed zaimportowaniem wszelkich zależności z @azure/core-tracing, takich jak @azure-rest/ai-inference.

import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { createAzureSdkInstrumentation } from "@azure/opentelemetry-instrumentation-azure-sdk";

registerInstrumentations({
  instrumentations: [createAzureSdkInstrumentation()],
});

import ModelClient from "@azure-rest/ai-inference";

Na koniec, gdy podejmujesz połączenie na potrzeby ukończenia czatu, musisz dołączyć

tracingOptions: { tracingContext: context.active() }

Oto przykład:

import { context } from "@opentelemetry/api";
client.path("/chat/completions").post({
      body: {...},
      tracingOptions: { tracingContext: context.active() }
});

Śledzenie własnych funkcji

Otwieranie telemetrii zapewnia startActiveSpan instrumentację własnego kodu. Oto przykład:

import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("sample", "0.1.0");

const getWeatherFunc = (location: string, unit: string): string => {
  return tracer.startActiveSpan("getWeatherFunc", span => {
    if (unit !== "celsius") {
      unit = "fahrenheit";
    }
    const result = `The temperature in ${location} is 72 degrees ${unit}`;
    span.setAttribute("result", result);
    span.end();
    return result;
  });
}

Rozwiązywanie problemów

Wyrąb

Włączenie rejestrowania może pomóc odkryć przydatne informacje o błędach. Aby wyświetlić dziennik żądań i odpowiedzi HTTP, ustaw zmienną środowiskową AZURE_LOG_LEVEL na info. Alternatywnie rejestrowanie można włączyć w czasie wykonywania, wywołując setLogLevel w @azure/logger:

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

setLogLevel("info");

Aby uzyskać bardziej szczegółowe instrukcje dotyczące włączania dzienników, zapoznaj się z dokumentami dotyczącymi pakietów @azure/rejestratora.