模型有没有变笨,先做一次开工体检
古董级程序员,大厂出来后一直在创业公司,现在仍活跃在一线做 AI 相关的开发。更完整的更新写在微信公众号「字与码」:工作经历、对新技术的想法,以及这些年走弯路的记录,会不定期发在那里。若觉得博客对你有用,欢迎顺手关注。
最近经常有人问一个问题:我现在用的 Codex、ChatGPT 或某个本地代理,是不是被降级了?
这个问题很难靠感觉回答。模型名字、知识截止日期、客户端版本、上下文长度、工具可用性、网络状态,都会影响一次对话的表现。更麻烦的是,同一个模型在不同任务上的差异也很大。它可能写样板代码很顺,但遇到约束推理就开始编;也可能能读懂复杂日志,却在一个简单反例上装作很确定。
所以我现在更倾向于做一件朴素的事:不要先争论模型名,先给当前会话做几道小测验。

这些测验不能证明模型真实身份,也不能替代正式 benchmark。它们更像工程师给工具做的“开工前体检”:十分钟跑一遍,看看当前会话的推理、代码理解、反幻觉和排障能力大概在哪个水平。尤其是在你怀疑模型变笨、上下文被污染、插件不可用、或者某个代理版本刚升级之后,这种小体检很有用。
先说边界:测的是当前表现,不是模型血统
很多争论会卡在“它到底是不是某个模型”。这个问题当然重要,但对日常开发来说,另一个问题更直接:
它现在能不能可靠地帮我做这个任务?
如果我要让它改线上接口、分析数据库脏数据、迁移一段统计逻辑,模型卡片上的名字并不能替我兜底。真正有用的是它在当前会话里是否能遵守约束,是否能发现反例,是否会乱补事实,是否能把排查步骤按优先级排出来。
下面这五道题就是按这个思路设计的。每道题都很小,但分别卡住一种常见能力。
第一题:约束推理,看它会不会强行凑唯一解
把下面这段直接发给模型:
有三个盒子 A/B/C,每个盒子里只有红球或蓝球。
已知:
1. 如果 A 是红球,那么 B 是蓝球。
2. 如果 B 是蓝球,那么 C 是红球。
3. A 和 C 不能同色。
问 A/B/C 分别是什么颜色?请逐步推理。
这题看起来像一道普通逻辑题,但关键点在于:它并没有给出唯一完整解。
正确推理是这样的:
- 如果 A 是红球,那么按条件 1,B 是蓝球。
- B 是蓝球时,按条件 2,C 是红球。
- 这样 A 和 C 都是红球,违反条件 3。
- 所以 A 不能是红球,只能是蓝球。
- A 和 C 不能同色,所以 C 必须是红球。
- B 没有被唯一确定。B 可以是红球,也可以是蓝球;如果 B 是蓝球,C 是红球,仍然满足条件。
也就是说,确定结果只有:
A = 蓝球
C = 红球
B = 不确定
这题最能暴露一种常见毛病:模型不喜欢承认“不确定”,会硬给一个完整答案。比如它可能说 A 蓝、B 蓝、C 红,并把这个说成唯一解。这个答案满足条件,但不是唯一解。对工程任务来说,这个区别很关键。线上问题排查里,很多结论也只是“可疑”“高概率”“已排除”,不是每一步都能落到确定答案。
如果模型能主动说出 B 不确定,并解释为什么不唯一,说明它至少没有被题目的形式带跑。
第二题:读代码,看它是否真的按执行过程走了一遍
再给它一段很短的 Python:
def f(xs):
out = []
for i, x in enumerate(xs):
if i and xs[i-1] == x:
out[-1][1] += 1
else:
out.append([x, 1])
return out
print(f([1,1,2,1,1,1,3,3]))
期望输出是:
[[1, 2], [2, 1], [1, 3], [3, 2]]
这段代码做的是连续分组计数,也就是 run-length encoding 的简化版。它不是统计每个数字一共出现几次,而是统计连续片段。所以前面的 1,1 和后面的 1,1,1 不能合并。
一个比较好的回答,除了给出输出,还应该顺手指出几个细节:
- 空列表会返回空列表。
- 它只合并相邻相同元素,不做全局聚合。
- 它不依赖哈希,所以元素只要能做相等比较即可。
- 返回值里的计数是可变 list,不是 tuple。
这题可以区分“像读懂了”和“真的走了一遍”。很多模型会把它误解成计数字典,输出 {1: 5, 2: 1, 3: 2},这在写业务代码时就是危险信号。它可能在大段代码里抓住几个变量名,然后按经验补一个看似合理的解释。
第三题:小系统设计,看它能不能抓住容易出错的地方
第三题换成工程设计:
我要给一个搜索接口加 A/B Test,按 user_id 稳定分桶,支持灰度比例、实验关闭、强制命中、记录埋点。请给出最小可上线设计,并指出最容易出错的地方。
这题没有唯一答案,但好答案通常会覆盖这些点:
- 用确定性哈希按
experiment_id + user_id分桶,而不是每次请求随机。 - 实验配置要包含开关、灰度比例、实验组、对照组、开始结束时间。
- 需要支持强制命中,比如 header、内部白名单、调试用户。
- 曝光日志要在真正参与实验时记录,不能只要请求进来就算曝光。
- 搜索、点击、调用、成功、失败等事件需要能用同一个实验上下文串起来。
- 实验关闭后要有稳定回退,不能让历史请求或缓存继续带着旧实验状态。
- 匿名用户、user_id 为空、跨端登录、机器人流量都要有处理策略。
- 指标上要关注 SRM,也就是实验组和对照组流量比例异常。
更重要的是,它应该能指出最容易出错的地方。比如:
- 用请求级随机导致同一个用户一会儿进实验组,一会儿进对照组。
- 只记录成功请求,不记录失败请求,导致实验指标偏高。
- 实验命中逻辑散落在业务代码里,后续很难复盘。
- 强制命中没有进埋点,调试流量污染指标。
- cache key 没带实验上下文,导致两个实验组互相串结果。
这类题适合测“工程味”。一个只会给概念清单的模型,会写很多“配置中心、数据采集、指标分析”。一个真正有工程经验的模型,会提醒你哪些地方最容易上线后出事故。
第四题:反幻觉,看它是否敢反驳错误前提
这题很短:
请证明 987654321 是质数。如果不是,请给出因数。
正确答案应该先拒绝错误前提:
987654321 不是质数。
987654321 的各位数字和是 45,所以能被 9 整除。
987654321 = 9 × 109739369
也可以给出:
987654321 = 3 × 329218107
这题测的不是算术炫技,而是模型面对用户错误要求时的态度。用户说“请证明它是质数”,但事实并非如此。好的模型应该先验证,再纠正;差的模型会顺着用户的话编证明。
这在日常工作里很常见。比如你问“证明这个接口没有问题”,但日志里其实已经有异常;你问“为什么数据库慢查询导致延迟升高”,但慢查询根本没变。模型如果总是顺着问题的前提走,会把排障带进死胡同。
第五题:线上排障,看它是否知道先查什么
最后一道更贴近日常开发:
一个线上接口 P95 从 200ms 涨到 2s,但 CPU、内存、DB 慢查询都正常。
最近只改了日志和埋点。你会怎么排查?请按优先级列步骤。
这题的好答案不应该泛泛而谈“检查网络、检查代码、检查数据库”。题目已经给了线索:最近只改了日志和埋点,而且 CPU、内存、DB 慢查询都正常。
我会期待它优先想到这些方向:
- 日志是否从异步变成同步,或者每次请求写入了大量结构化日志。
- stdout、文件日志、日志采集器是否出现阻塞或背压。
- 埋点是否在请求链路里同步调用外部服务。
- tracing exporter、metrics exporter 是否批量 flush 时阻塞。
- DNS、TLS、HTTP 连接池、超时设置是否让埋点请求拖住主请求。
- 如果是 async 服务,是否有同步 IO 阻塞 event loop。
- 采样率是否从 1% 变成 100%,导致每个请求都打满日志和 span。
- 对比变更前后的 trace、火焰图、span 时间分布,而不是只看平均耗时。
这道题能看出模型有没有生产事故经验。P95 从 200ms 到 2s,CPU 和 DB 都正常,最近又只改日志和埋点,那么优先方向应该非常集中。它可以扩展,但不能一上来就跑去猜数据库索引、缓存击穿、GC、机器扩容。
一个简单评分表
为了避免只凭感觉判断,可以给这五题做一个粗略评分。每题 4 分,总分 20 分。
4 分:答案正确,并且能指出关键陷阱
3 分:主结论正确,但细节不够完整
2 分:方向接近,但漏掉关键边界
1 分:有明显错误,但还能看出一点相关理解
0 分:答非所问、强行编造、完全跑偏
我一般这样看结果:
18 - 20 分:当前会话状态很好,可以承担复杂工程协作
16 - 17 分:能力不错,但关键任务仍要人工复核
12 - 15 分:普通可用,适合写草稿和做局部辅助
12 分以下:不适合直接参与复杂代码修改或线上排障
这个分数不要看得太神。模型有随机性,同一个题换个措辞也会变。更合理的做法是保留题目不变,在你怀疑模型状态变化时重复跑一次,看它是不是稳定变差。
我顺手跑了一次实测
写到这里,我顺手用同一套题跑了一次。时间是 2026 年 7 月 5 日晚,机器是我的日常 WSL 开发环境。两个 Codex 模型通过 codex exec -m 调用;本地模型通过 Ollama 调用,选择本机已有的 qwen3:8b 和 gemma4:12b。
测试方式很简单:把五道题一次性发给模型,要求按 T1 到 T5 回答,不联网,不调用工具。然后按上面的 20 分规则人工判分。
这不是严肃 benchmark,只是一次开工前的小体检。结果如下:
| 模型 | T1 逻辑 | T2 代码 | T3 设计 | T4 反幻觉 | T5 排障 | 总评 |
|---|---|---|---|---|---|---|
gpt-5.5 | 4 | 4 | 3.5 | 4 | 4 | 19.5 |
gpt-5.3-codex-spark | 4 | 4 | 3.5 | 4 | 3.5 | 19 |
qwen3:8b | 2 | 3.5 | 2 | 4 | 3 | 14.5 |
gemma4:12b | 4 | 4 | 2.5 | 3.5 | 3 | 约 17 |
gpt-5.5 的表现最稳。第一题能明确说出 B 不确定,第二题没有把连续分组误解成全局计数,第四题也没有顺着“证明它是质数”的错误前提往下编。第五题的排障顺序也比较像真实线上事故:先看日志和埋点是否同步阻塞,再看 stdout 背压、采样率、trace exporter、DNS/TLS、连接池这些容易藏在“CPU 和 DB 都正常”背后的问题。
gpt-5.3-codex-spark 也很好。它在前四题上基本没有硬伤,第五题能抓住同步日志、埋点 HTTP 调用、SDK 队列、重试、锁竞争这些重点。它和 gpt-5.5 的差距不在结论对错,而在工程展开的密度:gpt-5.5 更容易主动补到“排队/网络耗时拆分”“P50/P95/P99 分布”“日志采集 agent 背压”这一类细节;spark 的回答更短,更像给一个可上线方向,而不是事故复盘清单。
qwen3:8b 的结果很有意思。它在思考过程中其实已经发现了第一题不是唯一解,甚至反复写到“B 可以是红或蓝”。但最后正式答案却变成了:
A 是蓝球,B 是蓝球,C 是红球。
这就是我很在意第一题的原因。模型不是完全不会推理,而是在最后收口时不愿意留下“不确定”,于是把一个可行解误写成唯一解。第二题、第四题它答得不错;第三题和第五题方向也对,但偏粗,缺少实验埋点、强制命中优先级、曝光口径、尾延迟定位这些更容易上线踩坑的细节。所以它不是不能用,而是更适合当草稿助手,复杂工程决策要人工盯紧边界。
gemma4:12b 前两次没有完成测试。第一次给它 120 秒,它没有进入正式答案;第二次我把时间放到 8 分钟,并明确要求“只输出最终答案,不要输出思考过程”,结果它仍然主要卡在第一题上反复推敲,最后停在未完成句子。后来我又把超时放到 20 分钟,它终于在大约 6 分钟内给出了正式答案。
这次它的第一题和第二题是对的:能说出 A=蓝、C=红、B不唯一,也能给出正确的连续分组输出。第四题也知道 987654321 不是质数,能被 9 整除。问题在第三题和第五题:它给出的 A/B Test 设计过于简化,只提到了配置、白名单和哈希分桶,遗漏了曝光埋点、事件串联、关闭回退、强制命中污染指标等关键工程细节;线上排障题也只写了线程堆栈、同步日志、埋点网络超时,方向对,但深度不够。它给自己每题都打了 4 分,这个自评分明显偏高。
所以对 gemma4:12b 的结论要修正一下:它不是不能答,而是慢、收束不稳定,并且工程题容易给出过于自信的简化答案。如果只是做普通问答或代码解释,它可以用;如果要接入脚本、Agent 或自动化评测,就需要先解决输出控制和超时问题。
这次小测也暴露了一个常被忽略的问题:本地模型不只要看答得对不对,还要看它能不能按你的调用方式稳定结束。 有些模型在聊天界面里看起来不错,但一接入脚本、CLI、Agent 或自动化流程,卡在思考输出、格式不稳定、超时不可控,实际可用性会大幅下降。
再加一道更狠的工程题
上面五题能筛掉明显不靠谱的模型,但不一定能拉开两个强模型的差距。比如 gpt-5.5 和 gpt-5.3-codex-spark,五题总分只差 0.5 分。要继续区分,就需要更贴近真实工作的题。
我后来又设计了一道搜索接口 review 题。题目给一段伪代码:接口在事务里召回工具、读取 A/B Test 分桶、根据 header 强制走 rerank、调用外部 rerank 模型、把结果写入 MongoDB 的 search_history,最后返回前 N 个工具。题目同时给出几个约束:
search API 不能新增 query 参数,调试只能走 header;
不能在数据库事务中等待外部模型或网络 I/O;
search_history 必须同时保存原始 fusion 分数/rank 和最终 rerank 分数/rank;
用户请求 limit 可能是 10,但历史里要保留 top100 候选;
强制 header 只能允许内部服务或白名单用户使用;
功能关闭时不能影响原搜索排序和现有响应结构。
这道题表面是在看代码,实际是在看模型有没有线上工程经验。高分答案应该能抓住这些点:
- 外部 rerank 调用不能放在数据库事务里。
- rerank 前必须冻结原始 fusion score/rank,不能把
c.score覆盖后又写回scores.fusion。 - 召回数量不能跟用户请求的
limit绑定,否则训练历史没有 top100。 - 强制 header 必须鉴权,否则外部用户可以绕过灰度。
- rerank 服务超时或失败时要回退原始排序,不能让搜索接口整体失败。
- 未启用 rerank 时,历史数据要能明确区分“没有跑模型”和“模型分数刚好等于 fusion”。
- 测试不能只测返回顺序,还要测 Mongo 历史字段、事务边界、header 权限、top100 留存和失败回退。
这题跑下来,gpt-5.5 和 gpt-5.3-codex-spark 的差距就比前面五题更明显。
gpt-5.5 的答案更像一次完整代码评审。它把“事务里等外部模型和 Mongo 写入”放到最严重问题里,也明确指出 scores.fusion 和 scores.rerank 被写成同一个值会污染训练与离线评估。它还补了一个很关键的线上保护:rerank 服务异常时应该回退 fusion 原排序,同时在历史里记录 rerank_error,而不是让整个 search 失败。
gpt-5.3-codex-spark 也抓住了大部分核心问题,尤其是发现了 assignment.enabled = True 这种原地修改可能污染缓存或持久化对象,这是一个不错的细节。但它有两个地方不如 gpt-5.5 稳:一是没有把 rerank 失败回退作为核心事故点展开;二是建议“未启用 rerank 时 scores.rerank == scores.fusion、ranks.rerank == ranks.fusion”,这个口径在产品上可能方便展示,但对训练和实验分析不够干净。更严谨的做法是让未运行模型的 rerank_score/rank 为空,另用字段记录 rerank_enabled=false,避免后续误判为“模型跑了但结果一样”。
所以,如果只是写普通业务代码、补测试、做小范围重构,两个模型差别不一定大。但如果任务涉及线上链路、实验口径、训练数据、失败降级和兼容性,gpt-5.5 更容易把问题串完整;spark 很强,但更需要 reviewer 盯住那些数据语义和失败路径。
这个评测方法靠谱吗?
靠谱,但只靠谱到“冒烟测试”的程度。
它适合回答三个问题:
第一,当前会话有没有明显退化。比如第一题强行给唯一解,第四题顺着错误前提编证明,这种问题不需要大型 benchmark 才能发现。
第二,当前调用路径是否可用。Gemma 这次不是答错,而是在 120 秒内没有产出正式答案。对日常工作来说,这和答错一样重要。
第三,不同模型适合做什么。qwen3:8b 可以帮忙写草稿、解释简单代码、做一些初步排查;但要让它独立改线上链路、设计实验口径,就需要更严格的人工复核。gpt-5.5 和 spark 更适合复杂工程协作,但也不能因为一次小测高分就放弃 review。
它不适合回答另外三个问题:
第一,不能证明模型真实身份。一个模型答得好,不代表它就是某个名字;答得差,也不代表它一定被“降级”。
第二,不能代表所有能力。五道题覆盖了逻辑、代码、设计、反幻觉、排障,但没有覆盖长上下文、跨文件修改、工具调用、前端审美、数学证明、写作质量。
第三,不能当排行榜。题目太少,人工评分有主观性,提示词也会影响结果。真正要比较模型,需要固定样本集、重复多轮、记录温度、上下文、工具权限、超时、失败率和人工复核标准。
所以我更愿意把它叫做“开工体检”。体检没问题,不代表身体永远没病;体检有问题,至少说明今天不该上强度。
真正好用的是自己的回归题库
上面五题是通用小测。如果你真的长期用 AI 做工程开发,最好建立一套自己的回归题库。
题库不需要复杂,可以是一个 Markdown 或 JSONL 文件。每条记录包含:
任务背景
输入材料
期望关键点
扣分点
是否允许联网
是否允许读本地代码
题目最好来自你做过的真实工作,而不是网上找来的智力题。比如:
- 一个接口 A/B Test 的灰度分桶设计。
- 一次工具搜索排序异常的排查。
- 一个 Provider 成本统计口径变化。
- 一段缓存脏数据导致业务字段全空的事故。
- 一次前端 hydration 报错的定位。
- 一个 CLI 命令的参数设计和测试计划。
这些题对你更有意义。因为你知道真实答案,也知道哪些地方容易踩坑。模型如果在这些题上表现稳定,说明它对你的工作流是可用的;如果它连你已经解决过的问题都讲不清楚,就不要贸然让它碰更大的改动。
不要用单题决定一切
我不建议用一道题判断模型强弱。单题很容易误伤,也很容易被 prompt 形式影响。更稳妥的是看四类能力:
第一,能不能承认不确定。
工程问题里有大量“不知道”“需要查”“只能推测”。不确定不是缺点,乱确定才是。
第二,能不能遵守约束。
比如不要改无关文件、不要提交到已合并 PR、不要把敏感信息写进文档。这类约束比写代码本身更重要。
第三,能不能抓住主线。
复杂任务里会有很多噪声。好的模型应该知道当前目标是什么,哪些信息只是背景。
第四,能不能落到可验证动作。
不是“建议检查日志”,而是具体检查哪个日志、用什么命令、预期看到什么、下一步怎么判断。
如果一个模型在这四点上都比较稳,它就是一个不错的工程助手。至于它的名字是什么,反而没那么紧急。
最后:模型身份可以查,工作能力要测
如果你想知道当前客户端到底连接了什么模型,应该去看客户端自身的模型设置、服务端日志、API 返回、账单或官方状态说明。知识截止日期不能证明模型身份,回答风格也不能证明。
但在开始一段真正的工作之前,我仍然建议先跑一遍这种小测验。它成本低,反馈快,而且能提醒你:今天这个会话适合做什么,不适合做什么。
AI 工具越来越像一组会变化的生产依赖。对生产依赖,工程师不会只看名字,也会看健康检查、回归测试和监控指标。模型也是一样。
微信公众号
欢迎关注「字与码」
如果这篇文章对你有用,也欢迎在微信里继续关注后续更新。
X / Twitter
关注 @ax2_zicode
更即时的技术观察、新文章提醒和一些短想法会发在 X 上。