1. 1. 目录
  2. 2. 前置条件
    1. 2.1. 1. 环境要求
    2. 2.2. 2. 安装扩展
    3. 2.3. 3. 基本配置
  3. 3. 自定义指令配置
    1. 3.1. 1. 配置类型概述
      1. 3.1.1. 1.1 .github/copilot-instructions.md 文件
      2. 3.1.2. 1.2 .instructions.md 文件
      3. 3.1.3. 1.3 VS Code 设置
    2. 3.2. 2. 项目级别配置
      1. 3.2.1. 2.1 创建 .github/copilot-instructions.md
      2. 3.2.2. 2.2 配置工作区设置
    3. 3.3. 3. 场景特定指令
      1. 3.3.1. 3.1 Vue 组件指令
  4. 4. Agent 模式使用
    1. 4.1. 1. 什么是 Agent 模式
    2. 4.2. 2. 启用 Agent 模式
      1. 4.2.1. 2.1 配置设置
      2. 4.2.2. 2.2 使用方法
    3. 4.3. 3. Agent 模式示例
      1. 4.3.1. 3.1 创建完整的 Vue 3 组件
      2. 4.3.2. 3.2 重构现有代码
      3. 4.3.3. 3.3 添加新功能
    4. 4.4. 4. 工具管理
      1. 4.4.1. 4.1 查看可用工具
      2. 4.4.2. 4.2 工具集配置
    5. 4.5. 5. 工具确认管理
      1. 4.5.1. 5.1 自动确认设置
      2. 4.5.2. 5.2 重置工具确认
  5. 5. MCP 服务器配置
    1. 5.1. 1. 什么是 MCP
    2. 5.2. 2. 启用 MCP 支持
      1. 5.2.1. 2.1 配置设置
    3. 5.3. 3. 添加 MCP 服务器
      1. 5.3.1. 3.1 工作区级别配置
      2. 5.3.2. 3.2 用户级别配置
    4. 5.4. 4. 常用 MCP 服务器
      1. 5.4.1. 4.1 文件系统服务器
      2. 5.4.2. 4.2 数据库服务器
      3. 5.4.3. 4.3 Web 抓取服务器
    5. 5.5. 5. 使用 MCP 工具
      1. 5.5.1. 5.1 在 Agent 模式中使用
      2. 5.5.2. 5.2 添加 MCP 资源
      3. 5.5.3. 5.3 使用 MCP 提示
  6. 6. 提示词工程
    1. 6.1. 1. 内联建议优化
      1. 6.1.1. 1.1 提供充分的上下文
      2. 6.1.2. 1.2 使用有意义的函数名
      3. 6.1.3. 1.3 添加具体的函数注释
    2. 6.2. 2. Copilot Chat 优化
      1. 6.2.1. 2.1 使用聊天参与者
      2. 6.2.2. 2.2 使用斜杠命令
      3. 6.2.3. 2.3 使用上下文变量
      4. 6.2.4. 2.4 具体明确的提示
      5. 6.2.5. 2.5 迭代改进
  7. 7. Vue 3 项目实践
    1. 7.1. 1. 项目结构配置
      1. 7.1.1. 1.1 创建项目级别指令
    2. 7.2. 2. 实际开发示例
      1. 7.2.1. 2.1 创建用户管理组件
      2. 7.2.2. 2.2 生成的代码示例
    3. 7.3. 3. 测试用例生成
  8. 8. 最佳实践
    1. 8.1. 1. 自定义指令最佳实践
      1. 8.1.1. 1.1 分层配置策略
      2. 8.1.2. 1.2 指令编写原则
      3. 8.1.3. 1.3 指令文件组织
    2. 8.2. 2. Agent 模式最佳实践
      1. 8.2.1. 2.1 任务分解
      2. 8.2.2. 2.2 上下文管理
      3. 8.2.3. 2.3 工具使用
    3. 8.3. 3. 提示词优化
      1. 8.3.1. 3.1 结构化提示
      2. 8.3.2. 3.2 上下文提供
      3. 8.3.3. 3.3 迭代改进
  9. 9. 常见问题
    1. 9.1. 1. 自定义指令相关
    2. 9.2. 2. Agent 模式相关
    3. 9.3. 3. MCP 服务器相关
    4. 9.4. 4. 性能优化
  10. 10. 总结
  11. 11. 参考资源

GitHub Copilot 完整使用教程

本教程将详细介绍如何在 VS Code 中使用 GitHub Copilot,包括自定义指令、Agent 模式、MCP 服务器配置以及最佳实践。

