一、AI 编程助手到底改变了什么

用了一年多 Copilot、Claude、Cursor 之后,我的一个朴素感受是:它几乎没有提高我的打字速度,却大幅降低了"把想法翻译成代码"的成本。以前真正卡住我的,往往是"这段逻辑我知道怎么写,但敲完得十几分钟",或者是"这个库的 API 我记不住,得翻半天文档"。这些摩擦点现在基本被抹平了。

更深层的变化在于瓶颈的转移。过去开发的瓶颈在"写",如今转移到了"把需求描述清楚"和"快速验证结果对不对"两件事上。所以效率差异并不完全取决于模型有多强,而取决于使用者能不能把意图组织成高质量上下文、能不能一眼看出生成代码的破绽。同样一个工具,有人用出一天顶三天的效果,有人却越用越乱——差别就在这里。

提示:不要问"AI 能帮我写多少代码",要问"我怎么才能更快地确认这段代码是对的"。后者才是效率的真正来源。

二、Prompt 就是新的「需求文档」

我发现,prompt 写得好不好,产出质量的差距大概是 3 倍以上。一段合格的提示词至少要包含四件事:背景(什么语言/框架/版本)、目标(具体要做什么)、约束(不要用哪些库、性能要求、代码风格)、输出形式(只要代码、还是带解释、还是要测试)。

举个反例和正例的对比。反例是"帮我写个解析时间的函数",模型会自由发挥,大概率不符合你的项目约定。正例则是把上下文补齐:

背景:Python 3.11 项目,用 mypy 严格模式,只允许标准库。
目标:实现 parse_duration(text: str) -> int,把 "1h30m"、"45s"、"2d" 解析成秒数。
约束:
  - 不合法输入抛 ValueError,不要静默返回 0
  - 单位只支持 d / h / m / s,不区分大小写
  - 不允许用正则以外的第三方解析库
输出:只给函数实现,加上类型标注和 docstring,不要额外解释。

同一段需求,前后两种问法的产出质量完全是两个级别。Prompt 的本质就是需求文档——你写给同事看会含糊的地方,写给模型也一样会出问题。养成"先写清楚再提问"的习惯,本身就是对工程表达能力的训练。

三、把它当结对程序员,而不是万能生成器

很多人把 AI 当成"代码自动售货机":扔一句需求,等一段代码,复制粘贴就完事。这种用法短期爽,长期会积累大量你自己都看不懂的代码。我更推荐的定位是结对编程的伙伴——它负责快速起草和提供思路,你负责决策、质疑和收口。

具体做法上,我常用这几个互动方式:

提示:对话是 AI 编程助手最大的价值之一。一次只推进一小步、及时纠偏,比一次性要求"生成整个模块"的可靠性高一个数量级。

四、效率提升最明显的几个场景

从我的实际使用来看,收益最大的场景集中在四类:样板代码生成、单元测试补全、陌生代码/报错解读、数据处理与 SQL 脚本。它们共同的特征是"规则明确、可验证、但手写繁琐"。而架构设计、性能调优这类需要全局判断的事,AI 目前更多是提供思路,不能替你拍板。

测试生成是我觉得性价比最高的一项。给它一段函数,让它补全 pytest 用例,往往能覆盖到我自己想不到的边界:

# 原始实现:我只写了主体逻辑,边界处理是 AI 补的
def parse_duration(text: str) -> int:
    """把 "1h30m"、"45s"、"2d" 这类字符串解析成秒数。"""
    if not text:
        return 0
    total, num = 0, 0
    unit_seconds = {"d": 86400, "h": 3600, "m": 60, "s": 1}
    for ch in text.lower():
        if ch.isdigit():
            num = num * 10 + int(ch)
        elif ch in unit_seconds:
            total += num * unit_seconds[ch]
            num = 0
        else:
            raise ValueError(f"invalid character: {ch!r}")
    return total
# AI 生成的测试:参数化 + 异常路径,我只需确认断言是否符合预期
import pytest
from myapp.time import parse_duration

@pytest.mark.parametrize("raw, expected", [
    ("30s", 30),
    ("1h30m", 5400),
    ("2d", 172800),
    ("", 0),
])
def test_parse_duration_ok(raw, expected):
    assert parse_duration(raw) == expected

def test_parse_duration_rejects_bad_char():
    with pytest.raises(ValueError):
        parse_duration("5x")

def test_parse_duration_rejects_trailing_number():
    assert parse_duration("5") == 5  # 我补充的:确认裸数字的语义

注意最后一行我手动加了一个断言——生成的测试同样需要被审阅,否则会出现"测试通过了,但它测的根本不是你以为的行为"这种隐蔽问题。

五、警惕「看起来对」的代码

AI 最危险的地方不是明显错误,而是微小的、能跑通但语义不对的错误。我踩过的坑大致有三类:API 幻觉(编造不存在的方法)、版本漂移(按旧版本库生成已废弃的写法)、逻辑偏移(边界条件少处理一个、异常被吞掉)。这些错误编译能过、甚至测试也能过,但上线后才暴露。

一个典型例子:

# ❌ 模型幻觉:pandas 里根本没有 remove_duplicates 这个方法
df = df.remove_duplicates(subset="id")

# ✅ 真实 API
df = df.drop_duplicates(subset="id")

我的应对策略是三条:先跑再信(生成的代码必须实际执行,最好加一次 mypy / ruff)、让 AI 自己写测试(再用测试反向验证实现)、对关键路径逐行读 diff(尤其是涉及金额、权限、并发的代码,一行都不能略过)。

提示:把 AI 当作"非常自信的初级工程师"来管理——它的产出默认需要 Code Review,越接近生产环境,审阅强度越高。

六、我的日常工作流(可复用的落地建议)

经过一段时间的迭代,我目前固定下来的流程大致是这样:先用自然语言在笔记里写下需求和约束,再交给 AI 起草;拿到结果后立刻跑测试和静态检查;确认无误后再让 AI 补文档和注释;最后自己过一遍 diff 并提交。整个过程里,"写需求"和"验证"占的时间变多了,"敲代码"变少了,这是健康的信号。

如果你刚开始用,我建议优先做这几件事:

  1. 先在低风险场景练手,比如写测试、写脚本、解读报错,而不是直接让它改核心业务逻辑;
  2. 建立自己的常用 Prompt 模板,把项目约定(语言版本、代码风格、禁止项)固化进去,避免每次都重复交代;
  3. 保持"它起草、我负责"的心态,代码的所有权始终在你手里;
  4. 定期回顾哪些场景真的省了时间、哪些反而返工更多,主动淘汰低效用法。
提示:工具的价值不是让你少思考,而是让你把思考花在更值得的地方——设计、取舍、以及那些真正需要人类判断的边界上。