Partilhar via


Biblioteca de cliente REST do Azure Inference para JavaScript - versão 1.0.0-beta.4

API de inferência para modelos de IA suportados pelo Azure

Por favor, confie muito em nossos documentos de cliente REST para usar esta biblioteca

Ligações principais:

Primeiros passos

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

Ambientes atualmente suportados

  • Versões LTS do Node.js

Pré-requisitos

  • Você deve ter um de assinatura do Azure para usar este pacote.

Instalar o pacote @azure-rest/ai-inference

Instale a biblioteca de cliente REST do cliente REST do Azure ModelClient para JavaScript com npm:

npm install @azure-rest/ai-inference

Criar e autenticar um ModelClient

Usando uma chave de API do Azure

Você pode autenticar com uma chave de API do Azure usando a biblioteca Azure Core Auth. Para usar o provedor AzureKeyCredential mostrado abaixo, instale o pacote @azure/core-auth:

npm install @azure/core-auth

Use o do Portal do Azure para navegar até a implantação do Modelo e recuperar uma chave de API.

Nota: Às vezes, a chave da API é chamada de "chave de assinatura" ou "chave da API de assinatura".

Depois de ter uma chave de API e um ponto de extremidade, você pode usar a classe AzureKeyCredential para autenticar o cliente da seguinte maneira:

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

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

Usando uma credencial do Azure Ative Directory

Você também pode autenticar com o Azure Ative Directory usando o biblioteca de Identidade do Azure. Para usar o provedor de DefaultAzureCredential mostrado abaixo ou outros provedores de credenciais fornecidos com o SDK do Azure, instale o pacote @azure/identity:

npm install @azure/identity

Defina os valores do ID do cliente, ID do locatário e segredo do cliente do aplicativo AAD como variáveis de ambiente: 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());

Conceitos-chave

O conceito principal a entender é Finalizações. Explicado resumidamente, as finalizações fornecem sua funcionalidade na forma de um prompt de texto, que usando um modelo de específico, tentará corresponder ao contexto e aos padrões, fornecendo um texto de saída. O trecho de código a seguir fornece uma visão geral aproximada:

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

Exemplos

Gerar resposta do chatbot

O bate-papo de streaming com o SDK de inferência requer suporte de streaming principal; Para habilitar esse suporte, instale o pacote @azure/core-sse:

npm install @azure/core-sse

Este exemplo autentica usando um DefaultAzureCredential e, em seguida, gera respostas de bate-papo para inserir perguntas e mensagens de bate-papo.

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

Gerar várias conclusões com chave de assinatura

Este exemplo gera respostas de texto para prompts de entrada usando uma chave de assinatura do 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);
});

Resumir texto com conclusão

Este exemplo gera um resumo do prompt de entrada fornecido.

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

Usar ferramentas de bate-papo

Ferramentas estender a conclusão do bate-papo, permitindo que um assistente invoque funções definidas e outros recursos no processo de cumprimento de uma solicitação de conclusão de bate-papo. Para usar ferramentas de chat, comece definindo uma ferramenta de função:

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

Com a ferramenta definida, inclua essa nova definição nas opções para uma solicitação de conclusão de chat:

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

Quando o assistente decide que uma ou mais ferramentas devem ser usadas, a mensagem de resposta inclui uma ou mais "chamadas de ferramentas" que devem ser resolvidas por meio de "mensagens de ferramentas" na solicitação subsequente. Essa resolução de chamadas de ferramentas em novas mensagens de solicitação pode ser pensada como uma espécie de "retorno de chamada" para a conclusão do bate-papo.

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

Para fornecer resoluções de chamada de ferramenta ao assistente para permitir que a solicitação continue, forneça todo o contexto histórico anterior - incluindo o sistema original e as mensagens do usuário, a resposta do assistente que incluiu as chamadas de ferramenta e as mensagens da ferramenta que resolveram cada uma dessas ferramentas - ao fazer uma solicitação subsequente.

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

Bate-papo com imagens (usando modelos que suportam bate-papo de imagem, como gpt-4o)

Alguns modelos do Azure permitem que você use imagens como componentes de entrada em finalizações de bate-papo.

Para fazer isso, forneça itens de conteúdo distintos na(s) mensagem(ões) do usuário para a solicitação de conclusão do chat:

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

As finalizações do bate-papo prosseguirão como de costume, embora o modelo possa relatar as finish_details mais informativas em vez de finish_reason:

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

Exemplo de incorporação de texto

Este exemplo demonstra como obter incorporações de texto com a autenticação Entra ID.

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

O comprimento do vetor de incorporação depende do modelo, mas você deve ver algo assim:

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]

Para gerar incorporações para frases adicionais, basta ligar para client.path("/embeddings").post várias vezes usando o mesmo client.

Instrumentação

Atualmente, a instrumentação é suportada apenas para Chat Completion without streaming. Para habilitar a instrumentação, é necessário registrar o(s) exportador(es).

Aqui está um exemplo para adicionar console como exportador:

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

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

Aqui está um exemplo para adicionar informações de aplicativo para ser um exportador:

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

Para usar a instrumentação para o SDK do Azure, você precisa registrá-la antes de importar quaisquer dependências do @azure/core-tracing, como @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";

Finalmente, quando você está fazendo uma chamada para a conclusão do bate-papo, você precisa incluir

tracingOptions: { tracingContext: context.active() }

Segue-se um exemplo:

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

Rastreando suas próprias funções

A Telemetria Aberta fornece startActiveSpan para instrumentar seu próprio código. Segue-se um exemplo:

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

Solução de problemas

Registo

Habilitar o registro em log pode ajudar a descobrir informações úteis sobre falhas. Para ver um log de solicitações e respostas HTTP, defina a variável de ambiente AZURE_LOG_LEVEL como info. Como alternativa, o registro em log pode ser habilitado em tempo de execução chamando setLogLevel no @azure/logger:

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

setLogLevel("info");

Para obter instruções mais detalhadas sobre como habilitar logs, você pode consultar os documentos do pacote @azure/logger.