Partager via


Bibliothèque de client Azure AI Projects pour JavaScript - version 1.0.0-beta.2

Utilisez la bibliothèque cliente AI Projects (en préversion) pour :

  • Énumérer les connexions dans votre projet Azure AI Foundry et obtenir les propriétés de connexion. Par exemple, obtenez l’URL du point de terminaison d’inférence et les informations d’identification associées à votre connexion Azure OpenAI.
  • Développer des agents à l’aide du service Azure AI Agent, en tirant parti d’un vaste écosystème de modèles, d’outils et de fonctionnalités d’OpenAI, de Microsoft et d’autres fournisseurs LLM. Le service d’agent Azure AI permet de créer des agents pour un large éventail de cas d’utilisation de l’IA générative. Le package est actuellement en préversion privée.
  • Activer le suivi OpenTelemetry.

documentation produit

Table des matières

Commencer

Prérequis

  • versions LTS de Node.js
  • Un abonnement Azure .
  • Un projet dans Azure AI Foundry.
  • Chaîne de connexion du projet. Il se trouve dans la page de présentation de votre projet Azure AI Foundry, sous « Détails du projet ». Ci-dessous, nous partons du principe que la variable d’environnement AZURE_AI_PROJECTS_CONNECTION_STRING a été définie pour contenir cette valeur.
  • L’ID Entra est nécessaire pour authentifier le client. Votre application a besoin d’un objet qui implémente l’interface TokenCredential. Les exemples de code ici utilisent DefaultAzureCredential. Pour travailler, vous aurez besoin des éléments suivants :
    • Rôle Contributor. Le rôle attribué peut être effectué via l’onglet « Contrôle d’accès (IAM) » de votre ressource Azure AI Project dans le portail Azure.
    • azure CLI installé.
    • Vous êtes connecté à votre compte Azure en exécutant az login.
    • Notez que si vous avez plusieurs abonnements Azure, l’abonnement qui contient votre ressource Azure AI Project doit être votre abonnement par défaut. Exécutez az account list --output table pour répertorier l’ensemble de votre abonnement et voir lequel est la valeur par défaut. Exécutez az account set --subscription "Your Subscription ID or Name" pour modifier votre abonnement par défaut.

Installer le package

npm install @azure/ai-projects

Concepts clés

Créer et authentifier le client

La méthode de fabrique de classes fromConnectionString est utilisée pour construire le client. Pour construire un client :

import { AIProjectsClient } from "@azure/ai-projects";
import { DefaultAzureCredential } from "@azure/identity";

import "dotenv/config";  

const connectionString = process.env["AZURE_AI_PROJECTS_CONNECTION_STRING"] || "<connectionString>";

const client = AIProjectsClient.fromConnectionString(
  connectionString,
  new DefaultAzureCredential(),
);

Exemples

Énumérer les connexions

Votre projet Azure AI Foundry dispose d’un « Centre de gestion ». Lorsque vous y entrez, vous verrez un onglet nommé « Ressources connectées » sous votre projet. Les opérations .connections sur le client vous permettent d’énumérer les connexions et d’obtenir les propriétés de connexion. Les propriétés de connexion incluent l’URL de ressource et les informations d’identification d’authentification, entre autres.

Vous trouverez ci-dessous des exemples de code des opérations de connexion. Vous trouverez des exemples complets sous le dossier « connexions » dans les [exemples de package][samples].

Obtenir les propriétés de toutes les connexions

Pour répertorier les propriétés de toutes les connexions dans le projet Azure AI Foundry :

const connections = await client.connections.listConnections();
for (const connection of connections) {
  console.log(connection);
}

Obtenir les propriétés de toutes les connexions d’un type particulier

Pour répertorier les propriétés des connexions d’un certain type (ici Azure OpenAI) :

const connections = await client.connections.listConnections({ category: "AzureOpenAI" });
for (const connection of connections) {
  console.log(connection);
}

Obtenir les propriétés d’une connexion par son nom de connexion

