风芒短剧
111.32MB · 2025-10-23
GitHub Copilot Chat 扩展通过以下机制来应用 copilot-instructions.md
文件:
关键设置: github.copilot.chat.codeGeneration.useInstructionFiles
true
主要服务: CustomInstructionsService
这个服务负责:
系统支持两种类型的指令文件:
.instructions.md
).instructions.md
chat.instructionsFilesLocations
设置控制applyTo
前端元数据,可以根据 glob 模式自动应用useInstructionFiles
当构建 AI 提示时,CustomInstructions
组件会:
if (includeCodeGenerationInstructions !== false) {
customInstructions.push(...await this.customInstructionsService.fetchInstructionsFromSetting(ConfigKey.CodeGenerationInstructions));
}
获取配置的指令
CustomInstructionsService.fetchInstructionsFromSetting()
方法:
const inspect = this.configurationService.inspectConfig(configKey);
收集指令
{ file: "filename" }
){ text: "instruction text" }
)文件读取 当遇到文件引用时,通过 _collectInstructionsFromFile()
方法:
const promises = this.workspaceService.getWorkspaceFolders().map(async folderUri => {
const fileUri = Uri.joinPath(folderUri, customInstructionsFile);
const instruction = await this.readInstructionsFromFile(fileUri);
if (instruction) {
result.push(instruction);
}
});
对于 copilot-instructions.md
文件:
useInstructionFiles
设置为 true
时copilot-instructions.md
readInstructionsFromFile()
方法指令在以下情况下被应用:
{
"github.copilot.chat.codeGeneration.instructions": [
{
"file": ".github/copilot-instructions.md"
}
]
}
{
"github.copilot.chat.codeGeneration.useInstructionFiles": true
}
从 0.29 版本开始,系统支持按需加载指令文件:
相关代码分析:
export class CustomInstructionsService implements ICustomInstructionsService {
// 从文件加载指令
public async fetchInstructionsFromFile(fileUri: Uri): Promise<ICustomInstructions | undefined> {
return await this.readInstructionsFromFile(fileUri);
}
// 从设置加载指令
public async fetchInstructionsFromSetting(configKey: Config<CodeGenerationInstruction[]>): Promise<ICustomInstructions[]> {
const result: ICustomInstructions[] = [];
const instructions: IInstruction[] = [];
const seenFiles: Set<string> = new Set();
const inspect = this.configurationService.inspectConfig(configKey);
if (inspect) {
await this.collectInstructionsFromSettings(
[inspect.workspaceFolderValue, inspect.workspaceValue, inspect.globalValue],
seenFiles, instructions, result
);
}
const reference = Uri.from({
scheme: this.envService.uriScheme,
authority: 'settings',
path: `/${configKey.fullyQualifiedId}`
});
if (instructions.length > 0) {
result.push({
kind: CustomInstructionsKind.Setting,
content: instructions,
reference,
});
}
return result;
}
// 读取指令文件内容
private async readInstructionsFromFile(fileUri: Uri, languageId?: string): Promise<ICustomInstructions | undefined> {
try {
const fileContents = await this.fileSystemService.readFile(fileUri);
const content = new TextDecoder().decode(fileContents);
const instruction = content.trim();
if (!instruction) {
this.logService.debug(`Instructions file is empty: ${fileUri.toString()}`);
return;
}
return {
kind: CustomInstructionsKind.File,
content: [{ instruction, languageId }],
reference: fileUri
};
} catch (e) {
this.logService.debug(`Instructions file not found: ${fileUri.toString()}`);
return undefined;
}
}
}
CustomInstructions
渲染组件:
export class CustomInstructions extends PromptElement<CustomInstructionsProps> {
override async render(state: void, sizing: PromptSizing) {
const chunks = [];
// 处理聊天变量中的指令(按需加载)
if (includeCodeGenerationInstructions !== false && this.props.chatVariables) {
for (const variable of this.props.chatVariables) {
if (isPromptInstruction(variable)) {
if (isString(variable.value)) {
chunks.unshift(<TextChunk>{variable.value}</TextChunk>);
} else if (isUri(variable.value)) {
// 按需加载指令文件
const instructions = await this.customInstructionsService.fetchInstructionsFromFile(variable.value);
if (instructions) {
chunks.push(
<Tag name='attachment' attrs={{
filePath: this.promptPathRepresentationService.getFilePath(variable.value)
}}>
<references value={[new CustomInstructionPromptReference(instructions, instructions.content.map(instruction => instruction.instruction))]} />
{instructions.content.map(instruction => <TextChunk>{instruction.instruction}</TextChunk>)}
</Tag>
);
}
}
}
}
}
// 从设置加载指令
const customInstructions: ICustomInstructions[] = [];
if (includeCodeGenerationInstructions !== false) {
customInstructions.push(...await this.customInstructionsService.fetchInstructionsFromSetting(ConfigKey.CodeGenerationInstructions));
}
if (includeTestGenerationInstructions) {
customInstructions.push(...await this.customInstructionsService.fetchInstructionsFromSetting(ConfigKey.TestGenerationInstructions));
}
return (<>
{introduction}{systemMessageConflictWarning}<br />
<Tag name='instructions'>
{chunks}
</Tag>
</>);
}
// 创建指令元素,支持语言过滤
private createInstructionElement(instructions: ICustomInstructions) {
const lines = [];
for (const entry of instructions.content) {
if (entry.languageId) {
if (entry.languageId === this.props.languageId) {
lines.push(`For ${entry.languageId} code: ${entry.instruction}`);
}
} else {
lines.push(entry.instruction);
}
}
if (lines.length === 0) {
return undefined;
}
return (<>
<references value={[new CustomInstructionPromptReference(instructions, lines)]} />
<>
{lines.map(line => <TextChunk>{line}</TextChunk>)}
</>
</>);
}
}
实际工作流程:
// 指令文件格式示例
/*
---
applyTo: "**/*.ts"
description: "TypeScript coding style rules"
---
Use camelCase for variable names.
Always use strict type annotations.
Prefer const over let when possible.
*/
// 按需加载的触发机制
const availableInstructions = await this.customInstructionsService.fetchInstructionsFromSetting(ConfigKey.CodeGenerationInstructions);
// 语言模型工具可以访问指令列表
for (const instruction of availableInstructions) {
if (matchesCurrentContext(instruction.reference, currentFiles)) {
chunks.push(this.createInstructionElement(instruction));
}
}
扩展提供了 Chat: Generate Instructions 命令来:
copilot-instructions.md
文件.github
文件夹中copilot-instructions.md
文件的应用是一个 多层次、可配置的系统:
useInstructionFiles
设置自动加载这个系统让开发者可以为项目定制 AI 行为,而无需在每次交互中手动指定规则。