尝试以扩展 VS Code 中的代理模式!

语言模型工具 API

语言模型工具使您能够通过特定领域的功能扩展大型语言模型 (LLM) 在聊天中的功能。为了处理用户的聊天提示,VS Code 中的代理模式可以自动调用这些工具,作为对话的一部分执行专门任务。通过在 VS Code 扩展中贡献语言模型工具,您可以扩展代理编码工作流程,同时提供与编辑器的深度集成。

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

您还可以通过贡献MCP 服务器来扩展具有专用工具的聊天体验。有关不同选项以及如何决定使用哪种方法的详细信息,请参阅AI 扩展性概述

LLM 中的工具调用是什么?

语言模型工具是作为语言模型请求的一部分可以调用的函数。例如,您可能有一个从数据库检索信息、执行一些计算或调用在线 API 的函数。当您在 VS Code 扩展中贡献工具时,代理模式可以根据对话的上下文调用该工具。

LLM 实际上从不执行工具本身,而是 LLM 生成用于调用工具的参数。清楚地描述工具的用途、功能和输入参数非常重要,以便可以在正确的上下文中调用该工具。

下图显示了 VS Code 中代理模式下的工具调用流程。有关涉及的具体步骤的详细信息,请参阅工具调用流程

Diagram that shows the Copilot tool-calling flow

在 OpenAI 文档中阅读有关函数调用的更多信息。

为什么在扩展中实现语言模型工具?

在扩展中实现语言模型工具有几个好处:

  • 通过专门的、特定领域的工具扩展代理模式,这些工具会自动作为响应用户提示的一部分被调用。例如,启用数据库搭建和查询以动态地为 LLM 提供相关上下文。
  • 通过使用广泛的扩展 API与 VS Code 深度集成。例如,使用调试 API 获取当前调试上下文并将其用作工具功能的一部分。
  • 通过 Visual Studio Marketplace分发和部署工具,为用户提供可靠、无缝的体验。用户无需单独安装和更新您的工具。

在以下情况下,您可能会考虑使用MCP 服务器实现语言模型工具:

  • 您已经有一个 MCP 服务器实现,并且还想在 VS Code 中使用它。
  • 您想在不同的开发环境和平台中重用相同的工具。
  • 您的工具作为服务远程托管。
  • 您不需要访问 VS Code API。

创建语言模型工具

实现语言模型工具包括两个主要部分:

  1. 在扩展的package.json文件中定义工具的配置。
  2. 使用语言模型 API 参考在扩展代码中实现工具

您可以从基本示例项目开始。

1. package.json中的静态配置

在扩展中定义语言模型工具的第一步是在扩展的package.json文件中定义它。此配置包括工具名称、描述、输入架构和其他元数据

  1. 在扩展的package.json文件的contributes.languageModelTools部分中为您的工具添加一个条目。

  2. 为工具指定一个唯一的名称

    属性 描述
    name 工具的唯一名称,用于在扩展实现代码中引用工具。以{verb}_{noun}格式命名。请参阅命名准则
    displayName 工具的用户友好名称,用于在 UI 中显示。
  3. 如果工具可以在代理模式下使用或在聊天提示中用#引用,请添加以下属性

    用户可以在聊天视图中启用或禁用工具,类似于模型上下文协议 (MCP) 工具的启用和禁用方式。

    属性 描述
    canBeReferencedInPrompt 如果工具可以在代理模式下使用或在聊天中引用,则设置为true
    toolReferenceName 用户通过#在聊天提示中引用工具的名称。
    icon 在 UI 中为工具显示的图标。
    userDescription 工具的用户友好描述,用于在 UI 中显示。
  4. modelDescription中添加详细描述。此信息由 LLM 用于确定在何种上下文中应使用您的工具。

    • 工具到底做什么?
    • 它返回什么样的信息?
    • 何时应该使用和不应该使用它?
    • 描述工具的重要限制或约束。
  5. 如果工具接受输入参数,请添加一个inputSchema属性,该属性描述工具的输入参数。

    此 JSON 架构描述了一个对象,其中包含工具作为输入接受的属性,以及它们是否是必需的。文件路径应为绝对路径。

    描述每个参数的作用以及它与工具功能的关系。

  6. 添加一个when子句来控制工具何时可用。

    languageModelTools贡献点允许您使用when 子句限制工具何时可用于代理模式或可在提示中引用。例如,一个获取调试调用堆栈信息的工具只应在用户正在调试时才可用。

    "contributes": {
        "languageModelTools": [
            {
                "name": "chat-tools-sample_tabCount",
                ...
                "when": "debugState == 'running'"
            }
        ]
    }
    
