语言模型工具 API

在本扩展指南中,您将学习如何创建一个语言模型工具以及如何在聊天扩展中实现工具调用。

什么是LLM中的工具调用?

工具调用使您能够通过将大型语言模型(LLM)连接到外部工具和系统来扩展其功能,以执行超出文本处理范围的任务。

语言模型工具是可以作为语言模型请求的一部分调用的函数。例如,您可能有一个从数据库检索信息、查找文件或执行某些计算的函数。您可以在扩展中实现语言模型工具,或使用其他扩展中公开可用的工具。

LLM实际上从不执行工具本身,而是生成可用于调用您的工具的参数,您的代码可以通过调用指定的函数来选择如何处理这些参数。您的扩展始终完全控制工具调用过程。

阅读更多关于function calling在OpenAI文档中的内容。

为什么要使用工具调用?

在聊天扩展中有多种场景可能需要使用工具调用。一些例子包括:

  • 让LLM动态请求更多上下文。例如,您可以使用工具从数据库中检索信息,或查找相关文件。
  • 让LLM动态地采取一些行动。LLM本身无法执行计算或调用其他系统。例如,使用工具运行终端命令并将输出返回给LLM。
  • 连接由另一个 VS Code 扩展提供的上下文/行为。例如,您可能有一个工具使用 Git 扩展来检索有关当前存储库的信息。

工具调用流程

聊天扩展中的工具调用流程如下:

  1. 检索相关工具的列表

  2. 将请求发送到LLM,提供要考虑的工具定义列表

  3. LLM生成一个响应,可能包括一个或多个调用工具的请求

  4. 使用LLM响应中提供的参数值调用工具

  5. 向LLM发送另一个请求,包括工具结果

  6. LLM生成最终的用户响应,其中可能包含工具响应

    如果LLM响应包含更多工具调用的请求,重复步骤4-6,直到没有更多的工具请求。

使用聊天扩展库实现工具调用

你可以使用@vscode/chat-extension-utils来简化在聊天扩展中调用工具的过程。

在你的聊天参与者vscode.ChatRequestHandler函数中实现工具调用。

  1. 确定当前聊天上下文的相关工具。您可以通过使用vscode.lm.tools访问所有可用的工具。

    以下代码片段展示了如何过滤工具,仅保留具有特定标签的工具。

    const tools =
      request.command === 'all'
        ? vscode.lm.tools
        : vscode.lm.tools.filter(tool => tool.tags.includes('chat-tools-sample'));
    
  2. 通过使用sendChatParticipantRequest将请求和工具定义发送给LLM。

    const libResult = chatUtils.sendChatParticipantRequest(
      request,
      chatContext,
      {
        prompt: 'You are a cat! Answer as a cat.',
        responseStreamOptions: {
          stream,
          references: true,
          responseText: true
        },
        tools
      },
      token
    );
    

    ChatHandlerOptions 对象具有以下属性:

    • prompt: (optional) Instructions for the chat participant prompt.
    • model: (optional) The model to use for the request. If not specified, the model from the chat context is used.
    • tools: (optional) The list of tools to consider for the request.
    • requestJustification: (optional) A string that describes why the request is being made.
    • responseStreamOptions: (optional) Enable sendChatParticipantRequest to stream the response back to VS Code. Optionally, you can also enable references and/or response text.
  3. 返回LLM的结果。这可能包含错误详情或工具调用元数据。

    return await libResult.result;
    

这个工具调用示例的完整源代码可以在VS Code扩展示例仓库中找到。

自己实现工具调用

对于更高级的场景,你也可以自己实现工具调用。可选地,你可以使用@vscode/prompt-tsx库来制作LLM提示。通过自己实现工具调用,你可以更好地控制工具调用的过程。例如,执行额外的验证或在将工具响应发送给LLM之前以特定方式处理它们。

查看在VS Code扩展示例仓库中使用prompt-tsx实现工具调用的完整源代码

创建一个语言模型工具

在调用工具时,您可以调用由其他扩展贡献的公开可用的语言模型工具,或者您可以创建自己的工具。当您创建工具时,您可以选择是否将其注册到VS Code API,或者仅在您的扩展中将其作为私有工具使用。

当你使用VS Code API发布一个工具时,该工具对所有扩展都可用。

在注册工具和将其用作私有工具之间做出决定