目录

  1. 前置条件
  2. 自定义指令配置
  3. Agent 模式使用
  4. MCP 服务器配置
  5. 提示词工程
  6. Vue 3 项目实践
  7. 最佳实践
  8. 常见问题

前置条件

1. 环境要求

  • VS Code 版本: 1.99 或更高版本
  • GitHub Copilot 扩展: 最新版本
  • GitHub Copilot Chat 扩展: 最新版本
  • 有效的 GitHub Copilot 订阅

2. 安装扩展

1
2
3
4
# 通过 VS Code 扩展市场安装
# 或使用命令行
code --install-extension GitHub.copilot
code --install-extension GitHub.copilot-chat

3. 基本配置

在 VS Code 中启用必要的设置:

1
2
3
4
5
6
7
8
9
{
"github.copilot.enable": {
"*": true,
"yaml": false,
"plaintext": false,
"markdown": false
},
"github.copilot.chat.enabled": true
}

自定义指令配置

1. 配置类型概述

GitHub Copilot 支持三种主要的自定义指令配置方式:

1.1 .github/copilot-instructions.md 文件

  • 用途: 定义项目级别的通用编码规范
  • 自动应用: 对所有聊天请求自动生效
  • 团队共享: 通过版本控制与团队成员共享

1.2 .instructions.md 文件

  • 用途: 创建特定场景的指令
  • 灵活控制: 支持 glob 模式匹配
  • 分层管理: 可创建多个指令文件

1.3 VS Code 设置

  • 用途: 在设置中定义不同场景的指令
  • 场景特定: 支持代码生成、测试、提交信息等多种场景
  • 个人定制: 支持用户级别和工作区级别配置

2. 项目级别配置

2.1 创建 .github/copilot-instructions.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# Vue 3 项目编码规范

## 通用规范

- 使用 TypeScript 进行开发
- 使用 Composition API 而非 Options API
- 组件名使用 PascalCase
- 文件名使用 kebab-case
- 使用 2 空格缩进

## Vue 特定规范

- 使用 `<script setup>` 语法
- 使用 `ref``reactive` 进行响应式数据管理
- 使用 `computed` 进行计算属性
- 使用 `watch` 进行数据监听
- 组件导入使用相对路径

## 样式规范

- 使用 Scoped CSS 或 CSS Modules
- 优先使用 Flexbox 和 Grid 布局
- 使用语义化的 CSS 类名

## 代码质量

- 所有函数和组件都要添加 JSDoc 注释
- 使用 ESLint 和 Prettier 格式化代码
- 避免使用 any 类型,尽量使用具体类型
- 使用 const 声明不可变变量

2.2 配置工作区设置

创建或编辑 .vscode/settings.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"github.copilot.chat.codeGeneration.useInstructionFiles": true,
"github.copilot.chat.codeGeneration.instructions": [
{
"text": "生成的代码要符合 Vue 3 和 TypeScript 最佳实践"
},
{
"text": "组件要使用 Composition API 和 script setup 语法"
},
{
"text": "为所有公共函数和组件添加 TypeScript 类型注解"
}
],
"github.copilot.chat.testGeneration.instructions": [
{
"text": "使用 Vitest 编写单元测试"
},
{
"text": "为组件编写测试时使用 Vue Test Utils"
}
],
"github.copilot.chat.commitMessageGeneration.instructions": [
{
"text": "使用约定式提交格式:type(scope): description"
},
{
"text": "常用类型:feat, fix, docs, style, refactor, test, chore"
}
]
}

3. 场景特定指令

3.1 Vue 组件指令

创建 .github/instructions/vue-components.instructions.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
---
description: "Vue 组件开发指令"
applyTo: "**/*.vue"
---

# Vue 组件开发规范

## 组件结构

- 使用 `<script setup>` 语法
- 按照 script、template、style 顺序组织
- 使用 TypeScript 类型定义

## 响应式数据

- 简单数据使用 `ref`
- 复杂对象使用 `reactive`
- 计算属性使用 `computed`

## 事件处理

- 事件处理函数使用 `handle` 前缀
- 使用 `emit` 向父组件通信
- 使用 `defineEmits` 定义事件类型

## 示例模板

