共用方式為


適用於 JavaScript 的 Azure OpenAI Assistants 用戶端連結庫 - 1.0.0-beta.5 版

適用於 JavaScript 的 Azure OpenAI 小幫手用戶端連結庫是 OpenAI REST API 的調整,可提供慣用介面,並與其餘 Azure SDK 生態系統的豐富整合。 它可以連線到 Azure OpenAI 資源或非 Azure OpenAI 推斷端點,使其成為甚至是非 Azure OpenAI 開發的絕佳選擇。

重要連結:

開始使用

目前支援的環境

必要條件

如果您想要使用 Azure OpenAI 資源,您必須擁有 Azure 訂 用帳戶和 Azure OpenAI 存取權。 這可讓您建立 Azure OpenAI 資源,並同時取得連線 URL 和 API 金鑰。 如需詳細資訊,請參閱 快速入門:開始使用 Azure OpenAI 服務產生文字

如果您想要使用 Azure OpenAI 小幫手 JS 用戶端連結庫來連線到非 Azure OpenAI,您需要開發人員帳戶的 API 金鑰,網址為 https://platform.openai.com/

安裝 @azure/openai-assistants 套件

使用 npm安裝適用於 JavaScript 的 Azure OpenAI Assistants 用戶端連結庫:

npm install @azure/openai-assistants

建立和驗證 AssistantsClient

若要設定用戶端以搭配 Azure OpenAI 使用,請提供有效的端點 URI 給 Azure OpenAI 資源,以及獲授權使用 Azure OpenAI 資源的對應密鑰認證、令牌認證或 Azure 身分識別。 若要改為將用戶端設定為連線到 OpenAI 的服務,請從 OpenAI 的開發人員入口網站提供 API 金鑰。

從 Azure 使用 API 金鑰

使用 Azure 入口網站 流覽至 OpenAI 資源並擷取 API 金鑰,或使用下列 Azure CLI 代碼段:

注意: 有時候 API 金鑰稱為「訂用帳戶金鑰」或「訂用帳戶 API 金鑰」。

az cognitiveservices account keys list --resource-group <your-resource-group-name> --name <your-resource-name>

重要概念

如需與助理搭配使用的概念和關聯性概觀,請參閱 OpenAI 的「助理運作方式」 檔。 此概觀密切遵循 OpenAI 的概觀範例 ,示範建立、執行和使用助理和線程的基本概念。

若要開始使用,請建立 AssistantsClient

const assistantsClient = new AssistantsClient("<endpoint>", new AzureKeyCredential("<azure_api_key>"));

透過客戶端,接著可以建立 助理。 助理 是 OpenAI 模型的用途建置介面,可呼叫 Tools,同時允許 助理 存留期的高階指示。

要建立 助理 的程式代碼:

const assistant = await assistantsClient.createAssistant({
  model: "gpt-4-1106-preview",
  name: "JS Math Tutor",
  instructions: "You are a personal math tutor. Write and run code to answer math questions.",
  tools: [{ type: "code_interpreter" }]
});

助理與用戶之間的交談會話稱為線程。 線程會儲存訊息,並自動處理截斷,以將內容放入模型的內容中。

若要建立線程:

const assistantThread = await assistantsClient.createThread();

訊息代表助理或使用者所建立的訊息。 訊息可以包含文字、影像和其他檔案。 訊息會儲存為線程上的清單。 建立線程之後,即可在其中建立訊息:

const question = "I need to solve the equation '3x + 11 = 14'. Can you help me?";
const messageResponse = await assistantsClient.createMessage(assistantThread.id, "user", question);

Run 代表線程上助理的叫用。 小幫手會使用其設定和線程的訊息,藉由呼叫模型和工具來執行工作。 在執行過程中,小幫手會將訊息附加至線程。 接著,您可以啟動執行,以針對 助理 評估線程:

let runResponse = await assistantsClient.createRun(assistantThread.id, {
   assistantId: assistant.id,
   instructions: "Please address the user as Jane Doe. The user has a premium account." 
});

