用了 let cancelled = false 的 closure 方案,方向对但没处理 fetch 错误的情况,生产环境直接用会有隐患。
场景二:SQL 慢查询优化
这个来自我们项目的真实场景。一个统计接口跑了 8 秒,DBA 已经甩脸子了:
SELECT u.name, COUNT(o.id) as order_count, SUM(o.amount) as total_amount
FROM users u
LEFTJOIN orders o ON u.id = o.user_id
WHERE o.created_at >='2026-01-01'AND o.status IN ('paid', 'shipped', 'completed')
GROUPBY u.id, u.name
HAVINGCOUNT(o.id) >5ORDERBY total_amount DESC
LIMIT 20;
问题:orders 表 2000 万行,created_at 有索引但 status 没有,执行计划显示全表扫描。
结果对比
这轮差距不大,Opus 给了最完整的方案——建复合索引 (created_at, status, user_id, amount) 覆盖查询,并且建议把 WHERE 条件里的 LEFT JOIN 改成 INNER JOIN(因为 WHERE 条件已经过滤了 NULL)。其他模型基本都能给出正确的索引建议,只有 Gemini 漏掉了 amount 字段导致无法 covering index。
fetch(`/api/search?id, u.name HAVING COUNT(o.id) > 5 ORDER BY total_amount DESC LIMIT 20;
问题:orders 表 2000 万行,created_at 有索引但 status 没有,执行计划显示全表扫描。
最近刷掘金看到 Cursor 官方搞了个模型 PK 的功能,评论区一堆人在争"Opus 强还是 GPT 强"。说实话,我之前也只看 benchmark 选模型,直到上周我在生产环境踩了一个坑——Claude 和 GPT 对同一个 Bug 给出了完全相反的修法,其中一个差点让我上线 P0 故障。
这件事让我意识到:SWE-bench 80% 和"能修你的 Bug"是两回事。
于是我花了两天,拿 3 个从实际项目里扒出来的典型 Bug,喂给 5 个主流模型,记录下每个模型的表现。结果挺有意思的。
先说结论
没错,SWE-bench 上差 0.2% 的模型,真实场景能差出一条街。
测试方法
先说下我的测试环境:
"你是一个高级软件工程师,请分析并修复以下代码中的 bug"API 调用这块,我是用的 OpenAI 兼容接口统一测的,一个 base_url 切所有模型,省得每家单独搞 SDK:
from openai import OpenAI client = OpenAI( api_key="sk-xxx", base_url="https://api.ofox.ai/v1" # 兼容 OpenAI 协议 ) models = [ "anthropic/claude-opus-4-6", "openai/gpt-5.3", "google/gemini-3.1-pro", "qwen/qwen3-max", "deepseek/deepseek-v3" ] for model in models: resp = client.chat.completions.create( model=model, messages=[ {"role": "system", "content": "你是一个高级软件工程师,请分析并修复以下代码中的 bug。"}, {"role": "user", "content": bug_code} ], temperature=0 ) print(f"\n{'='*50}") print(f"模型: {model}") print(resp.choices[0].message.content)场景一:React useEffect 竞态条件
这是我在生产环境里真实遇到的问题。一个搜索组件,用户快速输入时,旧请求的结果可能覆盖新请求:
function SearchResults({ query }) { const [results, setResults] = useState([]); useEffect(() => { fetch(`/api/search?q=${query}`) .then(res => res.json()) .then(data => setResults(data)); }, [query]); return <ResultList items={results} />; }经典 race condition——用户输入 "react",依次触发 "r"、"re"、"rea"、"reac"、"react" 五个请求,但网络不保证顺序返回。如果 "reac" 的结果比 "react" 晚到,就会覆盖正确结果。
各模型表现
Opus 4.6:✅ 教科书级
直接用 AbortController + cleanup 函数,干净利落:
useEffect(() => { const controller = new AbortController(); fetch(`/api/search?q=${query}`, { signal: controller.signal }) .then(res => res.json()) .then(data => setResults(data)) .catch(err => { if (err.name !== 'AbortError') throw err; }); return () => controller.abort(); }, [query]);没多余的废话,一次到位。
GPT-5.3:⚠️ 正确但过度设计
GPT 不仅加了 AbortController,还额外包了一层 debounce + loading state + error boundary。代码量直接翻了三倍。功能上没问题,但说实话,一个简单的 race condition 修复,你给我整 40 行?
Gemini 3.1 Pro:✅ 换了个思路
用
useRef记录请求序号,只接受最新一次:useEffect(() => { const requestId = ++requestIdRef.current; fetch(`/api/search?q=${query}`) .then(res => res.json()) .then(data => { if (requestId === requestIdRef.current) { setResults(data); } }); }, [query]);思路不同但同样有效,而且不会取消已经发出的请求,某些场景下反而更省资源。
Qwen3-Max:❌ 方向跑偏
给了一个
setTimeout+clearTimeout的 debounce 方案。这不是修 race condition,这是回避问题——如果用户就是快速输入后停了,最后一个请求仍然可能被更早的慢请求覆盖。DeepSeek V3:⚠️ 能用但有坑
用了
let cancelled = false的 closure 方案,方向对但没处理 fetch 错误的情况,生产环境直接用会有隐患。场景二:SQL 慢查询优化
这个来自我们项目的真实场景。一个统计接口跑了 8 秒,DBA 已经甩脸子了:
SELECT u.name, COUNT(o.id) as order_count, SUM(o.amount) as total_amount FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE o.created_at >= '2026-01-01' AND o.status IN ('paid', 'shipped', 'completed') GROUP BY u.id, u.name HAVING COUNT(o.id) > 5 ORDER BY total_amount DESC LIMIT 20;问题:
orders表 2000 万行,created_at有索引但status没有,执行计划显示全表扫描。结果对比
这轮差距不大,Opus 给了最完整的方案——建复合索引
(created_at, status, user_id, amount)覆盖查询,并且建议把WHERE条件里的LEFT JOIN改成INNER JOIN(因为 WHERE 条件已经过滤了 NULL)。其他模型基本都能给出正确的索引建议,只有 Gemini 漏掉了amount字段导致无法 covering index。场景三:Python async 死锁
这个 Bug 最阴间,我排查了大半天才找到原因:
import asyncio class ConnectionPool: def __init__(self, size=5): self._semaphore = asyncio.Semaphore(size) self._connections = [] async def acquire(self): await self._semaphore.acquire() if not self._connections: conn = await self._create_connection() return conn return self._connections.pop() async def release(self, conn): self._connections.append(conn) self._semaphore.release() async def execute(self, query): conn = await self.acquire() try: result = await conn.execute(query) # 如果这里抛异常... await self.release(conn) return result except Exception: await self.release(conn) raise async def batch_execute(self, queries): tasks = [self.execute(q) for q in queries] return await asyncio.gather(*tasks)看出来了吗?当
batch_execute传入的 queries 数量超过 pool size(5)时,asyncio.gather会同时启动所有 task。前 5 个 task 拿到 semaphore,后面的卡在acquire等待。但如果前面的 task 在conn.execute时抛异常,虽然release了 semaphore,但连接可能已经坏了。更狠的是——如果_create_connection本身也需要 pool 里的连接(比如要先查配置),直接死锁。各模型表现
Opus 4.6:✅ 一眼看穿
精准指出了三个问题:
execute没用try/finally,异常路径可能泄漏 semaphorebatch_execute的并发量可能超过 pool size,应该用asyncio.Semaphore或asyncio.TaskGroup限制给出的修复代码直接可用。
GPT-5.3:✅ 找到了核心问题
定位到了
try/finally和连接泄漏问题,但漏掉了batch_execute的并发超限。Gemini 3.1 Pro:❌ 误诊了
认为问题出在
Semaphore的实现上,建议换成asyncio.Queue。方向完全错了,Semaphore本身没问题,是使用方式有问题。Qwen3-Max:⚠️ 半对半错
找到了
try/finally问题,但建议的修复里把release放在finally的同时没处理坏连接,相当于把坏连接放回了池子。DeepSeek V3:✅ 意外惊喜
不仅找到了核心问题,还额外指出了
_connections列表在并发场景下不是线程安全的(虽然 asyncio 是单线程的,但如果未来改成多线程就会出事)。思考得很全面。踩坑记录
测试过程中遇到几个坑:
Gemini 的输出格式不稳定:同样的 prompt,有时候给完整代码,有时候只给 diff,有时候先分析一大段再给代码。做自动化测试的话需要额外处理。
Qwen3-Max 的中文理解很强,但代码上下文推理弱一些:如果 prompt 用中文描述 Bug,Qwen 的分析部分写得很好,但修出来的代码容易有小瑕疵。
DeepSeek V3 性价比真高:2.5/3 的成绩,但 API 价格只有 Opus 的 1/10 不到。日常开发用 DeepSeek 打底、关键修复切 Opus,是目前我觉得最划算的组合。
统一 API 接口真的省事:之前每个模型单独调,光是 SDK 依赖就装了一堆,现在改成 OpenAI 兼容协议统一调用,切模型就改个 model 参数的事。
小结
SWE-bench 80% 听着很猛,但真实 Bug 的复杂度远超基准测试。我的建议:
别迷信单一模型,多模型切换才是正解。毕竟现在切模型的成本几乎为零——改个 model 字符串就完事了。