Compartir a través de


Biblioteca cliente de proyectos de Azure AI para JavaScript: versión 1.0.0-beta.2

Use la biblioteca cliente de proyectos de IA (en versión preliminar) para:

  • Enumerar conexiones en el proyecto de Azure AI Foundry y obtener las propiedades de conexión. Por ejemplo, obtenga la dirección URL del punto de conexión de inferencia y las credenciales asociadas a la conexión de Azure OpenAI.
  • Desarrollar agentes mediante azure AI Agent Service, aprovechando un amplio ecosistema de modelos, herramientas y funcionalidades de OpenAI, Microsoft y otros proveedores de LLM. El servicio agente de Azure AI permite la creación de agentes para una amplia gama de casos de uso de IA generativas. El paquete está actualmente en versión preliminar privada.
  • habilitar el seguimiento de OpenTelemetry.

documentación del producto de

Tabla de contenido

Empezar

Prerrequisito

  • versiones ltS de Node.js
  • Una suscripción de Azure .
  • Un proyecto de en Azure AI Foundry.
  • Cadena de conexión del proyecto. Puede encontrarse en la página de información general del proyecto de Azure AI Foundry, en "Detalles del proyecto". A continuación se supone que la variable de entorno AZURE_AI_PROJECTS_CONNECTION_STRING se definió para contener este valor.
  • Se necesita entra ID para autenticar al cliente. La aplicación necesita un objeto que implemente la interfaz TokenCredential. Los ejemplos de código aquí usan DefaultAzureCredential. Para que funcione, necesitará lo siguiente:
    • Rol de Contributor. El rol asignado se puede realizar a través de la pestaña "Control de acceso (IAM)" del recurso del proyecto de Azure AI en Azure Portal.
    • de la CLI de Azure instalada.
    • Ha iniciado sesión en su cuenta de Azure mediante la ejecución de az login.
    • Tenga en cuenta que si tiene varias suscripciones de Azure, la suscripción que contiene el recurso de Proyecto de Azure AI debe ser la suscripción predeterminada. Ejecute az account list --output table para enumerar toda la suscripción y ver cuál es el valor predeterminado. Ejecute az account set --subscription "Your Subscription ID or Name" para cambiar la suscripción predeterminada.

Instalación del paquete

npm install @azure/ai-projects

Conceptos clave

Creación y autenticación del cliente

El método de fábrica de clases fromConnectionString se usa para construir el cliente. Para construir un cliente:

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

Ejemplos

Enumerar conexiones

El proyecto de Azure AI Foundry tiene un "Centro de administración". Al escribirlo, verá una pestaña denominada "Recursos conectados" en el proyecto. Las operaciones de .connections en el cliente le permiten enumerar las conexiones y obtener las propiedades de conexión. Las propiedades de conexión incluyen la dirección URL del recurso y las credenciales de autenticación, entre otras cosas.

A continuación se muestran ejemplos de código de las operaciones de conexión. Los ejemplos completos se pueden encontrar en la carpeta "connections" de [ejemplos de paquete][samples].

Obtener propiedades de todas las conexiones

Para enumerar las propiedades de todas las conexiones del proyecto Azure AI Foundry:

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

Obtener propiedades de todas las conexiones de un tipo determinado

Para enumerar las propiedades de las conexiones de un tipo determinado (aquí Azure OpenAI):

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

Obtener propiedades de una conexión por su nombre de conexión

Para obtener las propiedades de conexión de una conexión denominada connectionName:

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

Para obtener las propiedades de conexión con sus credenciales de autenticación:

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

Agentes (versión preliminar)

Los agentes de la biblioteca cliente de proyectos de Azure AI están diseñados para facilitar diversas interacciones y operaciones dentro de los proyectos de IA. Sirven como componentes principales que administran y ejecutan tareas, aprovechando diferentes herramientas y recursos para lograr objetivos específicos. En los pasos siguientes se describe la secuencia típica para interactuar con agentes. Consulte la carpeta "agents" en [ejemplos de paquetes][samples] para ver ejemplos adicionales del agente.

Los agentes se están desarrollando activamente. Pronto estará disponible un formulario de registro para la versión preliminar privada.

Crear agente

Este es un ejemplo de cómo crear un agente:

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

Para permitir que los agentes accedan a los recursos o a las funciones personalizadas, necesita herramientas. Puede pasar herramientas para createAgent a través de los argumentos tools y toolResources.

Puede usar ToolSet para hacerlo:

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

Para realizar la búsqueda de archivos mediante un agente, primero es necesario cargar un archivo, crear un almacén de vectores y asociar el archivo al almacén de vectores. Este es un ejemplo:

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

Creación de agente con el intérprete de código

Este es un ejemplo para cargar un archivo y usarlo para el intérprete de código por un agente:

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

Creación de un agente con Bing Grounding

Para permitir que el agente realice búsquedas a través de Bing Search API, use ToolUtility.createConnectionTool() junto con una conexión.

Este es un ejemplo:

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 es un sistema de búsqueda empresarial para aplicaciones de alto rendimiento. Se integra con Azure OpenAI Service y Azure Machine Learning, que ofrece tecnologías de búsqueda avanzadas, como la búsqueda de vectores y la búsqueda de texto completo. Ideal para la información de la base de conocimiento, la detección de información y la automatización

