本站点文档内容均翻译自code.visualstudio.com,仅供个人学习,如有差异请以官网为准。

教程:使用 Chat API 构建代码教程聊天参与者

在这个教程中,您将学习如何创建一个与 GitHub Copilot 聊天体验集成的 Visual Studio Code 扩展。您将使用 Chat 扩展 API 来贡献一个聊天参与者。您的参与者将是一个代码导师,可以为编程概念提供解释和示例练习。

先决条件

完成本教程需要以下工具和账户:

步骤 1:设置您的项目

首先,使用 Yeoman 和 VS Code 扩展生成器生成扩展项目。

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

选择以下选项以完成设置:

# ? 您想创建什么类型的扩展?新扩展(TypeScript)
# ? 您的扩展名称是什么?Code Tutor

### 按 

# ? 你的扩展的标识符是什么? code-tutor
# ? 你的扩展的描述是什么? 留空
# ? 初始化一个git仓库? 是
# ? 用webpack打包源代码? 否
# ? 使用哪个包管理器? npm

# ? 您是否想用Visual Studio Code打开新文件夹?用`code`打开

一旦你的扩展项目生成,你将编辑两个文件:扩展.tspackage.json,您可以在扩展解剖学文档中了解更多。作为一个快速概述:

  • 扩展.ts是您的扩展的主要入口点,并包含您的聊天参与者的逻辑。
  • package.json包含您的扩展的元数据,例如您的参与者的名称和描述。

删除自动生成的代码扩展.ts 激活()方法。 这是您将放置我们聊天参与者的逻辑的地方。

步骤 2:注册聊天参与者

package.json文件,替换自动生成的贡献部分包含以下内容:

"贡献":{
    "聊天参与者": [
    {
        "id": "chat-tutorial.code-tutor",
        "全名": "代码导师",
        "名字": "导师",
        "描述": "我能教您什么?",
        "是否粘性": true
    }
    ]
}

此代码注册了一个聊天参与者,具有以下属性:

  • 唯一IDchat-tutorial.code-tutor,这将在代码中被引用
  • 全名代码导师,这将在您的参与者响应的标题区域显示
  • 名字导师,这将用于引用聊天参与者@导师在聊天视图中
  • 描述 "我能教您什么?",将会显示在聊天输入字段中作为占位符文本

最后,设置是否粘性:真用户开始与参与者互动后,系统会自动在聊天输入字段前添加参与者的名称。

步骤 3:设计提示

既然参与者已经注册,你就可以开始实现代码导师的逻辑了。扩展.ts文件,您将为请求定义一个提示。

制定一个好的提示是获得最佳参与者响应的关键。查看这篇文章获取提示工程的建议。

您的代码导师应该通过引导学生理解概念而不是直接提供答案来模仿现实生活中的导师。此外,导师应专注于主题,避免回答与编程无关的问题。

考虑以下两个提示。哪一个更有可能导致指定的行为?

  1. 你是一个乐于助人的代码导师。你的工作是用简单的描述和示例代码来教授用户概念。

  2. 你是有帮助的代码导师。你的工作是用简单的描述和示例代码来教授用户概念。以一系列消息的形式,引导用户概述该概念。不要直接给用户答案,而是引导他们自己找到答案。如果用户问非编程问题,请礼貌地拒绝回应。

第二个提示更具体,给参与者一个明确的方向来回应。将此提示添加到扩展.ts文件。

常量 基础提示 =
  '你是一个乐于助人的代码导师。你的工作是用简单的描述和示例代码来教授用户概念。以一系列消息的形式引导用户概述该概念。不要直接给用户答案,而是引导他们自己找到答案。如果用户问非编程问题,请礼貌地拒绝回应。';

步骤 4:实现请求处理程序

既然提示已被选择,您需要实现请求处理程序。这将处理用户的聊天请求。您将定义请求处理程序,执行处理请求的逻辑,并将响应返回给用户。

首先,定义处理程序:

// 定义一个聊天处理器
const handler: vscode.ChatRequestHandler = async (
  request: vscode.ChatRequest,
  context: vscode.ChatContext,
  stream: vscode.ChatResponseStream,
  token: vscode.CancellationToken
) => {
  return;
};

在这个处理程序的主体中,初始化提示和一个消息将提示输入数组。然后,发送用户在聊天框中输入的内容。您可以通过访问请求提示输入:.

发送请求使用请求.模型.发送请求,将使用当前选择的模型发送请求。最后,将响应流发送给用户。