如果满足以下条件,请使用VS Code API注册工具:

  • 该工具对其他扩展有意义,并且可以在不需要对特定工具进行特殊处理的情况下使用
  • 扩展需要提供进度消息和确认

在以下情况下使用私人工具:

  • 该工具不能公开,例如因为它特定于您的公司或检索非公开数据
  • 该工具需要一些特殊处理,并且特定于您的扩展

实现一个语言模型工具

实现一个语言模型工具:

  1. package.jsoncontributes属性中定义工具

    以下示例展示了如何定义一个工具来计算标签组中活动标签的数量。

    "contributes": {
        "languageModelTools": [
            {
                "name": "chat-tools-sample_tabCount",
                "tags": [
                    "editors",
                    "chat-tools-sample"
                ],
                "toolReferenceName": "tabCount",
                "displayName": "Tab Count",
                "modelDescription": "The number of active tabs in a tab group",
                "icon": "$(files)",
                "inputSchema": {
                    "type": "object",
                    "properties": {
                        "tabGroup": {
                            "type": "number",
                            "description": "The index of the tab group to check. This is optional- if not specified, the active tab group will be checked.",
                            "default": 0
                        }
                    }
                }
            }
        ]
    }
    

    语言模型工具具有以下属性:

    • name: The unique name of the tool. This is used to reference the tool in the extension implementation code.
    • tags: An array of tags that describe the tool. This is used to filter the list of tools that are relevant for a specific request.
    • toolReferenceName: If enabled, the name for users to reference the tool in a chat prompt via #.
    • displayName: The user-friendly name of the tool, used for displaying in the UI.
    • modelDescription: Description of the tool, which can be used by the language model to select it.
    • icon: The icon to display for the tool in the UI.
    • inputSchema: The JSON schema that describes the input parameters for the tool. This is used by the language model to provide parameter values for the tool invocation.
  2. (可选)使用 vscode.lm.registerTool 注册工具

    如果你想发布工具供其他扩展使用,你必须使用vscode.lm.registerTool API注册该工具。提供你在package.json文件中指定的工具名称。

    export function registerChatTools(context: vscode.ExtensionContext) {
      context.subscriptions.push(
        vscode.lm.registerTool('chat-tools-sample_tabCount', new TabCountTool())
      );
    }
    
  3. 通过实现vscode.LanguageModelTool<>接口来实现语言模型工具。

    • 实现 prepareInvocation 以提供工具调用的确认消息。

      以下示例展示了如何为标签计数工具提供确认消息。

      async prepareInvocation(
          options: vscode.LanguageModelToolInvocationPrepareOptions<ITabCountParameters>,
          _token: vscode.CancellationToken
      ) {
          const confirmationMessages = {
              title: 'Count the number of open tabs',
              message: new vscode.MarkdownString(
                  `Count the number of open tabs?` +
                  (options.input.tabGroup !== undefined
                      ? ` in tab group ${options.input.tabGroup}`
                      : '')
              ),
          };
      
          return {
              invocationMessage: 'Counting the number of tabs',
              confirmationMessages,
          };
      }
      
    • 定义一个描述工具输入参数的接口。此接口用于invoke方法中。

      以下示例显示了标签计数工具的界面。

      export interface ITabCountParameters {
        tabGroup?: number;
      }
      
    • 实现invoke,当工具被调用时会被调用。它在options参数中接收工具输入参数。

      以下示例展示了标签计数工具的实现。该工具的结果是类型为 vscode.LanguageModelToolResult 的实例。

      async invoke(
          options: vscode.LanguageModelToolInvocationOptions<ITabCountParameters>,
          _token: vscode.CancellationToken
      ) {
          const params = options.input;
          if (typeof params.tabGroup === 'number') {
              const group = vscode.window.tabGroups.all[Math.max(params.tabGroup - 1, 0)];
              const nth =
                  params.tabGroup === 1
                      ? '1st'
                      : params.tabGroup === 2
                          ? '2nd'
                          : params.tabGroup === 3
                              ? '3rd'
                              : `${params.tabGroup}th`;
              return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(`There are ${group.tabs.length} tabs open in the ${nth} tab group.`)]);
          } else {
              const group = vscode.window.tabGroups.activeTabGroup;
              return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(`There are ${group.tabs.length} tabs open.`)]);
          }
      }
      

查看在VS Code扩展示例仓库中实现语言模型工具的完整源代码。

入门指南