```vue
<script setup lang="ts">
import { ref, computed } from "vue";

interface Props {
title: string;
count?: number;
}

interface Emits {
(e: "update", value: number): void;
}

const props = withDefaults(defineProps<Props>(), {
count: 0,
});

const emit = defineEmits<Emits>();

const internalCount = ref(props.count);

const displayText = computed(() => `${props.title}: ${internalCount.value}`);

const handleIncrement = () => {
internalCount.value++;
emit("update", internalCount.value);
};
</script>

<template>
<div class="component">
<h3>{{ displayText }}</h3>
<button @click="handleIncrement">增加</button>
</div>
</template>

<style scoped>
.component {
padding: 1rem;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

#### 3.2 测试指令

创建 `.github/instructions/testing.instructions.md`:

```markdown
---
description: "测试编写指令"
applyTo: "**/*.test.ts,**/*.spec.ts"
---

# 测试编写规范

## 测试框架
- 使用 Vitest 进行单元测试
- 使用 Vue Test Utils 测试组件
- 使用 @testing-library/vue 进行用户行为测试

## 测试结构
- 使用 describe 分组测试
- 使用 it 描述测试用例
- 使用 beforeEach 进行测试前置操作

## 断言规范
- 使用 expect 进行断言
- 测试覆盖率要求达到 80% 以上
- 测试用例要包含边界情况

## 组件测试模板
```typescript
import { describe, it, expect, beforeEach } from 'vitest'
import { mount } from '@vue/test-utils'
import { ComponentName } from './component-name.vue'

describe('ComponentName', () => {
let wrapper: any

beforeEach(() => {
wrapper = mount(ComponentName, {
props: {
// 测试属性
}
})
})

it('should render correctly', () => {
expect(wrapper.exists()).toBe(true)
})

it('should emit event when clicked', async () => {
await wrapper.find('button').trigger('click')
expect(wrapper.emitted('update')).toBeTruthy()
})
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

### 4. 用户级别配置

#### 4.1 创建用户级别指令

通过 VS Code 命令创建:

1. 打开命令面板 (`Cmd+Shift+P`)
2. 输入 `Chat: New Instructions File`
3. 选择 **"User"** 作为存储位置
4. 创建个人编码风格指令

#### 4.2 个人编码风格示例

```markdown
---
description: "个人编码风格偏好"
applyTo: "**"
---

# 个人编码风格

## 通用偏好
- 使用 4 空格缩进(个人喜好)
- 字符串优先使用单引号
- 函数名使用动词开头:getUserData, handleClick
- 避免使用 var,优先使用 const

## 注释规范
- 所有公共函数必须有 JSDoc 注释
- 复杂逻辑要有行内注释
- TODO 注释要包含日期和负责人

## 错误处理
- 使用 try-catch 处理异步操作
- 总是验证函数参数
- 提供有意义的错误信息

Agent 模式使用

1. 什么是 Agent 模式

Agent 模式是 GitHub Copilot 的高级功能,它可以:

  • 自主编辑多个文件:一次性修改项目中的多个文件
  • 调用工具和命令:执行终端命令、运行测试、构建项目
  • 自我修复:检测并修复代码中的错误
  • 复杂任务规划:将复杂任务分解为多个步骤

2. 启用 Agent 模式

2.1 配置设置

1
2
3
4
5
6
7
{
"chat.agent.enabled": true,
"chat.agent.maxRequests": 15,
"github.copilot.chat.agent.runTasks": true,
"github.copilot.chat.agent.autoFix": true,
"chat.extensionTools.enabled": true
}

2.2 使用方法

  1. 打开 Chat 视图: Ctrl+Cmd+I (Mac) 或 Ctrl+Shift+I (Windows/Linux)
  2. 选择 Agent 模式: 在聊天模式选择器中选择 “Agent”
  3. 输入高级任务: 描述您想要完成的复杂任务

3. Agent 模式示例

3.1 创建完整的 Vue 3 组件

1
2
3
4
5
6
7
8
创建一个用户管理组件,包含:
- 用户列表显示
- 添加用户表单
- 编辑用户功能
- 删除用户确认
- 使用 Pinia 进行状态管理
- 包含完整的 TypeScript 类型定义
- 编写单元测试

3.2 重构现有代码

1
2
3
4
5
6
重构当前的用户认证系统:
- 从 localStorage 迁移到 JWT token
- 添加 token 刷新机制
- 实现自动登出功能
- 更新所有相关的 API 调用
- 更新测试用例

3.3 添加新功能

1
2
3
4
5
6
7
为电商项目添加购物车功能:
- 创建购物车状态管理
- 实现添加/删除商品功能
- 创建购物车页面组件
- 添加商品数量控制
- 实现价格计算逻辑
- 添加持久化存储

4. 工具管理

4.1 查看可用工具

点击 Chat 视图中的 “Tools” 图标,查看可用的工具:

  • 内置工具: 文件操作、终端命令、代码分析
  • MCP 工具: 扩展的自定义工具
  • 扩展工具: 由其他扩展提供的工具