Pour obtenir les propriétés de connexion d’une connexion nommée connectionName:

const connection = await client.connections.getConnection("connectionName");
console.log(connection);

Pour obtenir les propriétés de connexion avec ses informations d’identification d’authentification :

const connection = await client.connections.getConnectionWithSecrets("connectionName");
console.log(connection);

Agents (préversion)

Les agents de la bibliothèque cliente Azure AI Projects sont conçus pour faciliter diverses interactions et opérations au sein de vos projets IA. Ils servent de composants principaux qui gèrent et exécutent des tâches, en tirant parti de différents outils et ressources pour atteindre des objectifs spécifiques. Les étapes suivantes décrivent la séquence classique d’interaction avec les agents. Consultez le dossier « agents » dans les [exemples de package][exemples] pour obtenir d’autres exemples d’agent.

Les agents sont activement développés. Un formulaire d’inscription pour la préversion privée sera bientôt disponible.

Créer un agent

Voici un exemple de création d’un agent :

const agent = await client.agents.createAgent("gpt-4o", {
  name: "my-agent",
  instructions: "You are a helpful assistant",
});

Pour autoriser les agents à accéder à vos ressources ou fonctions personnalisées, vous avez besoin d’outils. Vous pouvez transmettre des outils pour createAgent par le biais des arguments tools et toolResources.

Vous pouvez utiliser ToolSet pour ce faire :

const toolSet = new ToolSet();
toolSet.addFileSearchTool([vectorStore.id]);
toolSet.addCodeInterpreterTool([codeInterpreterFile.id]);

// Create agent with tool set
const agent = await client.agents.createAgent("gpt-4o", {
  name: "my-agent",
  instructions: "You are a helpful agent",
  tools: toolSet.toolDefinitions,
  toolResources: toolSet.toolResources,
});
console.log(`Created agent, agent ID: ${agent.id}`);

Pour effectuer une recherche de fichiers par un agent, nous devons d’abord charger un fichier, créer un magasin de vecteurs et associer le fichier au magasin vectoriel. Voici un exemple :

const localFileStream = fs.createReadStream("sample_file_for_upload.txt");
const file = await client.agents.uploadFile(localFileStream, "assistants", {
  fileName: "sample_file_for_upload.txt",
});
console.log(`Uploaded file, ID: ${file.id}`);

const vectorStore = await client.agents.createVectorStore({
  fileIds: [file.id],
  name: "my_vector_store",
});
console.log(`Created vector store, ID: ${vectorStore.id}`);

const fileSearchTool = ToolUtility.createFileSearchTool([vectorStore.id]);

const agent = await client.agents.createAgent("gpt-4o", {
  name: "SDK Test Agent - Retrieval",
  instructions: "You are helpful agent that can help fetch data from files you know about.",
  tools: [fileSearchTool.definition],
  toolResources: fileSearchTool.resources,
});
console.log(`Created agent, agent ID : ${agent.id}`);

Créer un agent avec l’interpréteur de code

Voici un exemple pour charger un fichier et l’utiliser pour l’interpréteur de code par un agent :

const fileStream = fs.createReadStream("nifty_500_quarterly_results.csv");
const fFile = await client.agents.uploadFile(fileStream, "assistants", {
  fileName: "nifty_500_quarterly_results.csv",
});
console.log(`Uploaded local file, file ID : ${file.id}`);

const codeInterpreterTool = ToolUtility.createCodeInterpreterTool([file.id]);

// Notice that CodeInterpreter must be enabled in the agent creation, otherwise the agent will not be able to see the file attachment
const agent = await client.agents.createAgent("gpt-4o-mini", {
  name: "my-agent",
  instructions: "You are a helpful agent",
  tools: [codeInterpreterTool.definition],
  toolResources: codeInterpreterTool.resources,
});
console.log(`Created agent, agent ID: ${agent.id}`);

Créer un agent avec Bing Grounding

Pour permettre à votre agent d’effectuer une recherche via l’API recherche Bing, vous utilisez ToolUtility.createConnectionTool() avec une connexion.

