ChatGLM2-6B-32K 长文本评测实战:用 LongBench 验证 32k 上下文理解能力
发布时间:2026/9/25 10:44:15 作者:尧图编辑部 阅读量:1,286

1. 为什么我要用 LongBench 重新测一遍 ChatGLM2-6B-32K如果你正在做长文档问答、合同比对、论文摘要或者 RAG 检索增强大概率会遇到一个很尴尬的问题模型号称支持 32k 上下文但把一篇两万字的材料塞进去它要么答非所问要么把中间段落的内容直接忽略。上下文窗口标称长度和真实的长文本理解能力从来不是一回事。ChatGLM2-6B-32K 是智谱在 ChatGLM2-6B 基础上扩展上下文到 32k 的版本而 LongBench 是 THUDM 团队专门为长文本理解设计的双语评测基准包含 13 个英文任务、5 个中文任务和 2 个代码任务共约 4500 条测试数据覆盖单文档 QA、多文档 QA、摘要、Few-shot 学习、代码补全和合成任务六大类。把这两个东西组合起来就能得到一份相对客观的“32k 上下文到底能不能用”的答案。这篇内容面向需要评估长文档问答、摘要与检索增强的开发者我会交付一套可复制的 LongBench 数据准备与推理配置骨架包括 config 文件示例、逐项指标采集方式以及结果比对的可验证动作。你跟着做能在自己的机器上跑出一份属于自己硬件环境的评测报告而不是只看官方那张图。需要说明的是LongBench 的评测是自动化的官方采用基于规则的打分方式比如 QA 用 F1、摘要用 ROUGE不需要人工标注也不需要调用外部 API这对成本敏感的长文本场景非常友好。下面从环境准备开始一步步来。2. 前置准备模型、数据集与推理入口2.1 硬件与依赖的现实预期ChatGLM2-6B-32K 是 6B 量级模型FP16 权重约 12GB 出头。如果你用单张 24GB 显存的卡比如 3090/4090FP16 推理基本够用如果显存只有 16GB建议用 int4 量化加载但要注意量化会轻微影响长文本任务上的表现评测时最好固定一种精度别混着比。依赖方面核心是 transformers、torch、datasets、jieba中文任务分词用、rouge摘要打分用。我实测下来transformers 版本建议 4.33 以上低版本对 ChatGLM2 的 remote code 支持偶尔会出问题。pip install torch transformers datasets jieba rouge nltk python -c import nltk; nltk.download(punkt)2.2 拉取 LongBench 与模型LongBench 的数据通过 Hugging Face datasets 加载模型从 Hugging Face 或镜像站拉取。如果你在推理侧需要统一管理模型调用和密钥可以把模型服务挂在 TaoToken 的 API 入口后面这样评测脚本里的请求地址和密钥可以集中配置不用每个脚本改一遍。from datasets import load_dataset datasets_list [ hotpotqa, 2wikimqa, musique, dureader, narrativeqa, qasper, multifieldqa_en, multifieldqa_zh, gov_report, qmsum, vcsum, trec, nq, triviaqa, lsht, passage_count, passage_retrieval_en, passage_retrieval_zh, lcc, repobench-p ] for name in datasets_list: data load_dataset(THUDM/LongBench, name, splittest) print(name, len(data))每个名称对应一个子任务比如 hotpotqa 是多文档 QAgov_report 是长摘要lcc 是代码补全。先确认每个子集都能正常加载再进入推理环节。2.3 用 TaoToken 统一推理入口如果你的评测脚本需要同时对比多个模型或者想把本地模型和 API 模型放在同一套流程里跑建议把推理请求统一走 TaoToken 的 API。模型对话入口在 https://taotoken.net/api 密钥在 console 的 API Keys 页面生成。这样你的 pred.py 里只需要改 model 字段不用改请求逻辑。注意评测脚本里不要把密钥硬编码进 git 仓库用环境变量读取。3. 可复制的 LongBench 推理配置骨架3.1 config 文件示例官方 pred.py 把配置写死在代码里实际做对比评测时很不方便。我习惯抽一个 config.yaml 出来把模型路径、上下文长度、batch size、输出目录都参数化。# config.yaml model: name: chatglm2-6b-32k path: /models/chatglm2-6b-32k dtype: fp16 # fp16 / int4 max_length: 31500 # 留出生成空间别顶满 32768 trust_remote_code: true inference: batch_size: 1 temperature: 0.1 top_p: 0.7 do_sample: false max_new_tokens: 512 data: root: ./LongBench/data datasets: - hotpotqa - multifieldqa_zh - gov_report - vcsum - lcc prompt_format: default output: pred_dir: ./pred result_file: ./result.jsonmax_length 这里设 31500 而不是 32768是因为要留出 max_new_tokens 的生成空间。如果你把输入顶满 32768生成阶段会直接截断长摘要任务会拿到空结果这是新手最容易踩的坑。3.2 推理脚本骨架下面这段是 pred.py 的核心逻辑我做了简化保留了可运行的关键部分。它按 LongBench 的 prompt 模板拼接输入逐条推理并写入 pred 目录。import os, json, yaml, torch from transformers import AutoTokenizer, AutoModel from datasets import load_dataset cfg yaml.safe_load(open(config.yaml)) tok AutoTokenizer.from_pretrained(cfg[model][path], trust_remote_codeTrue) model AutoModel.from_pretrained( cfg[model][path], trust_remote_codeTrue, torch_dtypetorch.float16 if cfg[model][dtype] fp16 else torch.int4 ).cuda().eval() PROMPT 阅读以下材料回答问题。\n\n{context}\n\n问题{input}\n答案 os.makedirs(cfg[output][pred_dir], exist_okTrue) for name in cfg[data][datasets]: ds load_dataset(THUDM/LongBench, name, splittest) out_path os.path.join(cfg[output][pred_dir], f{name}.jsonl) with open(out_path, w, encodingutf-8) as f: for item in ds: prompt PROMPT.format(contextitem[context], inputitem[input]) inputs tok(prompt, return_tensorspt, truncationTrue, max_lengthcfg[model][max_length]).to(cuda) with torch.no_grad(): ids model.generate( **inputs, max_new_tokenscfg[inference][max_new_tokens], do_samplecfg[inference][do_sample], temperaturecfg[inference][temperature], ) pred tok.decode(ids[0][inputs[input_ids].shape[1]:], skip_special_tokensTrue) f.write(json.dumps({ pred: pred, answers: item[answers], all_classes: item.get(all_classes, None), length: item[length], }, ensure_asciiFalse) \n) print(f{name} done)跑之前确认 pred 目录为空避免旧结果混进新评测。如果你要对比 ChatGLM2-6B 和 ChatGLM2-6B-32K把 config 里的 path 换掉输出目录也换掉两份结果分开存。3.3 中文任务的 prompt 差异LongBench 里中文任务multifieldqa_zh、dureader、vcsum的 prompt 模板和英文不完全一样。官方在 pred.py 里用了一个 prompt_format 字典做映射。如果你自己写脚本至少要保证中文 QA 的指令是中文否则模型会用英文回答中文问题F1 直接掉一截。我试过偷懒统一用英文模板multifieldqa_zh 的分数比正确模板低了将近 8 个点。4. 验证请求与结果采集4.1 先跑单条确认链路通正式跑全量之前先拿一条数据验证推理链路。下面这段只取 hotpotqa 的第一条打印输入长度和输出确认没有报错、没有截断异常。ds load_dataset(THUDM/LongBench, hotpotqa, splittest) item ds[0] print(context length:, len(item[context])) print(input:, item[input]) print(gold answers:, item[answers])如果 context length 超过 30000说明这条数据本身就很长正好用来验证 32k 窗口。输出里如果出现大量重复或者直接复述原文说明生成参数需要调先把 do_sample 设为 false 试。4.2 运行评测并采集逐项指标推理完成后用 eval.py 打分。官方脚本会读取 pred 目录按任务类型选择打分函数QA 类用 F1摘要类用 ROUGE-L代码补全用编辑相似度合成任务用准确率。python eval.py --pred_dir ./pred --result_file ./result.jsonresult.json 的结构大致是每个数据集一个分数。为了做逐项对比我建议把结果整理成表格按任务大类聚合。任务大类子任务ChatGLM2-6BChatGLM2-6B-32K单文档 QAnarrativeqa待填待填多文档 QAhotpotqa待填待填摘要gov_report待填待填Few-shottrec待填待填代码补全lcc待填待填合成任务passage_count待填待填这张表就是你最终要交付的比对结果。32K 版本的优势通常在多文档 QA 和长摘要上更明显因为这两类任务对跨段落信息整合要求最高。4.3 按长度区间切片分析LongBench 每条数据都带 length 字段这是它比普通评测集更有价值的地方。你可以把结果按 0-5k、5k-15k、15k-32k 三个区间分组看模型分数随长度衰减的曲线。import json from collections import defaultdict buckets defaultdict(list) with open(./pred/hotpotqa.jsonl, encodingutf-8) as f: for line in f: r json.loads(line) L r[length] key 0-5k if L 5000 else (5-15k if L 15000 else 15k) buckets[key].append(r) for k, v in buckets.items(): print(k, len(v))如果 15k 区间的样本数为 0说明这个子任务本身没有超长样本换 hotpotqa 或 gov_report 再看。这个切片动作能直接回答“32k 到底在哪个长度段开始起作用”。5. 本篇常见错排查5.1 显存溢出与 max_length 设置报错 CUDA out of memory先降 max_length 到 16000 试确认能跑通再往上加。另一个常见原因是 tokenizer 没有设置 truncation长样本直接顶爆。检查你的 tokenizer 调用里有没有 truncationTrue 和 max_length。5.2 生成结果为空或全是特殊符号多半是 max_new_tokens 太小或者输入把上下文占满导致没有生成空间。把 max_length 降到 30000 以下max_new_tokens 保持 512再跑一条看。如果还是空检查 tokenizer 的 decode 有没有加 skip_special_tokensTrue。5.3 中文任务分数异常低先确认 prompt 模板是中文。其次检查 jieba 分词是否正常F1 计算依赖分词质量。如果 jieba 没装或者版本不对中文 QA 的 F1 会明显偏低。5.4 结果无法复现固定随机种子do_sample 设为 false。LongBench 的评测本身是确定性的但生成阶段如果开了采样每次结果都不一样。做对比评测时两个模型必须用完全相同的生成参数。5.5 数据集加载失败Hugging Face 加载超时或报 ConnectionError先确认网络能访问 datasets 仓库。如果持续失败可以手动下载 data.zip 解压到本地改成本地路径加载。官方数据地址在 LongBench 的 GitHub 仓库里有说明。6. 评测之后把结论落到实际选型上跑完这一轮你手里应该有两份 result.json 和一张按长度切片的对比表。接下来怎么用这份结果取决于你的场景。如果你做的是长文档问答重点看多文档 QA 和单文档 QA 在 15k 区间的分数差。32K 版本如果在这个区间明显高于 6B 原版说明扩展上下文确实带来了跨段落整合能力的提升值得在 RAG 的生成阶段替换。如果你做的是长摘要看 gov_report 和 vcsum 的 ROUGE-L摘要任务对上下文完整性的要求比 QA 更敏感。如果你需要长期跑编码类或 Agent 类任务单次评测只是一部分还要考虑调用成本和稳定性。这种情况下可以了解 TaoToken 的 Coding Plan把评测和日常编码统一到一套入口。模型对话的验证入口在 https://taotoken.net/api 接入文档在 doc 页面密钥管理在 console 的 API Keys。最后提醒一句LongBench 的分数是自动化指标它衡量的是模型输出和参考答案的相似度不完全等于人类主观感受。做最终选型时建议在你自己业务的真实长文本样本上再抽 20 条人工看一眼自动化指标和真实体验对上了这个结论才站得住。