4.2 工具集配置

创建自定义工具集 .vscode/tool-sets.jsonc

1
2
3
4
5
6
7
8
9
10
11
12
{
"frontend": {
"tools": ["codebase", "findTestFiles", "problems", "terminal"],
"description": "前端开发工具集",
"icon": "code"
},
"testing": {
"tools": ["findTestFiles", "terminal", "problems"],
"description": "测试相关工具",
"icon": "test-view-icon"
}
}

5. 工具确认管理

5.1 自动确认设置

1
2
3
4
{
"chat.tools.autoApprove": false, // 建议保持 false 以确保安全
"chat.agent.autoFix": true
}

5.2 重置工具确认

使用命令:Chat: Reset Tool Confirmations


MCP 服务器配置

1. 什么是 MCP

Model Context Protocol (MCP) 是一个开放标准,允许 AI 模型通过统一接口与外部工具和服务交互。

2. 启用 MCP 支持

2.1 配置设置

1
2
3
4
{
"chat.mcp.enabled": true,
"chat.mcp.discovery.enabled": true
}

3. 添加 MCP 服务器

3.1 工作区级别配置

创建 .vscode/mcp.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
"inputs": [
{
"type": "promptString",
"id": "openai-key",
"description": "OpenAI API Key",
"password": true
}
],
"servers": {
"github": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github-token}"
}
},
"filesystem": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/path/to/allowed/files"
]
},
"postgres": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"POSTGRES_CONNECTION_STRING": "${input:postgres-connection}"
}
}
}
}

3.2 用户级别配置

settings.json 中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"mcp": {
"servers": {
"fetch": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-server-fetch"]
},
"memory": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
}
}
}
}

4. 常用 MCP 服务器

4.1 文件系统服务器

1
2
3
4
5
6
7
8
9
10
11
{
"filesystem": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"${workspaceFolder}"
]
}
}

4.2 数据库服务器

1
2
3
4
5
6
7
8
9
10
11
{
"database": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sqlite",
"${workspaceFolder}/database.db"
]
}
}

4.3 Web 抓取服务器

1
2
3
4
5
6
7
{
"fetch": {
"type": "stdio",
"command": "npx",
"args": ["-y", "mcp-server-fetch"]
}
}

5. 使用 MCP 工具

5.1 在 Agent 模式中使用

  1. 打开 Agent 模式
  2. 选择要使用的 MCP 工具
  3. 在提示中直接引用工具:#fetch#database

5.2 添加 MCP 资源

通过 “Add Context > MCP Resources” 添加外部资源作为聊天上下文。

5.3 使用 MCP 提示

直接调用 MCP 服务器提供的预配置提示:

1
2
/mcp.github.createIssue
/mcp.database.queryTable

提示词工程

1. 内联建议优化

1.1 提供充分的上下文

打开相关文件

  • 打开与当前工作相关的所有文件
  • 让 Copilot 了解项目的整体结构

添加顶级注释

1
2
3
4
5
/**
* 用户管理组件
* 提供用户的增删改查功能
* 使用 Pinia 进行状态管理
*/

明确的导入引用

1
2
3
import { defineStore } from "pinia";
import { User } from "@/types/user";
import { userApi } from "@/api/user";

1.2 使用有意义的函数名

1
2
3
4
5
6
7
8
9
// 好的例子
const fetchUsersByRole = async (role: string) => {
// Copilot 会根据函数名推断实现
};

// 不好的例子
const fetchData = async () => {
// Copilot 无法推断具体要做什么
};

1.3 添加具体的函数注释

1
2
3
4
5
6
7
8
9
10
/**
* 根据用户角色获取用户列表
* @param role - 用户角色 ('admin', 'user', 'guest')
* @param page - 页码,默认为 1
* @param pageSize - 每页数量,默认为 10
* @returns Promise<{ users: User[], total: number }>
*/
const fetchUsersByRole = async (role: string, page = 1, pageSize = 10) => {
// Copilot 会根据注释生成符合要求的实现
};

2. Copilot Chat 优化

2.1 使用聊天参与者

1
2
3
@workspace 如何重构用户认证系统?
@vscode 如何配置 TypeScript 编译选项?
@terminal 如何设置 Vue 3 项目的构建脚本?

2.2 使用斜杠命令

1
2
3
4
/explain 解释这个函数的作用
/fix 修复这个组件中的错误
/tests 为这个函数生成测试用例
/doc 为这个类添加文档注释

2.3 使用上下文变量