Voici un exemple :

const bingGroundingConnectionId = "<bingGroundingConnectionId>";
const bingTool = ToolUtility.createConnectionTool(connectionToolType.BingGrounding, [
  bingGroundingConnectionId,
]);

const agent = await client.agents.createAgent("gpt-4-0125-preview", {
  name: "my-agent",
  instructions: "You are a helpful agent",
  tools: [bingTool.definition],
});
console.log(`Created agent, agent ID : ${agent.id}`);

Azure AI Search est un système de recherche d’entreprise pour les applications hautes performances. Il s’intègre à Azure OpenAI Service et Azure Machine Learning, offrant des technologies de recherche avancées telles que la recherche vectorielle et la recherche en texte intégral. Idéal pour les insights de base de connaissances, la découverte des informations et l’automatisation

Voici un exemple d’intégration d’Azure AI Search :

const cognitiveServicesConnectionName = "<cognitiveServicesConnectionName>";
const cognitiveServicesConnection = await client.connections.getConnection(
  cognitiveServicesConnectionName,
);
const azureAISearchTool = ToolUtility.createAzureAISearchTool(
  cognitiveServicesConnection.id,
  cognitiveServicesConnection.name,
);

// Create agent with the Azure AI search tool
const agent = await client.agents.createAgent("gpt-4-0125-preview", {
  name: "my-agent",
  instructions: "You are a helpful agent",
  tools: [azureAISearchTool.definition],
  toolResources: azureAISearchTool.resources,
});
console.log(`Created agent, agent ID : ${agent.id}`);

Créer un agent avec l’appel de fonction

Vous pouvez améliorer vos agents en définissant des fonctions de rappel en tant qu’outils de fonction. Ceux-ci peuvent être fournis à createAgent via la combinaison de tools et de toolResources. Seules les définitions et descriptions des fonctions sont fournies à createAgent, sans les implémentations. Le Run ou event handler of stream déclenche un état de requires_action en fonction des définitions de fonction. Votre code doit gérer cet état et appeler les fonctions appropriées.

Voici un exemple :

class FunctionToolExecutor {
  private functionTools: { func: Function, definition: FunctionToolDefinition }[];

  constructor() {
    this.functionTools = [{
      func: this.getUserFavoriteCity,
      ...ToolUtility.createFunctionTool({
        name: "getUserFavoriteCity",
        description: "Gets the user's favorite city.",
        parameters: {}
      })
    }, {
      func: this.getCityNickname,
      ...ToolUtility.createFunctionTool({
        name: "getCityNickname",
        description: "Gets the nickname of a city, e.g. 'LA' for 'Los Angeles, CA'.",
        parameters: { type: "object", properties: { location: { type: "string", description: "The city and state, e.g. Seattle, Wa" } } }
      })
    }, {
      func: this.getWeather,
      ...ToolUtility.createFunctionTool({
        name: "getWeather",
        description: "Gets the weather for a location.",
        parameters: { type: "object", properties: { location: { type: "string", description: "The city and state, e.g. Seattle, Wa" }, unit: { type: "string", enum: ['c', 'f'] } } }
      })
    }];
  }

  private getUserFavoriteCity(): {} {
    return { "location": "Seattle, WA" };
  }

  private getCityNickname(location: string): {} {
    return { "nickname": "The Emerald City" };
  }

  private getWeather(location: string, unit: string): {} {
    return { "weather": unit === "f" ? "72f" : "22c" };
  }

  public invokeTool(toolCall: RequiredToolCallOutput & FunctionToolDefinitionOutput): ToolOutput | undefined {
    console.log(`Function tool call - ${toolCall.function.name}`);
    const args = [];
    if (toolCall.function.parameters) {
      try {
        const params = JSON.parse(toolCall.function.parameters);
        for (const key in params) {
          if (Object.prototype.hasOwnProperty.call(params, key)) {
            args.push(params[key]);
          }
        }
      } catch (error) {
        console.error(`Failed to parse parameters: ${toolCall.function.parameters}`, error);
        return undefined;
      }
    }
    const result = this.functionTools.find((tool) => tool.definition.function.name === toolCall.function.name)?.func(...args);
    return result ? {
      toolCallId: toolCall.id,
      output: JSON.stringify(result)
    } : undefined;
  }

