🚀 在 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。