Claude 与 GPT 编程对比:用同一项 Bug 修复任务,看谁更适合真实项目
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 编程能力时,至少要区分三种使用方式:
- 在网页聊天框中粘贴代码,让模型回答;
- 在 IDE 中让 AI 读取当前文件和项目上下文;
- 使用具备文件、终端和测试能力的编程代理处理整个仓库。
这三种方式得到的结果并不等价。
当一个工具只能看到几段复制出来的代码,而另一个工具可以读取完整仓库、执行测试命令时,最后的差距不一定来自模型本身,也可能来自:
- 上下文范围不同;
- 文件权限不同;
- 是否可以运行终端命令;
- 是否读取了项目规范;
- 是否能看到完整报错和测试结果;
- 任务说明是否足够明确。
因此,想做一次有价值的对比,必须保证:
- 使用同一份代码;
- 使用同一项任务;
- 使用相同的限制条件;
- 使用相同的验收标准;
- 最终由开发者人工审查结果。

二、准备一个可以稳定复现的 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 作为信息参考入口之一,具体支持范围和服务说明以页面实时内容为准。
更多推荐
所有评论(0)