🚀 在 VS Code 中

語言模型 API

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

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

使用語言模型 API 的流程包含下列步驟

  1. 建置語言模型提示
  2. 傳送語言模型請求
  3. 解譯回應

以下章節將提供更多關於如何在您的擴充功能中實作這些步驟的詳細資訊。

建置語言模型提示

為了與語言模型互動,擴充功能應先設計其提示,然後將請求傳送至語言模型。您可以使用提示來向語言模型提供關於您使用模型之廣泛任務的指示。提示也可以定義使用者訊息被解譯的背景脈絡。

在建置語言模型提示時,語言模型 API 支援兩種訊息類型

  • 使用者 - 用於提供指示和使用者的請求
  • 助理 - 用於新增先前語言模型回應的歷史記錄,作為提示的背景脈絡

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

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

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

如果您想要更精確地控制語言模型提示的組成方式,可以使用 prompt-tsx 程式庫。例如,該程式庫可以協助動態調整提示的長度,以符合每個語言模型的背景脈絡視窗大小。深入瞭解 @vscode/prompt-tsx 或瀏覽 聊天擴充功能範例 以開始使用。

若要深入瞭解提示工程的概念,我們建議您閱讀 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 方法選取您想要使用的語言模型。此方法會傳回符合指定條件的語言模型陣列。如果您正在實作聊天參與者,我們建議您改為使用在聊天請求處理常式中作為 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 方法,將請求傳送至語言模型。您傳遞先前設計的 提示,以及任何其他選項和取消權杖。

當您向語言模型 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) 是基於串流的,這讓您能夠提供流暢的使用者體驗。例如,當您將 API 與 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 符記的限制。從 selectChatModels 呼叫傳回的模型物件具有 maxInputTokens 屬性,可顯示符記限制。當我們更瞭解擴充功能如何使用語言模型時,這些限制將會擴展。

速率限制

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

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

測試您的擴充功能

語言模型 API 提供的回應是不具決定性的,這表示您可能會針對相同的請求獲得不同的回應。這種行為可能會對測試您的擴充功能造成挑戰。

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

發佈您的擴充功能

一旦您建立了 AI 擴充功能,您就可以將您的擴充功能發佈到 Visual Studio Marketplace

  • 在發佈到 VS Marketplace 之前,我們建議您閱讀 Microsoft AI 工具和實務指南。這些指南提供了負責任地開發和使用 AI 技術的最佳實務。
  • 透過發佈到 VS Marketplace,您的擴充功能即遵守 GitHub Copilot 擴充性可接受的開發和使用政策
  • 如果您的擴充功能已貢獻語言模型 API 以外的功能,我們建議您不要在 擴充功能資訊清單 中引入 GitHub Copilot 的擴充功能相依性。這可確保不使用 GitHub Copilot 的擴充功能使用者可以使用非語言模型功能,而無需安裝 GitHub Copilot。在這種情況下,請務必具有適當的錯誤處理,以便存取語言模型。
  • 依照 發佈擴充功能 中所述,上傳至 Marketplace。