1
2
3
如何优化 #user-profile.vue 的性能?
#package.json 中应该添加哪些依赖?
分析 #src/store 目录下的状态管理结构

2.4 具体明确的提示

好的提示

1
2
3
4
5
6
7
创建一个 Vue 3 组件,使用 TypeScript 和 Composition API,
包含以下功能:
- 用户列表展示(表格形式)
- 搜索和过滤功能
- 分页控制
- 使用 Element Plus 组件库
- 包含 loading 状态管理

不好的提示

1
创建一个用户组件

2.5 迭代改进

1
2
3
4
5
6
7
8
// 第一次提示
创建一个计算斐波那契数列的函数

// 改进提示
不要使用递归,改用循环实现

// 进一步改进
使用更好的变量名,并添加类型注解

Vue 3 项目实践

1. 项目结构配置

1.1 创建项目级别指令

1
2
3
4
5
6
7
8
9
10
11
# Vue 3 电商项目编码规范

## 项目架构

- 使用 Vite 作为构建工具
- 使用 Pinia 进行状态管理
- 使用 Vue Router 进行路由管理
- 使用 Axios 进行 HTTP 请求
- 使用 Element Plus 作为 UI 组件库

## 目录结构

src/
├── components/ # 通用组件
├── views/ # 页面组件
├── stores/ # Pinia 状态管理
├── types/ # TypeScript 类型定义
├── utils/ # 工具函数
├── api/ # API 请求封装
├── router/ # 路由配置
└── assets/ # 静态资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

## 组件规范
- 页面组件放在 views/ 目录,使用 PascalCase 命名
- 通用组件放在 components/ 目录,使用 PascalCase 命名
- 组件文件名使用 kebab-case
- 所有组件都要有 TypeScript 类型定义

## 状态管理规范
- 使用 Pinia 创建模块化的 store
- 每个 store 都要有对应的 TypeScript 类型
- 状态变更要通过 actions 进行
- 使用 computed 创建派生状态

## API 调用规范
- 所有 API 调用都要通过 services/ 目录下的服务
- 使用 TypeScript 接口定义请求和响应类型
- 统一的错误处理机制
- 使用 loading 状态管理

## 样式规范
- 使用 SCSS 预处理器
- 优先使用 scoped 样式
- 使用 BEM 命名规范
- 统一的设计令牌(颜色、字体、间距)

2. 实际开发示例

2.1 创建用户管理组件

Agent 模式提示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
为 Vue 3 电商项目创建用户管理功能,包含:

1. 用户列表组件 (UserList.vue)
- 使用 Element Plus 表格组件
- 包含搜索、过滤、分页功能
- 支持用户状态切换(启用/禁用)
- 包含编辑和删除操作

2. 用户表单组件 (UserForm.vue)
- 支持新增和编辑模式
- 包含表单验证
- 使用 Element Plus 表单组件

3. Pinia 状态管理 (userStore.ts)
- 用户列表状态管理
- API 调用封装
- 错误处理

4. TypeScript 类型定义 (types/user.ts)
- 用户数据结构
- API 请求/响应类型

5. API 服务 (api/user.ts)
- 用户 CRUD 操作
- 统一的错误处理

6. 单元测试
- 组件测试
- Store 测试
- API 测试

请遵循项目的编码规范,使用 TypeScript 和 Composition API。

2.2 生成的代码示例

**类型定义 (types/user.ts)**:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
export interface User {
id: number;
username: string;
email: string;
role: "admin" | "user" | "guest";
status: "active" | "inactive";
createdAt: string;
updatedAt: string;
}

export interface CreateUserRequest {
username: string;
email: string;
password: string;
role: "admin" | "user" | "guest";
}

export interface UpdateUserRequest {
id: number;
username?: string;
email?: string;
role?: "admin" | "user" | "guest";
status?: "active" | "inactive";
}

export interface UserListResponse {
users: User[];
total: number;
page: number;
pageSize: number;
}

**Pinia Store (stores/userStore.ts)**:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { defineStore } from "pinia";
import { ref, computed } from "vue";
import type { User, CreateUserRequest, UpdateUserRequest } from "@/types/user";
import { userApi } from "@/api/user";

