语言模型 API

语言模型 API 使你能够使用语言模型,并将 AI 驱动的功能及自然语言处理集成到你的 Visual Studio Code 扩展中。

你可以在多种类型的扩展中使用语言模型 API。该 API 的一个典型用途是聊天扩展,在此类扩展中,你利用语言模型来理解用户请求并协助提供答案。然而,语言模型 API 的用途并不局限于此。你可以在语言调试器扩展中使用语言模型,也可以将其作为自定义扩展中命令任务的一部分。例如,Rust 扩展可能会使用语言模型来提供默认名称,从而改善重命名体验。

使用语言模型 API 的过程包含以下步骤:

  1. 构建语言模型提示词(Prompt)
  2. 发送语言模型请求
  3. 解读响应

以下章节详细介绍了如何在你的扩展中实现这些步骤。

若要开始,你可以探索 聊天扩展示例

构建语言模型提示词(Prompt)

为了与语言模型进行交互,扩展程序应首先构思提示词,然后向语言模型发送请求。你可以使用提示词向语言模型提供有关你正在执行的任务的广泛说明。提示词还可以定义解释用户消息的上下文。

构建语言模型提示词时,语言模型 API 支持两种类型的消息:

  • User(用户) - 用于提供指令和用户请求。
  • Assistant(助手) - 用于将之前语言模型响应的历史记录作为上下文添加到提示词中。

注意:目前,语言模型 API 不支持使用系统消息(System messages)。

你可以通过两种方式构建语言模型提示词:

  • LanguageModelChatMessage - 通过提供一条或多条字符串消息来创建提示词。如果你刚开始接触语言模型 API,可以使用这种方法。
  • @vscode/prompt-tsx - 使用 TSX 语法声明提示词。

如果你想更精细地控制语言模型提示词的组成,可以使用 prompt-tsx 库。例如,该库可以帮助动态调整提示词的长度,以适配每个语言模型的上下文窗口大小。了解有关 @vscode/prompt-tsx 的更多信息,或查看 聊天扩展示例 以开始使用。

若要了解更多关于提示词工程(Prompt Engineering)的概念,我们建议阅读 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 方法选择要使用的语言模型。此方法返回一个符合指定条件的语言模型数组。如果你正在实现聊天参与者(chat participant),我们建议使用作为聊天请求处理程序中 request 对象一部分传递的模型。这可以确保你的扩展程序遵循用户在聊天模型下拉菜单中选择的模型。然后,使用 sendRequest 方法将请求发送给语言模型。

要选择语言模型,你可以指定以下属性:vendor(供应商)、idfamily(系列)或 version(版本)。使用这些属性可以广泛匹配给定供应商或系列的所有模型,或通过 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 方法向语言模型发送请求。传入你之前构建的提示词、任何附加选项以及一个取消令牌(cancellation token)。

当你向语言模型 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 与聊天 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 token 的限制。selectChatModels 调用返回的模型对象具有一个 maxInputTokens 属性,该属性显示了 token 上限。随着我们对扩展如何使用语言模型的了解深入,这些限制将会扩大。

速率限制

扩展应负责任地使用语言模型,并注意速率限制。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。
© . This site is unofficial and not affiliated with Microsoft.