title: Claude 与 GPT 编程对比:用同一项 Bug 修复任务,看谁更适合真实项目
description: 不再用算法题简单比较 Claude 与 GPT,而是从代码库理解、根因定位、修改范围、自动测试和 Git Diff 等维度,建立一套可复现的 AI 编程评估流程。
tags:

  • Claude
  • GPT
  • Codex
  • AI编程
  • 软件工程

Claude 与 GPT 编程对比:用同一项 Bug 修复任务,看谁更适合真实项目

请添加图片描述

比较 Claude 和 GPT 写代码,不能只看谁一次生成得更快。真实项目更在意的是:谁能理解现有代码、控制修改范围、运行验证命令,并交付一份容易审查的 Git Diff。

近两年,Claude、GPT 以及围绕它们构建的编程工具越来越强。很多开发者已经不再满足于让 AI 补一个函数,而是开始让它读取项目、定位问题、修改文件、补测试,甚至处理一整项开发任务。

但网上常见的对比方式仍然很简单:

  • 给两个模型同一道算法题;
  • 比较谁一次运行通过;
  • 看谁输出的代码更长、更完整;
  • 根据一次结果判断谁更强。

这种测试有参考价值,却不能代表真实开发。

在生产项目里,最难的通常不是“写出一段能运行的代码”,而是在不破坏原有功能的前提下,准确理解上下文,完成最小修改,并证明修改有效

这篇文章不直接宣布 Claude 或 GPT 谁获胜,而是给出一套开发者可以复用的实战评估方法。


一、先把比较对象弄清楚

讨论 Claude 与 GPT 编程能力时,至少要区分三种使用方式:

  1. 在网页聊天框中粘贴代码,让模型回答;
  2. 在 IDE 中让 AI 读取当前文件和项目上下文;
  3. 使用具备文件、终端和测试能力的编程代理处理整个仓库。

这三种方式得到的结果并不等价。

当一个工具只能看到几段复制出来的代码,而另一个工具可以读取完整仓库、执行测试命令时,最后的差距不一定来自模型本身,也可能来自:

  • 上下文范围不同;
  • 文件权限不同;
  • 是否可以运行终端命令;
  • 是否读取了项目规范;
  • 是否能看到完整报错和测试结果;
  • 任务说明是否足够明确。

因此,想做一次有价值的对比,必须保证:

  • 使用同一份代码;
  • 使用同一项任务;
  • 使用相同的限制条件;
  • 使用相同的验收标准;
  • 最终由开发者人工审查结果。

在这里插入图片描述


二、准备一个可以稳定复现的 Bug

下面用一个简化的 TypeScript 缓存问题作为测试任务。

业务需求是:根据用户 ID 和语言返回个人资料,并缓存查询结果。

export type Locale = "zh-CN" | "en-US";

const cache = new Map<string, string>();

export async function getProfile(
  userId: string,
  locale: Locale,
  fetcher: (userId: string, locale: Locale) => Promise<string>
): Promise<string> {
  const cacheKey = userId;

  const cached = cache.get(cacheKey);
  if (cached !== undefined) {
    return cached;
  }

  const profile = await fetcher(userId, locale);
  cache.set(cacheKey, profile);

  return profile;
}

代码没有语法错误,单独请求中文或英文时也能工作。

问题出现在同一个用户连续请求不同语言时:

const zh = await getProfile("user-001", "zh-CN", fetcher);
const en = await getProfile("user-001", "en-US", fetcher);

因为缓存键只有 userId,第二次请求会直接命中第一次的结果,导致英文请求返回中文内容。

这个 Bug 的正确修复并不复杂:

const cacheKey = `${userId}:${locale}`;

但我们的测试重点不是看 AI 能不能猜到这一行,而是看它能否完成下面的完整工作:

  • 找到相关实现和测试;
  • 解释根因;
  • 判断最小修改范围;
  • 增加能够复现问题的测试;
  • 运行单元测试和类型检查;
  • 汇总实际修改;
  • 不触碰无关文件。

三、不要只说“帮我修复一下”

很多 AI 编程任务失败,并不是因为模型不会写,而是任务描述太模糊。

例如:

帮我修复缓存问题。