export const useUserStore = defineStore("user", () => {
// 状态
const users = ref<User[]>([]);
const loading = ref(false);
const error = ref<string | null>(null);
const total = ref(0);
const currentPage = ref(1);
const pageSize = ref(10);

// 计算属性
const activeUsers = computed(() =>
users.value.filter((user) => user.status === "active")
);

const adminUsers = computed(() =>
users.value.filter((user) => user.role === "admin")
);

// 操作
const fetchUsers = async (params?: {
page?: number;
pageSize?: number;
search?: string;
role?: string;
}) => {
loading.value = true;
error.value = null;

try {
const response = await userApi.getUsers(params);
users.value = response.users;
total.value = response.total;
currentPage.value = response.page;
pageSize.value = response.pageSize;
} catch (err) {
error.value = err instanceof Error ? err.message : "获取用户列表失败";
} finally {
loading.value = false;
}
};

const createUser = async (userData: CreateUserRequest) => {
loading.value = true;
error.value = null;

try {
const newUser = await userApi.createUser(userData);
users.value.unshift(newUser);
total.value += 1;
} catch (err) {
error.value = err instanceof Error ? err.message : "创建用户失败";
throw err;
} finally {
loading.value = false;
}
};

const updateUser = async (userData: UpdateUserRequest) => {
loading.value = true;
error.value = null;

try {
const updatedUser = await userApi.updateUser(userData);
const index = users.value.findIndex((user) => user.id === updatedUser.id);
if (index !== -1) {
users.value[index] = updatedUser;
}
} catch (err) {
error.value = err instanceof Error ? err.message : "更新用户失败";
throw err;
} finally {
loading.value = false;
}
};

const deleteUser = async (userId: number) => {
loading.value = true;
error.value = null;

try {
await userApi.deleteUser(userId);
users.value = users.value.filter((user) => user.id !== userId);
total.value -= 1;
} catch (err) {
error.value = err instanceof Error ? err.message : "删除用户失败";
throw err;
} finally {
loading.value = false;
}
};

return {
// 状态
users,
loading,
error,
total,
currentPage,
pageSize,
// 计算属性
activeUsers,
adminUsers,
// 操作
fetchUsers,
createUser,
updateUser,
deleteUser,
};
});

**用户列表组件 (components/UserList.vue)**:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
<script setup lang="ts">
import { ref, onMounted, computed } from "vue";
import {
ElTable,
ElTableColumn,
ElButton,
ElInput,
ElSelect,
ElPagination,
ElMessage,
ElMessageBox,
} from "element-plus";
import { useUserStore } from "@/stores/userStore";
import type { User } from "@/types/user";

interface Props {
showActions?: boolean;
}

interface Emits {
(e: "edit", user: User): void;
(e: "delete", userId: number): void;
}

const props = withDefaults(defineProps<Props>(), {
showActions: true,
});

const emit = defineEmits<Emits>();

const userStore = useUserStore();

// 搜索和过滤
const searchText = ref("");
const roleFilter = ref("");
const statusFilter = ref("");

// 计算属性
const filteredUsers = computed(() => {
let filtered = userStore.users;

if (searchText.value) {
filtered = filtered.filter(
(user) =>
user.username.toLowerCase().includes(searchText.value.toLowerCase()) ||
user.email.toLowerCase().includes(searchText.value.toLowerCase())
);
}

if (roleFilter.value) {
filtered = filtered.filter((user) => user.role === roleFilter.value);
}

if (statusFilter.value) {
filtered = filtered.filter((user) => user.status === statusFilter.value);
}

return filtered;
});

// 方法
const handleSearch = () => {
userStore.fetchUsers({
page: 1,
pageSize: userStore.pageSize,
search: searchText.value,
role: roleFilter.value,
});
};

const handleReset = () => {
searchText.value = "";
roleFilter.value = "";
statusFilter.value = "";
userStore.fetchUsers({ page: 1, pageSize: userStore.pageSize });
};

const handleEdit = (user: User) => {
emit("edit", user);
};

const handleDelete = async (userId: number) => {
try {
await ElMessageBox.confirm("确定要删除这个用户吗?", "确认删除", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
});

await userStore.deleteUser(userId);
ElMessage.success("用户删除成功");
emit("delete", userId);
} catch (error) {
if (error !== "cancel") {
ElMessage.error("删除用户失败");
}
}
};

const handleStatusChange = async (
user: User,
newStatus: "active" | "inactive"
) => {
try {
await userStore.updateUser({
id: user.id,
status: newStatus,
});
ElMessage.success("用户状态更新成功");
} catch (error) {
ElMessage.error("更新用户状态失败");
}
};

const handlePageChange = (page: number) => {
userStore.fetchUsers({
page,
pageSize: userStore.pageSize,
search: searchText.value,
role: roleFilter.value,
});
};

const handlePageSizeChange = (size: number) => {
userStore.fetchUsers({
page: 1,
pageSize: size,
search: searchText.value,
role: roleFilter.value,
});
};

// 生命周期
onMounted(() => {
userStore.fetchUsers();
});
</script>

