🚀 在 VS Code 中取得

教學課程:使用 Chat API 建置程式碼教學課程聊天參與者

在本教學課程中,您將學習如何建立與 GitHub Copilot Chat 體驗整合的 Visual Studio Code 擴充功能。您將使用 Chat 擴充功能 API 來貢獻聊天參與者。您的參與者將成為程式碼導師,可以為程式設計概念提供說明和範例練習。

先決條件

您需要以下工具和帳戶才能完成本教學課程

步驟 1:設定您的專案

首先,使用 Yeoman 和 VS Code 擴充功能產生器產生擴充功能專案。

npx --package yo --package generator-code -- yo code

選取以下選項以完成設定

# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? Code Tutor

### Press <Enter> to choose default for all options below ###

# ? What's the identifier of your extension? code-tutor
# ? What's the description of your extension? LEAVE BLANK
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? No
# ? Which package manager to use? npm

# ? Do you want to open the new folder with Visual Studio Code? Open with `code`

產生擴充功能專案後,您將在兩個檔案中工作:extension.tspackage.json,您可以在擴充功能剖析文件中瞭解更多資訊。快速概觀如下

  • extension.ts 是您擴充功能的主要進入點,其中包含聊天參與者的邏輯。
  • package.json 包含您擴充功能的 metadata,例如參與者的名稱和描述。

刪除 extension.ts activate() 方法中自動產生的程式碼。您將在此處放置聊天參與者的邏輯。

步驟 2:註冊聊天參與者

package.json 檔案中,將自動產生的 contributes 區段替換為以下內容

"contributes":{
    "chatParticipants": [
    {
        "id": "chat-tutorial.code-tutor",
        "fullName": "Code Tutor",
        "name": "tutor",
        "description": "What can I teach you?",
        "isSticky": true
    }
    ]
}

此程式碼註冊具有以下屬性的聊天參與者

  • 唯一 ID chat-tutorial.code-tutor,將在程式碼中參考
  • 全名 Code Tutor,將顯示在參與者回應的標題區域中
  • 名稱 tutor,將用於在「聊天」檢視中將聊天參與者參考為 @tutor
  • 描述「我可以教您什麼?」,將在聊天輸入欄位中顯示為預留位置文字

最後,設定 isSticky: true 將在使用者開始與參與者互動後,自動將參與者名稱預先附加在聊天輸入欄位中。

步驟 3:設計提示

現在參與者已註冊,您可以開始實作程式碼導師的邏輯。在 extension.ts 檔案中,您將為請求定義提示。

設計良好的提示是從參與者獲得最佳回應的關鍵。請查看這篇文章,以取得有關提示工程的秘訣。

您的程式碼導師應模仿真實世界的導師,引導學生理解概念,而不是提供直接答案。此外,導師應專注於主題,避免回答非程式設計問題。

請考慮以下兩個提示。哪一個更可能提供指定的行為?

  1. 您是一位有幫助的程式碼導師。您的工作是以簡單的描述和概念的範例程式碼來教導使用者。

  2. 您是一位有幫助的程式碼導師。您的工作是以簡單的描述和概念的範例程式碼來教導使用者。在一系列訊息中,以引導式概述來回應概念。不要直接給使用者答案,而是引導他們自行找到答案。如果使用者詢問非程式設計問題,請禮貌地拒絕回應。

第二個提示更具體,並為參與者提供有關如何回應的明確方向。將此提示新增至 extension.ts 檔案中。

const BASE_PROMPT =
  'You are a helpful code tutor. Your job is to teach the user with simple descriptions and sample code of the concept. Respond with a guided overview of the concept in a series of messages. Do not give the user the answer directly, but guide them to find the answer themselves. If the user asks a non-programming question, politely decline to respond.';

步驟 4:實作請求處理常式

現在已選取提示,您需要實作請求處理常式。這將處理使用者的聊天請求。您將定義請求處理常式、執行邏輯以處理請求,並將回應傳回給使用者。

首先,定義處理常式

// define a chat handler
const handler: vscode.ChatRequestHandler = async (
  request: vscode.ChatRequest,
  context: vscode.ChatContext,
  stream: vscode.ChatResponseStream,
  token: vscode.CancellationToken
) => {
  return;
};

在此處理常式的內文中,初始化提示和包含提示的 messages 陣列。然後,傳送使用者在聊天框中輸入的內容。您可以透過 request.prompt 存取此內容。

