
很多开发者在 Code Review 时都遇到过一种说不清道不明的别扭AI 提交的代码功能没问题测试也能过但看起来就是不对劲——注释多得像在写作文函数被拆得又碎又没必要一个 if 能解决的事硬是给你抽象出三层接口。过去一年AI 编程模型的评测都在比“能不能过题”。能跑过 HumanEval、SWE-bench 的模型越来越多可真正把 AI 代码放进生产环境的人反而越来越不放心。原因很简单传统基准测试测的是“正确性”不是“代码质量”。一个模型可以做出正确的题同时稳定地产出一堆进不了生产环境的 “slop code”——中文社区有人叫它“AI 味代码”也有人叫它“缝合代码”。最近一个叫 SlopCodeBench 的新基准测试把这个长期被忽视的问题摆到了台面上。它把 Fable、Sol、Kimi K3 这几个近期热度很高的模型拉到同一套标准下正面比较谁生成的代码更像“人写的”而不是“AI 糊的”。与此同时DeepSeek V4、Qwen3.8 这些模型也在被社区反复讨论但 SlopCodeBench 选择了一个独特的切入角度不卷参数、不卷刷题分数而是直接卷“代码垃圾率”。这篇文章我会做三件事第一讲清楚 SlopCodeBench 到底在测什么为什么它比单纯刷题式评测更接近真实工程第二分析 Fable、Sol、Kimi K3 三个被测对象各自的定位差异包括 Kimi K3 背后 2.8T 参数 MoE 架构带来的影响第三给出一套你可以自己跑的最小评测流程用代码演示如何把“垃圾代码率”量化出来。看完你不仅知道怎么看这份榜单还能自己搭一套评估系统避免被任何单一指标带偏。1. 传统基准测试的盲区能跑和能维护是两回事先抛一个判断HumanEval 这类基准测试的成绩和代码是否真的能进生产环境相关性正在快速下降。原因不复杂。HumanEval 考的是“给一个函数签名写一个能跑过单元测试的实现”这类题目本质上偏向短代码、单文件、明确输入输出。模型只需要在局部做过拟合就能拿到很高分数。可真实的软件工程是另一种游戏代码要被人读、被团队维护、被后续需求改三次以上。于是出现了一个很怪的现象刷榜模型在一个 kata 题目上写出了优雅的解法同一个模型在真实仓库里能给你生成一屏又一屏的防御性代码、冗余注释和过度抽象测试覆盖率看起来不低但改起来想骂人。这背后的原因可以从两个层面看。第一训练语料的影响。模型在海量开源代码上训练而开源仓库的代码质量分布极其不均匀。大量样板代码、脚手架代码、文档注释在语料里占比很高。模型学到的是“统计上最常见”的写法而不是“工程上最优”的写法。于是输出会偏向啰嗦、模板化、防御过度。第二评测指标的误导。传统基准测试只给一个二元结果测试通过或失败。它完全不关心代码体积、注释密度、圈复杂度、命名质量、模块边界是否合理。当一个指标只衡量“能不能跑”参与刷榜的人自然会往这个方向优化。模型厂商不是不知道代码质量重要而是评测体系没有逼他们证明这一点。SlopCodeBench 的价值恰恰在于它试图把“垃圾代码”这个模糊的质量问题变成一套可量化的测量体系。它本质上不是要淘汰谁而是逼着模型厂商回答一个所有一线工程师都想知道的问题你的模型写出来的代码到底敢不敢让我接手维护这里需要先说明一点SlopCodeBench 目前还属于社区性质的基准测试方法学还在快速迭代。但它的出现本身就是信号——AI 编程模型的竞争正在从“能不能写对”进入“能不能写好”的阶段。这段时间 DeepSeek V4、Qwen3.8 的讨论也印证了这一点各家的技术路线开始分化有的继续堆参数有的押注推理效率而 SlopCodeBench 选择用“代码质量”作为一把横切刀。2. SlopCodeBench 在测什么拆解“Slop Code”“Slop” 这个词原本在英文社区里指代 AI 生成内容中那种“没有灵魂、批量生产、一眼假”的质感。当它和代码放在一起Slop Code 指的不是有 bug 的代码而是那种“能跑但很糟糕”的代码。具体来说Slop Code 通常有几种典型表现过度注释。把代码用自然语言复述一遍甚至每一行都写注释仿佛在写小学生作文。不必要地拆函数。两个三行的动作被拆成四个函数还起了很泛化的名字。抽象过度。为一个现在只需要 if-else 的逻辑设计出策略模式加工厂模式。防御性编程变成防御性表演。到处判空、到处 try-catch、到处加日志但实际上什么都没处理。模板化命名和结构。变量叫 data、result、config函数叫 processData、handleClick、doSomething。重复代码。同样的逻辑在文件里出现三次只因为每次的参数类型微妙地不同。风格不一致。同一份代码里一会儿用流式 API一会儿用传统循环一会儿用 Optional一会儿又直接返回 null。SlopCodeBench 的思路就是围绕这些表现设计一套评测维度。从目前公开的信息看它比传统基准测试多覆盖了以下几个方向维度传统基准测试SlopCodeBench 侧重点功能正确性核心关注仍然关注但只是前提代码长度不关心关注冗长度惩罚注水代码注释质量不关心关注注释是解释“为什么”还是复述“是什么”结构复杂度不关心关注圈复杂度、函数长度重复度不关心关注重复代码率可维护性不关心尝试用代理指标量化安全与性能有限关注检查明显的安全反模式和性能问题这个对比表格已经能说明问题了传统基准测试像一个只检查答案对错的考试SlopCodeBench 则试图模拟一位带代码评审视角的资深工程师在看代码。所以它的评分体系里“能跑”只是一个进入讨论的入场券真正拉开差距的是代码的整洁度、抽象合理性和命名质量。需要强调一个容易误解的点SlopCodeBench 并不是要所有模型都写成最小化代码。它的核心诉求是“代码质量对得起工程标准”而不是“越短越好”。短而无意义的一行流同样可能是 slop因为可读性极差。关键在于能不能用合理的结构、恰到好处的抽象和清晰的命名把问题表达好。这个平衡点很难用一条规则定义也正因为难才需要有专门的数据集和评分体系来做持续测量。3. 三个被测模型Fable、Sol 与 Kimi K3 的定位差异把一个基准测试的价值说清楚之后再来看这次测试的三个主角Fable、Sol 和 Kimi K3。为什么是这三个放在一起比表面上看它们都是代码生成模型或工具实际走的路线差别非常大。与其简单看排名不如先理解三条路线的内在逻辑。3.1 Fable强调“代码叙事”的新面孔Fable 是近期社区讨论中比较特殊的一个。它的名字本身就是“寓言”的意思主打的方向是让生成的代码有清晰的叙述逻辑和风格一致性。从目前的公开信息看Fable 更强调在生成过程中维持统一的代码风格避免“一个文件里出现三种流派”。它试图解决的核心痛点是AI 生成代码的“缝合感”——同一个任务里模型一会儿写函数式风格一会儿写命令式风格仿佛从不同仓库里抄了三段代码拼在一起。如果你让 Fable 写一个小模块它会倾向于先给一个领域相关的命名骨架再填充逻辑。这种做法的好处是可读性好坏处是如果任务本身很简单它可能会显得“用力过猛”——为了风格统一而引入不必要的结构。这恰恰是 SlopCodeBench 要衡量的点因为过度设计也是 slop code 的一种典型形态。3.2 Sol轻量高效路线的代表Sol 在讨论中的定位更偏向“效率型”模型围绕它的关键词是体量小、推理快、适合本地部署。从 “5.6 sol 和 terra” 这类社区讨论能看出Sol 被关注的原因不在于参数规模大而在于它试图用更小的体量挑战大模型在代码任务上的表现。Sol 的思路代表了一部分开发者的真实需求不是每个人都有 GPU 集群去跑 2.8T 参数的 MoE 模型更多场景是希望在本地一台还行的机器上快速、低成本地获得可用的代码生成能力。代码生成是高频操作每一次补全都要一次推理推理速度直接决定了开发体验。Sol 走的正是“性价比”路线。但轻量模型在 SlopCodeBench 上往往面临一个尴尬它们更容易生成平庸、模板化的代码。因为参数量限制了模型的“思考深度”它们更倾向于输出训练分布里最常见的解而最常见往往意味着最啰嗦、最保守。当然如果 Sol 在推理时做了额外的搜索或采样优化这个劣势可以部分被弥补。从 SiB 的角度看它能不能在有限参数量下同时保证“正确性”和“简洁性”是评测里最有看点的地方。3.3 Kimi K32.8T 参数背后的 MoE 思路Kimi K3 是目前三者里背景最明确、讨论热度也最高的模型。围绕它最核心的信息有两个一是总参数规模达到 2.8T二是采用了 MoEMixture of Experts混合专家架构并且在本地部署话题上也有很高关注度。参数规模到 2.8T很多人第一反应是“这谁能跑得动”。但 MoE 架构的关键恰恰在这里模型的总参数可以很大但每次推理只激活其中一部分专家。这意味着理论上它能记住更多的知识、覆盖更多的代码模式而推理成本不会像稠密模型那样随总参数线性增长。可以打一个比方MoE 像一家大公司员工总人数很多但处理一个具体任务时只需要调动相关部门的几个人而不是全公司一起上。Kimi K3 在代码任务上的优势逻辑也在这里由于专家可以分工处理语法、框架 API、业务模式等不同侧面生成复杂代码时更可能保持结构清晰。但它要面对的挑战同样明显——架构复杂、部署成本高而且在“简洁优先”的评测维度上一个知识量很大的模型更容易过度设计。它可能知道太多设计模式于是在一个小需求上也忍不住端出一整套架构来。3.4 为什么把三者放在同一个基准测试里Fable、Sol、Kimi K3分别代表了代码生成模型的三条路线风格质量路线Fable轻量本地路线Sol大体量工程路线Kimi K3SlopCodeBench 把它们放在一起本质上不是在排一个简单名次而是在回答一个问题哪条路线在当前工程标准下产出的代码最“靠谱”这个答案对开发者的选型参考价值比单纯的能力排行榜要大得多。尤其对团队技术负责人来说选模型不再只是选“谁笨谁聪明”而是选“谁的代码风格和我们的工程文化更匹配”。4. 自己动手评估从“看榜单”到“跑评测”面对 SlopCodeBench 这类社区基准测试一个理性的做法不是直接相信榜单结果而是搭建一套最小评估流程验证它是否符合你自己的工程标准。原因很简单评测设计里有大量主观选择。prompt 怎么写、测试任务选什么、代码质量指标怎么定义都会影响最终排名。直接照搬榜单可能带偏你的技术选型。自己动手跑一遍至少你能确认这些结论在你关心的场景下是否成立。下面我给出一个可以本地运行的最小流程。它不依赖特定厂商的 API兼容 OpenAI 格式的模型服务都可以接入——无论你用的是云端 API还是本地部署的模型只要把 base_url 和模型名改一下就能跑。4.1 环境准备建议环境如下项目建议值操作系统Linux / macOS / Windows WSL2Python3.10 或以上依赖openai、tabulate、pyyaml模型服务任意 OpenAI 兼容接口或本地部署服务依赖安装命令pip install openai tabulate pyyaml如果你的模型服务不在 127.0.0.1把 base_url 改成实际地址即可。注意不同模型服务的模型名可能不同建议先通过服务端的模型列表接口确认你准备调用的模型名。4.2 准备测试任务集评估 Slop Code 的第一步是准备一组有代表性的代码生成任务。任务集不需要大但要有区分度。如果任务太简单所有模型都能写得很好如果任务太难所有模型都会为了“通过”而牺牲质量。理想的评测任务应该处在“好工程师能写得很简洁、普通模型容易写啰嗦”的位置上。我建议从以下四类任务中挑选“简单但易过度设计”的任务比如写一个解析 HTTP query string 的函数。好的实现十行内能完成差的实现会写出一堆辅助函数和抽象。“需要边界处理”的任务比如实现一个限流器需要处理并发和超时。“业务语义明显”的任务比如电商订单状态流转好的实现会用清晰的领域命名差的实现会全用 if-else 和魔法数字。“性能敏感”的任务比如对一个大数据集做去重聚合要能看出模型是否关心复杂度。将任务写入一个 YAML 文件tasks.yamltasks: - id: parse_query_string description: 解析 HTTP query string支持无嵌套的 keyvalue 对返回字典。对空值做合理处理。 lang: python quality_criteria: [简洁, 可读, 边界完整] - id: rate_limiter description: 实现一个固定窗口限流器支持单机并发安全接口简单。 lang: python quality_criteria: [并发安全, 接口简洁, 注释适度] - id: order_status_machine description: 实现订单状态流转待支付、已支付、已发货、已完成、已取消。禁止非法状态跳转。 lang: python quality_criteria: [状态建模清晰, 非法跳转处理, 命名可读] - id: dedup_aggregate description: 对极大列表去重并统计频次要求时间复杂度接近 O(n)。 lang: python quality_criteria: [复杂度合理, 内存友好, 实现简洁]这里的关键点是每个任务都要附带质量评判标准。没有质量标准的任务最后只会评出“能跑”和“不能跑”那就退回传统基准测试的老路了。质量标准不一定要多但必须能区分“及格”和“优秀”比如“命名可读”和“复杂度合理”这类主观标准恰恰是 SlopCodeBench 想要量化的东西。4.3 定义统一的评测 Prompt为了让三个模型公平竞争需要使用完全相同的 prompt 模板。模板里要明确指出代码质量要求避免模型默认输出“教科书风格”的长篇实现。这一步在真实使用中同样重要因为你给 AI 下需求时的措辞很大程度上决定了它交付代码的质量。# 文件路径eval_prompt.py EVAL_PROMPT_TEMPLATE 你是资深软件工程师。请用 Python 实现下面这个需求。 需求 {description} 要求 1. 代码必须能直接运行输入输出符合需求。 2. 保持代码简洁避免不必要的抽象、防御性代码和冗余注释。 3. 命名要体现业务语义禁止使用 data、result、config 这类无信息量的泛化命名。 4. 只为“为什么这样做”的关键逻辑写注释不要复述代码本身。 5. 尽量保持函数数量合理一个能简单完成的需求不要拆出多余的辅助函数。 直接输出代码不要输出解释。这段 prompt 本身就是一个质量约束器。它明确告诉模型长篇大论、过度设计、模板化命名都会被扣分。在跨模型比较时这个约束对所有被测模型一视同仁因此最终差异更能反映模型在“被要求写高质量代码”时的真实能力上限而不是它默认的放飞状态。4.4 调用模型并收集输出接下来是核心评估脚本。下面的代码演示如何调用 OpenAI 兼容接口依次生成代码并保存结果。这个脚本只是骨架你可以根据自己的任务集、采样参数和模型列表扩展。# 文件路径slop_eval.py import json import time from pathlib import Path import yaml from openai import OpenAI from eval_prompt import EVAL_PROMPT_TEMPLATE # 模型服务的 base_url 和 key 请根据实际情况填写 client OpenAI( base_urlhttp://127.0.0.1:8000/v1, api_keysk-local-test, ) def generate_code(model: str, description: str) - str: resp client.chat.completions.create( modelmodel, messages[ {role: system, content: 你是一名严谨的软件工程师。}, {role: user, content: EVAL_PROMPT_TEMPLATE.format(descriptiondescription)}, ], temperature0.2, # 低温度保证可复现 max_tokens2048, ) return resp.choices[0].message.content def run_eval(model: str): tasks yaml.safe_load(Path(tasks.yaml).read_text(encodingutf-8)) results [] for task in tasks[tasks]: code generate_code(model, task[description]) item { task_id: task[id], model: model, code: code, quality_criteria: task[quality_criteria], } results.append(item) # 避免触发服务端限流 time.sleep(1) out_path foutput_{model}.json Path(out_path).write_text( json.dumps(results, ensure_asciiFalse, indent2), encodingutf-8, ) print(f完成 {model} 的 {len(results)} 个任务结果已写入 {out_path}) if __name__ __main__: run_eval(your-model-name)运行方式很简单python slop_eval.py这个脚本把每个模型的输出落到本地 JSON 文件为下一步的静态分析做准备。运行前记得确认模型名和你的目标服务一致。如果某个任务生成失败或返回空内容建议在脚本里增加重试机制避免单个任务的失败影响整个评测批次。4.5 计算 Slop 指标拿到模型输出之后我们可以用一套简单的静态指标量化“垃圾代码率”。这里演示几个最核心的指标代码可以放在slop_metrics.py中。这里的指标设计思路是用 AST 解析和简单的行统计把“代码质量”从可读性、结构复杂度、重复度等角度做有损量化。这些代理指标只能帮你做初筛最终判断还需要人工介入。# 文件路径slop_metrics.py import ast import json import re import sys from pathlib import Path def extract_code_block(raw: str) - str: m re.search(r(?:python)?\n(.*?), raw, re.DOTALL) return m.group(1) if m else raw.strip() def count_lines(code: str) - int: return max(1, len([l for l in code.strip().splitlines() if l.strip()])) def comment_density(code: str) - float: try: tree ast.parse(code) except SyntaxError: return 0.0 total_lines count_lines(code) comment_lines 0 for node in ast.walk(tree): if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)): docstring ast.get_docstring(node) if docstring: comment_lines len(docstring.splitlines()) comment_lines len(re.findall(r^\s*#, code, re.MULTILINE)) return comment_lines / total_lines def duplicate_lines(code: str) - float: lines [l.strip() for l in code.splitlines() if l.strip()] total max(1, len(lines)) seen set() dup 0 for line in lines: if line in seen: dup 1 else: seen.add(line) return dup / total def function_count(code: str) - int: try: tree ast.parse(code) except SyntaxError: return 0 return len([n for n in ast.walk(tree) if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef))]) def analyze_file(path: str): data json.loads(Path(path).read_text(encodingutf-8)) rows [] for item in data: code extract_code_block(item[code]) try: ast.parse(code) valid True except SyntaxError: valid False rows.append({ task_id: item[task_id], valid_syntax: valid, lines: count_lines(code), functions: function_count(code), comment_density: round(comment_density(code), 3), duplicate_rate: round(duplicate_lines(code), 3), }) return rows if __name__ __main__: for path in sys.argv[1:]: print(f--- {path} ---) for row in analyze_file(path): print(row)运行方式python slop_metrics.py output_your-model-name.json这里需要说明一下指标的意义valid_syntax是底线指标。语法都不对后面的讨论没有意义。lines和functions是冗长度代理指标。同一个任务行数越多、函数拆得越多不代表一定越差但偏离中位数过远通常意味着过度设计。comment_density是注释密度。密度过高意味着模型在用注释凑篇幅、复述代码。duplicate_rate是重复率。重复率高说明模型没有抽象能力只是一味复制粘贴。这些指标之间可能互相矛盾比如一个模型注释密度很低但重复率很高。这正是需要人工评审兜底的原因。你可以先把三个模型的指标输出打印出来对比每个任务上的差异再针对差异最明显的任务做人工阅读。5. 如何解读结果从数字回到工程判断把指标算出来之后真正的难点来了怎么判断哪个模型的输出更“不 slop”我建议不要直接按某个单项指标排名而是建立一个综合判断流程。第一步看语法有效性。如果三个模型里某个模型的代码频繁语法错误说明它的基础生成能力有硬伤不需要继续看质量指标。第二步看行数分布。如果一个模型在每个任务上都稳定地比另一个模型多 30% 以上的行数而且不是必需的那基本可以判断它存在“注水”倾向。这里的“必需”怎么判断可以对比团队里资深工程师的手写实现以人工实现为基准线。第三步人工阅读“中位数样本”。把三个模型在同一个任务上的输出放在一起不看模型名让团队里一位不了解结果的人挑出“你愿意接手维护”的那份。这个方法很朴素但在实践中比任何量化指标都有效。因为“代码质量”最终是一个人的主观判断一个有经验的工程师扫一眼就能看出代码是不是 AI 味。第四步反向验证。把模型输出交给资深工程师做一轮 code review记录他们挑出的“会让你皱眉”的地方。如果评审者对某个模型的负面反馈集中在“注释过多”“抽象过度”“命名泛化”那这个模型在 SlopCodeBench 上的得分大概率不会好看。必须提醒的是SlopCodeBench 的分数并不等同于模型的实际工程能力。它把“代码质量”这件事做了有损压缩任何一个指标集都无法覆盖所有工程场景。比如一个在限流器任务上表现出色的模型可能在业务系统的领域建模上完全失败。评测的意义是告诉你“这个模型的风格偏好”而不是“这个模型能不能用”。所以在读任何 SlopCodeBench 相关结果时建议带着以下问题测试集覆盖的任务类型和我的业务场景是否一致评分的权重设计是否默认偏爱简洁风格如果我的项目强制要求大量防御性编程这个评分对我不适用。测试用的 prompt 是否加了质量约束如果评测用的是没有任何约束的裸 prompt结果反映的是模型默认风格而不是最佳能力。测试任务是单文件生成还是多文件仓库级修改如果是前者说明它还不能完全代表真实工程场景。6. 常见问题与排查方法在搭建这套评估流程的过程中你大概率会遇到一些问题。下面把最常见的几个整理出来方便在本地环境里按顺序排查。问题现象可能原因排查方式解决方案请求模型服务时报 timeoutbase_url 配置错误或本地服务未启动用 curl 直接请求 /v1/models 验证服务确认服务地址和端口确认模型服务支持 OpenAI 兼容接口模型输出包含大量解释文字而不是纯代码prompt 里没有强调“直接输出代码”检查 prompt 模板确认有输出格式约束在 prompt 末尾追加“直接输出代码不要输出解释”提取代码块后 SyntaxError模型返回了 Markdown 包裹或截断代码打印 extract_code_block