如何用 GitHub Copilot 写代码

codingbeginner

# 如何用 GitHub Copilot 写代码(而不让它写出垃圾代码)

上周我花了整整三个小时调试一个 GitHub Copilot 替我写的函数。代码编译没问题,逻辑看起来也对,但就是存在一个只有在生产环境极端负载下才会暴露的微妙错误。这就是 Copilot 的问题所在:它擅长生成看起来合理的代码,但当你盲目信任它时,后果很可怕。

在 Python、TypeScript 和 Go 项目上每天使用 Copilot 六个月后,我总结出了如何让它真正有用而非成为累赘的经验。

## 真正有效的配置方案

首先,打好基础。我在 VS Code 中使用 Copilot,但这些方法同样适用于 JetBrains、Neovim 等其他编辑器。

**安装和认证:**

```

1. 安装 GitHub Copilot 扩展

2. 使用 GitHub 账号登录(需订阅,每月 10 美元,学生或开源项目免费)

3. 设置快捷键:Tab 接受建议,Ctrl+Enter 打开建议面板

```

**大多数教程忽略的关键配置**:我关闭了 Copilot 在注释和字符串中的自动建议。原因如下:当你输入 `// TODO: implement sorting algorithm` 时,Copilot 通常会直接填入一个冒泡排序,而不是等待更多上下文。这种噪音只会浪费时间。

在 VS Code 的 settings.json 中:

```json

{

"github.copilot.enable": {

"*": true,

"plaintext": false,

"markdown": false

}

}

```

## 80/20 法则:Copilot 的闪光点

经过数百次使用,我发现 Copilot 在以下三个方面表现最出色:

### 1. 遵循清晰模式的样板代码

编写 CRUD 端点?Copilot 能完美搞定,因为这些代码都是公式化的。以下是我通常输入的内容:

```python

# app/routes/users.py

from fastapi import APIRouter, Depends, HTTPException

from sqlalchemy.orm import Session

router = APIRouter(prefix="/users", tags=["users"])

@router.get("/")

def list_users(

```

此时,Copilot 会建议整个函数体:数据库查询、分页、错误处理。我 90% 的情况下会接受,因为这个模式是可预测的。

**陷阱**:Copilot 会愉快地生成带有细微不一致的相同样板代码。我曾经遇到过两个端点,一个使用 `offset` 分页,另一个使用 `cursor` 分页,因为 Copilot 从代码库中不同的示例学习了。一定要检查参数名称是否一致。

### 2. 正则表达式和字符串处理

我无法凭记忆写出正则表达式。但 Copilot 可以,而且对于常见模式通常是正确的:

```python

def extract_email_addresses(text: str) -> list[str]:

```

Copilot 生成:

```python

import re

pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'

return re.findall(pattern, text)

```

这个正则表达式是标准的,可以正常工作。但当我让 Copilot 写"匹配有效 IPv6 地址的正则表达式"时,它生成了能通过基本测试但在处理 `::1` 这种压缩格式时失败的内容。始终要测试边界情况。

### 3. 为现有代码编写测试

这是 Copilot 的杀手锏功能。写完一个函数后,我输入:

```python

def calculate_discount(price: float, tier: str) -> float:

if tier == "gold":

return price * 0.8

elif tier == "silver":

return price * 0.9

return price

# Test:

```

然后 Copilot 建议:

```python

def test_calculate_discount():

assert calculate_discount(100, "gold") == 80.0

assert calculate_discount(100, "silver") == 90.0

assert calculate_discount(100, "bronze") == 100.0

assert calculate_discount(0, "gold") == 0.0

```

我接受这些,然后添加 Copilot 遗漏的边界情况:负数价格、未知等级、浮点数精度。

## 没人谈论的提示工程

Copilot 不是魔法——它是一个根据上下文做出反应的语言模型。以下是如何引导它的方法:

**糟糕的提示:**

```python

# function to sort data

def sort_data(data):

```

Copilot 可能会生成冒泡排序,或者使用没有自定义键的 `sorted()`。

**好的提示:**

```python

# Sort list of user dicts by last_name, then first_name, case-insensitive

def sort_users(users: list[dict]) -> list[dict]:

```

现在 Copilot 生成:

```python

return sorted(users, key=lambda u: (u['last_name'].lower(), u['first_name'].lower()))

```

区别在于具体性。我学会了像向一个热情但缺乏经验的初级开发者解释那样写注释。

## 当 Copilot 撒谎时(以及如何发现)

Copilot 最危险的行为是:它会编造不存在的 API。

上周的例子。我在使用 Python 的 `pathlib`:

```python

from pathlib import Path

p = Path("/tmp/data")

p.

```

Copilot 建议了不存在的 `p.listdir()`。正确的方法是 `p.iterdir()`。但 `listdir` 看起来合理,因为它在 `os.listdir` 中存在。Copilot 混淆了这两者。

**我的生存清单:**

1. **不阅读绝不接受**——这听起来显而易见,但当你在心流状态时,很容易不停地按 Tab 接受建议。我强迫自己阅读每一行生成的代码。

2. **立即用真实数据测试**——接受建议后,在继续之前先用实际输入运行它。

3. **警惕幻觉导入**——Copilot 有时会导入不存在的模块或使用已弃用的函数。我现在首先检查导入。

4. **对"巧妙"的代码保持怀疑**——如果 Copilot 建议一个包含嵌套推导式和可变默认值的一行代码,它很可能是错的。我曾抓到过在应该使用简单字典的地方使用 `defaultdict(lambda: [])`,导致微妙的变异错误。

## 真实工作流:构建一个 CLI 工具

让我带你走一遍真实的会话。我正在构建一个处理 CSV 文件的 CLI 工具。

**步骤 1:骨架**

我输入:

```python

import click

import csv

from pathlib import Path

@click.command()

@click.argument("input_file", type=click.Path(exists=True))

@click.option("--output", "-o", default="output.csv")

def process_csv(input_file, output):

```

Copilot 建议函数体:

```python

"""Process CSV file and write results."""

data = []

with open(input_file, "r") as f:

reader = csv.DictReader(f)

for row in reader:

data.append(row)

# Process data

processed = []

for row in data:

# Add processing logic

processed.append(row)

with open(output, "w") as f:

writer = csv.DictWriter(f, fieldnames=processed[0].keys())

writer.writeheader()

writer.writerows(processed)

```

我接受这个骨架。它是正确的但为空。现在我来填充实际的处理逻辑。

**步骤 2:具体逻辑**

我添加一条注释:

```python

for row in data:

# Convert 'price' column from string to float, handle missing values

```

Copilot 建议:

```python

try:

row["price"] = float(row.get("price", "0.0"))

except ValueError:

row["price"] = 0.0

```

这在 90% 的情况下都有效。我手动添加了对 `$` 前缀和欧洲小数点逗号的处理。

**步骤 3:边界情况**

我编写一个测试文件:

```python

def test_process_csv():

# Test with empty file

# Test with missing columns

# Test with malformed data

```

Copilot 生成基本测试。我添加了一个它遗漏的:

```python

# Test with BOM character in file

with open("test_bom.csv", "w", encoding="utf-8-sig") as f:

f.write("\ufeffname,price\nitem,10.0")

```

## 关于生产力的残酷真相

六个月后,我的实际生产力提升大约是样板代码的 30-40%,而新算法则是 0%。Copilot 在以下方面毫无用处:

- 系统架构决策

- 性能优化

- 安全关键代码(如果不小心,它会产生 SQL 注入漏洞)

- 任何需要深度领域知识的内容

我犯过的最严重的错误是让 Copilot 生成我不理解的代码。我有一个使用 `itertools.groupby` 的函数,但我无法解释其原理。它通过了测试,也能正常工作。但一年后,一个 bug 出现了,因为 `groupby` 需要排序后的输入,而数据并不总是排序的。

## 实用的下一步

与其一次性学习 Copilot 的所有功能,不如这样做:接下来一周,只使用 Copilot 编写测试和文档字符串。这是它风险最小、价值最大的地方。当你能够批判性地阅读它的输出后,再开始使用它编写实现代码。

还有,在提交之前,一定要运行你的测试。Copilot 会写出看起来正确但在第一个边界情况下就失败的代码。我是通过惨痛教训学到这一点的——那三个小时的调试时间再也回不来了。