这句话没有说明:

  • 哪个缓存;
  • 已知现象是什么;
  • 哪些接口不能改;
  • 是否允许重构;
  • 需要运行什么测试;
  • 什么结果才算完成。

更可靠的任务说明可以写成:

请检查当前项目中的用户资料缓存问题。

已知现象:
同一个用户先请求 zh-CN,再请求 en-US 时,
第二次返回了 zh-CN 的缓存结果。

任务要求:
1. 先阅读相关实现和测试,不要立即修改。
2. 说明根因以及准备修改的文件。
3. 保持现有函数签名不变。
4. 采用最小范围修改,不重构无关代码。
5. 增加能够复现问题的测试。
6. 运行单元测试、类型检查和 Lint。
7. 最后汇总修改文件、测试结果和潜在影响。

禁止事项:
- 不新增第三方依赖;
- 不修改无关文件;
- 不自动提交 Git;
- 不读取或输出密钥、Token 和生产环境配置。

一份明确的任务说明,本质上是在给 AI 建立“交付合同”。


四、第一轮只让 AI 阅读项目

拿到任务后,不要马上让 AI 修改代码。

第一轮可以这样要求:

先不要修改任何文件。

请阅读与 getProfile、缓存键和对应测试有关的代码,然后回答:

1. 问题的根因是什么?
2. 哪些文件与问题直接相关?
3. 最小修复方案是什么?
4. 修改后可能影响哪些已有行为?
5. 应该增加什么测试?

这一步主要检查 AI 的代码理解能力。

1. 是否找到了真正的调用链

不能只盯着报错文件,还要确认:

  • getProfile 在哪些地方被调用;
  • locale 是否只有两种值;
  • 缓存是否跨测试共享;
  • 清理缓存的逻辑是否需要调整;
  • 修改缓存键会不会影响其他读取逻辑。

2. 是否区分根因和表象

表象是英文请求返回了中文内容。

根因是缓存键没有包含会影响返回结果的 locale

3. 是否主动控制范围

合理方案通常只需要调整缓存键,并补充测试。

如果 AI 一开始就建议替换缓存框架、修改函数签名或重构整个模块,说明它没有很好地控制任务范围。


五、第二轮再执行最小修改

确认计划合理后,再允许它修改:

按照刚才的计划执行修复。

要求:
1. 只修改与该 Bug 直接相关的文件;
2. 保留当前公共接口;
3. 测试必须覆盖同一用户请求不同语言的场景;
4. 不进行额外重构;
5. 修改完成后不要提交 Git。

理想的生产代码修改应该非常小:

- const cacheKey = userId;
+ const cacheKey = `${userId}:${locale}`;

测试则至少要覆盖返回值和调用次数:

it("同一用户请求不同语言时应分别获取数据", async () => {
  const fetcher = vi.fn(
    async (_userId: string, locale: Locale) => `profile-${locale}`
  );

  const zhProfile = await getProfile("user-001", "zh-CN", fetcher);
  const enProfile = await getProfile("user-001", "en-US", fetcher);

  expect(zhProfile).toBe("profile-zh-CN");
  expect(enProfile).toBe("profile-en-US");
  expect(fetcher).toHaveBeenCalledTimes(2);
});

调用次数的断言很重要。

如果只检查返回值,有时无法确认缓存逻辑是否真的按照预期执行;检查 fetcher 被调用两次,可以证明两个语言版本被分别获取和缓存。


六、让 AI 验证,但不要只相信它的总结

修改完成后,可以要求它运行项目已有命令:

npm test
npm run typecheck
npm run lint

具体命令要以项目的 package.json 为准。

之后开发者仍然需要亲自检查:

git status --short
git diff --stat
git diff

重点看下面这些问题:

  • 是否修改了任务之外的文件;
  • 是否自动格式化了整个项目;
  • 是否删除或弱化了已有测试;
  • 是否为了测试通过而改变业务要求;
  • 是否引入了不必要的依赖;
  • 是否生成了临时文件和日志;
  • 是否存在密钥、Token 或隐私数据。

AI 报告“测试通过”,不等于开发者可以跳过审查。

请添加图片描述


七、Claude 与 GPT 应该比较哪些指标

完成同一项任务后,可以按照下面的维度记录结果。

