聊天擴充功能
Visual Studio Code 的 Copilot 聊天架構讓擴充功能作者能夠與 GitHub Copilot Chat 體驗整合。聊天擴充功能是一種 VS Code 擴充功能,透過貢獻聊天參與者來使用聊天擴充功能 API。
聊天參與者是領域專家,可以回答特定領域內的使用者查詢。參與者可以使用不同的方法來處理使用者查詢
- 使用 AI 來解讀請求並產生回應,例如使用語言模型 API
- 將使用者請求轉發到後端服務
- 使用程序邏輯和本機資源
參與者可以在廣泛的方式中使用語言模型。有些參與者僅使用語言模型來取得自訂提示的答案,例如範例聊天參與者。其他參與者更進階,並且像自主代理程式一樣運作,在語言模型的幫助下調用多個工具。這種進階參與者的一個範例是內建的 @workspace
,它了解您的工作區,並且可以回答關於它的問題。在內部,@workspace
由多個工具驅動:GitHub 的知識圖譜,結合語意搜尋、本機程式碼索引和 VS Code 的語言服務。
當使用者在其聊天提示中明確提及 @participant
時,該提示會轉發到貢獻該特定聊天參與者的擴充功能。然後,參與者使用 ResponseStream
來回應請求。為了提供流暢的使用者體驗,聊天 API 是基於串流的。聊天回應可以包含豐富的內容,例如 Markdown、檔案樹、命令按鈕等等。取得關於支援的回應輸出類型的更多資訊。
為了幫助使用者進一步深入對話,參與者可以為每個回應提供後續。後續問題是在聊天使用者介面中呈現的建議,可能會給予使用者關於聊天擴充功能功能的靈感。
參與者還可以貢獻命令,這是常見使用者意圖的簡寫符號,並以 /
符號表示。然後擴充功能可以使用命令來適當地提示語言模型。例如,/explain
是 @workspace
參與者的命令,對應於語言模型應解釋某些程式碼的意圖。
透過 GitHub 應用程式擴充 GitHub Copilot
或者,可以透過建立 GitHub 應用程式來擴充 GitHub Copilot,該應用程式在聊天檢視中貢獻聊天參與者。GitHub 應用程式由服務支援,並且跨所有 GitHub Copilot 介面運作,例如 github.com、Visual Studio 或 VS Code。另一方面,GitHub 應用程式無法完全存取 VS Code API。若要深入了解透過 GitHub 應用程式擴充 GitHub Copilot,請參閱GitHub 文件。
連結
聊天使用者體驗的組成部分
以下螢幕截圖顯示了範例擴充功能的 Visual Studio Code 聊天體驗中不同的聊天概念。
- 使用
@
語法來調用@cat
聊天參與者 - 使用
/
語法來呼叫/teach
命令 - 使用者提供的查詢,也稱為使用者提示
- 圖示和參與者
fullName
,表示 Copilot 正在使用@cat
聊天參與者 - Markdown 回應,由
@cat
提供 - 包含在 markdown 回應中的程式碼片段
- 包含在
@cat
回應中的按鈕,該按鈕調用 VS Code 命令 - 由聊天參與者提供的建議後續問題
- 聊天輸入欄位,其中包含聊天參與者的
description
屬性提供的預留位置文字
開發聊天擴充功能
聊天擴充功能是一種擴充功能,它將聊天參與者貢獻給聊天檢視。
實作聊天擴充功能所需的最低功能是
- 註冊聊天參與者,讓使用者可以使用 VS Code 聊天檢視中的
@
符號來調用它。 - 定義請求處理常式,以解讀使用者的問題,並在聊天檢視中傳回回應。
您可以透過以下可選功能進一步擴充聊天擴充功能的功能
- 註冊聊天命令,為使用者提供常用問題的簡寫符號
- 定義建議的後續問題,以幫助使用者繼續對話
作為開發聊天擴充功能的起點,您可以參考我們的聊天擴充功能範例。此範例實作了一個簡單的貓導師,可以使用貓的隱喻來解釋電腦科學主題。
註冊聊天擴充功能
建立聊天擴充功能的第一步是在您的 package.json
中註冊它,方法是提供唯一的 id
、name
和 description
。
"contributes": {
"chatParticipants": [
{
"id": "chat-sample.cat",
"name": "cat",
"fullName": "Cat",
"description": "Meow! What can I teach you?",
"isSticky": true
}
]
}
然後,使用者可以在聊天檢視中使用 @
符號和您提供的 name
來參考聊天參與者。fullName
會顯示在來自您的參與者的回應的標題區域中。description
用作聊天輸入欄位中的預留位置文字。
isSticky
屬性控制聊天參與者是否為持久性,這表示在使用者開始與參與者互動後,參與者名稱會自動預先添加到聊天輸入欄位中。
我們建議使用小寫 name
,並為 fullName
使用標題大小寫,以與現有的聊天參與者保持一致。取得關於聊天參與者命名慣例的更多資訊。
某些參與者名稱是保留的,如果您使用保留名稱,VS Code 將顯示您的參與者的完整限定名稱(包括擴充功能 ID)。
需要預先註冊參與者和命令在 package.json
中,以便 VS Code 可以在正確的時間啟動您的擴充功能,而不是在需要之前。
註冊後,您的擴充功能要做的就是使用 vscode.chat.createChatParticipant
建立參與者。在建立參與者時,您必須提供您在 package.json
中定義的 ID,以及請求處理常式。
以下程式碼片段顯示如何建立 @cat
聊天參與者(在您在 package.json
中註冊它之後)
export function activate(context: vscode.ExtensionContext) {
// Register the chat participant and its request handler
const cat = vscode.chat.createChatParticipant('chat-sample.cat', handler);
// Optionally, set some properties for @cat
cat.iconPath = vscode.Uri.joinPath(context.extensionUri, 'cat.jpeg');
// Add the chat request handler here
}
在註冊和建立聊天參與者之後,您現在需要實作請求處理常式來處理使用者的請求。
實作請求處理常式
請求處理常式負責處理 VS Code 聊天檢視中的使用者聊天請求。每次使用者在聊天輸入欄位中輸入提示時,都會調用聊天請求處理常式。以下是實作聊天請求處理常式的典型步驟
- 定義請求處理常式
- 判斷使用者請求的意圖
- 執行邏輯以回答使用者的問題
- 傳回對使用者的回應
定義請求處理常式
您可以在擴充功能的 activate
函數內定義請求處理常式 (vscode.ChatRequestHandler
)。
以下程式碼片段顯示如何定義請求處理常式
const handler: vscode.ChatRequestHandler = async (
request: vscode.ChatRequest,
context: vscode.ChatContext,
stream: vscode.ChatResponseStream,
token: vscode.CancellationToken
): Promise<ICatChatResult> => {
// Chat request handler implementation goes here
};
判斷請求意圖
為了判斷使用者請求的意圖,您可以參考 vscode.ChatRequest
參數來存取使用者的提示、命令和聊天位置。或者,您可以利用語言模型來判斷使用者的意圖,而不是使用傳統邏輯。作為 request
物件的一部分,您會取得使用者在聊天模型下拉式選單中選取的語言模型實例。了解如何在您的擴充功能中使用語言模型 API。
以下程式碼片段顯示首先使用命令,然後使用使用者提示來判斷使用者意圖的基本結構
const handler: vscode.ChatRequestHandler = async (
request: vscode.ChatRequest,
context: vscode.ChatContext,
stream: vscode.ChatResponseStream,
token: vscode.CancellationToken
): Promise<ICatChatResult> => {
// Test for the `teach` command
if (request.command == 'teach') {
// Add logic here to handle the teaching scenario
doTeaching(request.prompt, request.variables);
} else {
// Determine the user's intent
const intent = determineUserIntent(request.prompt, request.variables, request.model);
// Add logic here to handle other scenarios
}
};
處理請求
接下來,您需要實作處理使用者請求的實際邏輯。通常,聊天擴充功能會使用 request.model
語言模型實例來處理請求。在這種情況下,您可能會調整語言模型提示以符合使用者的意圖。或者,您可以透過調用後端服務、使用傳統程式設計邏輯或結合所有這些選項來實作擴充功能邏輯。例如,您可以調用 Web 搜尋來收集額外資訊,然後將其作為上下文提供給語言模型。
在處理目前請求時,您可能想要參考先前的聊天訊息。例如,如果先前的回應傳回了 C# 程式碼片段,則使用者目前的請求可能是「以 Python 給出程式碼」。了解如何使用聊天訊息記錄。
如果您想要根據聊天輸入的位置以不同的方式處理請求,您可以使用 vscode.ChatRequest
的 location
屬性。例如,如果使用者從終端機內嵌聊天傳送請求,您可能會查閱 shell 命令。相反地,如果使用者使用聊天檢視,您可以傳回更詳細的回應。
傳回聊天回應
一旦您處理了請求,您必須在聊天檢視中傳回對使用者的回應。聊天擴充功能可以使用串流來回應使用者查詢。回應可以包含不同的內容類型:markdown、圖片、參考、進度、按鈕和檔案樹。例如,產生此回應
擴充功能可以使用以下方式使用回應串流
stream.progress('Picking the right topic to teach...');
stream.markdown(`\`\`\`typescript
const myStack = new Stack();
myStack.push(1); // pushing a number on the stack (or let's say, adding a fish to the stack)
myStack.push(2); // adding another fish (number 2)
console.log(myStack.pop()); // eating the top fish, will output: 2
\`\`\`
So remember, Code Kitten, in a stack, the last fish in is the first fish out - which we tech cats call LIFO (Last In, First Out).`);
stream.button({
command: 'cat.meow',
title: vscode.l10n.t('Meow!'),
arguments: []
});
取得關於支援的聊天回應輸出類型的更多資訊。
實際上,擴充功能通常會將請求傳送到語言模型。一旦他們從語言模型取得回應,他們可能會進一步處理它,並決定是否應該將任何內容串流回使用者。VS Code 聊天 API 是基於串流的,並且與串流語言模型 API 相容。這讓擴充功能能夠持續報告進度和結果,目標是擁有流暢的使用者體驗。了解如何使用語言模型 API。
使用聊天訊息記錄
參與者可以存取目前聊天會話的訊息記錄。參與者只能存取提及它的訊息。history
項目是 ChatRequestTurn
或 ChatResponseTurn
。例如,使用以下程式碼片段來檢索使用者在目前聊天會話中傳送給您的參與者的所有先前請求
const previousMessages = context.history.filter(h => h instanceof vscode.ChatRequestTurn);
記錄不會自動包含在提示中,是否要將記錄作為額外上下文添加到傳遞給語言模型的訊息中,由參與者決定。
註冊命令
聊天參與者可以貢獻命令,這些命令是擴充功能提供的特定功能的快捷方式。使用者可以使用 /
語法在聊天中參考命令,例如 /explain
。
回答問題的任務之一是判斷使用者意圖。例如,VS Code 可以推斷 Create a new workspace with Node.js Express Pug TypeScript
表示您想要一個新專案,但 @workspace /new Node.js Express Pug TypeScript
更明確、簡潔且節省輸入時間。如果您在聊天輸入欄位中輸入 /
,VS Code 會提供已註冊命令及其描述的列表。
聊天參與者可以透過在 package.json
中新增命令及其描述來貢獻命令
"contributes": {
"chatParticipants": [
{
"id": "chat-sample.cat",
"name": "cat",
"fullName": "Cat",
"description": "Meow! What can I teach you?",
"isSticky": true,
"commands": [
{
"name": "teach",
"description": "Pick at random a computer science concept then explain it in purfect way of a cat"
},
{
"name": "play",
"description": "Do whatever you want, you are a cat after all"
}
]
}
]
}
取得關於斜線命令命名慣例的更多資訊。
註冊後續請求
在每個聊天請求之後,VS Code 都會調用後續提供者,以取得建議的後續問題,向使用者顯示。然後,使用者可以選取後續問題,並立即將其傳送給聊天擴充功能。後續問題可以為使用者提供靈感,以進一步深入對話,或探索聊天擴充功能的更多功能。
以下程式碼片段顯示如何在聊天擴充功能中註冊後續請求
cat.followupProvider = {
provideFollowups(result: ICatChatResult, context: vscode.ChatContext, token: vscode.CancellationToken) {
if (result.metadata.command === 'teach') {
return [{
prompt: 'let us play',
title: vscode.l10n.t('Play with the cat')
} satisfies vscode.ChatFollowup];
}
}
};
後續問題應寫成問題或指示,而不僅僅是簡潔的命令。
實作參與者偵測
為了更輕鬆地使用自然語言的聊天參與者,您可以實作參與者偵測。參與者偵測是一種自動將使用者的問題路由到合適的參與者的方式,而無需在提示中明確提及參與者。例如,如果使用者詢問「如何將登入頁面新增到我的專案?」,則問題將自動路由到 @workspace
參與者,因為它可以回答關於使用者專案的問題。
VS Code 使用聊天參與者描述和範例來判斷要將聊天提示路由到哪個參與者。您可以在擴充功能 package.json
檔案中的 disambiguation
屬性中指定此資訊。disambiguation
屬性包含偵測類別的列表,每個類別都包含描述和範例。
屬性 | 描述 | 範例 |
---|---|---|
category |
偵測類別。如果參與者有多種用途,您可以為每個用途設定一個類別。 |
|
description |
適合此參與者的問題種類的詳細描述。 |
|
examples |
代表性範例問題的列表。 |
|
您可以為整體聊天參與者、特定命令或兩者的組合定義參與者偵測。
以下程式碼片段顯示如何在參與者層級實作參與者偵測。
"contributes": {
"chatParticipants": [
{
"id": "chat-sample.cat",
"fullName": "Cat",
"name": "cat",
"description": "Meow! What can I teach you?",
"disambiguation": [
{
"category": "cat",
"description": "The user wants to learn a specific computer science topic in an informal way.",
"examples": [
"Teach me C++ pointers using metaphors",
"Explain to me what is a linked list in a simple way",
"Can you explain to me what is a function in programming?"
]
}
]
}
]
}
同樣地,您也可以透過為 commands
屬性中的一個或多個項目新增 disambiguation
屬性,在命令層級設定參與者偵測。
套用以下指南以提高擴充功能參與者偵測的準確性
- 具體說明:描述和範例應盡可能具體,以避免與其他參與者發生衝突。避免在參與者和命令資訊中使用通用術語。
- 使用範例:範例應代表適合參與者的問題種類。使用同義詞和變體來涵蓋廣泛的使用者查詢。
- 使用自然語言:描述和範例應以自然語言撰寫,就像您向使用者解釋參與者一樣。
- 測試偵測:使用範例問題的變體測試參與者偵測,並驗證是否與內建聊天參與者沒有衝突。
內建聊天參與者在參與者偵測中優先。例如,在工作區檔案上運作的聊天參與者可能會與內建的 @workspace
參與者衝突。
支援的聊天回應輸出類型
若要傳回對聊天請求的回應,您可以使用ChatResponseStream
參數在 ChatRequestHandler
上。
以下列表提供聊天檢視中聊天回應的輸出類型。聊天回應可以組合多種不同的輸出類型。
-
Markdown
呈現 Markdown 文字片段、簡單文字或圖片。您可以使用屬於 CommonMark 規範的任何 Markdown 語法。使用
ChatResponseStream.markdown
方法並提供 Markdown 文字。範例程式碼片段
// Render Markdown text stream.markdown('# This is a title \n'); stream.markdown('This is stylized text that uses _italics_ and **bold**. '); stream.markdown('This is a [link](https://vscode.dev.org.tw).\n\n'); stream.markdown('');
-
程式碼區塊
呈現支援 IntelliSense、程式碼格式化和互動式控制項的程式碼區塊,以將程式碼套用至活動編輯器。若要顯示程式碼區塊,請使用
ChatResponseStream.markdown
方法並套用程式碼區塊的 Markdown 語法(使用反引號)。範例程式碼片段
// Render a code block that enables users to interact with stream.markdown('```bash\n'); stream.markdown('```ls -l\n'); stream.markdown('```');
-
命令連結
在聊天回應中內嵌呈現連結,使用者可以選取該連結來調用 VS Code 命令。若要顯示命令連結,請使用
ChatResponseStream.markdown
方法並使用連結的 Markdown 語法[連結文字](command:commandId)
,您在 URL 中提供命令 ID。例如,以下連結會開啟命令面板:[命令面板](command:workbench.action.showCommands)
。為了防止從服務載入 Markdown 文字時發生命令注入,您必須使用
vscode.MarkdownString
物件,並將isTrusted
屬性設定為受信任的 VS Code 命令 ID 列表。此屬性是啟用命令連結運作的必要條件。如果未設定isTrusted
屬性或未列出命令,則命令連結將無法運作。範例程式碼片段
// Use command URIs to link to commands from Markdown let markdownCommandString: vscode.MarkdownString = new vscode.MarkdownString( `[Use cat names](command:${CAT_NAMES_COMMAND_ID})` ); markdownCommandString.isTrusted = { enabledCommands: [CAT_NAMES_COMMAND_ID] }; stream.markdown(markdownCommandString);
如果命令採用引數,您需要先對引數進行 JSON 編碼,然後將 JSON 字串編碼為 URI 元件。然後,將編碼的引數作為查詢字串附加到命令連結。
// Encode the command arguments const encodedArgs = encodeURIComponent(JSON.stringify(args)); // Use command URIs with arguments to link to commands from Markdown let markdownCommandString: vscode.MarkdownString = new vscode.MarkdownString( `[Use cat names](command:${CAT_NAMES_COMMAND_ID}?${encodedArgs})` ); markdownCommandString.isTrusted = { enabledCommands: [CAT_NAMES_COMMAND_ID] }; stream.markdown(markdownCommandString);
-
命令按鈕
呈現一個按鈕,用於調用 VS Code 命令。該命令可以是內建命令,也可以是您在擴充功能中定義的命令。使用
ChatResponseStream.button
方法並提供按鈕文字和命令 ID。範例程式碼片段
// Render a button to trigger a VS Code command stream.button({ command: 'my.command', title: vscode.l10n.t('Run my command') });
-
檔案樹
呈現檔案樹控制項,讓使用者可以預覽個別檔案。例如,在建議建立新工作區時顯示工作區預覽。使用
ChatResponseStream.filetree
方法並提供檔案樹元素陣列和檔案的基本位置(資料夾)。範例程式碼片段
// Create a file tree instance var tree: vscode.ChatResponseFileTree[] = [ { name: 'myworkspace', children: [{ name: 'README.md' }, { name: 'app.js' }, { name: 'package.json' }] } ]; // Render the file tree control at a base location stream.filetree(tree, baseLocation);
-
進度訊息
在長時間執行的操作期間呈現進度訊息,以向使用者提供中繼回饋。例如,報告多步驟操作中每個步驟的完成情況。使用
ChatResponseStream.progress
方法並提供訊息。範例程式碼片段
// Render a progress message stream.progress('Connecting to the database.');
-
參考
在參考列表中新增外部 URL 或編輯器位置的參考,以指示您用作上下文的資訊。使用
ChatResponseStream.reference
方法並提供參考位置。範例程式碼片段
const fileUri: vscode.Uri = vscode.Uri.file('/path/to/workspace/app.js'); // On Windows, the path should be in the format of 'c:\\path\\to\\workspace\\app.js' const fileRange: vscode.Range = new vscode.Range(0, 0, 3, 0); const externalUri: vscode.Uri = vscode.Uri.parse('https://vscode.dev.org.tw'); // Add a reference to an entire file stream.reference(fileUri); // Add a reference to a specific selection within a file stream.reference(new vscode.Location(fileUri, fileRange)); // Add a reference to an external URL stream.reference(externalUri);
-
內嵌參考
新增 URI 或編輯器位置的內嵌參考。使用
ChatResponseStream.anchor
方法並提供錨點位置和可選標題。若要參考符號(例如,類別或變數),您可以使用編輯器中的位置。範例程式碼片段
const symbolLocation: vscode.Uri = vscode.Uri.parse('location-to-a-symbol'); // Render an inline anchor to a symbol in the workspace stream.anchor(symbolLocation, 'MySymbol');
重要事項:圖片和連結僅在它們來自受信任網域列表中的網域時才可用。取得關於 VS Code 中的連結保護的更多資訊。
衡量成功
我們建議您透過為 Unhelpful
使用者回饋事件以及參與者處理的請求總數新增遙測記錄來衡量參與者的成功程度。然後,初始參與者成功指標可以定義為:unhelpful_feedback_count / total_requests
。
const logger = vscode.env.createTelemetryLogger({
// telemetry logging implementation goes here
});
cat.onDidReceiveFeedback((feedback: vscode.ChatResultFeedback) => {
// Log chat result feedback to be able to compute the success metric of the participant
logger.logUsage('chatResultFeedback', {
kind: feedback.kind
});
});
與您的聊天回應的任何其他使用者互動都應衡量為正面指標(例如,使用者選取聊天回應中產生的按鈕)。在使用 AI 時,使用遙測衡量成功至關重要,因為它是一種非確定性技術。執行實驗、衡量和迭代改進您的參與者,以確保良好的使用者體驗。
命名限制與慣例
聊天參與者命名慣例
屬性 | 描述 | 命名指南 |
---|---|---|
id |
聊天參與者的全域唯一識別碼 |
|
name |
聊天參與者的名稱,使用者透過 @ 符號參考 |
|
fullName |
(可選)參與者的完整名稱,顯示為來自參與者的回應的標籤 |
|
description |
(可選)聊天參與者功能的簡短描述,顯示為聊天輸入欄位或參與者列表中的預留位置文字 |
|
當在任何使用者面向的元素(例如屬性、聊天回應或聊天使用者介面)中提及您的聊天參與者時,建議不要使用術語參與者,因為它是 API 的名稱。例如,@cat
擴充功能可以稱為「適用於 GitHub Copilot 的貓擴充功能」。
斜線命令命名慣例
屬性 | 描述 | 命名指南 |
---|---|---|
name |
斜線命令的名稱,使用者透過 / 符號參考 |
|
description |
(可選)斜線命令功能的簡短描述,顯示為聊天輸入欄位或參與者和命令列表中的預留位置文字 |
|
指南
聊天參與者不應僅僅是問答機器人。在建立聊天參與者時,要有創意並使用現有的 VS Code API 來建立 VS Code 中豐富的整合。使用者也喜歡豐富且便利的互動,例如回應中的按鈕、將使用者帶到聊天中的參與者的選單項目。思考 AI 可以幫助您的使用者的真實情境。
並非每個擴充功能都貢獻聊天參與者才有意義。在聊天中擁有太多參與者可能會導致不良的使用者體驗。當您想要控制完整提示時,聊天參與者是最佳的,包括對語言模型的指示。您可以重複使用精心製作的 Copilot 系統訊息,並且可以為其他參與者貢獻上下文。
例如,語言擴充功能(例如 C++ 擴充功能)可以透過各種其他方式貢獻
- 貢獻工具,將語言服務智慧帶給使用者查詢。例如,C++ 擴充功能可以將
#cpp
工具解析為工作區的 C++ 狀態。這為 Copilot 語言模型提供了正確的 C++ 上下文,以提高 Copilot 回答 C++ 的品質。 - 貢獻智慧動作,這些動作使用語言模型,可選地與傳統語言服務知識結合使用,以提供出色的使用者體驗。例如,C++ 可能已經提供「提取到方法」智慧動作,該動作使用語言模型為新方法產生合適的預設名稱。
聊天擴充功能應明確徵求使用者同意,如果它們即將執行成本高昂的操作,或者即將編輯或刪除無法復原的內容。為了獲得出色的使用者體驗,我們不鼓勵擴充功能貢獻多個聊天參與者。每個擴充功能最多一個聊天參與者是一個簡單的模型,可以在 UI 中良好地擴展。
發佈您的擴充功能
一旦您建立了 AI 擴充功能,您就可以將您的擴充功能發佈到 Visual Studio Marketplace
- 在發佈到 VS Marketplace 之前,我們建議您閱讀Microsoft AI 工具和實務指南。這些指南為負責任地開發和使用 AI 技術提供了最佳實務。
- 透過發佈到 VS Marketplace,您的擴充功能即遵守GitHub Copilot 擴充性可接受的開發和使用政策。
- 如發佈擴充功能中所述,上傳到 Marketplace。
- 如果您的擴充功能已提供聊天以外的功能,我們建議您不要在擴充功能資訊清單中引入 GitHub Copilot 的擴充功能相依性。 這樣可確保不使用 GitHub Copilot 的擴充功能使用者可以使用非聊天功能,而無需安裝 GitHub Copilot。