使用 request.model.sendRequest 傳送請求,這將使用目前選取的模型傳送請求。最後,將回應串流傳輸給使用者。

// define a chat handler
const handler: vscode.ChatRequestHandler = async (
  request: vscode.ChatRequest,
  context: vscode.ChatContext,
  stream: vscode.ChatResponseStream,
  token: vscode.CancellationToken
) => {
  // initialize the prompt
  let prompt = BASE_PROMPT;

  // initialize the messages array with the prompt
  const messages = [vscode.LanguageModelChatMessage.User(prompt)];

  // add in the user's message
  messages.push(vscode.LanguageModelChatMessage.User(request.prompt));

  // send the request
  const chatResponse = await request.model.sendRequest(messages, {}, token);

  // stream the response
  for await (const fragment of chatResponse.text) {
    stream.markdown(fragment);
  }

  return;
};

步驟 5:建立聊天參與者

實作處理常式後,最後一個步驟是使用 Chat 擴充功能 API 中的 createChatParticipant 方法建立聊天參與者。請務必使用您在 package.json 中使用的相同 ID。

您應該進一步自訂參與者,為其新增圖示。這將在與參與者互動時顯示在「聊天」檢視中。

// define a chat handler
const handler: vscode.ChatRequestHandler = async (
  request: vscode.ChatRequest,
  context: vscode.ChatContext,
  stream: vscode.ChatResponseStream,
  token: vscode.CancellationToken
) => {
  // initialize the prompt
  let prompt = BASE_PROMPT;

  // initialize the messages array with the prompt
  const messages = [vscode.LanguageModelChatMessage.User(prompt)];

  // add in the user's message
  messages.push(vscode.LanguageModelChatMessage.User(request.prompt));

  // send the request
  const chatResponse = await request.model.sendRequest(messages, {}, token);

  // stream the response
  for await (const fragment of chatResponse.text) {
    stream.markdown(fragment);
  }

  return;
};

// create participant
const tutor = vscode.chat.createChatParticipant('chat-tutorial.code-tutor', handler);

// add icon to participant
tutor.iconPath = vscode.Uri.joinPath(context.extensionUri, 'tutor.jpeg');

步驟 6:執行程式碼

您現在已準備好試用聊天參與者!按下 F5 以執行程式碼。VS Code 的新視窗將會開啟,其中包含您的聊天參與者。

在 Copilot Chat 窗格中,您現在可以透過輸入 @tutor 來叫用您的參與者!

Participant in Chat pane

輸入您想學習的內容來測試看看。您應該會看到回應,提供您概念的概觀!

如果您輸入相關訊息以繼續對話,您會注意到參與者不會根據您的對話提供後續回應。這是因為我們目前的參與者只傳送使用者的目前訊息,而不是參與者訊息記錄。

在以下螢幕截圖中,導師正確地回應了堆疊的起始說明。但是,在後續追蹤中,它不了解使用者正在繼續對話以查看 Python 中堆疊的實作,因此它反而給出了關於 Python 的通用回應。

Participant with no message history

步驟 7:新增訊息記錄以取得更多內容

Copilot Chat 的最大價值之一是能夠反覆運算多個訊息以獲得最佳回應。若要執行此操作,您需要將參與者的訊息記錄傳送至聊天請求。您可以透過 context.history 存取此記錄。

您需要擷取該記錄,並將其新增至 messages 陣列。您需要在新增 request.prompt 之前執行此操作。

// define a chat handler
const handler: vscode.ChatRequestHandler = async (
  request: vscode.ChatRequest,
  context: vscode.ChatContext,
  stream: vscode.ChatResponseStream,
  token: vscode.CancellationToken
) => {
  // initialize the prompt
  let prompt = BASE_PROMPT;

  // initialize the messages array with the prompt
  const messages = [vscode.LanguageModelChatMessage.User(prompt)];

  // get all the previous participant messages
  const previousMessages = context.history.filter(
    h => h instanceof vscode.ChatResponseTurn
  );

  // add the previous messages to the messages array
  previousMessages.forEach(m => {
    let fullMessage = '';
    m.response.forEach(r => {
      const mdPart = r as vscode.ChatResponseMarkdownPart;
      fullMessage += mdPart.value.value;
    });
    messages.push(vscode.LanguageModelChatMessage.Assistant(fullMessage));
  });

  // add in the user's message
  messages.push(vscode.LanguageModelChatMessage.User(request.prompt));

  // send the request
  const chatResponse = await request.model.sendRequest(messages, {}, token);

  // stream the response
  for await (const fragment of chatResponse.text) {
    stream.markdown(fragment);
  }

  return;
};