  public getFunctionDefinitions(): FunctionToolDefinition[] {
    return this.functionTools.map(tool => {return tool.definition});
  }
}

const functionToolExecutor = new FunctionToolExecutor();
const functionTools = functionToolExecutor.getFunctionDefinitions();
const agent = await client.agents.createAgent("gpt-4o",
  {
    name: "my-agent",
    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: functionTools
  });
console.log(`Created agent, agent ID: ${agent.id}`);

Créer un thread

Pour chaque session ou conversation, un thread est requis. Voici un exemple :

const thread = await client.agents.createThread();

Créer un thread avec une ressource d’outil

Dans certains scénarios, vous devrez peut-être affecter des ressources spécifiques à des threads individuels. Pour ce faire, vous fournissez l’argument toolResources à createThread. Dans l’exemple suivant, vous créez un magasin de vecteurs et chargez un fichier, activez un agent pour la recherche de fichiers à l’aide de l’argument tools, puis associez le fichier au thread à l’aide de l’argument toolResources.

const localFileStream = fs.createReadStream("sample_file_for_upload.txt");
const file = await client.agents.uploadFile(localFileStream, "assistants", {
  fileName: "sample_file_for_upload.txt",
});
console.log(`Uploaded file, ID: ${file.id}`);

const vectorStore = await client.agents.createVectorStore({
  fileIds: [file.id],
  name: "my_vector_store",
});
console.log(`Created vector store, ID: ${vectorStore.id}`);

const fileSearchTool = ToolUtility.createFileSearchTool([vectorStore.id]);

const agent = await client.agents.createAgent("gpt-4o", {
  name: "SDK Test Agent - Retrieval",
  instructions: "You are helpful agent that can help fetch data from files you know about.",
  tools: [fileSearchTool.definition],
});
console.log(`Created agent, agent ID : ${agent.id}`);

// Create thread with file resources.
// If the agent has multiple threads, only this thread can search this file.
const thread = await client.agents.createThread({ toolResources: fileSearchTool.resources });

Créer un message

Pour créer un message permettant à l’Assistant de traiter, vous transmettez user en tant que role et une question en tant que content:

const message = await client.agents.createMessage(thread.id, {
  role: "user",
  content: "hello, world!",
});

Créer un message avec une pièce jointe de recherche de fichiers

Pour joindre un fichier à un message pour la recherche de contenu, vous utilisez ToolUtility.createFileSearchTool() et l’argument attachments :

const fileSearchTool = ToolUtility.createFileSearchTool();
const message = await client.agents.createMessage(thread.id, {
  role: "user",
  content: "What feature does Smart Eyewear offer?",
  attachments: {
    fileId: file.id,
    tools: [fileSearchTool.definition],
  },
});

Créer un message avec une pièce jointe de l’interpréteur de code

Pour joindre un fichier à un message pour l’analyse des données, vous utilisez ToolUtility.createCodeInterpreterTool() et l’argument attachment.

Voici un exemple :

// notice that CodeInterpreter must be enabled in the agent creation,
// otherwise the agent will not be able to see the file attachment for code interpretation
const codeInterpreterTool = ToolUtility.createCodeInterpreterTool();
const agent = await client.agents.createAgent("gpt-4-1106-preview", {
  name: "my-assistant",
  instructions: "You are helpful assistant",
  tools: [codeInterpreterTool.definition],
});
console.log(`Created agent, agent ID: ${agent.id}`);

const thread = client.agents.createThread();
console.log(`Created thread, thread ID: ${thread.id}`);