// 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);

  // 流式传输响应
  for await (const fragment of chatResponse.text) {
    stream.markdown(fragment);
  }

  返回;
};

步骤 5:创建聊天参与者

一旦处理程序实现后,最后一步是使用该处理程序创建聊天参与者。创建聊天参与者方法在Chat扩展API中。确保使用与你在中使用的相同ID。package.json输入:.

您应该通过添加图标来进一步自定义您的参与者。这将在与参与者互动时显示在聊天视图中。

// 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);

// 向参与者添加图标
导师.图标路径 = vscode.Uri.joinPath(上下文.扩展路径, 'tutor.jpeg');

步骤 6: 运行代码

现在您可以尝试使用您的聊天参与者了! 按F5运行代码。一个带有您聊天参与者的 VS Code 新Windows将会打开。

在Copilot聊天面板中,您现在可以通过输入来调用您的参与者@导师

聊天面板中的参与者

试着输入你想了解的内容。你应该会看到一个回复,概述这个概念!

如果你输入一条相关消息以继续对话,你会发现参与者没有根据你的对话给出跟进回应。这是因为我们当前的参与者只发送用户的当前消息,而不是参与者消息历史。

在下面的截图中,导师正确地回应了堆栈的起始解释。然而,在后续中,它没有理解用户正在继续对话以查看堆栈在Python中的实现,而是给出了关于Python的通用回应。

参与者没有消息历史记录

步骤 7:添加消息历史记录以提供更多上下文

Copilot Chat 的一个最大价值是能够迭代多个消息以获得最佳响应。为此,您希望将参与者的消息历史记录发送到聊天请求中。您可以通过访问上下文历史输入:.

你需要检索该历史记录并将其添加到消息数组。您需要在...之前进行此操作。请求提示添加。

// 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);

  // 流式传输响应
  for await (const fragment of chatResponse.text) {
    stream.markdown(fragment);
  }

  返回;
};

现在,当你运行代码时,你可以与参与者进行对话,并且所有之前消息的上下文信息都会被考虑进去!在下面的截图中,参与者正确理解了用户要求查看Python中栈的实现。

参与者与消息历史记录

步骤 8:添加命令

既然基本的参与者已经实现,您可以通过添加命令来扩展它。命令是常见用户意图的简写表示法,并且由 标记。输入:/符号。扩展程序可以使用该命令来相应地提示语言模型。

添加一个命令来提示您的导师提供一个概念的练习题将是非常棒的。您需要在 中注册该命令package.json文件并实现逻辑在扩展.ts你可以命名这个命令锻炼这样就可以通过输入来调用/锻炼输入:.

package.json添加命令属性到聊天参与者属性。在这里,您将指定命令的名称和简短描述:

"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."
          }
        ]
      }
    ]
  },

要实现从导师获取示例练习题的逻辑,最简单的方法是更改您发送到请求的提示。创建一个新的提示,练习_提示,这要求参与者提交示例练习。以下是一个可能的样子的示例:

常量 练习提示 =
  '你是一个乐于助人的导师。你的工作是用有趣、简单的练习来教导用户,这些练习用户可以在编辑器中完成。你的练习应该从简单开始,随着用户的进步变得越来越复杂。一次只移动一个概念,直到用户给出正确的答案之前,不要进行下一个概念。在你的练习中提供提示来帮助用户学习。如果用户卡住了,你可以提供答案并解释为什么这是答案。如果用户问非编程问题,礼貌地拒绝回应。';

在请求处理程序中,您需要添加逻辑来检测用户是否引用了该命令。您可以此通过请求.命令财产。

如果命令被引用,请将提示更新为新创建的练习_提示

// 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);

  // 流式传输响应
  for await (const fragment of chatResponse.text) {
    stream.markdown(fragment);
  }

  返回;
};

那么这些就是所有需要添加的内容!其余获取消息历史记录、发送请求和流式传输请求的逻辑都保持不变。

现在你可以输入/锻炼,这将弹出你的聊天参与者,并且你可以进行互动练习来练习编码!

参与者与斜线命令

下一步

恭喜!您已成功创建一个聊天参与者,该参与者可以为编程概念提供解释和示例练习。您可以通过微调提示、添加更多斜线命令或利用其他API(如语言模型API)进一步扩展您的参与者。一旦准备好了,您还可以将您的扩展发布到Visual Studio Code市场

你可以在这个教程的完整源代码在vscode-extensions-sample 仓库中找到