現在當您執行程式碼時,您可以與您的參與者進行對話,其中包含先前訊息的所有內容!在以下螢幕截圖中,參與者正確地理解使用者要求查看 Python 中堆疊的實作。

Participant with message history

步驟 8:新增命令

現在基本參與者已實作,您可以透過新增命令來擴充它。命令是常見使用者意圖的簡寫符號,以 / 符號表示。然後,擴充功能可以使用命令來相應地提示語言模型。

新增命令以提示您的導師提供概念的練習會很棒。您需要在 package.json 檔案中註冊命令,並在 extension.ts 中實作邏輯。您可以將命令命名為 exercise,以便可以透過輸入 /exercise 來叫用它。

package.json 中,將 commands 屬性新增至 chatParticipants 屬性。在此處,您將指定命令的名稱和快速描述

"contributes": {
    "chatParticipants": [
      {
        "id": "chat-tutorial.code-tutor",
        "fullName": "Code Tutor",
        "name": "tutor",
        "description": "What can I teach you?",
        "isSticky": true,
        "commands": [
          {
            "name": "exercise",
            "description": "Provide exercises to practice a concept."
          }
        ]
      }
    ]
  },

若要實作從導師取得範例練習的邏輯,最簡單的方法是變更您傳送至請求的提示。建立新的提示 EXERCISES_PROMPT,要求參與者傳回範例練習。以下是可能的外觀範例

const EXERCISES_PROMPT =
  'You are a helpful tutor. Your job is to teach the user with fun, simple exercises that they can complete in the editor. Your exercises should start simple and get more complex as the user progresses. Move one concept at a time, and do not move on to the next concept until the user provides the correct answer. Give hints in your exercises to help the user learn. If the user is stuck, you can provide the answer and explain why it is the answer. If the user asks a non-programming question, politely decline to respond.';

在請求處理常式中,您接著需要新增邏輯來偵測使用者是否參考了命令。您可以透過 request.command 屬性來執行此操作。

如果參考了命令,請將提示更新為新建立的 EXERCISES_PROMPT

// define a chat handler
const handler: vscode.ChatRequestHandler = async (
  request: vscode.ChatRequest,
  context: vscode.ChatContext,
  stream: vscode.ChatResponseStream,
  token: vscode.CancellationToken
) => {
  // initialize the prompt
  let prompt = BASE_PROMPT;

  if (request.command === 'exercise') {
    prompt = EXERCISES_PROMPT;
  }

  // initialize the messages array with the prompt
  const messages = [vscode.LanguageModelChatMessage.User(prompt)];

  // get all the previous participant messages
  const previousMessages = context.history.filter(
    h => h instanceof vscode.ChatResponseTurn
  );

  // add the previous messages to the messages array
  previousMessages.forEach(m => {
    let fullMessage = '';
    m.response.forEach(r => {
      const mdPart = r as vscode.ChatResponseMarkdownPart;
      fullMessage += mdPart.value.value;
    });
    messages.push(vscode.LanguageModelChatMessage.Assistant(fullMessage));
  });

  // add in the user's message
  messages.push(vscode.LanguageModelChatMessage.User(request.prompt));

  // send the request
  const chatResponse = await request.model.sendRequest(messages, {}, token);

  // stream the response
  for await (const fragment of chatResponse.text) {
    stream.markdown(fragment);
  }

  return;
};

這就是需要新增的所有內容!其餘邏輯(取得訊息記錄、傳送請求和串流請求)都保持不變。

現在您可以輸入 /exercise,這將會啟動您的聊天參與者,而且您可以取得互動式練習來練習程式碼!

Participant with a slash command

後續步驟

恭喜!您已成功建立聊天參與者,可以為程式設計概念提供說明和範例練習。您可以透過微調提示、新增更多斜線命令或利用其他 API(例如語言模型 API)來進一步擴充您的參與者。準備就緒後,您也可以將您的擴充功能發佈到 Visual Studio Code Marketplace

您可以在vscode-extensions-sample 儲存庫中找到本教學課程的完整原始碼。