你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

适用于 JavaScript 的 Azure AI 代理客户端库 - 版本 1.0.0

使用 AI Agents 客户端库可以:

  • 使用 Azure AI 代理服务开发代理,利用 OpenAI、Microsoft 和其他 LLM 提供商提供的大量模型、工具和功能生态系统。 Azure AI 代理服务支持为各种生成式 AI 用例构建代理。
  • 注意: 虽然此包可以独立使用,但我们建议使用 Azure AI Projects 客户端库 来增强体验。 Projects 库提供了对高级功能的简化访问,例如创建和管理代理、枚举 AI 模型、使用数据集和管理搜索索引、评估生成式 AI 性能以及启用 OpenTelemetry 跟踪。

产品文档 | 样品 | 包 (npm) | API 参考文档

目录

入门指南

先决条件

授权

  • 需要 Entra ID 来验证客户端。 应用程序需要实现 TokenCredential 接口的对象。 此处的代码示例使用 DefaultAzureCredential。 若要使该工作正常,需要:
    • Contributor 角色。 可以通过 Azure 门户中 Azure AI 项目资源的“访问控制(IAM)”选项卡完成分配的角色。 在此处了解有关角色分配的更多信息。
    • 已安装 Azure CLI
    • 通过运行 az login登录到 Azure 帐户。
    • 请注意,如果有多个 Azure 订阅,则包含 Azure AI 项目资源的订阅必须是默认订阅。 运行 az account list --output table 列出所有订阅,并查看默认订阅。 运行 az account set --subscription "Your Subscription ID or Name" 以更改默认订阅。

安装软件包

npm install @azure/ai-agents @azure/identity

重要概念

创建客户端并对其进行身份验证

用于 AgentsClient 构造客户端。 目前,我们建议您通过 client.agents使用 AgentsClient。

要获取项目终端节点,您可以参考 文档。 下面我们假设环境变量 PROJECT_ENDPOINT 保存此值。

import { AgentsClient } from "@azure/ai-agents";
import { DefaultAzureCredential } from "@azure/identity";

const projectEndpoint = process.env["PROJECT_ENDPOINT"] || "<project endpoint>";
const modelDeploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "gpt-4o";
const client = new AgentsClient(projectEndpoint, new DefaultAzureCredential());

例子

代理人

Azure AI Projects 客户端库中的代理旨在促进 AI 项目中的各种交互和操作。 它们充当管理和执行任务的核心组件,利用不同的工具和资源来实现特定目标。 以下步骤概述了与代理交互的典型顺序。 有关其他代理示例,请参阅 包示例

创建代理

下面是有关如何创建代理的示例:

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

若要允许代理访问资源或自定义函数,需要工具。 可以将工具传递给 createAgenttoolstoolResources 参数。

可以使用 ToolSet 执行此操作:

import { ToolSet } from "@azure/ai-agents";

// Upload file for code interpreter tool
const filePath1 = "./data/syntheticCompanyQuarterlyResults.csv";
const fileStream1 = fs.createReadStream(filePath1);
const codeInterpreterFile = await client.files.upload(fileStream1, "assistants", {
  fileName: "myLocalFile",
});
console.log(`Uploaded local file, file ID : ${codeInterpreterFile.id}`);
// Upload file for file search tool
const filePath2 = "./data/sampleFileForUpload.txt";
const fileStream2 = fs.createReadStream(filePath2);
const fileSearchFile = await client.files.upload(fileStream2, "assistants", {
  fileName: "sampleFileForUpload.txt",
});
console.log(`Uploaded file, file ID: ${fileSearchFile.id}`);
// Create vector store for file search tool
const vectorStore = await client.vectorStores
  .createAndPoll({
    fileIds: [fileSearchFile.id],
  })
  .pollUntilDone();
// Create tool set
const toolSet = new ToolSet();
toolSet.addFileSearchTool([vectorStore.id]);
toolSet.addCodeInterpreterTool([codeInterpreterFile.id]);

// Create agent with tool set
const agent = await client.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}`);

若要按代理执行文件搜索,首先需要上传文件、创建向量存储并将该文件关联到向量存储。 下面是一个示例:

import { ToolUtility } from "@azure/ai-agents";

const filePath = "./data/sampleFileForUpload.txt";
const localFileStream = fs.createReadStream(filePath);
const file = await client.files.upload(localFileStream, "assistants", {
  fileName: "sampleFileForUpload.txt",
});
console.log(`Uploaded file, file ID: ${file.id}`);

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

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

const agent = await client.createAgent("gpt-4o", {
  name: "File Search Agent",
  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}`);

