次の方法で共有


JavaScript 用 Azure AI Projects クライアント ライブラリ - バージョン 1.0.0-beta.2

AI Projects クライアント ライブラリ (プレビュー段階) を使用して、次の手順を実行します。

  • Azure AI Foundry プロジェクトで 接続を列挙し、接続プロパティを取得します。 たとえば、Azure OpenAI 接続に関連付けられている推論エンドポイントの URL と資格情報を取得します。
  • Azure AI Agent Serviceを使用してエージェントを開発し、OpenAI、Microsoft、およびその他の LLM プロバイダーからのモデル、ツール、機能の広範なエコシステムを活用します。 Azure AI エージェント サービスを使用すると、さまざまな生成 AI ユース ケースに対してエージェントを構築できます。 パッケージは現在プライベート プレビュー段階です。
  • OpenTelemetry トレースを有効にします。

製品のドキュメント

目次

はじめ

前提

  • Node.js の LTS バージョンを する
  • Azure サブスクリプション
  • Azure AI Foundryの プロジェクト。
  • プロジェクト接続文字列。 これは、Azure AI Foundry プロジェクトの概要ページの [プロジェクトの詳細] にあります。 以下では、この値を保持 AZURE_AI_PROJECTS_CONNECTION_STRING 環境変数が定義されていることを前提としています。
  • クライアントを認証するには、Entra ID が必要です。 アプリケーションには、TokenCredential インターフェイスを実装するオブジェクトが必要です。 ここでのコード サンプルでは、DefaultAzureCredential使用します。 この作業を行うには、次のものが必要です。
    • Contributor ロール。 割り当てられたロールは、Azure portal の Azure AI プロジェクト リソースの [アクセス制御 (IAM)]タブを使用して実行できます。
    • Azure CLI インストール
    • az loginを実行して、Azure アカウントにログインします。
    • 複数の Azure サブスクリプションがある場合は、Azure AI Project リソースを含むサブスクリプションが既定のサブスクリプションである必要があることに注意してください。 az account list --output table 実行して、すべてのサブスクリプションを一覧表示し、既定のサブスクリプションを確認します。 az account set --subscription "Your Subscription ID or Name" を実行して、既定のサブスクリプションを変更します。

パッケージをインストールする

npm install @azure/ai-projects

主な概念

クライアントを作成して認証する

fromConnectionString クラス ファクトリ メソッドは、クライアントの構築に使用されます。 クライアントを構築するには:

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

接続を列挙する

Azure AI Foundry プロジェクトに "管理センター" があります。 入力すると、プロジェクトの下に [接続済みリソース] という名前のタブが表示されます。 クライアントに対する .connections 操作を使用すると、接続を列挙し、接続プロパティを取得できます。 接続プロパティには、リソース URL と認証資格情報などが含まれます。

接続操作のコード例を次に示します。 完全なサンプルは、[パッケージ サンプル][samples]の "connections" フォルダーにあります。

すべての接続のプロパティを取得する

Azure AI Foundry プロジェクト内のすべての接続のプロパティを一覧表示するには:

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

特定の型のすべての接続のプロパティを取得する

特定の種類の接続のプロパティを一覧表示するには (ここでは Azure OpenAI)。

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

接続名で接続のプロパティを取得する

connectionNameという名前の接続の接続プロパティを取得するには:

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

認証資格情報を使用して接続プロパティを取得するには:

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

エージェント (プレビュー)

Azure AI Projects クライアント ライブラリのエージェントは、AI プロジェクト内のさまざまな対話と操作を容易にするように設計されています。 タスクを管理および実行するコア コンポーネントとして機能し、さまざまなツールとリソースを活用して特定の目標を達成します。 次の手順では、エージェントと対話するための一般的なシーケンスについて説明します。 その他のエージェント サンプルについては、[パッケージ サンプル][サンプル] の "agents" フォルダーを参照してください。

エージェントは積極的に開発されています。 プライベート プレビューのサインアップ フォームは近日公開予定です。

エージェントの作成

エージェントを作成する方法の例を次に示します。

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

エージェントがリソースまたはカスタム関数にアクセスできるようにするには、ツールが必要です。 tools 引数と toolResources 引数を使用して createAgent するツールを渡すことができます。

ToolSet を使用してこれを行うことができます。

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

エージェントによるファイル検索を実行するには、まずファイルをアップロードし、ベクター ストアを作成し、そのファイルをベクター ストアに関連付ける必要があります。 次に例を示します。

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

コード インタープリターを使用してエージェントを作成する

ファイルをアップロードし、エージェントによるコード インタープリターに使用する例を次に示します。

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

Bing Grounding を使用してエージェントを作成する

エージェントが検索 API を使用して検索Bing実行できるようにするには、接続と共に ToolUtility.createConnectionTool() を使用します。

