聊天参与者 API
聊天参与者是专门的助手,用户可以通过它们使用特定领域的专家扩展 VS Code 中的聊天。用户通过 @ 提及来调用聊天参与者,然后参与者负责处理用户的自然语言提示。
在本扩展指南中,你将学习如何使用聊天参与者 API 创建聊天参与者。
VS Code 有几个内置的聊天参与者,例如 @vscode
、@terminal
或 @workspace
。它们经过优化,可以回答其各自领域的问题。
聊天参与者不同于 语言模型工具,后者是 LLM 编排解决用户聊天提示所需步骤的一部分。聊天参与者接收用户的提示并自行编排所需的任务。
为什么要你的扩展中实现聊天参与者?
在你的扩展中实现聊天参与者有几个好处
- 用专业的领域特定知识和专业技能扩展聊天。例如,内置的
@vscode
参与者拥有关于 VS Code 及其扩展 API 的知识。 - 拥有对话,通过管理端到端用户聊天提示和响应。
- 与 VS Code 深度集成,通过使用广泛的扩展 API。例如,使用 调试 API 获取当前调试上下文并将其用作工具功能的一部分。
- 通过 Visual Studio Marketplace 分发和部署聊天参与者,为用户提供可靠、无缝的体验。用户无需单独安装和更新过程。
如果你想提供可在自主代理编码会话中自动调用的领域特定功能,你可能需要考虑实现 语言模型工具 或 MCP 服务器。有关不同选项以及如何决定使用哪种方法的详细信息,请参阅 AI 扩展性概述。
聊天用户体验的组成部分
以下屏幕截图显示了示例扩展在 Visual Studio Code 聊天体验中的不同聊天概念。
- 使用
@
语法调用@cat
聊天参与者 - 使用
/
语法调用/teach
命令 - 用户提供的查询,也称为用户提示
- 图标和参与者
fullName
,表示 Copilot 正在使用@cat
聊天参与者 - 由
@cat
提供的 Markdown 响应 - Markdown 响应中包含的代码片段
@cat
响应中包含的按钮,该按钮调用 VS Code 命令- 聊天参与者提供的建议 后续问题
- 聊天输入字段,其中包含由聊天参与者的
description
属性提供的占位符文本
创建聊天参与者
实现聊天参与者包括以下部分
- 在扩展的
package.json
文件中定义聊天参与者。 - 实现请求处理程序以处理用户的聊天提示并返回响应。
- (可选)实现聊天斜杠命令,为用户提供常见任务的简写表示法。
- (可选)定义建议的后续问题。
- (可选)实现参与者检测,VS Code 在无需用户明确提及的情况下自动将聊天请求路由到适当的聊天参与者。
你可以从 基本示例项目 开始。
1. 注册聊天参与者
创建聊天扩展的第一步是在 package.json
中注册它,包含以下属性
id
:聊天参与者的唯一标识符,如package.json
文件中定义的。name
:聊天参与者的短名称,用于聊天中的 @ 提及。fullName
:聊天参与者的全名,显示在响应的标题区域。description
:聊天参与者目的的简要描述,用作聊天输入字段中的占位符文本。isSticky
:一个布尔值,指示聊天参与者在响应后是否在聊天输入字段中保持不变。
"contributes": {
"chatParticipants": [
{
"id": "chat-sample.my-participant",
"name": "my-participant",
"fullName": "My Participant",
"description": "What can I teach you?",
"isSticky": true
}
]
}
我们建议使用小写 name
并使用首字母大写 fullName
以与现有聊天参与者对齐。获取有关 聊天参与者的命名约定 的更多信息。
某些参与者名称是保留的。如果你使用此类保留名称,VS Code 将显示你的聊天参与者的完全限定名称(包括扩展 ID)。
2. 实现请求处理程序
使用 聊天参与者 API 实现聊天参与者。这包括以下步骤
-
在扩展激活时,使用
vscode.chat.createChatParticipant
创建参与者。提供你在
package.json
中定义的 ID,以及你将在下一步中实现的请求处理程序的引用。export function activate(context: vscode.ExtensionContext) { // Register the chat participant and its request handler const cat = vscode.chat.createChatParticipant('chat-sample.my-participant', handler); // Optionally, set some properties for @cat cat.iconPath = vscode.Uri.joinPath(context.extensionUri, 'cat.jpeg'); // Add the chat request handler here }
-
在
activate
函数中,定义vscode.ChatRequestHandler
请求处理程序。请求处理程序负责处理 VS Code 聊天视图中用户的聊天请求。每次用户在聊天输入字段中输入提示时,都会调用聊天请求处理程序。
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
确定用户的意图。为了确定用户请求的意图,你可以引用
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
语言模型实例来处理请求。在这种情况下,你可能需要调整语言模型提示以匹配用户的意图。或者,你可以通过调用后端服务、使用传统编程逻辑或结合所有这些选项来实现扩展逻辑。例如,你可以调用网络搜索以收集额外信息,然后将其作为上下文提供给语言模型。
在处理当前请求时,你可能需要引用以前的聊天消息。例如,如果以前的响应返回了 C# 代码片段,用户的当前请求可能是“用 Python 提供代码”。了解如何使用聊天消息历史记录](#use-the-chat-message-history)。
如果你想根据聊天输入的位置(聊天视图、快速聊天、内联聊天)以不同方式处理请求,可以使用
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。
3. 注册斜杠命令
聊天参与者可以贡献斜杠命令,这是扩展提供的特定功能的快捷方式。用户可以使用 /
语法在聊天中引用斜杠命令,例如 /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"
}
]
}
]
}
获取有关 斜杠命令命名约定 的更多信息。
4. 注册后续请求
在每个聊天请求之后,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];
}
}
};
后续应写成问题或方向,而不仅仅是简洁的命令。
5. 实现参与者检测
为了更容易地使用自然语言聊天参与者,你可以实现参与者检测。参与者检测是一种自动将用户问题路由到合适的参与者的方法,而无需在提示中明确提及参与者。例如,如果用户询问“如何向我的项目添加登录页面?”,则该问题将自动路由到 @workspace
参与者,因为它可以回答有关用户项目的问题。
VS Code 使用聊天参与者描述和示例来确定将聊天提示路由到哪个参与者。你可以在扩展的 package.json
文件中的 disambiguation
属性中指定此信息。disambiguation
属性包含一个检测类别列表,每个类别都有描述和示例。
属性 | 描述 | 示例 |
---|---|---|
类别 |
检测类别。如果参与者有不同的目的,你可以为每个目的设置一个类别。 |
|
描述 |
适合此参与者的问题类型的详细描述。 |
|
示例 |
代表性示例问题列表。 |
|
你可以为整体聊天参与者、特定命令或两者的组合定义参与者检测。
以下代码片段显示了如何在参与者级别实现参与者检测。
"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
参与者冲突。
使用聊天消息历史记录
参与者可以访问当前聊天会话的消息历史记录。参与者只能访问提及它的消息。history
项可以是 ChatRequestTurn
或 ChatResponseTurn
。例如,使用以下代码片段检索用户在当前聊天会话中发送给你的参与者的所有以前的请求
const previousMessages = context.history.filter(h => h instanceof vscode.ChatRequestTurn);
历史记录不会自动包含在提示中,由参与者决定是否在将消息传递给语言模型时将历史记录添加为附加上下文。
支持的聊天响应输出类型
要向聊天请求返回响应,你可以在 ChatRequestHandler
上使用 ChatResponseStream
参数。
以下列表提供了聊天视图中聊天响应的输出类型。聊天响应可以组合多种不同的输出类型。
-
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.js.cn).\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' }, { 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.js.cn'); // 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 中的链接保护 的更多信息。
实现工具调用
为了响应用户请求,聊天扩展可以调用语言模型工具。了解更多关于 语言模型工具 和 工具调用流程 的信息。
你可以通过两种方式实现工具调用
- 使用
@vscode/chat-extension-utils
库 来简化聊天扩展中调用工具的过程。 - 自行实现工具调用,这可以让你对工具调用过程有更多控制。例如,在将工具响应发送到 LLM 之前执行额外的验证或以特定方式处理工具响应。
使用聊天扩展库实现工具调用
你可以使用 @vscode/chat-extension-utils
库 来简化聊天扩展中调用工具的过程。
在你的 聊天参与者 的 vscode.ChatRequestHandler
函数中实现工具调用。
-
确定当前聊天上下文的相关工具。你可以使用
vscode.lm.tools
访问所有可用的工具。以下代码片段显示了如何过滤工具,仅选择具有特定标签的工具。
const tools = request.command === 'all' ? vscode.lm.tools : vscode.lm.tools.filter(tool => tool.tags.includes('chat-tools-sample'));
-
使用
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
:(可选)聊天参与者提示的说明。model
:(可选)用于请求的模型。如果未指定,则使用聊天上下文中的模型。tools
:(可选)要考虑用于请求的工具列表。requestJustification
:(可选)描述请求原因的字符串。responseStreamOptions
:(可选)使sendChatParticipantRequest
能够将响应流式传输回 VS Code。此外,你还可以选择启用引用和/或响应文本。
-
返回 LLM 的结果。这可能包含错误详细信息或工具调用元数据。
return await libResult.result;
此 工具调用示例 的完整源代码可在 VS Code 扩展示例存储库中找到。
自行实现工具调用
对于更高级的场景,你也可以自行实现工具调用。或者,你可以使用 @vscode/prompt-tsx
库来制作 LLM 提示。通过自行实现工具调用,你可以对工具调用过程有更多控制。例如,在将工具响应发送到 LLM 之前执行额外的验证或以特定方式处理工具响应。
在 VS Code 扩展示例存储库中查看使用 prompt-tsx 实现工具调用 的完整源代码。
衡量成功
我们建议你通过为“无用”用户反馈事件和参与者处理的请求总数添加遥测日志来衡量参与者的成功。然后,可以将初始参与者成功指标定义为: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 时,通过遥测衡量成功至关重要,因为它是一种非确定性技术。运行实验,衡量并迭代改进你的参与者,以确保良好的用户体验。
指南和约定
指南
聊天参与者不应仅仅是问答机器人。在构建聊天参与者时,要发挥创造力,并使用现有的 VS Code API 在 VS Code 中创建丰富的集成。用户也喜欢丰富便捷的交互,例如回复中的按钮、将用户带到聊天中参与者的菜单项。思考 AI 可以帮助用户的真实生活场景。
并非每个扩展都贡献聊天参与者都是有意义的。聊天中参与者过多可能会导致糟糕的用户体验。当你想要控制完整的提示(包括对语言模型的指令)时,聊天参与者是最佳选择。你可以重用精心制作的 Copilot 系统消息,并且可以为其他参与者贡献上下文。
例如,语言扩展(例如 C++ 扩展)可以通过多种其他方式做出贡献
- 贡献工具,将语言服务智能带到用户查询中。例如,C++ 扩展可以将
#cpp
工具解析为工作区的 C++ 状态。这为 Copilot 语言模型提供了正确的 C++ 上下文,以提高 Copilot 对 C++ 的回答质量。 - 贡献使用语言模型的智能操作,可选地与传统语言服务知识结合,以提供出色的用户体验。例如,C++ 可能已经提供了“提取到方法”智能操作,该操作使用语言模型为新方法生成合适的默认名称。
如果聊天扩展即将执行耗费资源的操作或即将编辑或删除无法撤销的内容,则应明确征求用户同意。为了获得出色的用户体验,我们不鼓励扩展贡献多个聊天参与者。每个扩展最多一个聊天参与者是一种在 UI 中良好扩展的简单模型。
聊天参与者命名约定
属性 | 描述 | 命名指南 |
---|---|---|
id |
聊天参与者的全局唯一标识符 |
|
|
聊天参与者的名称,用户通过 @ 符号引用 |
|
fullName |
(可选)参与者的全名,显示为来自参与者的响应的标签 |
|
描述 |
(可选)聊天参与者功能的简短描述,在聊天输入字段或参与者列表中显示为占位符文本 |
|
在任何面向用户的元素(例如属性、聊天响应或聊天用户界面)中引用你的聊天参与者时,建议不要使用术语 参与者,因为它是 API 的名称。例如,@cat
扩展可以称为“GitHub Copilot 的 Cat 扩展”。
斜杠命令命名约定
属性 | 描述 | 命名指南 |
---|---|---|
|
斜杠命令的名称,用户通过 / 符号引用 |
|
描述 |
(可选)斜杠命令功能的简短描述,在聊天输入字段或参与者和命令列表中显示为占位符文本 |
|
发布你的扩展
创建 AI 扩展后,你可以将扩展发布到 Visual Studio Marketplace
- 在发布到 VS Marketplace 之前,我们建议你阅读 Microsoft AI 工具和实践指南。这些指南提供了负责任地开发和使用 AI 技术的最佳实践。
- 通过发布到 VS Marketplace,你的扩展符合 GitHub Copilot 可扩展性可接受的开发和使用策略。
- 按照 发布扩展 中所述上传到 Marketplace。
- 如果你的扩展除了聊天之外还提供其他功能,我们建议你不要在 扩展清单 中引入对 GitHub Copilot 的扩展依赖项。这确保了不使用 GitHub Copilot 的扩展用户无需安装 GitHub Copilot 即可使用非聊天功能。
通过 GitHub Apps 扩展 GitHub Copilot
或者,可以通过创建 GitHub App 来扩展 GitHub Copilot,该 App 在聊天视图中贡献一个聊天参与者。GitHub App 由服务支持,并适用于所有 GitHub Copilot 表面,例如 github.com、Visual Studio 或 VS Code。另一方面,GitHub Apps 无法完全访问 VS Code API。要了解更多关于通过 GitHub App 扩展 GitHub Copilot 的信息,请参阅 GitHub 文档。
使用语言模型
聊天参与者可以通过多种方式使用语言模型。一些参与者只使用语言模型来获取自定义提示的答案,例如 示例聊天参与者。其他参与者更高级,并像自主代理一样,在语言模型的帮助下调用多个工具。这种高级参与者的一个例子是内置的 @workspace
,它了解你的工作区并可以回答有关它的问题。在内部,@workspace
由多个工具提供支持:GitHub 的知识图谱、语义搜索、本地代码索引以及 VS Code 的语言服务。