const message = await client.agents.createMessage(thread.id, {
  role: "user",
  content:
    "Could you please create bar chart in TRANSPORTATION sector for the operating profit from the uploaded csv file and provide file to me?",
  attachments: {
    fileId: file.id,
    tools: [codeInterpreterTool.definition],
  },
});
console.log(`Created message, message ID: ${message.id}`);

Créer une exécution, un Run_and_Process ou un flux

Voici un exemple de createRun et d’interrogation jusqu’à ce que l’exécution soit terminée :

let run = await client.agents.createRun(thread.id, agent.id);

// Poll the run as long as run status is queued or in progress
while (
  run.status === "queued" ||
  run.status === "in_progress" ||
  run.status === "requires_action"
) {
  // Wait for a second
  await new Promise((resolve) => setTimeout(resolve, 1000));
  run = await client.agents.getRun(thread.id, run.id);
}

Pour que le SDK interroge votre nom, utilisez la méthode createThreadAndRun.

Voici un exemple :

const run = await client.agents.createThreadAndRun(thread.id, agent.id);

Avec la diffusion en continu, l’interrogation n’a pas besoin d’être prise en compte.

Voici un exemple :

const streamEventMessages = await client.agents.createRun(thread.id, agent.id).stream();

La gestion des événements peut être effectuée comme suit :

for await (const eventMessage of streamEventMessages) {
switch (eventMessage.event) {
  case RunStreamEvent.ThreadRunCreated:
    console.log(`ThreadRun status: ${(eventMessage.data as ThreadRunOutput).status}`)
    break;
  case MessageStreamEvent.ThreadMessageDelta:
    {
      const messageDelta = eventMessage.data as MessageDeltaChunk;
      messageDelta.delta.content.forEach((contentPart) => {
        if (contentPart.type === "text") {
          const textContent = contentPart as MessageDeltaTextContent
          const textValue = textContent.text?.value || "No text"
          console.log(`Text delta received:: ${textValue}`)
        }
      });
    }
    break;

  case RunStreamEvent.ThreadRunCompleted:
    console.log("Thread Run Completed");
    break;
  case ErrorEvent.Error:
    console.log(`An error occurred. Data ${eventMessage.data}`);
    break;
  case DoneEvent.Done:
    console.log("Stream completed.");
    break;
  }
}

Récupérer le message

Pour récupérer des messages à partir d’agents, utilisez l’exemple suivant :

const messages = await client.agents.listMessages(thread.id);

// The messages are following in the reverse order,
// we will iterate them and output only text contents.
for (const dataPoint of messages.data.reverse()) {
    const lastMessageContent: MessageContentOutput = dataPoint.content[dataPoint.content.length - 1];
    console.log( lastMessageContent);
    if (isOutputOfType<MessageTextContentOutput>(lastMessageContent, "text")) {
      console.log(`${dataPoint.role}: ${(lastMessageContent as MessageTextContentOutput).text.value}`);
    }
  }

Récupérer un fichier

Les fichiers chargés par les agents ne peuvent pas être récupérés. Si votre cas d’usage doit accéder au contenu du fichier chargé par les agents, il est conseillé de conserver une copie supplémentaire accessible par votre application. Toutefois, les fichiers générés par les agents sont récupérables par getFileContent.

Voici un exemple de récupération d’ID de fichier à partir de messages :

const messages = await client.agents.listMessages(thread.id);
const imageFile = (messages.data[0].content[0] as MessageImageFileContentOutput).imageFile;
const imageFileName = (await client.agents.getFile(imageFile.fileId)).filename;

const fileContent = await (await client.agents.getFileContent(imageFile.fileId).asNodeStream()).body;
if (fileContent) {
  const chunks: Buffer[] = [];
  for await (const chunk of fileContent) {
    chunks.push(Buffer.from(chunk));
  }
  const buffer = Buffer.concat(chunks);
  fs.writeFileSync(imageFileName, buffer);
} else {
  console.error("Failed to retrieve file content: fileContent is undefined");
}
console.log(`Saved image file to: ${imageFileName}`);

Démontage

