🚀 在 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 相同的 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 儲存庫中找到本教學課程的完整原始碼。