简介C-EVAL是一套面向中文语境的多级多学科大模型评估套件专供自然语言处理研究者与技术从业者分析大型语言模型在中文环境中的高级知识与推理能力。该资源为PDF格式的完整论文共1个文件压缩包大小约4.89MB目前已吸引76人下载学习。内容详细介绍四个难度层级中学、高中、大学、专业与52个学科划分涵盖人文到科学工程并单独定义了C-EVAL HARD子集以考察困难推理问题。同时整理了对GPT-4及其他主流模型的评测对比明确指出仅GPT-4平均准确率超过60%为后续模型优化提供了清晰基线。阅读者可从中获取评估体系构建思路、任务设计逻辑、实验结果分析及C-EVAL公开评测代码的引用说明有助于设计或选用更贴合中文场景的模型评测方案。1. C-EVAL是什么先弄清一个评估套件在帮你测什么有开发者在英文多任务基准上刷到高分的开源模型切到中文知识问答后反而被一个参数量小很多的中文特化模型按在地上摩擦。这种反差不是个例根因往往出在评测维度上——英文基准考的是英文语境下的知识而中文多级多学科评估套件C-EVAL考的是中国语境下的高级知识与推理能力。它用中学、大学、研究生及职业考试四个层级的上万道中文题目直接量化一个大模型“在中国语境下懂多少、会不会推理”。这篇文章写给手里已经有一个模型、想知道它在中文场景里到底强不强、短板在哪、下一步怎么调的开发者。2. C-EVAL的评估设计先看懂数据再动手跑分跑分之前先花二十分钟把“考什么”搞明白。C-EVAL不是一个普通的多选题集合它的题目组织带着明显的中文教育体系特征。这一章把它拆到三块级别的难度梯度、学科的知识跨度以及中文语境带来的独特评估价值。2.1 四个级别与52个学科难度梯度从哪来C-EVAL的题库按教育阶段分成四级中学、大学、研究生、职业考试。这四级本身就是一个天然的难度梯度。中学题主要覆盖基础知识比如初中数学的简单计算、语文的文学常识大学题开始考察学科方法论比如线性代数、宏观经济学里的概念辨析研究生题进一步强调综合运用很多题目需要跨章节甚至跨学科推导职业考试题则把知识放进实际职业场景中比如法律案例判断、医学诊断推理、工程方案选择。这种分层对模型诊断很有用。一个模型可能在中学级别拿高分到研究生级别明显下滑说明它的知识覆盖偏向基础层。另一个模型可能在中学和大学都一般但职业考试分数较高说明它对场景化、实操性知识的记忆更牢。只看总分看不到这些差异所以动手之前先把每个级别的样本量摸清。不少自定义评估集在切分时存在样本量不均衡比如某学科只有几十条统计出来的分数波动会非常大参考价值很低。import json from collections import Counter def inspect_split(path): level_counter Counter() subject_counter Counter() with open(path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue item json.loads(line) level_counter[item.get(level, unknown)] 1 subject_counter[item.get(subject, unknown)] 1 print(级别分布, dict(level_counter)) print(学科数量, len(subject_counter)) print(学科分布TOP10, subject_counter.most_common(10)) inspect_split(ceval_test.jsonl)这段脚本假设数据是JSONL逐行存储每行是一个题目对象字段里带level和subject。跑完之后核对级别数量和学科数量如果发现“研究生”这一级只有几十条样本后面这一级的分数就没有统计意义。字段名以你实际拿到的数据集为准有的版本叫category或phase需要从数据说明里确认后再改。学科跨度是第二个设计重点。公开资料里C-EVAL覆盖52个学科大类上可以归到理工、人文、社会科学和职业类目。不同学科考的认知能力很不一样数学、物理偏多步计算和符号推理法学、医学偏条文记忆与案例匹配历史、文学偏事实记忆与文化理解。模型在这些学科上的得分结构能直接反映训练语料的偏向——如果所有人文类学科都低基本可以判断训练数据里中文文科内容偏少而不是模型推理能力不足。2.2 高级知识与推理能力到底测什么题目结构拆解C-EVAL的题目以选择题为主包含单选题和不定项选择题。多选的存在意味着评估不能只看模型是否猜中了第一选项还要看它是否具备“选出全部正确项”的集合判断能力。这也是标题里“高级知识与推理能力”的具体体现多选题天然要求模型先全面评估每个选项再决定取舍而不是靠概率采样碰运气。从认知层次上我习惯把题目分成两类知识记忆型和推理应用型。知识记忆型题目模型只要在训练阶段见过相关知识就能答对典型的是朝代、作者、条约内容、公式定义推理应用型题目即使模型知道相关概念也必须经过多步推断、排除干扰项或实际计算才能得到答案典型的是数学应用题、需要综合多个法律条文才能判断的案例题。在跑分之前先按题型和大致认知层次做一个分层统计。最直接的办法是同时读取题目和选项计算题干长度、选项个数并结合关键词做一个粗筛。这样做的目的不是把题目精确定义成记忆或推理而是确认测试集里确实存在一定比例的推理型题目让后续bad case归因不至于低估难度。import json, re from collections import Counter def rough_label(item): question item.get(question, ) if any(k in question for k in [计算, 推理, 分析, 推导, 论证]): return 推理型 return 记忆型 def inspect_types(path): type_counter Counter() option_counter Counter() with open(path, r, encodingutf-8) as f: for line in f: item json.loads(line.strip()) type_counter[rough_label(item)] 1 option_count len(re.findall(r[(]\s*[ABCD]\s*[)], item.get(options, ))) option_counter[option_count] 1 print(认知类型粗筛, dict(type_counter)) print(选项数量统计, {k: v for k, v in sorted(option_counter.items())}) inspect_types(ceval_test.jsonl)这个脚本只是一个摸底工具不要把它当准确标注。比如题干里有“计算”二字的题未必就是推理题有的只是直接考计算法则。真正可靠的做法是跑完一轮之后抽几十个答错的题人工看一遍确定错误的真实原因是知识盲区、计算失误还是选项理解偏差。这个过程会在第6章展开。2.3 为什么不用英文基准直接翻译中文语境的特殊性有人会问为什么不直接拿英文多学科选择题基准的翻译版来用这里有两个硬伤。第一个硬伤是翻译带来的语义歧义。英文法律术语直译成中文后与中文法律用语的惯常表达不一致选项之间的区分度会降低。比如英文合同条款里的某个概念直译成中文后模型没有见过足够的中国法律语料会把该概念理解成普通日常含义导致该选的不选。这类问题不是模型笨而是“翻译题”本身没法完全等价。第二个硬伤是知识框架的错位。英文基准的学科内容以西方教育体系为蓝本包含大量西方历史文化、政治制度、文学作品的内容。对面向中文用户的模型来说这些内容既不是训练语料重点也不是实际使用场景。测出来的低分要么是“模型确实不懂”要么是“语料天然缺失”对下一步优化没有指向性。C-EVAL把知识框架换成了中文考试体系语文的文言文与成语、中国历史脉络、法律职业情境题、行政能力测试题。这类题目所依赖的文化前提和推理习惯只能通过中文语料习得。C-EVAL跑出的分数和模型在中文知识问答、中文客服、中文内容理解上的表现相关性通常更高。跑分时还有一个原则要提前定好C-EVAL是评估集不是训练集。处理数据时会把它单独放在只读目录不进训练管线任何想拿它做继续预训练或数据增强的想法都要拦下来。分数好看的前提是测试集从未被污染一旦污染后面每一版模型的分值都失去横向对比意义。3. 把C-EVAL跑起来本地推理、结果生成与评分这里从头到尾做一个可复现的最小闭环读取题目文件构造提示词批量推理再把结果按统一规则评分。环境假设是你已经有一个可以本地加载的大模型权重无论是开源权重还是自己微调的模型都不影响流程。3.1 准备数据与构造提示词固定模板是分数可复现的前提跑分最怕的是“每次提示词不一样”导致分数差异分不清是模型变化还是模板变化。评估时要固定一个提示词模板所有题目共用。C-EVAL没有规定唯一模板但公开评测实践里常见做法是把“角色设定 作答要求 题目选项 答案引导”拼在一段文本里让模型只输出选项而不是长篇分析。模板里的一个重要细节是“答案引导”。只给题目选项模型可能输出一整段解释在末尾加上“【答案】”或“正确答案是”模型会更倾向于直接输出选项字母。这个技巧在指令微调过的模型上尤其明显。SYSTEM_PROMPT 你是中国教育考试领域的专家请依据题目选出正确选项。 def build_prompt(item, fewshot_examplesNone, use_cotFalse): if use_cot: instruction 请先逐步推理再在最后一行以“答案字母”给出结论。 answer_mark else: instruction 请直接给出正确选项。 answer_mark 【答案】 prompt f{SYSTEM_PROMPT}\n{instruction}\n if fewshot_examples: for ex in fewshot_examples: prompt f【题目】{ex[question]}\n【选项】{ex[options]}\n【答案】{ex[answer]}\n prompt f【题目】{item[question]}\n【选项】{item[options]}\n{answer_mark} return prompt这段代码实现三种设置的基础zero-shot直接给题few-shot在题目前插入示例CoT则把指令换成“先逐步推理再给答案”。最容易踩的坑是示例里漏了答案行。模型会误以为你要它做对话而不是做选择题。示例里不仅要有题目和选项还要有标准答案模型才能从示例中模仿“输出字母”的行为模式。3.2 选择推理引擎与生成参数答案稳定性靠低温度保证提示词构造好之后进入批量推理。先跑小规模验证流程再上全量集。下面是用HuggingFace transformers做单机推理的最小代码。from transformers import AutoModelForCausalLM, AutoTokenizer import torch model_path ./your_model_dir tokenizer AutoTokenizer.from_pretrained(model_path) model AutoModelForCausalLM.from_pretrained( model_path, torch_dtypetorch.float16, device_mapauto ) def generate_answer(prompt_text, max_new_tokens32): inputs tokenizer(prompt_text, return_tensorspt).to(model.device) with torch.no_grad(): output model.generate( inputs.input_ids, max_new_tokensmax_new_tokens, temperature0.05, top_p0.9, do_sampleTrue, repetition_penalty1.1, pad_token_idtokenizer.eos_token_id ) generated output[0][len(inputs.input_ids):] return tokenizer.decode(generated, skip_special_tokensTrue) sample json.loads(open(ceval_test.jsonl, r, encodingutf-8).readline().strip()) print(generate_answer(build_prompt(sample)))几个参数说明。temperature设0.05而不是0因为部分实现里为0时的归一化可能触发随机性分支0.05已经接近贪心解码选择题不是创意写作不需要随机性。top_p保持0.9是为了兼容那些有概率依赖的tokenizer设置。max_new_tokens默认32零样本时足够如果用CoT需要单独调成128或256否则推理过程会被截断。repetition_penalty 1.1能显著减少模型重复输出选项序列。pad_token_id要显式指定为eos_token_id否则批量推理时会产生不均匀的padding警告。如果测试集规模大逐条推理会比较慢。可以把引擎换成vLLM用离线批处理方式同时跑几百条吞吐量高一个数量级。提示词构造逻辑不变只需要把生成参数对齐到vLLM接口from vllm import LLM, SamplingParams sampling_params SamplingParams( temperature0.05, top_p0.9, max_tokens32, repetition_penalty1.1 ) llm LLM(model./your_model_dir, tensor_parallel_size1, dtypefloat16) prompts [build_prompt(item) for item in test_items] outputs llm.generate(prompts, sampling_params) predictions [out.outputs[0].text for out in outputs]这里的关键是把prompt列表一次性传入vLLM内部会做continuous batching。显存不够时调低gpu_memory_utilization比如0.85。并发请求数是自动管理的不需要手动控制但仍建议先从几十条开始试跑确认显存峰值避免被系统OOM杀掉。3.3 统一抽取答案与评分把格式噪声挡在指标外模型输出经常带着格式噪声比如“答案B”“B. 分析正确”“B”。评分前要先做一次文本抽取。常见做法提供两级提取优先找“答案X”这种显式标记找不到就找最后一个出现在行内的选项字母。之所以找“最后一个”是因为模型可能会在中间复述题干里的选项字母而真正的结论一般在末尾。import re def extract_answer(raw_text): if not raw_text: return None match re.search(r[答|正确答案][:]\s*([ABCD]), raw_text) if match: return match.group(1) matches re.findall(r([ABCD])[.\、\)]?(\s|$), raw_text) if matches: return matches[-1][0] return None def evaluate(predictions, ground_truths): single_total, single_correct 0, 0 multi_total, multi_correct 0, 0 for pred_text, gt in zip(predictions, ground_truths): letter extract_answer(pred_text) if letter is None: continue if isinstance(gt, str): single_total 1 if letter gt: single_correct 1 elif isinstance(gt, list): multi_total 1 if set(letter) set(gt): multi_correct 1 print(单选准确率, single_correct / max(single_total, 1)) print(多选准确率, multi_correct / max(multi_total, 1))多选的判定要严格一些。如果标准答案是AB模型只输出A会被判定为错误这是C-EVAL官方评分更倾向的做法因为多选题要全选对才给分。如果还想观察“模型离全对差多少”可以额外统计多选的命中率和误报率比如预测集合与标准答案的交并比。不过最终对外报数时还是按“全部匹配才算对”否则分数会虚高。到这里跑分闭环已经完成提示词固定、推理稳定、抽取一致、评分严格。接下来要讨论的是比跑分更难的一步——怎么从分数里读出模型的真实短板。4. 结果怎么读分数之外还要看什么跑分脚本输出一个总准确率后很多人就结束了。总准确率确实能说明模型整体水平但一个数字回答不了“模型弱在哪个级别、哪个学科、哪种题型”。这一章把读数方法拆成三块分级分学科看短板、对比Few-shot与CoT、把C-EVAL放进更大的评估矩阵。4.1 级别、学科与Hard子集三张表一眼定位短板第一张表是按级别的准确率表。C-EVAL四个级别本质上代表四个难度档位如果一个模型在中学档位高、研究生档位低说明它的知识深度不足只能答浅层题一遇到跨章节综合就露馅。第二张表是按学科的准确率表这张表能告诉你语料偏向理工类学科差是多数开源模型的通病但如果人文和社科类也差就要怀疑是中文语料覆盖不够而不是能力问题。第三张表是Hard子集的分数。这里需要特别注意Hard子集通常是一批难度更高、更接近真实考试里拔高题的样本它的准确率往往比总体低许多。Hard子集分数低本身不丢人但“总分离、Hard低”的模型和“总分不高、Hard也不低”的模型优化策略完全不同——前者要补推理能力后者要先补知识底座。我用一个脚本把三张表一次性输出。def build_report(results): df pd.DataFrame(results) report {} report[by_level] df.groupby(level)[correct].mean().round(3).to_dict() report[by_subject] df.groupby(subject)[correct].mean().round(3).sort_values(ascendingFalse).to_dict() if hard in df.columns: report[hard_accuracy] round(df[df[hard] True][correct].mean(), 3) return report report build_report(eval_results) print(report[by_level]) print(Hard子集准确率, report[hard_accuracy])生成报告时至少要保留四列level、subject、correct、hard。如果没有hard字段就跳过Hard子集统计不要硬凑。分学科表打印出来后我习惯再按人文、理工、社科、职业做一次聚合因为52个学科列在一张表里很难看出规律。聚合可以简单靠学科名映射def map_category(subject): if subject in [数学, 物理, 化学, 生物]: return 理工 if subject in [语文, 历史, 地理, 文学]: return 人文 if subject in [法律, 经济, 政治, 哲学]: return 社科 return 职业这种映射不追求完备只求快速看出大类差异。看到某一类整体偏低之后再回到学科明细表里去定位具体是哪个学科拉低了平均分。4.2 Few-shot与CoT的差异提示词写法如何影响分数同样一个模型选对提示词设置分数能差出十几个点。这不是模型作弊而是提示词确实改变了模型的信息处理方式。C-EVAL评测时最常用的三种设置是zero-shot、few-shot、CoT。zero-shot最公平反映的是模型在没有外部指导时的真实知识水平。few-shot通过一到两条示例教模型“输出什么格式”也顺带提供了一点任务示范。CoT则让模型在作答时把推理过程写出来等于强制它调用更深层的推理链路。我在实际跑分中的经验是few-shot示例必须贴题。给一道数学题配一道同知识点的数学示例比配一个法律示例有用得多。示例数量不是越多越好一到两个就够。理由很简单大模型在上下文里见过太多内容后注意力会被示例里的无关细节分散反而干扰判断。另一个经验是CoT提示词把推理步骤拆得越清楚分数越稳定。明确要求“先提取条件再逐一判断选项最后给出答案”的模板效果普遍好于只写“请仔细思考再做答”。def build_cot_prompt(item): cot_instruction ( 请按以下步骤作答\n 1. 阅读题目列出已知条件。\n 2. 逐个判断选项排除与条件冲突的项。\n 3. 在最后一行以“答案字母”输出结论。\n ) return f{cot_instruction}\n【题目】{item[question]}\n【选项】{item[options]}使用CoT时评测要用更长的max_new_tokens建议从128起并根据实际输出长度动态调整。抽取答案的规则要相应放宽不能只找第一个字母要在最后一行找“答案X”或倒数出现的选项字母。否则模型按要求输出了一整段推理最后答案被截断在生成尾部评分脚本却误判为没作答。4.3 把C-EVAL放进评估矩阵几类指标怎么配平C-EVAL测的是“在中文知识维度上的水平”它不是万能的。如果团队正在做客服机器人、知识问答系统这类需要事实密度的产品C-EVAL的高权重合理但如果做的是开放闲聊、小说生成或代码辅助C-EVAL分数高并不能代表产品体验好。评估矩阵至少要覆盖四类能力每类用不同工具度量评估目标典型手段C-EVAL的角色中文知识深度与推理多级多学科选择题主评测指令遵循与对话能力多轮对话、指令跟随测试辅助参考开放式生成质量摘要、问答人工评分不覆盖安全与合规专项安全测试不覆盖这张表的核心观点是C-EVAL管“知识”和“推理”不管“对话体验”和“安全合规”。如果只拿一个基准来调模型模型的分数会涨但真实业务指标未必跟着涨。我建议把C-EVAL作为每次模型迭代的必跑项目同时配上一组固定的对话评测集和安全性冒烟测试三块分数一起看。迭代时如果C-EVAL涨、对话体验跌说明改动可能偏向“背题”要回看训练数据权重。回归到落地场景里你还要知道C-EVAL分数的横向差距。不同模型在C-EVAL上的分差往往比在英文基准上的分差更小因为中文知识更依赖语料覆盖大家都能答对一部分常识题真正拉开差距的是Hard子集和冷门学科。所以当两个模型总准确率只差一个点时别急着换模型先比较它们的分学科分数和Hard子集分数再决定投入。5. C-EVAL实测中的常见问题与避坑记录跑C-EVAL的过程看着简单实际翻车的点都在细节里。这一章把实践中反复遇到、修复成本最高的几个问题写下来每条都按“现象→原因→解决”的路径说清楚。5.1 生成长度设太短计算题答案被截断现象数学、物理这类学科准确率异常低和语文、历史形成悬殊反差。把预测文本拉出来看模型已经写了一段计算过程但输出到一半就断了或者只输出到“B”就被截断后面的“. 25”没生成完。原因CoT模式下模型会把推理过程写在最终答案之前。max_new_tokens只设了32推理过程消耗了长度答案还没出现就到达上限。这是评测设置问题不是模型能力问题。很多第一次跑C-EVAL的人都会在这上面吃暗亏以为是模型数学不行其实是脚本没给够输出空间。解决跑CoT评测前先抽十条题测一下平均生成长度把max_new_tokens设为平均长度的1.5倍留足余量。我一般直接用256能同时覆盖推理过程和答案输出零样本时再调回32不要一刀切。另一个缓解手段是在提示词里用“最后一行以‘答案字母’输出”即使截断也尽量保住答案行。如果发现某道题答案行仍然丢失再根据日志单独重跑该题。5.2 答案提取规则不统一导致同模型同数据两次分数不一致现象同一版模型跑了两轮C-EVAL分数差了二到三个百分点。排查发现两次脚本抽取答案的逻辑不一样一次用的是“第一个出现的字母”另一次用的是“最后一个出现的字母”导致一部分输出被判成不同答案。原因模型输出常常混杂解释、复述、结论。如果输出里同时出现“A. xxx”和真正的答案“B”两种提取逻辑会选中不同的字符。这种坑在多人协作时尤其容易发生每个人写的正则规则各有偏好今天你跑一版明天同事跑一版数值对不上。解决把答案提取做成唯一函数加上明确优先级先找“答案X”“正确选项X”这类显式标记没有显式标记就找最后一行出现的选项字母最后再用“末尾字母”作兜底。写完之后用几个带噪声的样例做单元测试确认规则稳定后再跑全量。团队协作时把这个函数放在公共评估脚本里避免各写一套。5.3 温度过高低分数抖动掩盖真实水平现象用temperature0.7跑C-EVAL准确率在三次运行间波动三四个点。尤其是多选题模型在概率相近的选项间反复横跳今天选出AB明天选出AC。原因多选题的判断本质是集合预测高温采样增大了低置信度选项被选中的概率。选择题评测要的是稳定复现能力不是生成多样性高温度会让结果失真。生成多样性的设置用在这里等于给分数叠加了一层随机噪声前后两次对比根本看不出模型真实进步。解决选择题评测把temperature降到0到0.1之间。如果推理框架要求do_sample必须为True也要保持temperature在0.05附近。每次跑分固定随机种子并在输出文件名里注明温度和种子值方便后续对比。要报告采样随机性影响时用“跑三次取均值附标准差”的方式。只有当你需要评估模型在开放生成任务上的多样性时才把温度调高。5.4 大批量推理时显存溢出跑了一半挂掉现象用transformers直接跑全量C-EVAL跑到第几千题时CUDA OOM前面的结果没有保存进程被杀只能全部重来。原因选项文本拼接后单条输入可能超过2048 token显存分配不足此外如果device_map设置不当多GPU上显存分配不均衡某个卡先用满也会触发OOM。这属于资源管理问题和模型能力无关但代价很高——一次全量评测可能要跑几个小时中断一次就浪费几个小时。解决先跑一个小batch试探显存峰值比如batch_size8如果OOM就降到4或2。用torch.no_grad()包裹推理关闭不需要的梯度计算。vLLM用户要设置gpu_memory_utilization比如0.85给CUDA context留出余量。更稳妥的方案是边推理边把结果写入本地JSONL每条生成后立刻落盘一旦崩掉可以从断点继续跑而不是全部重来。我自己会在评测脚本里加一个参数--resume每次启动时检查已有结果文件跳过已完成的题目。5.5 评估数据被混入训练分数虚高后无法再信任现象某次版本升级后C-EVAL分数突然涨了六七个点但业务问答准确率没有同步增长。怀疑训练数据里混入了测试集。原因开发过程中有人为了提升公开榜单成绩把C-EVAL题目加入了预训练或指令微调数据模型背下了不少题分数虚高。之后每跑一版都是虚高整个评估体系失效。这种问题隐蔽性很强因为训练数据动辄几十GB混进一两份评估文件很难被发现。解决把C-EVAL数据放到独立目录并设置只读权限。数据管道在清洗时要做一次“评估集去重”把测试题文本与训练语料做哈希或字符串匹配过滤。团队协作时在数据准备脚本里默认忽略该目录不参与训练打包。如果你发现分数突变而业务指标不动第一件事就是检查是否有评估文件被误加进数据。这个教训我可以说是血泪经验一旦评估集被污染前面几个月的迭代记录都失去参考价值只能重搭评估基线。误差来源基本上就是设置、提取、污染三类。把这些源头卡死C-EVAL的分数才值得用来做决策。6. 进阶用法用C-EVAL做分学科诊断与bad case归因基础跑分之后真正投入产出比高的动作是bad case归因。我习惯把每次评估结果保存成一份带原始输出的JSONL然后按“抽取失败、答案越界、推理错误”三类去归因。6.1 三类错误的自动分类import json, re def classify_bad_cases(results): buckets {抽取失败: 0, 答案越界: 0, 推理错误: 0} subject_error {} for r in results: if r[pred] is None: buckets[抽取失败] 1 continue if r[correct]: continue answer_mark re.findall(r答案[:]\s*([ABCD]), r[raw_output]) if answer_mark: buckets[答案越界] 1 else: buckets[推理错误] 1 subject_error[r[subject]] subject_error.get(r[subject], 0) 1 print(buckets) print(sorted(subject_error.items(), keylambda x: x[1], reverseTrue)[:10]) classify_bad_cases(eval_results)抽取失败说明生成质量或抽取逻辑有问题需要看输出是否为空或乱码答案越界说明模型写了答案但格式不规整多数是提示词问题推理错误才是真正需要模型优化的部分。这三类错误的处理手段完全不同不分开就直接进优化会白费很多训练时间。6.2 用Hard子集定位知识盲区与推理弱环Hard子集筛出的题目通常涉及跨章节综合或复杂计算。我会把Hard子集里的错误题单独存一份人工抽二十条逐题记下错误类型是知识没见过、选项文字没读懂还是推理链条断了。这类人工标注很费时间但回报很高——它能直接告诉你优化优先级是继续补语料还是调整SFT数据里的推理类样本。6.3 把C-EVAL做成持续回归的固定流程最后把评估做成脚本每次模型改动后自动跑一遍#!/bin/bash for model in model_v1 model_v2 model_v3; do python run_eval.py --model $model --split all --output report_${model}.json python gen_report.py --input report_${model}.json --output table_${model}.md done我自己每周至少跑一次C-EVAL回归把准确率、Hard子集分数、Top5弱学科写进周报与训练数据变更一一对照。半年后你会积累出一套“模型在哪个学科上会因为哪种数据变化而波动”的经验库比任何单一分数都有价值。评估不是跑完一个基准就结束而是跑出能指导下一次改动的信号。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?