使用 AI Agents 用戶端庫可以:
- 使用 Azure AI 代理程式服務開發代理程式,利用 OpenAI、Microsoft 和其他 LLM 提供者的廣泛模型、工具和功能生態系統。 Azure AI 代理程式服務可讓您為各種產生式 AI 使用案例建置代理程式。
- 注意: 雖然此包可以獨立使用,但我們建議使用 Azure AI Projects 用戶端庫 來增強體驗。 Projects 庫提供了對高級功能的簡化訪問,例如創建和管理代理、枚舉 AI 模型、使用數據集和管理搜索索引、評估生成式 AI 性能以及啟用 OpenTelemetry 跟蹤。
產品文件 | 樣品 | 包 (npm) | API 參考文件
目錄
入門指南
先決條件
- LTS 版本的 Node.js
- Azure 訂用帳戶。
- Azure AI Foundry中的
專案。
授權
- 需要 Entra ID 來驗證用戶端。 您的應用程式需要實作 TokenCredential 介面的物件。 這裡的程式代碼範例會使用 DefaultAzureCredential。 若要讓該作業正常運作,您將需要:
-
Contributor角色。 在 Azure 入口網站中,您可以透過 Azure AI 專案資源的 [存取控制] 索引標籤來完成指派的角色。 在此處了解有關角色分配的更多資訊。 - 已安裝 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-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 專案用戶端連結庫中的代理程式是設計來協助 AI 專案內的各種互動和作業。 它們可作為管理和執行工作的核心元件,利用不同的工具和資源來達成特定目標。 下列步驟概述與 Agents 互動的典型順序。 有關其他代理範例,請參閱 包示例 。
建立代理程式
以下是如何建立代理程式的範例:
const agent = await client.createAgent("gpt-4o", {
name: "my-agent",
instructions: "You are a helpful assistant",
});
若要允許代理程式存取您的資源或自定義函式,您需要工具。 您可以將工具傳遞至 createAgenttools 和 toolResources 自變數。
您可以使用 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 connectedAgentName = "stock_price_bot";
const modelDeploymentName = process.env["MODEL_DEPLOYMENT_NAME"] || "gpt-4o";
const stockAgent = await client.createAgent(modelDeploymentName, {
name: "stock-price-agent",
instructions:
"Your job is to get the stock price of a company. If you don't know the realtime stock price, return the last known stock price.",
});
// Initialize Connected Agent tool with the agent id, name, and description
const connectedAgentTool = ToolUtility.createConnectedAgentTool(
stockAgent.id,
connectedAgentName,
"Gets the stock price of a company",
);
// Create agent with the Connected Agent tool and process assistant run
const agent = await client.createAgent(modelDeploymentName, {
name: "my-agent",
instructions: "You are a helpful assistant, and use the connected agent to get stock prices.",
tools: [connectedAgentTool.definition],
});
console.log(`Created agent, agent ID: ${agent.id}`);
使用檔案搜尋建立代理程式
若要執行 Agent 的檔案搜尋,我們必須先上傳檔案、建立向量存放區,並將檔案與向量存放區產生關聯。 以下是範例:
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}`);
使用程式代碼解釋器建立代理程式
以下是上傳檔案並將其用於 Agent 程式代碼解釋器的範例:
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}`);
使用 Bing 地面建立代理程式
若要讓代理程式透過 Bing 搜尋 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 AI 搜尋是高效能應用程式的企業搜尋系統。 它與 Azure OpenAI 服務和 Azure Machine Learning 整合,提供向量搜尋和全文搜索等進階搜尋技術。 適用於知識庫深入解析、資訊探索和自動化
以下是整合 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}`);
使用函數調用建立代理程式
您可以將回呼函式定義為函式工具,以增強代理程式。 您可以透過 createAgent 和 tools的組合,將這些專案提供給 toolResources。 只有函式定義和描述會提供給 createAgent,而不需要實作。
Run 或 event 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}`);
使用工具資源建立線程
在某些情況下,您可能需要將特定資源指派給個別線程。 若要達成此目的,您會提供 toolResources 自變數給 threads.create。 在下列範例中,您會建立向量存放區並上傳檔案、使用 tools 自變數啟用 Agent 進行檔案搜尋,然後使用 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",
imageUrl: {
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或 Stream
以下是 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擷取。
以下是從訊息擷取檔案標識碼的範例:
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}`);
故障排除
例外狀況
進行服務呼叫的用戶端方法會針對來自服務的非成功 HTTP 狀態代碼回應,引發 RestError。 例外狀況的 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-Bot 會自動判斷您是否需要提供 CLA 並適當裝飾 PR(例如標籤、批註)。 只要遵循 Bot 所提供的指示即可。 您只需要使用我們的 CLA 在所有存放庫上執行此動作一次。
此專案採用了 Microsoft 開放原始碼管理辦法。 如需詳細資訊,請參閱《管理辦法》常見問題或連絡 opencode@microsoft.com,以取得任何其他問題或意見。