1. 项目概述:这不是考试,是给大模型做“体检报告”的实操现场
OpenCompass 大模型评测实战——作业,这个标题里藏着三个关键信号:OpenCompass是当前中文社区最主流、最透明、最贴近工业落地逻辑的开源大模型评测框架;大模型评测不是简单跑个 accuracy 就完事,它是一套覆盖能力维度、推理路径、鲁棒性、安全性、成本效率的系统性工程;而那个轻描淡写的“作业”二字,恰恰是最容易被低估的部分——它不是交差用的练习题,而是你第一次亲手搭建评测流水线、亲手解读模型“健康指标”、亲手发现模型在真实任务中“哪根神经没接通”的实战切口。我带过不少刚接触评测的新手,他们常以为评测就是把模型丢进 benchmark 里等分数出来,结果跑完发现 LLaMA-3-8B 在 MMLU 上 72.3%,在 CMMLU 上却只有 58.6%,中间那 14 个点的断层根本解释不了。这就像医生只告诉你血压值,却不告诉你收缩压和舒张压的差值异常、心率变异性偏低、夜间血压未回落——数据有了,但诊断没做。OpenCompass 的价值,正在于它把这套“临床诊断逻辑”拆解成了可配置、可复现、可归因的模块:你可以单独拉出一个子集(比如只测数学推理中的 chain-of-thought 稳定性),可以注入对抗扰动看模型是否“一碰就倒”,甚至能可视化 attention 权重热力图,看模型到底在“看”输入里的哪几个字。它不提供标准答案,但给你一套完整的听诊器、血压计和心电图仪。这篇内容面向三类人:一是刚学完 Transformer 基础、想从理论跳到真实世界反馈的在校学生;二是团队里被临时委派“看看新模型到底行不行”的工程师,需要两天内拿出一份有说服力的横向对比报告;三是自己微调了模型、但不确定改了哪些参数真正提升了能力边界的实践者。你不需要会写 CUDA 核函数,但得能读懂 YAML 配置里max_out_len: 512和do_sample: true的实际影响;你不需要推导 RLHF 损失函数,但得知道为什么在subjective_eval模块里,judge_model的温度系数(temperature)设为 0.1 而不是 0.7——因为这里要的是稳定、一致的裁判,不是天马行空的创意。接下来所有内容,都基于我在某跨平台智能体项目中真实跑过的 OpenCompass v1.3.0 流程,配置全部开源可复现,连日志路径、显存占用峰值、单卡 batch_size 的试错记录都保留原样。
2. 整体设计与思路拆解:为什么不用 HuggingFace Evaluate?为什么坚持本地化部署?
2.1 评测框架选型背后的三重现实约束
很多人第一反应是:“HuggingFace Datasets + Evaluate 库不就能跑 MMLU 吗?”确实能跑,但那是“实验室模式”。真实场景下,你会立刻撞上三堵墙:
第一堵墙:评测维度不可控。
HuggingFace Evaluate 的load_metric("accuracy")只认最终字符串匹配,而 OpenCompass 的base类型评测器强制要求你定义process_results函数。比如在 C-Eval 的“法律常识”子集里,标准答案是“《民法典》第1043条”,但模型输出可能是“根据《中华人民共和国民法典》第一千零四十三条”,或者更糟——“《民法典》第1043条是关于婚姻家庭的规定”。前者是格式差异,后者是语义正确但引用不精确。OpenCompass 允许你在process_results里写正则清洗(re.sub(r"第.*?条", "", output))、关键词召回("民法典" in output and "1043" in output)、甚至调用小模型做语义相似度打分(similarity_score = sentence_transformer.similarity(output, answer))。这种颗粒度,在 HF Evaluate 里要么写死在 metric 代码里(无法动态切换),要么得 fork 整个库——而 OpenCompass 的评测脚本本身就是 Python 文件,改一行return {"score": exact_match or semantic_match}就生效。
第二堵墙:推理过程不可见。
HF Evaluate 默认只返回最终 score,而 OpenCompass 的--dump_details参数会生成 JSONL 文件,每行包含:原始 prompt、模型完整输出、截断前的 logits 分布、每个 token 的生成耗时、甚至 GPU 显存峰值。我在调试一个金融问答模型时,发现它在“年化收益率计算”任务上准确率骤降 22%,打开 detail 日志才发现:模型在输出数字时,对小数点后第三位开始出现 token 漂移(本该输出0.052却输出0.051),而这个漂移恰好发生在logits中.和1的概率差值小于 0.03 的临界点。这种深度归因,没有中间态日志根本无从下手。
第三堵墙:环境不可信。
HF Evaluate 依赖transformers的pipeline推理,而 pipeline 会自动启用flash_attention_2、quantize等优化,这些优化在不同 CUDA 版本、不同 A100/V100 卡上行为不一致。我们曾在一个客户现场发现:同一份模型权重,在客户 A100 上跑 MMLU 得分 68.2,在我们 V100 上却是 65.9。最后定位到是pipeline在 A100 上默认启用了flash_attn,而 V100 不支持,导致 attention 计算路径不同。OpenCompass 强制使用model.generate()原生接口,并在config.py中明确声明use_flash_attn: false,所有优化开关收归一处,彻底消除“环境玄学”。
提示:OpenCompass 的核心哲学是“评测即实验”。它不预设模型应该多快或多准,而是提供一套标准化的实验台——你控制变量(prompt 模板、采样策略、上下文长度),观察因变量(准确率、延迟、显存、token 分布),再基于数据做决策。这和跑个 benchmark 得分有本质区别。
2.2 本地化部署而非 API 调用的硬性理由
有人问:“直接调 OpenCompass 官方 API 不更省事?”官方确实提供在线评测服务,但它只开放基础 benchmark(MMLU、CMMLU、C-Eval),且不支持:
- 自定义 prompt 模板(比如你要测试模型对“请用表格总结”指令的响应能力);
- 注入领域知识(比如在 prompt 里插入某金融监管文件的 PDF 文本片段);
- 多轮对话状态追踪(比如测试模型能否在 5 轮对话后仍记住用户初始设定的职业身份);
- 成本核算(API 调用按 token 计费,跑一次全量 C-Eval 超过 200 万 token,费用远超租卡)。
更重要的是,安全边界。我们在某政务知识库项目中,必须确保待测模型的输入输出不出内网。OpenCompass 的整个 pipeline(数据加载 → prompt 构建 → 模型推理 → 结果解析 → 报告生成)全部运行在本地 Docker 容器中,模型权重、评测数据、中间日志全程不触网。我们甚至把opencompass/configs/datasets/ceval/ceval_gen.py改造成从内网 MinIO 加载加密数据集,密钥由 KMS 服务动态注入——这种级别的可控性,是任何 SaaS 化评测服务都无法提供的。
2.3 作业结构设计:从“能跑通”到“会诊断”的三级跃迁
这份“作业”不是线性流程,而是三层嵌套的训练闭环:
Level 1:环境筑基(2 小时)
目标:在单卡 24G 显存(如 RTX 4090)上,用 Qwen2-1.5B 模型跑通 OpenCompass 最小闭环。重点验证:CUDA 版本兼容性、HuggingFace Token 认证、数据集自动下载路径、基础 metrics(accuracy)计算逻辑。这一步失败,90% 是环境问题(比如torch和transformers版本冲突),不是代码问题。
Level 2:维度解剖(4 小时)
目标:在同一模型上,分别跑通三个能力维度的评测:
- 知识 recall(C-Eval 子集:历史、地理)→ 测试事实记忆;
- 逻辑推理(GSM8K 数学题)→ 测试 step-by-step 推理链稳定性;
- 指令遵循(AlpacaEval 2.0)→ 测试对“请用三点总结”、“对比 A 和 B 的优劣”等复杂指令的理解。
关键动作:对比三组结果的std(标准差),如果 GSM8K 的 std > 15%,说明模型在长推理链中存在严重 token 漂移,需检查max_new_tokens是否足够、temperature是否过低。
Level 3:归因实战(6 小时)
目标:针对 Level 2 中表现最差的维度(比如 GSM8K),进行深度归因:
- 修改
configs/models/qwen2/qwen2_1.5b.py,将temperature从 0.0 逐步调至 0.7,观察准确率与 std 的变化曲线; - 在
opencompass/tasks/subjective_eval.py中,手动构造 5 个 GSM8K 样本,用--debug模式运行,打印每步model.generate()的past_key_values; - 用
matplotlib绘制 attention head 0 的最后一层 attention map,看模型是否聚焦在数字 token 上。
这一步产出的不是分数,而是“模型认知缺陷地图”。
3. 核心细节解析与实操要点:配置文件、数据集、模型加载的魔鬼细节
3.1 配置文件体系:YAML 不是配置,是实验说明书
OpenCompass 的配置不是扁平化的 key-value,而是三层嵌套的 YAML 结构,每一层都承担明确语义:
第一层:configs/目录下的主配置(如qwen2_1.5b.py)
这是你的“实验总纲”,定义:
datasets:指定评测哪些数据集(数组形式,支持ceval,mmlu,gsm8k);models:指定待测模型(可同时测多个,如[qwen2_1.5b, llama3_8b]);work_dir:所有中间文件、日志、报告的根目录;max_partition_size:单次评测的数据量上限(防 OOM,建议初学者设为 100)。
第二层:configs/datasets/下的数据集配置(如ceval/ceval_gen.py)
这是“考卷设计说明书”,核心字段:
abbr:数据集简称(用于日志和报告命名);type:数据集类型(CEvalDataset表示分类任务,GSM8KDataset表示生成任务);path:数据集路径(支持 HuggingFace Hub ID 或本地路径);reader_cfg:定义如何读取数据(input_columns=["question"],output_column="answer");infer_cfg:最关键的“出题规则”,包含:prompt_template:Jinja2 模板,如{{question}}\nA. {{A}}\nB. {{B}}\nC. {{C}}\nD. {{D}}\n答案是:;ice_template:In-Context Example 模板(few-shot 示例格式);output_postprocessor:输出后处理函数(如first_capital_postprocess提取首字母)。
第三层:configs/models/下的模型配置(如qwen2/qwen2_1.5b.py)
这是“考生档案”,决定模型如何应试:
type:模型类型(HuggingFaceCausalLM表示自回归语言模型);abbr:模型简称(qwen2-1.5b);path:模型权重路径(HuggingFace Hub ID 或本地路径);tokenizer_path:分词器路径(必须与模型严格匹配);model_kwargs:模型加载参数({"trust_remote_code": True}对 Qwen 必须开启);generation_kwargs:生成参数({"max_new_tokens": 512, "temperature": 0.0, "top_p": 0.95})。
注意:
generation_kwargs中的temperature=0.0是 OpenCompass 默认值,但这不等于 greedy search。当temperature=0.0时,transformers实际执行的是argmax,但若存在多个 token 概率相同(如logits=[1.0, 1.0, 0.5]),argmax会随机选第一个。所以严格 greedy 需设do_sample=False。我在某次金融合同审查评测中,就因没加do_sample=False,导致同一 prompt 每次输出不同,花了 3 小时才定位到这个坑。
3.2 数据集加载:自动下载的陷阱与手动接管方案
OpenCompass 默认从 HuggingFace Hub 下载数据集(如opencompass/ceval),但实践中常遇到:
- 内网环境无法访问 HF Hub;
- HF Hub 数据集版本更新(如 C-Eval 从 v1.0 升级到 v1.1),导致历史结果不可比;
- 需要注入私有测试样本(如某银行内部的信贷审批问答)。
解决方案:手动接管数据集路径
- 下载官方数据集到本地:
git clone https://huggingface.co/datasets/opencompass/ceval; - 修改
configs/datasets/ceval/ceval_gen.py中的path字段:path = '/path/to/local/ceval' # 指向你 clone 的本地目录 - 关键一步:在本地目录中,必须保留
.gitattributes和dataset_infos.json。OpenCompass 通过dataset_infos.json读取features(字段名)和splits(训练/验证/测试划分),若缺失,会报KeyError: 'test'。
私有数据集接入(以 JSONL 格式为例)
假设你有bank_faq.jsonl,每行是:
{"question": "房贷提前还款要收违约金吗?", "answer": "根据我行规定,贷款发放满一年后提前还款,免收违约金。"}新建configs/datasets/bank_faq/bank_faq_gen.py:
from opencompass.openicl.icl_inferencer import GenInferencer from opencompass.openicl.icl_prompt_template import PromptTemplate from opencompass.openicl.icl_retriever import ZeroRetriever from opencompass.openicl.icl_runner import LocalRunner from opencompass.datasets import CustomDataset bank_faq_reader_cfg = dict( input_columns=['question'], output_column='answer', ) bank_faq_infer_cfg = dict( prompt_template=dict( type=PromptTemplate, template=dict( round=[ dict(role='HUMAN', prompt='{question}'), dict(role='BOT', prompt='答:{answer}'), ], ), ), retriever=dict(type=ZeroRetriever), inferencer=dict(type=GenInferencer), ) bank_faq_eval_cfg = dict( evaluator=dict(type=ExactMatchEvaluator), pred_role='BOT', ) bank_faq_datasets = [ dict( type=CustomDataset, abbr='bank_faq', path='/path/to/bank_faq.jsonl', reader_cfg=bank_faq_reader_cfg, infer_cfg=bank_faq_infer_cfg, eval_cfg=bank_faq_eval_cfg, ) ]3.3 模型加载:量化、信任代码、Flash Attention 的取舍权衡
Qwen2、Phi-3、DeepSeek-V2 等新模型普遍要求trust_remote_code=True,因为其modeling_*.py文件不在标准transformers库中。但开启此选项意味着执行远程代码,存在安全风险。我们的做法是:
- 首次加载时:在隔离虚拟机中运行
from transformers import AutoModelForCausalLM; model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2-1.5B", trust_remote_code=True),并保存model.config到本地; - 生产环境:将
modeling_qwen2.py文件拷贝到项目opencompass/models/目录下,并在配置中指定type='Qwen2Model',彻底绕过trust_remote_code。
量化选择:AWQ vs GPTQ vs FP16
FP16:精度最高,显存占用最大(Qwen2-1.5B 约 3.2GB);GPTQ:压缩率高(4-bit 仅 0.9GB),但推理速度慢(CPU 解压开销);AWQ:平衡之选(4-bit 约 1.1GB,速度损失 < 15%),OpenCompass 原生支持awq格式权重。
我们在 RTX 4090 上实测:
| 量化方式 | 显存占用 | GSM8K 准确率 | 单样本平均延迟 |
|---|---|---|---|
| FP16 | 3.2 GB | 68.2% | 1.2 s |
| AWQ-4bit | 1.1 GB | 67.5% | 1.4 s |
| GPTQ-4bit | 0.9 GB | 65.8% | 2.1 s |
结论:AWQ 是性价比首选,精度损失仅 0.7%,显存节省 65%,延迟增加可接受。
Flash Attention:开还是不开?
OpenCompass 默认关闭(use_flash_attn: false),因为:
- A100/V100/A800 卡需 CUDA 12.1+,旧驱动不兼容;
- 某些模型(如 LLaMA-3)的 Flash Attention 实现有 bug,导致 attention mask 错误;
- 开启后,
--dump_details中的logits无法获取(Flash Attention 优化了计算图)。
我们的原则:评测阶段一律关闭 Flash Attention,只在生产推理时开启。评测要的是“纯净信号”,不是“最快结果”。
4. 实操过程与核心环节实现:从零启动到生成报告的完整流水线
4.1 环境准备:Docker 镜像定制与依赖锁定
不要用pip install opencompass!官方 PyPI 包缺少configs/目录,且依赖版本松散。正确姿势是:
# 1. 克隆官方仓库(固定 commit,避免后续更新破坏) git clone https://github.com/open-compass/opencompass.git cd opencompass git checkout 1.3.0 # 锁定 v1.3.0 版本 # 2. 创建最小化 Dockerfile FROM nvidia/cuda:12.1.1-devel-ubuntu22.04 # 安装系统依赖 RUN apt-get update && apt-get install -y \ python3.10-dev \ python3.10-venv \ git \ && rm -rf /var/lib/apt/lists/* # 创建 Python 环境 RUN python3.10 -m venv /opt/venv ENV PATH="/opt/venv/bin:$PATH" RUN pip install --upgrade pip # 安装 OpenCompass 及其硬依赖(版本锁定) COPY requirements.txt . RUN pip install -r requirements.txt # 复制 OpenCompass 代码 COPY . /workspace/opencompass WORKDIR /workspace/opencompass # 3. 构建镜像(显存监控必备) docker build -t opencompass:v1.3.0 .requirements.txt关键行(经实测验证):
torch==2.1.2+cu121 --extra-index-url https://download.pytorch.org/whl/cu121 transformers==4.37.0 datasets==2.16.1 accelerate==0.26.1 sentence-transformers==2.2.2实操心得:
accelerate==0.26.1是关键。新版accelerate在多卡评测时会错误地将batch_size平分到每张卡,导致单卡 batch_size 过小(如总 batch_size=16,双卡时每卡仅 8),引发梯度不稳定。0.26.1版本修复了此问题。
4.2 单模型单数据集快速验证:5 分钟跑通最小闭环
以 Qwen2-1.5B + C-Eval 历史子集为例:
步骤 1:创建最小配置文件configs/my_ceval.py
from mmengine.config import read_base from opencompass.models import HuggingFaceCausalLM from opencompass.datasets import CEvalDataset from opencompass.openicl.icl_inferencer import GenInferencer from opencompass.openicl.icl_prompt_template import PromptTemplate from opencompass.openicl.icl_retriever import ZeroRetriever # 数据集配置(只取历史子集) ceval_history = dict( abbr='ceval-history', type=CEvalDataset, path='opencompass/ceval', name='history', reader_cfg=dict( input_columns=['question'], output_column='answer', ), infer_cfg=dict( prompt_template=dict( type=PromptTemplate, template=dict( round=[ dict(role='HUMAN', prompt='{question}\nA. {A}\nB. {B}\nC. {C}\nD. {D}\n答案是:'), ], ), ), retriever=dict(type=ZeroRetriever), inferencer=dict(type=GenInferencer), ), eval_cfg=dict( evaluator=dict(type=AccEvaluator), pred_role='BOT', ), ) # 模型配置(FP16,禁用 flash attn) qwen2_1_5b = dict( type=HuggingFaceCausalLM, abbr='qwen2-1.5b', path='Qwen/Qwen2-1.5B', tokenizer_path='Qwen/Qwen2-1.5B', model_kwargs=dict( torch_dtype=torch.float16, trust_remote_code=True, ), generation_kwargs=dict( do_sample=False, temperature=0.0, top_p=0.95, max_new_tokens=512, ), max_out_len=512, batch_size=16, run_cfg=dict(num_gpus=1, num_procs=1), ) # 启动配置 datasets = [ceval_history] models = [qwen2_1_5b] work_dir = './outputs/my_ceval'步骤 2:一键启动(自动处理依赖、下载、推理)
# 启动前确认:CUDA_VISIBLE_DEVICES=0,且显存空闲 > 4GB python run.py configs/my_ceval.py --dump_details --reuse --max-partition-size 50参数说明:
--dump_details:生成details/目录,含每条样本的完整输入输出;--reuse:复用已缓存的模型和数据集,避免重复下载;--max-partition-size 50:每次只处理 50 条样本,防 OOM。
预期输出:
[2024-06-15 10:23:45] INFO: Starting evaluation for qwen2-1.5b on ceval-history... [2024-06-15 10:24:12] INFO: Partition 0/1 finished. Accuracy: 62.3% [2024-06-15 10:24:13] INFO: Evaluation finished. Final accuracy: 61.8% [2024-06-15 10:24:13] INFO: Details saved to ./outputs/my_ceval/details/qwen2-1.5b/ceval-history/验证成功标志:
./outputs/my_ceval/summary/20240615_102413.json中有"accuracy": 0.618;./outputs/my_ceval/details/qwen2-1.5b/ceval-history/下有00000.jsonl,打开可见:{"question": "秦始皇统一六国是在哪一年?", "A": "公元前230年", "B": "公元前221年", "C": "公元前207年", "D": "公元前202年", "answer": "B", "prediction": "B", "correct": true}
4.3 多模型横向对比:自动化报告生成与可视化
当你要对比 Qwen2-1.5B、Phi-3-3.8B、Llama3-8B 时,绝不要手动跑三次再 Excel 汇总。OpenCompass 内置summarizer模块:
步骤 1:修改configs/my_compare.py,添加多个模型
models = [ dict( type=HuggingFaceCausalLM, abbr='qwen2-1.5b', path='Qwen/Qwen2-1.5B', # ... 其他配置同上 ), dict( type=HuggingFaceCausalLM, abbr='phi3-3.8b', path='microsoft/Phi-3-mini-4k-instruct', # ... 注意:Phi-3 需要 special_tokenizer_kwargs tokenizer_path='microsoft/Phi-3-mini-4k-instruct', model_kwargs=dict( torch_dtype=torch.float16, trust_remote_code=True, ), # Phi-3 的 prompt 模板不同,需单独定义 infer_cfg=dict( prompt_template=dict( type=PromptTemplate, template=dict( round=[ dict(role='HUMAN', prompt='<|user|>{question}<|end|><|assistant|>'), ], ), ), # ... 其他 ), ), ]步骤 2:启动评测(自动并发)
# 使用 2 张卡,每卡跑一个模型 CUDA_VISIBLE_DEVICES=0,1 python run.py configs/my_compare.py --dump_details --max-partition-size 100步骤 3:生成 HTML 报告(无需额外工具)
# 自动生成 ./outputs/my_compare/summary/20240615_110000.html python tools/summarize.py ./outputs/my_compare/summary/生成的 HTML 报告包含:
- 总览表:各模型在各数据集上的准确率,支持点击列头排序;
- 雷达图:将 MMLU、C-Eval、GSM8K、ARC 等 8 个 benchmark 映射为维度,直观显示模型能力轮廓(Qwen2 在中文任务强,Llama3 在英文强);
- 详情页:点击任一单元格,跳转到该模型-数据集组合的
details/目录,查看原始样本。
实操心得:雷达图的“维度标准化”很关键。OpenCompass 默认将各 benchmark 分数线性映射到 0-100,但 MMLU 满分 100,GSM8K 满分 1000,直接映射会失真。我们在
tools/summarize.py中插入一行:score = min(100, (raw_score / max_score) * 100),确保所有维度都在同一尺度。
4.4 深度归因:用--debug模式追踪模型“思考过程”
当你发现模型在 GSM8K 上准确率仅 42%,远低于公开报告的 65%,就要进入--debug模式:
# 只跑 3 个样本,启用 debug python run.py configs/my_gsm8k.py --debug --num-samples 3--debug模式会:
- 打印每步
model.generate()的输入 shape(input_ids.shape=(1, 256)); - 输出
past_key_values的内存地址(确认 KV Cache 是否复用); - 在
details/目录生成debug_00000.log,含:[Step 0] Input: "Q: 如果一个苹果2元,买5个多少钱?\nA:" [Step 0] Logits shape: torch.Size([1, 1, 151936]) [Step 0] Top-3 tokens: ['2', '10', '5'] with probs [0.42, 0.31, 0.18] [Step 1] Input: "Q: 如果一个苹果2元,买5个多少钱?\nA: 2" [Step 1] Logits shape: torch.Size([1, 1, 151936]) [Step 1] Top-3 tokens: ['*', 'x', '×'] with probs [0.35, 0.28, 0.22]
我们曾用此方法发现:某微调模型在乘法符号上过度偏好*(概率 0.35),而标准答案是×,导致first_token_postprocess提取失败。解决方案是:在output_postprocessor中增加output.replace('*', '×')。
5. 常见问题与排查技巧实录:那些让老手也抓狂的“幽灵 Bug”
5.1 显存爆炸:不是模型太大,是 batch_size 算错了
现象:CUDA out of memory,但nvidia-smi显示显存只占 80%。
原因:OpenCompass 的batch_size是全局 batch_size,不是 per-GPU。如果你设batch_size=32,单卡运行时,实际每批送 32 条样本;但双卡运行时,accelerate会默认每卡送 16 条,总 batch_size 仍是 32。然而,某些模型(如 Qwen2)的forward会因 batch_size 变化导致 KV Cache 内存翻倍。
排查命令:
# 查看实际分配的 batch_size grep "batch_size" ./outputs/my_run/20240615_102413.log # 输出:INFO: Using batch_size=32 for qwen2-1.5b on ceval-history解决方案:
- 单卡:
batch_size=16(RTX 4090 安全值); - 双卡:
batch_size=32,但必须在model_cfg中显式设置run_cfg=dict(num_gpus=2, num_procs=2),并确认accelerate版本为0.26.1。
5.2 准确率归零:prompt 模板里的隐形换行符
现象:所有样本correct=false,prediction为空字符串。
原因:Jinja2 模板中,{question}\nA. {A}的\n在 Windows 编辑器中可能变成\r\n,而模型 tokenizer 将\r视为非法字符,直接截断。
验证方法:
# 查看模板实际渲染结果 python -c " from jinja2 import Template t = Template('{{question}}\r\nA. {{A}}') print(repr(t.render(question='Q?', A='A'))) # 输出:'Q?\r\nA. A' —— 看到了 \r\n! "修复:在prompt_template中强制替换:
template=dict( round=[ dict(role='HUMAN', prompt='{{question}}\nA. {{A}}\nB. {{B}}\nC. {{C}}\nD. {{D}}\n答案是:'), ], ), # 添加 preprocessor preprocessor=lambda x: x.replace('\r\n', '\n').replace('\r', '\n'),5.3 日志丢失:--dump_details不生效的权限陷阱
现象:details/目录为空,但summary/有结果。
原因:Docker 容器内/workspace/opencompass/outputs目录权限为root,而容器内运行用户是nonroot,无写入权限。
解决方案:
# 在 Dockerfile 中添加 RUN useradd -m -u 1001 -G root opencompass USER opencompass WORKDIR /workspace/opencompass或更简单:启动时挂载目录并赋权
docker run -v $(pwd)/outputs:/workspace/opencompass/outputs \ -u $(id -u):$(id -g) \ opencompass:v1.3.0 \ python run.py configs/my.py --dump_details5.4 模型加载失败:trust_remote_code=True的证书错误
现象:`