Pour supprimer des ressources après avoir effectué des tâches, utilisez les fonctions suivantes :

await client.agents.deleteVectorStore(vectorStore.id);
console.log(`Deleted vector store, vector store ID: ${vectorStore.id}`);

await client.agents.deleteFile(file.id);
console.log(`Deleted file, file ID: ${file.id}`);

client.agents.deleteAgent(agent.id);
console.log(`Deleted agent, agent ID: ${agent.id}`);

Traçage

Vous pouvez ajouter une ressource Azure Application Insights à votre projet Azure AI Foundry. Consultez l’onglet Suivi dans votre studio. Si l’un d’eux a été activé, vous pouvez obtenir la chaîne de connexion Application Insights, configurer vos agents et observer le chemin d’exécution complet via Azure Monitor. En règle générale, vous pouvez commencer le suivi avant de créer un agent.

Installation

Veillez à installer OpenTelemetry et le plug-in de suivi du Kit de développement logiciel (SDK) Azure via

npm install @opentelemetry/api \
  @opentelemetry/instrumentation \
  @opentelemetry/sdk-trace-node \
  @azure/opentelemetry-instrumentation-azure-sdk \
  @azure/monitor-opentelemetry-exporter

Vous aurez également besoin d’un exportateur pour envoyer des données de télémétrie à votre back-end d’observabilité. Vous pouvez imprimer des traces dans la console ou utiliser une visionneuse locale telle que Tableau de bord Aspire.

Pour vous connecter au tableau de bord Aspire ou à un autre back-end compatible OpenTelemetry, installez l’exportateur OTLP :

npm install @opentelemetry/exporter-trace-otlp-proto \
  @opentelemetry/exporter-metrics-otlp-proto

Exemple de suivi

Voici un exemple de code à inclure ci-dessus createAgent:

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

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

const tracer = trace.getTracer("Agents Sample", "1.0.0");

const client = AIProjectsClient.fromConnectionString(
  connectionString || "", new DefaultAzureCredential()
);

if (!appInsightsConnectionString) {
  appInsightsConnectionString = await client.telemetry.getConnectionString();
}

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

await tracer.startActiveSpan("main", async (span) => {
    client.telemetry.updateSettings({enableContentRecording: true})
// ...

Dépannage

Exceptions

Les méthodes clientes qui effectuent des appels de service déclenchent une RestError pour une réponse de code d’état HTTP non réussie du service. La code de l’exception contiendra le code d’état de la réponse HTTP. Le error.message de l’exception contient un message détaillé qui peut être utile pour diagnostiquer le problème :

import { RestError } from "@azure/core-rest-pipeline"

// ...

try {
  const result = await client.connections.listConnections();
} catch (e as RestError) {
  console.log(`Status code: ${e.code}`);
  console.log(e.message);
}

Par exemple, lorsque vous fournissez des informations d’identification incorrectes :

Status code: 401 (Unauthorized)
Operation returned an invalid status 'Unauthorized'

Signaler des problèmes

Pour signaler des problèmes avec la bibliothèque cliente ou demander des fonctionnalités supplémentaires, ouvrez un problème GitHub ici

Contribuant

Ce projet accueille les contributions et suggestions. La plupart des contributions vous obligent à accepter un contrat de licence contributeur (CLA) déclarant que vous avez le droit, et en fait, de nous accorder les droits d’utilisation de votre contribution. Pour plus d’informations, visitez https://cla.microsoft.com.

Lorsque vous envoyez une demande de tirage( pull request), un bot CLA détermine automatiquement si vous devez fournir un CLA et décorer correctement la demande de tirage (par exemple, étiquette, commentaire). Suivez simplement les instructions fournies par le bot. Vous n’aurez besoin de le faire qu’une seule fois sur tous les dépôts à l’aide de notre CLA.

Ce projet a adopté le code de conduite Microsoft Open Source. Pour plus d’informations, consultez la FAQ sur le code de conduite ou contactez opencode@microsoft.com avec toutes les questions ou commentaires supplémentaires.