次に例を示します。

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 は、高パフォーマンス アプリケーション用のエンタープライズ検索システムです。 Azure OpenAI Service および Azure Machine Learning と統合され、ベクター検索やフルテキスト検索などの高度な検索テクノロジが提供されます。 ナレッジ ベースの分析情報、情報の検出、自動化に最適

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

関数呼び出しを使用してエージェントを作成する

コールバック関数を関数ツールとして定義することで、エージェントを拡張できます。 これらは、toolstoolResourcesの組み合わせを介して createAgent に提供することができます. createAgentには、実装なしで関数の定義と説明のみが提供されます。 Run または event handler of stream では、関数定義に基づいて requires_action 状態が発生します。 コードでこの状態を処理し、適切な関数を呼び出す必要があります。

次に例を示します。

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

スレッドの作成

セッションまたは会話ごとに、スレッドが必要です。 次に例を示します。

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

ツール リソースを使用してスレッドを作成する

シナリオによっては、個々のスレッドに特定のリソースを割り当てる必要がある場合があります。 これを実現するには、createThreadtoolResources 引数を指定します。 次の例では、ベクター ストアを作成してファイルをアップロードし、tools 引数を使用してエージェントでファイル検索を有効にしてから、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 });

メッセージの作成

アシスタントが処理するメッセージを作成するには、userrole として渡し、質問を contentとして渡します。

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

ファイル検索添付ファイルを含むメッセージを作成する

コンテンツ検索用のメッセージにファイルを添付するには、ToolUtility.createFileSearchTool() 引数と 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],
  },
});

コード インタープリター添付ファイルを含むメッセージを作成する

データ分析のためにファイルをメッセージに添付するには、ToolUtility.createCodeInterpreterTool()attachment 引数を使用します。

次に例を示します。

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

実行、Run_and_Process、またはストリームの作成

実行が完了するまでの createRun とポーリングの例を次に示します。

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

代わりに SDK をポーリングするには、createThreadAndRun メソッドを使用します。

次に例を示します。

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

ストリーミングでは、ポーリングも考慮する必要はありません。

次に例を示します。

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

イベント処理は次のように実行できます。

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

メッセージの取得

エージェントからメッセージを取得するには、次の例を使用します。

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

ファイルの取得

エージェントによってアップロードされたファイルを取得することはできません。 ユース ケースがエージェントによってアップロードされたファイル コンテンツにアクセスする必要がある場合は、アプリケーションからアクセス可能な追加のコピーを保持することをお勧めします。 ただし、エージェントによって生成されたファイルは、getFileContentで取得できます。

メッセージからファイル ID を取得する例を次に示します。

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

分解

タスクの完了後にリソースを削除するには、次の関数を使用します。

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

トレーシング

Application Insights Azure リソースを Azure AI Foundry プロジェクトに追加できます。 スタジオの [トレース] タブを参照してください。 有効になっている場合は、Application Insights 接続文字列を取得し、エージェントを構成し、Azure Monitor を介して完全な実行パスを確認できます。 通常は、エージェントを作成する前にトレースを開始できます。

取り付け

OpenTelemetry と Azure SDK トレース プラグインを必ずインストールします。

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

また、監視バックエンドにテレメトリを送信するエクスポーターも必要です。 トレースをコンソールに出力したり、アスパイア ダッシュボードなどのローカル ビューアーを使用したりできます。

アスパイア ダッシュボードまたは別の OpenTelemetry 互換バックエンドに接続するには、OTLP エクスポーターをインストールします。

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

トレースの例

上記の 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})
// ...

トラブルシューティング

例外

サービス呼び出しを行うクライアント メソッドは、サービスからの成功しない HTTP 状態コード応答に対して、RestError を発生させます。 例外の code は、HTTP 応答状態コードを保持します。 例外の error.message には、問題の診断に役立つ詳細なメッセージが含まれています。

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

たとえば、間違った資格情報を指定した場合は、次のようになります。

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

問題の報告

クライアント ライブラリに関する問題を報告したり、追加機能を要求したりするには、 で GitHub の問題 開いてください

貢献

このプロジェクトは、投稿と提案を歓迎します。 ほとんどの投稿では、お客様が投稿を使用する権利を当社に付与する権利を有し、実際に行うことを宣言する共同作成者ライセンス契約 (CLA) に同意する必要があります。 詳細については、https://cla.microsoft.comを参照してください。

プル要求を送信すると、CLA ボットは、CLA を提供し、PR を適切に装飾する必要があるかどうかを自動的に判断します (ラベル、コメントなど)。 ボットによって提供される指示に従うだけです。 これは、CLA を使用するすべてのリポジトリで 1 回だけ行う必要があります。

このプロジェクトでは、Microsoft オープン ソースの行動規範を採用しています。 詳細については、行動規範に関する FAQ を参照するか、その他の質問やコメントを opencode@microsoft.com にお問い合わせください。