Este es un ejemplo para integrar 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}`);

Creación de agente con llamada de función

Puede mejorar los agentes mediante la definición de funciones de devolución de llamada como herramientas de función. Se pueden proporcionar para createAgent mediante la combinación de tools y toolResources. Solo se proporcionan las definiciones y descripciones de función para createAgent, sin las implementaciones. El Run o event handler of stream generará un estado de requires_action en función de las definiciones de función. El código debe controlar este estado y llamar a las funciones adecuadas.

Este es un ejemplo:

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

Crear subproceso

Para cada sesión o conversación, se requiere un subproceso. Este es un ejemplo:

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

Creación de subprocesos con recurso de herramienta

En algunos escenarios, es posible que tenga que asignar recursos específicos a subprocesos individuales. Para ello, proporcione el argumento toolResources para createThread. En el ejemplo siguiente, creará un almacén de vectores y cargará un archivo, habilitará un agente para la búsqueda de archivos mediante el argumento tools y, a continuación, asociará el archivo al subproceso mediante el argumento 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 });

Crear mensaje

Para crear un mensaje para que el asistente procese, pase user como role y una pregunta como content:

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

Crear mensaje con datos adjuntos de búsqueda de archivos

Para adjuntar un archivo a un mensaje para la búsqueda de contenido, use ToolUtility.createFileSearchTool() y el argumento 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],
  },
});

Crear mensaje con datos adjuntos del intérprete de código

Para adjuntar un archivo a un mensaje para el análisis de datos, use ToolUtility.createCodeInterpreterTool() y el argumento attachment.

Este es un ejemplo:

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

Crear ejecución, Run_and_Process o Stream

Este es un ejemplo de createRun y sondeo hasta que se completa la ejecución:

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

Para que el SDK sondee en su nombre, use el método createThreadAndRun.

Este es un ejemplo:

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

Con el streaming, no es necesario tener en cuenta el sondeo.

Este es un ejemplo:

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

El control de eventos se puede realizar de la siguiente manera:

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

Recuperar mensaje

Para recuperar mensajes de agentes, use el ejemplo siguiente:

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

Recuperar archivo

No se pueden recuperar los archivos cargados por agentes. Si el caso de uso necesita acceder al contenido del archivo cargado por los agentes, se recomienda mantener una copia adicional accesible para la aplicación. Sin embargo, los archivos generados por los agentes se pueden recuperar mediante getFileContent.

Este es un ejemplo de recuperación de identificadores de archivo de mensajes:

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

Desmontaje

Para quitar recursos después de completar las tareas, use las funciones siguientes:

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

Trazado

Puede agregar un recurso de Azure de Application Insights al proyecto de Azure AI Foundry. Consulte la pestaña Seguimiento en studio. Si se ha habilitado una, puede obtener la cadena de conexión de Application Insights, configurar los agentes y observar la ruta de acceso de ejecución completa a través de Azure Monitor. Normalmente, es posible que desee iniciar el seguimiento antes de crear un agente.

Instalación

Asegúrese de instalar OpenTelemetry y el complemento de seguimiento del SDK de Azure mediante

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

También necesitará un exportador para enviar telemetría al back-end de observabilidad. Puede imprimir seguimientos en la consola o usar un visor local, como Aspire Dashboard.

Para conectarse a Aspire Dashboard u otro back-end compatible con OpenTelemetry, instale el exportador de OTLP:

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

Ejemplo de seguimiento

Este es un ejemplo de código que se incluirá anteriormente 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})
// ...

Solución de problemas

Excepciones

Los métodos cliente que realizan llamadas de servicio generan un restError para una respuesta de código de estado HTTP no correcta del servicio. El code de la excepción contendrá el código de estado de respuesta HTTP. El error.message de la excepción contiene un mensaje detallado que puede resultar útil para diagnosticar el problema:

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

Por ejemplo, cuando se proporcionan credenciales incorrectas:

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

Informes de problemas

Para notificar problemas con la biblioteca cliente o solicitar características adicionales, abra un problema de GitHub aquí

Contribuyendo

Este proyecto da la bienvenida a las contribuciones y sugerencias. La mayoría de las contribuciones requieren que acepte un Contrato de licencia de colaborador (CLA) declarando que tiene derecho a, y en realidad, concedanos los derechos para usar su contribución. Para obtener más información, visite https://cla.microsoft.com.

Al enviar una solicitud de incorporación de cambios, un bot CLA determinará automáticamente si necesita proporcionar un CLA y decorar la solicitud de incorporación de cambios de forma adecuada (por ejemplo, etiqueta, comentario). Solo tiene que seguir las instrucciones proporcionadas por el bot. Solo tendrá que hacerlo una vez en todos los repositorios mediante nuestro CLA.

Este proyecto ha adoptado el código abierto de conducta de Microsoft. Para obtener más información, consulte las preguntas más frecuentes sobre el código de conducta o póngase en contacto con opencode@microsoft.com con preguntas o comentarios adicionales.