Biblioteca de clientes do Azure AI Projects para JavaScript – versão 1.0.0-beta.2
Use a biblioteca de clientes de Projetos de IA (em versão prévia) para:
- enumerar conexões em seu projeto do Azure AI Foundry e obter propriedades de conexão. Por exemplo, obtenha a URL do ponto de extremidade de inferência e as credenciais associadas à sua conexão do Azure OpenAI.
- Desenvolver Agentes usando o Serviço do Agente de IA do Azure, aproveitando um amplo ecossistema de modelos, ferramentas e funcionalidades do OpenAI, microsoft e outros provedores llm. O Serviço do Agente de IA do Azure permite a criação de Agentes para uma ampla gama de casos de uso de IA generativos. O pacote está atualmente em versão prévia privada.
- habilitar o rastreamento opentelemetry.
Sumário
-
introdução
- de pré-requisitos
- Instalar o pacote
- principais conceitos
- exemplos de
- enumerar conexões
- agentes (versão prévia)
- criar um agente com:
-
Criar de thread com
- de recursos da Ferramenta de
- de recursos da Ferramenta de
- Criar de mensagem com:
- Executar, Criar Thread e Executar ou Transmitir
- Recuperar de mensagem
- Recuperar de arquivo
- Derrubar excluindo de recursos
- de rastreamento de
- de rastreamento de
-
solução de problemas
- exceções de
- problemas de relatório
- contribuindo com
Introdução
Pré-requisito
- versões lts do Node.js
- Uma assinatura do Azure.
- Um projeto de no Azure AI Foundry.
- A cadeia de conexão do projeto. Ele pode ser encontrado na página de visão geral do projeto do Azure AI Foundry, em "Detalhes do projeto". Abaixo, vamos supor que a variável de ambiente
AZURE_AI_PROJECTS_CONNECTION_STRING
foi definida para manter esse valor. - A ID do Entra é necessária para autenticar o cliente. Seu aplicativo precisa de um objeto que implemente a interface
TokenCredential. Exemplos de código aqui usam DefaultAzureCredential. Para que isso funcione, você precisará de: - A função
Contributor
. A função atribuída pode ser feita por meio da guia "Controle de Acesso (IAM)" do recurso do Projeto de IA do Azure no portal do Azure. - CLI do Azure instalada.
- Você está conectado à sua conta do Azure executando
az login
. - Observe que, se você tiver várias assinaturas do Azure, a assinatura que contém o recurso do Projeto de IA do Azure deverá ser sua assinatura padrão. Execute
az account list --output table
para listar toda a sua assinatura e ver qual é o padrão. Executeaz account set --subscription "Your Subscription ID or Name"
para alterar sua assinatura padrão.
- A função
Instalar o pacote
npm install @azure/ai-projects
Principais conceitos
Criar e autenticar o cliente
O método de fábrica de classe fromConnectionString
é usado para construir o cliente. Para construir um 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(),
);
Exemplos
Enumerar conexões
Seu projeto do Azure AI Foundry tem um "Centro de Gerenciamento". Ao inseri-lo, você verá uma guia chamada "Recursos conectados" em seu projeto. As operações de .connections
no cliente permitem enumerar as conexões e obter propriedades de conexão. As propriedades de conexão incluem a URL do recurso e as credenciais de autenticação, entre outras coisas.
Abaixo estão exemplos de código das operações de conexão. Exemplos completos podem ser encontrados na pasta "conexões" nos [exemplos de pacote][exemplos].
Obter propriedades de todas as conexões
Para listar as propriedades de todas as conexões no projeto do Azure AI Foundry:
const connections = await client.connections.listConnections();
for (const connection of connections) {
console.log(connection);
}
Obter propriedades de todas as conexões de um tipo específico
Para listar as propriedades de conexões de um determinado tipo (aqui Azure OpenAI):
const connections = await client.connections.listConnections({ category: "AzureOpenAI" });
for (const connection of connections) {
console.log(connection);
}
Obter propriedades de uma conexão por seu nome de conexão
Para obter as propriedades de conexão de uma conexão chamada connectionName
:
const connection = await client.connections.getConnection("connectionName");
console.log(connection);
Para obter as propriedades de conexão com suas credenciais de autenticação:
const connection = await client.connections.getConnectionWithSecrets("connectionName");
console.log(connection);
Agentes (versão prévia)
Os agentes na biblioteca de clientes de Projetos de IA do Azure foram projetados para facilitar várias interações e operações em seus projetos de IA. Eles servem como componentes principais que gerenciam e executam tarefas, aproveitando diferentes ferramentas e recursos para atingir metas específicas. As etapas a seguir descrevem a sequência típica para interagir com agentes. Consulte a pasta "agents" nos [exemplos de pacote][exemplos] para obter exemplos adicionais do Agente.
Os agentes estão sendo desenvolvidos ativamente. Um formulário de inscrição para visualização privada será criado em breve.
Criar Agente
Aqui está um exemplo de como criar um Agente:
const agent = await client.agents.createAgent("gpt-4o", {
name: "my-agent",
instructions: "You are a helpful assistant",
});
Para permitir que os Agentes acessem seus recursos ou funções personalizadas, você precisa de ferramentas. Você pode passar ferramentas para createAgent
pelos argumentos tools
e toolResources
.
Você pode usar ToolSet
para fazer isso:
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}`);
Criar agente com pesquisa de arquivo
Para executar a pesquisa de arquivos por um Agente, primeiro precisamos carregar um arquivo, criar um repositório de vetores e associar o arquivo ao repositório de vetores. Aqui está um exemplo:
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}`);
Criar agente com interpretador de código
Aqui está um exemplo para carregar um arquivo e usá-lo para interpretador de código por um 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}`);
Criar agente com aterramento do Bing
Para permitir que o Agente execute a pesquisa por meio da API de pesquisa do Bing, você usa ToolUtility.createConnectionTool()
junto com uma conexão.
Aqui está um exemplo:
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}`);
Criar agente com o Azure AI Search
O Azure AI Search é um sistema de pesquisa empresarial para aplicativos de alto desempenho. Ele se integra ao Serviço OpenAI do Azure e ao Azure Machine Learning, oferecendo tecnologias avançadas de pesquisa, como pesquisa de vetor e pesquisa de texto completo. Ideal para insights da base de dados de conhecimento, descoberta de informações e automação
Aqui está um exemplo para integrar o 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}`);
Criar agente com chamada de função
Você pode aprimorar seus Agentes definindo funções de retorno de chamada como ferramentas de função. Eles podem ser fornecidos para createAgent
por meio da combinação de tools
e toolResources
. Somente as definições e descrições de função são fornecidas para createAgent
, sem as implementações. O Run
ou event handler of stream
gerará um status de requires_action
com base nas definições de função. Seu código deve lidar com esse status e chamar as funções apropriadas.
Aqui está um exemplo:
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}`);
Criar Thread
Para cada sessão ou conversa, um thread é necessário. Aqui está um exemplo:
const thread = await client.agents.createThread();
Criar thread com recurso de ferramenta
Em alguns cenários, talvez seja necessário atribuir recursos específicos a threads individuais. Para conseguir isso, forneça o argumento toolResources
para createThread
. No exemplo a seguir, você cria um repositório de vetores e carrega um arquivo, habilita um Agente para pesquisa de arquivos usando o argumento tools
e associa o arquivo ao thread usando o 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 });
Criar Mensagem
Para criar uma mensagem para o assistente processar, você passa user
como role
e uma pergunta como content
:
const message = await client.agents.createMessage(thread.id, {
role: "user",
content: "hello, world!",
});
Criar mensagem com anexo de pesquisa de arquivo
Para anexar um arquivo a uma mensagem de pesquisa de conteúdo, use ToolUtility.createFileSearchTool()
e o 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],
},
});
Criar mensagem com anexo do interpretador de código
Para anexar um arquivo a uma mensagem para análise de dados, use ToolUtility.createCodeInterpreterTool()
e o argumento attachment
.
Aqui está um exemplo:
// 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}`);
Criar Execução, Run_and_Process ou Stream
Aqui está um exemplo de createRun
e sondagem até que a execução seja concluída:
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 ter a pesquisa do SDK em seu nome, use o método createThreadAndRun
.
Aqui está um exemplo:
const run = await client.agents.createThreadAndRun(thread.id, agent.id);
Com o streaming, a sondagem também não precisa ser considerada.
Aqui está um exemplo:
const streamEventMessages = await client.agents.createRun(thread.id, agent.id).stream();
O tratamento de eventos pode ser feito da seguinte maneira:
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 Mensagem
Para recuperar mensagens de agentes, use o seguinte exemplo:
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 Arquivo
Os arquivos carregados pelos Agentes não podem ser recuperados novamente. Se o caso de uso precisar acessar o conteúdo do arquivo carregado pelos Agentes, você será aconselhado a manter uma cópia adicional acessível pelo aplicativo. No entanto, os arquivos gerados pelos Agentes são recuperáveis por getFileContent
.
Aqui está um exemplo de recuperação de IDs de arquivo de mensagens:
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}`);
Subdivisão
Para remover recursos após a conclusão das tarefas, use as seguintes funções:
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}`);
Rastreamento
Você pode adicionar um recurso do Azure do Application Insights ao seu projeto do Azure AI Foundry. Consulte a guia Rastreamento em seu estúdio. Se um tiver sido habilitado, você poderá obter a cadeia de conexão do Application Insights, configurar seus Agentes e observar o caminho de execução completo por meio do Azure Monitor. Normalmente, talvez você queira iniciar o rastreamento antes de criar um Agente.
Instalação
Instale o OpenTelemetry e o plug-in de rastreamento do SDK do Azure por meio do
npm install @opentelemetry/api \
@opentelemetry/instrumentation \
@opentelemetry/sdk-trace-node \
@azure/opentelemetry-instrumentation-azure-sdk \
@azure/monitor-opentelemetry-exporter
Você também precisará de um exportador para enviar telemetria para seu back-end de observabilidade. Você pode imprimir rastreamentos no console ou usar um visualizador local, como de Painel do Aspire.
Para se conectar ao Aspire Dashboard ou a outro back-end compatível com OpenTelemetry, instale o exportador OTLP:
npm install @opentelemetry/exporter-trace-otlp-proto \
@opentelemetry/exporter-metrics-otlp-proto
Exemplo de rastreamento
Aqui está um exemplo de código a ser incluído acima 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})
// ...
Solucionando problemas
Exceções
Os métodos de cliente que fazem chamadas de serviço geram uma restError code
da exceção conterá o código de status de resposta HTTP. O error.message
da exceção contém uma mensagem detalhada que pode ser útil para diagnosticar o 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 exemplo, quando você fornece credenciais erradas:
Status code: 401 (Unauthorized)
Operation returned an invalid status 'Unauthorized'
Relatar problemas
Para relatar problemas com a biblioteca de clientes ou solicitar recursos adicionais, abra um problema do GitHub aqui
Contribuindo
Este projeto recebe contribuições e sugestões. A maioria das contribuições exige que você concorde com um CLA (Contrato de Licença de Colaborador) declarando que você tem o direito de, e realmente fazer, conceder-nos os direitos de usar sua contribuição. Para obter detalhes, visite https://cla.microsoft.com.
Ao enviar uma solicitação de pull, um CLA-bot determinará automaticamente se você precisa fornecer um CLA e decorar a PR adequadamente (por exemplo, rótulo, comentário). Basta seguir as instruções fornecidas pelo bot. Você só precisará fazer isso uma vez em todos os repositórios usando nosso CLA.
Este projeto adotou o
Azure SDK for JavaScript