题解代码质量自动评分:从正确性到可读性的多维评估体系 题解代码质量自动评分从正确性到可读性的多维评估体系一、代码能跑 ≠ 代码值得参考AI 生成的题解代码通过沙箱评测只能回答一个问题「这段代码对不对」。但作为题解它还需要回答更多问题可读性好吗命名合理吗复杂度分析准确吗有没有潜在的边界问题这些维度的评估不是非此即彼的判断题需要一套量化评分体系。这篇文章讨论题解代码质量的自动评分构建一个从「能不能跑」到「值不值得学」的多维评估框架。二、评分体系的维度设计flowchart TD A[代码质量评分] -- B[正确性 30%] A -- C[可读性 25%] A -- D[复杂度 20%] A -- E[稳健性 15%] A -- F[工程规范 10%] B -- B1[样例通过率] B -- B2[边界用例通过率] B -- B3[随机测试通过率] C -- C1[命名规范度] C -- C2[注释覆盖率] C -- C3[函数复杂度 圈复杂度] D -- D1[时间复杂度分析准确] D -- D2[空间复杂度分析准确] D -- D3[分析中说明了推导过程] E -- E1[空值处理] E -- E2[输入校验] E -- E3[异常边界处理] F -- F1[类型注解完整] F -- F2[遵循语言风格指南] F -- F3[无冗余代码]三、实现import ast import math from dataclasses import dataclass, field from typing import Optional dataclass class QualityScore: 代码质量评分 correctness: float # 正确性 0-100 readability: float # 可读性 0-100 complexity: float # 复杂度分析准确性 0-100 robustness: float # 稳健性 0-100 style: float # 工程规范 0-100 overall: float 0.0 # 加权总分 # 各维度权重 WEIGHTS { correctness: 0.30, readability: 0.25, complexity: 0.20, robustness: 0.15, style: 0.10, } def __post_init__(self): self.overall ( self.correctness * self.WEIGHTS[correctness] self.readability * self.WEIGHTS[readability] self.complexity * self.WEIGHTS[complexity] self.robustness * self.WEIGHTS[robustness] self.style * self.WEIGHTS[style] ) class CodeQualityEvaluator: 代码质量综合评估器 def evaluate( self, code: str, test_results: dict, # 沙箱评测结果 complexity_analysis: Optional[str] None, ) - QualityScore: 综合评估代码质量 return QualityScore( correctnessself._eval_correctness(test_results), readabilityself._eval_readability(code), complexityself._eval_complexity_analysis(complexity_analysis), robustnessself._eval_robustness(code), styleself._eval_style(code), ) def _eval_correctness(self, results: dict) - float: 评估正确性基于沙箱评测结果 total results.get(total_cases, 0) passed results.get(passed, 0) if total 0: return 0 base_score (passed / total) * 100 # 边界用例通过率权重更高 boundary_total results.get(boundary_cases, 0) boundary_passed results.get(boundary_passed, 0) if boundary_total 0: boundary_rate boundary_passed / boundary_total # 边界用例不通过最多扣 30 分 boundary_penalty (1 - boundary_rate) * 30 return max(0, base_score - boundary_penalty) return base_score def _eval_readability(self, code: str) - float: 评估可读性命名、注释、结构 score 100.0 # 1. 命名检查变量名长度 try: tree ast.parse(code) for node in ast.walk(tree): if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Store): # 单字母变量名除了 i, j, x, y, n, m 等常见迭代变量 if len(node.id) 1 and node.id not in ijkxyznms: score - 3 except SyntaxError: score - 20 # 语法错误代码本身有问题 # 2. 注释覆盖率 lines code.split(\n) total_lines len(lines) comment_lines sum( 1 for line in lines if line.strip().startswith(#) or line.strip().startswith(//) ) comment_ratio comment_lines / max(total_lines, 1) # 注释率 5% 扣分 20% 也可能过度注释 if comment_ratio 0.05: score - 15 if comment_ratio 0.40: score - 5 # 过度注释 # 3. 圈复杂度检查简化版 # 统计分支关键字 branch_keywords [if , elif , else:, for , while , except] branches sum(min(1, code.count(kw)) for kw in branch_keywords) # 分支数超过 15 扣分高圈复杂度 if branches 15: score - 10 return max(0, min(100, score)) def _eval_complexity_analysis(self, analysis: Optional[str]) - float: 评估复杂度分析的准确性 if not analysis: return 0 score 100.0 # 检查是否包含大 O 表示法 if O( not in analysis: score - 40 # 检查是否说明了推导过程关键词因为、由于、所以 if 因为 not in analysis and 由于 not in analysis: score - 20 # 检查是否区分了时间复杂度和空间复杂度 if 时间 not in analysis or 空间 not in analysis: score - 20 return max(0, score) def _eval_robustness(self, code: str) - float: 评估代码稳健性 score 100.0 # 检查空值处理 if None not in code and null not in code.lower(): # 没有空值处理的迹象不是所有场景都需要但提示扣分 score - 10 # 检查是否有输入校验如参数检查 validation_patterns [ if not, if .* is None, raise ValueError, raise TypeError, if .* 0, if .* 0, ] has_validation any( any(p in code for p in patterns.split(|)) for patterns in validation_patterns ) if not has_validation: score - 15 return max(0, score) def _eval_style(self, code: str) - float: 评估工程规范 score 100.0 # 检查是否有类型注解Python if def in code and : not in code.split(def )[-1].split())[0].split(()[-1]: score - 10 # 检查是否有文档字符串 if not in code and not in code: score - 15 # 检查变量命名风格snake_case for Python # 检测可能的 camelCase小写开头中间有大写 import re identifiers re.findall(r\b([a-z][A-Z][a-zA-Z]*)\b, code) if len(identifiers) 3: score - 10 # 可能存在命名风格不一致 return max(0, min(100, score))四、边界与权衡4.1 静态分析 vs 动态评测可读性、工程规范维度的评估依赖静态分析而正确性依赖动态评测。两者不可互相替代——静态分析不能保证代码逻辑正确动态评测不能检测代码是否脏。两者结合才是完整的评估。4.2 评分标准的场景依赖同样的代码在教学场景和竞赛场景的评分标准不同。教学场景重可读性竞赛场景重性能。评估系统需要支持按场景调整权重。4.3 注释质量的深层评估当前只统计注释行数占比无法评估注释的语义质量。真正的解决方案是让 LLM 评估注释与代码逻辑的一致性——注释是否准确描述了代码意图。4.4 避免过度优化评分评分体系容易引发过度优化——开发者为了让评分好看而添加冗余注释、无意义的类型注解。评分是手段不是目的设计时需要防止指标被玩弄。五、总结题解代码的质量评估是多维度的——正确性是及格线但不是全部。可读性决定了这道题解能否被读者理解复杂度分析决定了它是否可靠稳健性决定了它能否经受不同输入的考验。构建一个平衡的评分体系比追求某个单一指标的最大化更有价值。