啟動執行之後,它應該會輪詢到到達終端機狀態:

do {
  await new Promise((resolve) => setTimeout(resolve, 800));
  runResponse = await assistantsClient.getRun(assistantThread.id, runResponse.id);
} while (runResponse.status === "queued" || runResponse.status === "in_progress")

假設執行順利完成,列出執行線程中的訊息現在會反映 助理 所新增的新資訊:

const runMessages = await assistantsClient.listMessages(assistantThread.id);
for (const runMessageDatum of runMessages.data) {
  for (const item of runMessageDatum.content) {
    if (item.type === "text") {
      console.log(item.text.value);
    } else if (item.type === "image_file") {
      console.log(item.imageFile.fileId);
    }
  }
}

此序列的範例輸出:

2023-11-14 20:21:23 -  assistant: The solution to the equation \(3x + 11 = 14\) is \(x = 1\).
2023-11-14 20:21:18 -       user: I need to solve the equation `3x + 11 = 14`. Can you help me?

使用檔案進行擷取

檔案可以上傳,然後由助理或訊息參考。 首先,使用一般化的上傳 API 搭配 「助理」的目的,讓檔案標識碼可供使用:

const filename = "<path_to_text_file>";
await fs.writeFile(filename, "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457.", "utf8");
const uint8array = await fs.readFile(filename);
const uploadAssistantFile = await assistantsClient.uploadFile(uint8array, "assistants", { filename });

上傳之後,就可以在建立時將檔案標識碼提供給 助理。 請注意,只有在啟用程式代碼解釋器或擷取等適當工具時,才會使用檔案識別碼。

const fileAssistant = await assistantsClient.createAssistant({
  model: "gpt-4-1106-preview",
  name: "JS SDK Test Assistant - Retrieval",
  instructions: "You are a helpful assistant that can help fetch data from files you know about.",
  tools: [{ type: "retrieval" }],
  fileIds: [ uploadAssistantFile.id ]
});

啟用檔案識別碼關聯和支援的工具之後,助理 就可以在執行線程時取用相關聯的數據。

使用函式工具和平行函式呼叫

OpenAI 的 助理 工具檔所述,參考呼叫端定義功能的工具可以提供給 助理,以允許它在執行期間動態解析和釐清。

這裡概述的是透過呼叫端提供的函式「知道如何」的簡單 助理:

  1. 取得使用者最愛城市
  2. 取得指定城市昵稱
  3. 在城市中,以溫度單位選擇性取得目前的天氣

若要這樣做,請先定義要使用的函式-- 此處的實際實作只是具代表性的存根。

// Example of a function that defines no parameters
const getFavoriteCity = () => "Atlanta, GA";
const getUserFavoriteCityTool = { 
  type: "function",
  function: {
    name: "getUserFavoriteCity",
    description: "Gets the user's favorite city.",
    parameters: {
      type: "object",
      properties: {}
    }
  }
}; 

// Example of a function with a single required parameter
const getCityNickname = (city) => { 
  switch (city) { 
    case "Atlanta, GA": 
      return "The ATL"; 
    case "Seattle, WA": 
      return "The Emerald City"; 
    case "Los Angeles, CA":
      return "LA"; 
    default: 
      return "Unknown"; 
  }
};

const getCityNicknameTool = { 
  type: "function",
  function: {
    name: "getCityNickname",
    description: "Gets the nickname for a city, e.g. 'LA' for 'Los Angeles, CA'.",
    parameters: { 
      type: "object",
      properties: { 
        city: {
          type: "string",
          description: "The city and state, e.g. San Francisco, CA"
        } 
      }
    }
  }
};

// Example of a function with one required and one optional, enum parameter
const getWeatherAtLocation = (location, temperatureUnit = "f") => {
  switch (location) { 
    case "Atlanta, GA": 
      return temperatureUnit === "f" ? "84f" : "26c"; 
    case "Seattle, WA": 
      return temperatureUnit === "f" ? "70f" : "21c"; 
    case "Los Angeles, CA":
      return temperatureUnit === "f" ? "90f" : "28c"; 
    default: 
      return "Unknown"; 
  }
};