<template>
<div class="user-list">
<!-- 搜索栏 -->
<div class="search-bar">
<el-input
v-model="searchText"
placeholder="搜索用户名或邮箱"
clearable
class="search-input"
@clear="handleSearch"
@keyup.enter="handleSearch"
/>
<el-select
v-model="roleFilter"
placeholder="选择角色"
clearable
class="filter-select"
>
<el-option label="管理员" value="admin" />
<el-option label="用户" value="user" />
<el-option label="访客" value="guest" />
</el-select>
<el-select
v-model="statusFilter"
placeholder="选择状态"
clearable
class="filter-select"
>
<el-option label="活跃" value="active" />
<el-option label="非活跃" value="inactive" />
</el-select>
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</div>

<!-- 用户表格 -->
<el-table
:data="filteredUsers"
:loading="userStore.loading"
row-key="id"
class="user-table"
>
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="username" label="用户名" />
<el-table-column prop="email" label="邮箱" />
<el-table-column prop="role" label="角色" width="100">
<template #default="{ row }">
<el-tag
:type="
row.role === 'admin'
? 'danger'
: row.role === 'user'
? 'primary'
: 'info'
"
>
{{
row.role === "admin"
? "管理员"
: row.role === "user"
? "用户"
: "访客"
}}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="120">
<template #default="{ row }">
<el-switch
:model-value="row.status === 'active'"
@change="(val: boolean) => handleStatusChange(row, val ? 'active' : 'inactive')"
/>
</template>
</el-table-column>
<el-table-column prop="createdAt" label="创建时间" width="180">
<template #default="{ row }">
{{ new Date(row.createdAt).toLocaleString() }}
</template>
</el-table-column>
<el-table-column v-if="showActions" label="操作" width="200">
<template #default="{ row }">
<el-button type="primary" size="small" @click="handleEdit(row)">
编辑
</el-button>
<el-button type="danger" size="small" @click="handleDelete(row.id)">
删除
</el-button>
</template>
</el-table-column>
</el-table>

<!-- 分页 -->
<el-pagination
v-model:current-page="userStore.currentPage"
v-model:page-size="userStore.pageSize"
:total="userStore.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
class="pagination"
@size-change="handlePageSizeChange"
@current-change="handlePageChange"
/>
</div>
</template>

<style scoped>
.user-list {
padding: 20px;
}

.search-bar {
display: flex;
gap: 12px;
margin-bottom: 20px;
flex-wrap: wrap;
}

.search-input {
width: 300px;
}

.filter-select {
width: 120px;
}

.user-table {
margin-bottom: 20px;
}

.pagination {
justify-content: center;
}

@media (max-width: 768px) {
.search-bar {
flex-direction: column;
}

.search-input,
.filter-select {
width: 100%;
}
}
</style>

3. 测试用例生成

Agent 模式提示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
为 UserList 组件和 userStore 生成完整的测试用例,包括:

1. 组件测试
- 组件渲染测试
- 搜索功能测试
- 过滤功能测试
- 分页功能测试
- 用户操作测试(编辑、删除、状态切换)

2. Store 测试
- 状态初始化测试
- API 调用测试
- 错误处理测试
- 计算属性测试

使用 Vitest 和 Vue Test Utils,包含 mock 数据和模拟 API 调用。

最佳实践

1. 自定义指令最佳实践

1.1 分层配置策略

1
2
3
4
5
6
7
8
9
10
用户级别 (个人习惯)
├── 通用编码风格
├── 个人偏好设置
└── 跨项目通用规范

工作区级别 (项目特定)
├── 项目架构规范
├── 业务逻辑要求
├── 技术栈特定规范
└── 团队协作规范

1.2 指令编写原则

  • 保持简洁:每个指令应该是单一、简单的声明
  • 避免冲突:确保不同级别的指令不会产生矛盾
  • 明确具体:避免模糊的描述,使用具体的技术术语
  • 定期维护:随着项目演进更新指令内容

1.3 指令文件组织

1
2
3
4
5
6
7
.github/
├── copilot-instructions.md # 项目通用规范
└── instructions/
├── vue-components.instructions.md # Vue 组件规范
├── testing.instructions.md # 测试规范
├── api.instructions.md # API 规范
└── styling.instructions.md # 样式规范

2. Agent 模式最佳实践

2.1 任务分解

好的做法

1
2
3
4
5
6
步骤1:创建用户数据类型定义
步骤2:实现用户 API 服务
步骤3:创建 Pinia store
步骤4:开发用户列表组件
步骤5:添加用户表单组件
步骤6:编写单元测试

