語言模型 API

語言模型 API 讓您能夠使用語言模型,並將 AI 驅動的功能及自然語言處理整合到您的 Visual Studio Code 擴充功能中。

您可以在不同類型的擴充功能中使用語言模型 API。此 API 的典型用途是在聊天擴充功能中,您可以使用語言模型來解讀使用者的請求並協助提供答案。然而,語言模型 API 的應用並不限於此情境。您可以在程式語言除錯器擴充功能中使用語言模型,或是將其作為自訂擴充功能中命令任務的一部分。例如,Rust 擴充功能可以使用語言模型來提供預設名稱,以改善其重新命名體驗。

使用語言模型 API 的過程包含以下步驟:

  1. 建立語言模型提示詞 (Prompt)
  2. 發送語言模型請求
  3. 解讀回應

以下章節將詳細介紹如何在您的擴充功能中實作這些步驟。

若要開始使用,您可以探索聊天擴充功能範例

建立語言模型提示詞 (Prompt)

為了與語言模型互動,擴充功能應首先設計其提示詞,然後向語言模型發送請求。您可以使用提示詞來提供指令,告知語言模型您正在執行的大致任務。提示詞也可以定義使用者訊息被解讀時的上下文。

在建立語言模型提示詞時,語言模型 API 支援兩種類型的訊息:

  • 使用者 (User) - 用於提供指令及使用者的請求
  • 助理 (Assistant) - 用於將語言模型先前的回應歷史記錄作為提示詞的上下文

注意:目前語言模型 API 不支援使用系統訊息 (system messages)。

您可以使用兩種方法來建立語言模型提示詞:

  • LanguageModelChatMessage - 透過提供一個或多個字串形式的訊息來建立提示詞。如果您才剛開始使用語言模型 API,可以使用此方法。
  • @vscode/prompt-tsx - 使用 TSX 語法來宣告提示詞。

如果您希望對語言模型提示詞的構成方式有更多控制權,可以使用 prompt-tsx 函式庫。例如,該函式庫可以協助動態調整提示詞的長度,以適應每個語言模型的上下文視窗大小。深入了解 @vscode/prompt-tsx 或探索聊天擴充功能範例以開始使用。

若要進一步了解提示詞工程 (Prompt Engineering) 的概念,建議閱讀 OpenAI 出色的提示詞工程指南

提示:利用豐富的 VS Code 擴充功能 API 來獲取最相關的上下文,並將其包含在您的提示詞中。例如,將編輯器中活動檔案的內容包含在內。

使用 LanguageModelChatMessage 類別

語言模型 API 提供了 LanguageModelChatMessage 類別來表示並建立聊天訊息。您可以使用 LanguageModelChatMessage.UserLanguageModelChatMessage.Assistant 方法分別建立使用者或助理訊息。

在以下範例中,第一條訊息為提示詞提供了上下文:

  • 模型在回覆時所使用的角色(在此案例中為貓)
  • 模型在產生回應時應遵循的規則(在此案例中,以有趣的貓咪隱喻來解釋電腦科學概念)

第二條訊息則提供了來自使用者的具體請求或指令。它決定了在第一條訊息所提供的上下文下,需要完成的具體任務。

const craftedPrompt = [
  vscode.LanguageModelChatMessage.User(
    'You are a cat! Think carefully and step by step like a cat would. Your job is to explain computer science concepts in the funny manner of a cat, using cat metaphors. Always start your response by stating what concept you are explaining. Always include code samples.'
  ),
  vscode.LanguageModelChatMessage.User('I want to understand recursion')
];

發送語言模型請求

建立好語言模型的提示詞後,首先要使用 selectChatModels 方法選擇您想要使用的語言模型。此方法會回傳一組符合指定條件的語言模型陣列。如果您正在實作聊天參與者 (chat participant),我們建議改為使用在聊天請求處理常式中作為 request 物件的一部分傳遞進來的模型。這能確保您的擴充功能遵循使用者在聊天模型下拉選單中所選擇的模型。接著,使用 sendRequest 方法將請求發送給語言模型。

若要選擇語言模型,您可以指定以下屬性:vendoridfamilyversion。使用這些屬性來廣泛匹配特定供應商或系列的所有模型,或者透過 ID 選擇特定的模型。在 API 參考中進一步了解這些屬性。

注意:目前語言模型系列支援 gpt-4ogpt-4o-minio1o1-miniclaude-3.5-sonnet。如果您不確定該使用哪個模型,我們建議使用 gpt-4o,因其效能與品質表現優異。若是在編輯器中直接進行互動,建議使用 gpt-4o-mini,因其反應速度較快。

如果沒有符合指定條件的模型,selectChatModels 方法會回傳空陣列。您的擴充功能必須妥善處理此情況。

以下範例展示了如何選擇所有 Copilot 模型,而不論其系列或版本為何:

const models = await vscode.lm.selectChatModels({
  vendor: 'copilot'
});

// No models available
if (models.length === 0) {
  // TODO: handle the case when no models are available
}

重要:Copilot 的語言模型在擴充功能使用前需要取得使用者的同意。同意是以驗證對話框的形式實作。因此,selectChatModels 應作為使用者發起的動作(例如命令)的一部分來呼叫。

選擇模型後,您可以在模型實例上呼叫 sendRequest 方法來發送請求。您需要傳入稍早建立的提示詞,以及任何額外的選項和取消權杖 (cancellation token)。

當您向語言模型 API 發出請求時,請求可能會失敗。例如,模型不存在、使用者未同意使用語言模型 API,或是配額超限。請使用 LanguageModelError 來區分不同類型的錯誤。

以下程式碼片段展示了如何發出語言模型請求:

try {
  const [model] = await vscode.lm.selectChatModels({ vendor: 'copilot', family: 'gpt-4o' });
  const request = model.sendRequest(craftedPrompt, {}, token);
} catch (err) {
  // Making the chat request might fail because
  // - model does not exist
  // - user consent not given
  // - quota limits were exceeded
  if (err instanceof vscode.LanguageModelError) {
    console.log(err.message, err.code, err.cause);
    if (err.cause instanceof Error && err.cause.message.includes('off_topic')) {
      stream.markdown(
        vscode.l10n.t("I'm sorry, I can only explain computer science concepts.")
      );
    }
  } else {
    // add other error handling logic
    throw err;
  }
}

解讀回應

發送請求後,您必須處理來自語言模型 API 的回應。根據您的使用場景,您可以將回應直接呈現給使用者,或是解讀回應並執行額外的邏輯。

來自語言模型 API 的回應 (LanguageModelChatResponse) 是基於串流 (streaming-based) 的,這能讓您提供流暢的使用者體驗。例如,當您結合使用 Chat API 時,可以持續回報結果和進度。

在處理串流回應時可能會發生錯誤,例如網路連線問題。請務必在程式碼中加入適當的錯誤處理機制來應對這些錯誤。

以下程式碼片段展示了擴充功能如何註冊一個命令,該命令使用語言模型將活動編輯器中的所有變數名稱改為有趣的貓咪名稱。請注意,擴充功能會將程式碼串流回編輯器,以提供流暢的使用者體驗。

vscode.commands.registerTextEditorCommand(
  'cat.namesInEditor',
  async (textEditor: vscode.TextEditor) => {
    // Replace all variables in active editor with cat names and words

    const [model] = await vscode.lm.selectChatModels({
      vendor: 'copilot',
      family: 'gpt-4o'
    });
    let chatResponse: vscode.LanguageModelChatResponse | undefined;

    const text = textEditor.document.getText();

    const messages = [
      vscode.LanguageModelChatMessage
        .User(`You are a cat! Think carefully and step by step like a cat would.
        Your job is to replace all variable names in the following code with funny cat variable names. Be creative. IMPORTANT respond just with code. Do not use markdown!`),
      vscode.LanguageModelChatMessage.User(text)
    ];

    try {
      chatResponse = await model.sendRequest(
        messages,
        {},
        new vscode.CancellationTokenSource().token
      );
    } catch (err) {
      if (err instanceof vscode.LanguageModelError) {
        console.log(err.message, err.code, err.cause);
      } else {
        throw err;
      }
      return;
    }

    // Clear the editor content before inserting new content
    await textEditor.edit(edit => {
      const start = new vscode.Position(0, 0);
      const end = new vscode.Position(
        textEditor.document.lineCount - 1,
        textEditor.document.lineAt(textEditor.document.lineCount - 1).text.length
      );
      edit.delete(new vscode.Range(start, end));
    });

    try {
      // Stream the code into the editor as it is coming in from the Language Model
      for await (const fragment of chatResponse.text) {
        await textEditor.edit(edit => {
          const lastLine = textEditor.document.lineAt(textEditor.document.lineCount - 1);
          const position = new vscode.Position(lastLine.lineNumber, lastLine.text.length);
          edit.insert(position, fragment);
        });
      }
    } catch (err) {
      // async response stream may fail, e.g network interruption or server side error
      await textEditor.edit(edit => {
        const lastLine = textEditor.document.lineAt(textEditor.document.lineCount - 1);
        const position = new vscode.Position(lastLine.lineNumber, lastLine.text.length);
        edit.insert(position, (<Error>err).message);
      });
    }
  }
);

注意事項

模型可用性

我們預期並非所有特定模型都會永久受到支援。當您在擴充功能中參照語言模型時,請務必在發送請求時採取「防禦性」的程式編寫方式。這意味著您應該妥善處理無法存取特定模型的情況。

選擇合適的模型

擴充功能作者可以選擇最適合其擴充功能的模型。我們建議使用 gpt-4o,因其效能與品質表現優異。若要獲取可用模型的完整清單,可以使用此程式碼片段:

const allModels = await vscode.lm.selectChatModels(MODEL_SELECTOR);
注意

建議使用的 GPT-4o 模型有 64K 個 Token 的限制。從 selectChatModels 呼叫回傳的模型物件具有 maxInputTokens 屬性,可顯示 Token 上限。隨著我們深入了解擴充功能如何使用這些語言模型,這些限制將會擴展。

速率限制 (Rate limiting)

擴充功能應負責任地使用語言模型,並留意速率限制。VS Code 對使用者透明地呈現擴充功能如何使用語言模型、每個擴充功能發送了多少請求,以及這些請求如何影響各自的配額。

由於速率限制,擴充功能不應將語言模型 API 用於整合測試。在內部,VS Code 使用專門的非生產環境語言模型進行模擬測試,我們目前正在思考如何為擴充功能提供可擴展的語言模型測試解決方案。

測試您的擴充功能

語言模型 API 提供的回應是不具確定性的,這意味著針對相同的請求,您可能會收到不同的回應。這種行為可能會增加測試擴充功能的難度。

擴充功能中用於建立提示詞和解讀語言模型回應的部分是確定性的,因此可以在不使用實際語言模型的情況下進行單元測試。然而,與語言模型本身的互動並取得回應是不具確定性的,且不容易測試。請考慮以模組化的方式設計您的擴充功能程式碼,以便針對可測試的特定部分進行單元測試。

發佈您的擴充功能

建立 AI 擴充功能後,您可以將其發佈到 Visual Studio Marketplace。

© . This site is unofficial and not affiliated with Microsoft.