const getWeatherAtLocationTool = { 
  type: "function",
  function: {
    name: "getWeatherAtLocation",
    description: "Gets the current weather at a provided location.",
    parameters: { 
      type: "object",
      properties: { 
        location: {
          type: "string",
          description: "The city and state, e.g. San Francisco, CA"
        },
        temperatureUnit: {
          type: "string",
          enum: ["f", "c"],
        }
      },
      required: ["location"]
    }
  }
};

透過在其適當工具中定義的函式,現在可以建立已啟用這些工具的 助理:

  const weatherAssistant = await assistantsClient.createAssistant({
  // note: parallel function calling is only supported with newer models like gpt-4-1106-preview
  model: "gpt-4-1106-preview",
  name: "JS SDK Test Assistant - Weather",
  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: [getUserFavoriteCityTool, getCityNicknameTool, getWeatherAtLocationTool]
});

如果 助理呼叫工具,呼叫程式代碼將需要將實例解析ToolCall為相符ToolOutputSubmission的實例。 為了方便起見,這裡會擷取基本範例:

const getResolvedToolOutput = (toolCall) => {
  const toolOutput = { toolCallId: toolCall.id };

  if (toolCall["function"]) {
    const functionCall = toolCall["function"];
    const functionName = functionCall.name;
    const functionArgs = JSON.parse(functionCall["arguments"] ?? {});

    switch (functionName) {
      case "getUserFavoriteCity":
        toolOutput.output = getFavoriteCity();
        break;
      case "getCityNickname":
        toolOutput.output = getCityNickname(functionArgs["city"]);
        break;
      case "getWeatherAtLocation":
        toolOutput.output = getWeatherAtLocation(functionArgs.location, functionArgs.temperatureUnit);
        break;
      default:
        toolOutput.output = `Unknown function: ${functionName}`;
        break;
    }
  }
  return toolOutput;
};

若要處理使用者輸入,例如「我的最愛城市現在的天氣是什麼?」,輪詢完成響應應該由 RunStatus 檢查 RequiresAction 來補充,在此情況下,在執行中是否有 RequiredAction 屬性。 然後,應該透過 SubmitRunToolOutputs 方法將的ToolOutputSubmissions集合提交至執行,以便繼續執行:

const question = "What's the weather like right now in my favorite city?";
let runResponse = await assistantsClient.createThreadAndRun({ 
  assistantId: weatherAssistant.id, 
  thread: { messages: [{ role: "user", content: question }] },
  tools: [getUserFavoriteCityTool, getCityNicknameTool, getWeatherAtLocationTool]
});

do {
  await new Promise((resolve) => setTimeout(resolve, 500));
  runResponse = await assistantsClient.getRun(runResponse.threadId, runResponse.id);
  
  if (runResponse.status === "requires_action" && runResponse.requiredAction.type === "submit_tool_outputs") {
    const toolOutputs = [];

    for (const toolCall of runResponse.requiredAction.submitToolOutputs.toolCalls) {
      toolOutputs.push(getResolvedToolOutput(toolCall));
    }
    runResponse = await assistantsClient.submitToolOutputsToRun(runResponse.threadId, runResponse.id, toolOutputs);
  }
} while (runResponse.status === "queued" || runResponse.status === "in_progress")

請注意,使用支援的模型時,助理 可能會要求平行呼叫數個函式。 較舊的模型一次只能呼叫一個函式。

解析所有必要的函數調用之後,執行會正常進行,且線程上已完成的訊息將包含由提供的函式工具輸出補充的模型輸出。

疑難排解

記錄

啟用記錄有助於找出失敗的相關實用資訊。 若要查看 HTTP 的要求和回應記錄,請將 AZURE_LOG_LEVEL 環境變數設定為 info。 或者,您可以在 @azure/logger 中呼叫 setLogLevel,以在執行階段啟用記錄:

const { setLogLevel } = require("@azure/logger");

setLogLevel("info");

如需如何啟用記錄的詳細指示,可參閱 @azure/logger 套件文件