工具定义示例

以下示例显示了如何定义一个计算选项卡组中活动选项卡数量的工具。

"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 in VS Code.",
            "userDescription": "Count the number of active tabs in a tab group.",
            "canBeReferencedInPrompt": true,
            "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
                    }
                }
            }
        }
    ]
}

2. 工具实现

使用语言模型 API 实现语言模型工具。这包括以下步骤:

  1. 在扩展激活时,使用vscode.lm.registerTool注册工具。

    提供您在package.jsonname属性中指定的工具名称。

    如果您希望工具对您的扩展是私有的,请跳过工具注册步骤。

    export function registerChatTools(context: vscode.ExtensionContext) {
      context.subscriptions.push(
        vscode.lm.registerTool('chat-tools-sample_tabCount', new TabCountTool())
      );
    }
    
  2. 创建一个实现vscode.LanguageModelTool<>接口的类。

  3. prepareInvocation方法中添加工具确认消息。

    对于来自扩展的工具,将始终显示通用确认对话框,但工具可以自定义确认消息。向用户提供足够的上下文,以了解工具正在做什么。消息可以是包含代码块的MarkdownString

    以下示例显示了如何为选项卡计数工具提供确认消息。

    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,
        };
    }
    

    如果prepareInvocation返回undefined,将显示通用确认消息。请注意,用户也可以选择“始终允许”某个工具。

  4. 定义一个描述工具输入参数的接口。

    该接口在vscode.LanguageModelTool类的invoke方法中使用。输入参数根据您在package.jsoninputSchema中定义的 JSON 架构进行验证。

    以下示例显示了选项卡计数工具的接口。

    export interface ITabCountParameters {
      tabGroup?: number;
    }
    
  5. 实现invoke方法。当在处理聊天提示时调用语言模型工具时,将调用此方法。

    invoke方法在options参数中接收工具输入参数。参数根据package.jsoninputSchema中定义的 JSON 架构进行验证。

    当发生错误时,抛出一个对 LLM 有意义的消息的错误。可选地,提供关于 LLM 接下来应该做什么的说明,例如使用不同的参数重试,或者执行不同的操作。

    以下示例显示了选项卡计数工具的实现。工具的结果是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 扩展示例存储库中查看实现语言模型工具的完整源代码。

工具调用流程

当用户发送聊天提示时,会发生以下步骤:

  1. Copilot 根据用户的配置确定可用工具列表。

    工具列表包括内置工具、扩展注册的工具以及来自MCP 服务器的工具。您可以通过扩展或 MCP 服务器(图中标绿色)为代理模式做出贡献。

  2. Copilot 将请求发送到 LLM,并向其提供提示、聊天上下文以及要考虑的工具定义列表。

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

  3. 如果需要,Copilot 使用 LLM 提供的参数值调用建议的工具。

    工具响应可能会导致更多工具调用请求。

  4. 如果存在错误或后续工具请求,Copilot 将迭代工具调用流程,直到所有工具请求都得到解决。

  5. Copilot 向用户返回最终响应,其中可能包括来自多个工具的响应。

准则和约定

  • 命名:为工具和参数编写清晰和描述性的名称。

    • 工具名称:应唯一且清晰地描述其意图。以{verb}_{noun}格式构造工具名称。例如,get_weatherget_azure_deploymentget_terminal_output

    • 参数名称:应描述参数的用途。以{noun}格式构造参数名称。例如,destination_locationtickerfile_name

  • 描述:为工具和参数编写详细描述。

    • 描述工具的功能以及何时应该和不应该使用它。例如,“此工具检索给定位置的天气。”
    • 描述每个参数的作用以及它与工具功能的关系。例如,“destination_location参数指定要检索天气的地点。它应该是一个有效的地点名称或坐标。”
    • 描述工具的重要限制或约束。例如,“此工具仅检索美国境内地点的天气数据。它可能不适用于其他地区。”
  • 用户确认:为工具调用提供确认消息。对于来自扩展的工具,将始终显示通用确认对话框,但工具可以自定义确认消息。向用户提供足够的上下文,以了解工具正在做什么。

  • 错误处理:当发生错误时,抛出一个对 LLM 有意义的消息的错误。可选地,提供关于 LLM 接下来应该做什么的说明,例如使用不同的参数重试,或者执行不同的操作。

OpenAI 文档Anthropic 文档中获取更多创建工具的最佳实践。