使用代码解释器创建代理

下面是上传文件并将其用于代理的代码解释器的示例:

import { ToolUtility } from "@azure/ai-agents";

const filePath = "./data/syntheticCompanyQuarterlyResults.csv";
const localFileStream = fs.createReadStream(filePath);
const localFile = await client.files.upload(localFileStream, "assistants", {
  fileName: "localFile",
});

console.log(`Uploaded local file, file ID : ${localFile.id}`);

const codeInterpreterTool = ToolUtility.createCodeInterpreterTool([localFile.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.createAgent("gpt-4o", {
  name: "my-agent",
  instructions: "You are a helpful agent",
  tools: [codeInterpreterTool.definition],
  toolResources: codeInterpreterTool.resources,
});
console.log(`Created agent, agent ID: ${agent.id}`);

使用必应地面创建代理

若要使代理能够通过必应搜索 API 执行搜索,请使用 ToolUtility.createBingGroundingTool() 以及连接。 请参阅 此处 以了解有关使用 Bing Search 进行 Grounding 的更多信息。

下面是一个示例:

import { ToolUtility } from "@azure/ai-agents";

const connectionId = process.env["AZURE_BING_CONNECTION_ID"] || "<connection-name>";

// Initialize agent bing tool with the connection id
const bingTool = ToolUtility.createBingGroundingTool([{ connectionId: connectionId }]);

// Create agent with the bing tool and process assistant run
const agent = await client.createAgent("gpt-4o", {
  name: "my-agent",
  instructions: "You are a helpful agent",
  tools: [bingTool.definition],
});
console.log(`Created agent, agent ID : ${agent.id}`);

Azure AI 搜索是适用于高性能应用程序的企业搜索系统。 它与 Azure OpenAI 服务和 Azure 机器学习集成,提供高级搜索技术,如矢量搜索和全文搜索。 非常适合知识库见解、信息发现和自动化

下面是集成 Azure AI 搜索的示例:

import { ToolUtility } from "@azure/ai-agents";

const connectionName = process.env["AZURE_AI_SEARCH_CONNECTION_NAME"] || "<connection-name>";

// Initialize Azure AI Search tool
const azureAISearchTool = ToolUtility.createAzureAISearchTool(connectionName, "search-index", {
  queryType: "simple",
  topK: 3,
  filter: "", // Add string here to filter results
  indexConnectionId: connectionName,
  indexName: "search-index",
});

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

使用函数调用创建代理

可以通过将回调函数定义为函数工具来增强代理。 可以通过 createAgenttools的组合提供这些内容来 toolResources。 只有函数定义和说明提供给 createAgent,而不提供实现。 Runevent handler of stream 将根据函数定义引发 requires_action 状态。 代码必须处理此状态并调用相应的函数。

下面是一个示例:

import {
  FunctionToolDefinition,
  ToolUtility,
  RequiredToolCall,
  ToolOutput,
} from "@azure/ai-agents";

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: RequiredToolCall & FunctionToolDefinition): ToolOutput | undefined {
    console.log(`Function tool call - ${toolCall.function.name}`);
    const args: any[] = [];
    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;
      }
    }
    // Create a mapping of function names to their implementations
    const functionMap = new Map(
      this.functionTools.map((tool) => [tool.definition.function.name, tool.func]),
    );
    const result = functionMap.get(toolCall.function.name)?.(...args);
    return result
      ? {
          toolCallId: toolCall.id,
          output: JSON.stringify(result),
        }
      : {
          toolCallId: toolCall.id,
          output: JSON.stringify({
            error: `No matching tool found for function: ${toolCall.function.name}`,
          }),
        };
  }

  public getFunctionDefinitions(): FunctionToolDefinition[] {
    return this.functionTools.map((tool) => {
      return tool.definition;
    });
  }
}
const functionToolExecutor = new FunctionToolExecutor();
const functionTools = functionToolExecutor.getFunctionDefinitions();
const agent = await client.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}`);

使用 OpenAPI 创建代理

OpenAPI 规范描述针对特定终结点的 REST作。 代理 SDK 可以读取 OpenAPI 规范、从中创建函数,并针对 REST 终结点调用该函数,而无需执行其他客户端。 下面是创建 OpenAPI 工具(使用匿名身份验证)的示例:

import { ToolUtility } from "@azure/ai-agents";

// Read in OpenApi spec
const filePath = "./data/weatherOpenApi.json";
const openApiSpec = JSON.parse(fs.readFileSync(filePath, "utf-8"));

// Define OpenApi function
const openApiFunction = {
  name: "getWeather",
  spec: openApiSpec,
  description: "Retrieve weather information for a ___location",
  auth: {
    type: "anonymous",
  },
  default_params: ["format"], // optional
};

// Create OpenApi tool
const openApiTool = ToolUtility.createOpenApiTool(openApiFunction);

// Create agent with OpenApi tool
const agent = await client.createAgent("gpt-4o", {
  name: "myAgent",
  instructions: "You are a helpful agent",
  tools: [openApiTool.definition],
});
console.log(`Created agent, agent ID: ${agent.id}`);

创建线程

对于每个会话或对话,需要一个线程。 下面是一个示例:

const thread = await client.threads.create();
console.log(`Created thread, thread ID: ${thread.id}`);

使用工具资源创建线程

在某些情况下,可能需要将特定资源分配给单个线程。 为此,请提供 toolResourcesthreads.create 参数。 在下面的示例中,创建矢量存储并上传文件,使用 tools 参数启用代理进行文件搜索,然后使用 toolResources 参数将该文件与线程相关联。

import { ToolUtility } from "@azure/ai-agents";

const filePath = "./data/syntheticCompanyQuarterlyResults.csv";
const localFileStream = fs.createReadStream(filePath);
const file = await client.files.upload(localFileStream, "assistants", {
  fileName: "sample_file_for_upload.csv",
});
console.log(`Uploaded file, ID: ${file.id}`);

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

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

const agent = await client.agents.createAgent("gpt-4o", {
  name: "myAgent",
  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.threads.create({ toolResources: fileSearchTool.resources });

列出线程

要列出附加到给定代理的所有线程,请使用 threads.list

const threads = client.threads.list();
console.log(`Threads for agent ${agent.id}:`);
for await (const t of threads) {
  console.log(`Thread ID: ${t.id}`);
  console.log(`Created at: ${t.createdAt}`);
  console.log(`Metadata: ${t.metadata}`);
  console.log(`---- `);
}

创建消息

若要为助手创建要处理的消息,请将 user 作为 role 传递,并将问题作为 content传递:

const message = await client.messages.create(thread.id, "user", "hello, world!");
console.log(`Created message, message ID: ${message.id}`);

使用文件搜索附件创建邮件

若要将文件附加到消息进行内容搜索,请使用 ToolUtility.createFileSearchTool()attachments 参数:

import { ToolUtility } from "@azure/ai-agents";

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

使用代码解释器附件创建消息

若要将文件附加到消息以供数据分析,请使用 ToolUtility.createCodeInterpreterTool()attachment 参数。

下面是一个示例:

import { ToolUtility } from "@azure/ai-agents";

// 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-4o", {
  name: "my-assistant",
  instructions: "You are helpful assistant",
  tools: [codeInterpreterTool.definition],
});
console.log(`Created agent, agent ID: ${agent.id}`);

const thread = await client.threads.create();
console.log(`Created thread, thread ID: ${thread.id}`);

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

使用图像输入创建消息

可以通过以下方式将消息发送到包含映像输入的 Azure 代理:

  • 使用存储为上传文件的图像
  • 使用可通过 URL 访问的公共映像
  • 使用 base64 编码的图像字符串

以下示例演示了 base64 方法:

使用 base64 编码的图像输入创建消息
function imageToBase64DataUrl(imagePath: string, mimeType: string): string {
  try {
    // Read the image file as binary
    const imageBuffer = fs.readFileSync(imagePath);
    // Convert to base64
    const base64Data = imageBuffer.toString("base64");
    // Format as a data URL
    return `data:${mimeType};base64,${base64Data}`;
  } catch (error) {
    console.error(`Error reading image file at ${imagePath}:`, error);
    throw error;
  }
}

// Convert your image file to base64 format
const filePath = "./data/image_file.png";
const imageDataUrl = imageToBase64DataUrl(filePath, "image/png");

// Create a message with both text and image content
console.log("Creating message with image content...");
const inputMessage = "Hello, what is in the image?";
const content = [
  {
    type: "text",
    text: inputMessage,
  },
  {
    type: "image_url",
    image_url: {
      url: imageDataUrl,
      detail: "high",
    },
  },
];

const message = await client.messages.create(thread.id, "user", content);
console.log(`Created message, message ID: ${message.id}`);

创建运行、Run_and_Process或流

下面是在运行完成之前 runs.create 和轮询的示例:

// Create and poll a run
console.log("Creating run...");
const run = await client.runs.createAndPoll(thread.id, agent.id, {
  pollingOptions: {
    intervalInMs: 2000,
  },
  onResponse: (response): void => {
    console.log(`Received response with status: ${response.parsedBody.status}`);
  },
});
console.log(`Run finished with status: ${run.status}`);

若要代表你轮询 SDK,请使用 createThreadAndRun 方法。

下面是一个示例:

const run = await client.runs.createThreadAndRun(agent.id, {
  thread: {
    messages: [
      {
        role: "user",
        content: "hello, world!",
      },
    ],
  },
});

使用流式处理时,也无需考虑轮询。

下面是一个示例:

const streamEventMessages = await client.runs.create(thread.id, agent.id).stream();

事件处理可以按如下方式完成:

import { RunStreamEvent, MessageStreamEvent, ErrorEvent, DoneEvent } from "@azure/ai-agents";

const streamEventMessages = await client.runs.create(thread.id, agent.id).stream();

for await (const eventMessage of streamEventMessages) {
  switch (eventMessage.event) {
    case RunStreamEvent.ThreadRunCreated:
      console.log(`ThreadRun status: ${eventMessage.data.status}`);
      break;
    case MessageStreamEvent.ThreadMessageDelta:
      {
        const messageDelta = eventMessage.data;
        messageDelta.delta.content.forEach((contentPart) => {
          if (contentPart.type === "text") {
            const textContent = contentPart;
            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 messagesIterator = client.messages.list(thread.id);
const allMessages = [];
for await (const m of messagesIterator) {
  allMessages.push(m);
}
console.log("Messages:", allMessages);

// The messages are following in the reverse order,
// we will iterate them and output only text contents.
const messages = await client.messages.list(thread.id, {
  order: "asc",
});

for await (const dataPoint of messages) {
  const textContent = dataPoint.content.find((item) => item.type === "text");
  if (textContent && "text" in textContent) {
    console.log(`${dataPoint.role}: ${textContent.text.value}`);
  }
}

检索文件

无法检索代理上传的文件。 如果用例需要访问代理上传的文件内容,建议保留应用程序可访问的其他副本。 但是,代理生成的文件可通过 files.getContent检索。

下面是从消息检索文件 ID 的示例:

import { isOutputOfType, MessageTextContent, MessageImageFileContent } from "@azure/ai-agents";

const messagesIterator = client.messages.list(thread.id);
const allMessages = [];
for await (const m of messagesIterator) {
  allMessages.push(m);
}
console.log("Messages:", allMessages);

// Get most recent message from the assistant
const assistantMessage = allMessages.find((msg) => msg.role === "assistant");
if (assistantMessage) {
  const textContent = assistantMessage.content.find((content) =>
    isOutputOfType<MessageTextContent>(content, "text"),
  ) as MessageTextContent;
  if (textContent) {
    console.log(`Last message: ${textContent.text.value}`);
  }
}

const imageFile = (allMessages[0].content[0] as MessageImageFileContent).imageFile;
const imageFileName = (await client.agents.files.get(imageFile.fileId)).filename;

const fileContent = await (await client.files.getContent(imageFile.fileId).asNodeStream()).body;
if (fileContent) {
  const chunks: Buffer[] = [];
  for await (const chunk of fileContent) {
    chunks.push(Buffer.isBuffer(chunk) ? chunk : 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.vectorStores.delete(vectorStore.id);
console.log(`Deleted vector store, vector store ID: ${vectorStore.id}`);

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

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

故障排除

例外

发出服务调用的客户端方法会引发 RestError,以响应来自该服务的非成功 HTTP 状态代码响应。 异常 code 将保留 HTTP 响应状态代码。 异常 error.message 包含可能有助于诊断问题的详细消息:

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

try {
  const thread = await client.threads.create();
} catch (e) {
  if (e instanceof RestError) {
    console.log(`Status code: ${e.code}`);
    console.log(e.message);
  } else {
    console.error(e);
  }
}

例如,提供错误的凭据时:

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

报告问题

若要报告客户端库问题或请求其他功能,请在此处 打开 GitHub 问题

后续步骤

查看 包示例 文件夹,其中包含完全可运行的代码。

贡献

此项目欢迎贡献和建议。 大多数贡献要求你同意参与者许可协议(CLA),声明你有权(实际这样做)授予我们使用你的贡献的权利。 有关详细信息,请访问 https://cla.microsoft.com

提交拉取请求时,CLA 机器人会自动确定是否需要提供 CLA 并适当修饰 PR(例如标签、注释)。 只需按照机器人提供的说明进行操作。 只需使用 CLA 在所有存储库中执行此操作一次。

该项目已采用 Microsoft开源行为准则。 有关详细信息,请参阅《行为准则常见问题解答》或联系 opencode@microsoft.com,了解任何其他问题或意见。