避免的做法

1
创建一个完整的用户管理系统,包括前端、后端、数据库等所有功能

2.2 上下文管理

  • 明确项目结构:让 Agent 了解项目的目录结构
  • 提供相关文件:确保相关文件在工作区中打开
  • 使用具体的技术栈:明确指定使用的框架和库

2.3 工具使用

  • 谨慎使用自动确认:避免设置 chat.tools.autoApprove: true
  • 定期检查工具权限:使用 Chat: Reset Tool Confirmations 重置权限
  • 监控工具执行:关注工具执行的结果和日志

3. 提示词优化

3.1 结构化提示

1
2
3
4
5
6
7
8
9
10
任务:[明确的任务描述]
技术栈:[具体的技术和版本]
要求:
- [具体要求1]
- [具体要求2]
- [具体要求3]
约束:
- [约束条件1]
- [约束条件2]
输出:[期望的输出格式]

3.2 上下文提供

1
2
3
4
5
6
7
8
当前项目:Vue 3 + TypeScript + Pinia 电商项目
当前文件:src/components/UserList.vue
相关文件:
- src/types/user.ts
- src/stores/userStore.ts
- src/api/user.ts

任务:优化用户列表组件的性能

3.3 迭代改进

  • 逐步细化:从粗略的需求开始,逐步添加细节
  • 及时反馈:对生成的代码给出反馈和改进建议
  • 保持对话:利用对话历史进行上下文传递

常见问题

1. 自定义指令相关

Q: 为什么我的指令没有生效?
A: 检查以下几点:

  • 确保 useInstructionFiles 设置为 true
  • 检查指令文件路径是否正确
  • 重启 VS Code 让配置生效
  • 查看 Chat 视图中是否显示了指令

Q: 多个指令冲突怎么办?
A:

  • 使用更具体的指令覆盖通用指令
  • 检查不同级别的指令是否有矛盾
  • 使用 applyTo 属性限制指令的应用范围

Q: 如何查看当前生效的指令?
A:

  • 在 Chat 视图中点击设置图标
  • 查看 “Instructions” 部分
  • 使用 Chat: List Instructions 命令

2. Agent 模式相关

Q: Agent 模式执行速度很慢怎么办?
A:

  • 调整 chat.agent.maxRequests 设置
  • 将复杂任务分解为更小的步骤
  • 确保项目文件不会过大

Q: 如何防止 Agent 模式执行危险操作?
A:

  • 保持 chat.tools.autoApprove: false
  • 仔细检查每个工具调用的参数
  • 使用版本控制保护重要代码

Q: Agent 模式生成的代码质量不高怎么办?
A:

  • 完善自定义指令
  • 提供更详细的上下文信息
  • 使用迭代改进的方式

3. MCP 服务器相关

Q: MCP 服务器启动失败怎么办?
A:

  • 检查服务器配置是否正确
  • 查看 MCP 输出日志
  • 确保依赖项已正确安装
  • 检查网络连接和 API 密钥

Q: 如何调试 MCP 服务器?
A:

  • 使用 dev 配置启用调试模式
  • 查看服务器日志输出
  • 使用 MCP: Show Output 命令

Q: MCP 工具权限管理?
A:

  • 定期检查工具权限设置
  • 使用 Chat: Reset Tool Confirmations 重置权限
  • 避免在生产环境中使用自动确认

4. 性能优化

Q: Copilot 响应速度慢怎么办?
A:

  • 减少打开的文件数量
  • 优化自定义指令的长度
  • 使用更具体的提示词
  • 检查网络连接状态

Q: 如何提高代码建议的准确性?
A:

  • 提供充分的上下文信息
  • 使用有意义的变量和函数名
  • 添加详细的注释
  • 保持代码质量的一致性

总结

GitHub Copilot 是一个强大的 AI 编程助手,通过合理配置和使用,可以显著提升开发效率。本教程涵盖了:

  1. 自定义指令配置:通过项目级别和用户级别的指令定制,让 Copilot 更好地理解项目需求
  2. Agent 模式:利用 AI 的自主编程能力处理复杂任务
  3. MCP 服务器:扩展 Copilot 的功能,连接外部工具和服务
  4. 提示词工程:优化与 AI 的交互方式,获得更好的结果

记住,Copilot 是一个助手,而不是替代品。最好的结果来自于人机协作,充分利用 AI 的能力同时保持人类的判断和创意。

随着 GitHub Copilot 的持续发展,新功能和改进会不断出现。建议定期查看官方文档,了解最新的功能和最佳实践。


参考资源