对比维度 检查重点
代码库理解 是否准确找到入口、调用链和测试
根因定位 是否解释了问题为什么发生
修改最小化 是否只改必要文件和必要代码
测试质量 是否新增真正能够复现问题的测试
自动验证 是否实际执行测试、类型检查和 Lint
Diff 可读性 修改是否清晰、容易审查和回退
指令遵循 是否遵守不重构、不提交等限制
风险意识 是否说明兼容性和潜在影响

建议每次测试都记录:

## 工具名称

### 分析结果
- 找到的根因:
- 涉及的文件:
- 建议方案:

### 实际修改
- 修改文件数:
- 新增依赖数:
- 是否存在无关修改:

### 验证结果
- 单元测试:
- 类型检查:
- Lint:

### 人工审查
- 是否可直接合并:
- 仍需修改的问题:

持续记录十几个真实任务后,得到的结论会比一次算法题排名更有价值。


八、两类工具各自更适合什么场景

更偏连续探索的工作流

当任务需要:

  • 长时间阅读同一个项目;
  • 频繁运行终端命令;
  • 根据测试结果不断调整;
  • 维护固定的项目规范;
  • 处理跨文件调用关系;

这类场景更看重工具是否容易保持连续上下文,以及是否能自然融入终端和 IDE。

更偏任务拆分的工作流

当任务可以拆成:

  • 一个 Agent 负责调查;
  • 一个 Agent 负责补测试;
  • 一个 Agent 负责实现;
  • 一个 Agent 负责审查;

这类场景更看重任务隔离、并行执行和统一审查能力。

因此,Claude 和 GPT 并不是只能二选一。

一个更现实的分工方式是:

Claude:
本地项目探索、调用链分析、连续调试。

GPT / Codex:
任务拆分、独立实现、测试补充和交叉审查。

这不是固定答案,最终还是要根据自己的项目数据判断。


九、不要让同一个 AI 既开发又自我批准

在重要任务里,可以把实现和审查拆开。

Agent A:实现

根据任务说明完成修复。

负责:
- 阅读代码;
- 制定计划;
- 修改文件;
- 增加测试;
- 运行验证命令。

不要判断代码是否可以合并。

Agent B:审查

不要修改文件,只检查当前 Git Diff。

重点检查:
1. 是否改变原有接口行为;
2. 是否存在无关重构;
3. 测试是否真正覆盖问题;
4. 是否遗漏异常路径;
5. 是否引入安全风险;
6. 是否能够安全回退。

按照严重、高、中、低输出问题。

最后由开发者决定是否合并。

请添加图片描述


十、最终怎么选择

如果你主要是:

  • 在终端和 IDE 中长期维护同一个项目;
  • 经常进行跨文件调查;
  • 希望 AI 记住固定的项目规则;
  • 需要持续调试同一条调用链;

可以优先测试更适合连续项目协作的方案。

如果你主要是:

  • 同时处理多个独立任务;
  • 喜欢将实现、测试和审查拆开;
  • 需要比较多个实现方案;
  • 希望通过隔离任务降低相互影响;

可以优先测试任务代理和并行交付能力更强的方案。

真正值得关注的,不是谁在一次对话中写了更多代码,而是谁在你的项目里:

  • 返工更少;
  • 无关修改更少;
  • 测试覆盖更完整;
  • Diff 更容易审查;
  • 发生错误时更容易回退。

总结

Claude 与 GPT 的模型能力会不断变化,单次测试也容易受到上下文、权限、提示词和工具环境影响。

更稳定的比较方式是建立统一流程:

定义任务
→ 只读探索
→ 确认计划
→ 最小修改
→ 自动验证
→ 人工审查
→ 决定合并

当这套流程建立起来以后,开发者关心的问题会从:

Claude 和 GPT 谁更会写代码?

变成:

哪个工具在我的项目里交付更稳定,人工返工更少?

这才是更接近真实开发的答案。

对于需要长期使用 Claude、ChatGPT、Codex 等 AI 编程工具的开发者,建议先明确自己的项目类型、使用频率和工作流,再决定具体工具和订阅方式。第三方 AI 工具订阅服务可将 gpt68.com 作为信息参考入口之一,具体支持范围和服务说明以页面实时内容为准。


更多推荐