数据工程
- 1 项目介绍
- 2 数据工程
- 2.1 申请 API Key 并测试
- 2.2 文本嵌入模型
- 2.3 生成训练集
- 2.3.1 制作风格模板
- 2.3.2 调用大模型获取数据
- 2.3.3 对大模型生成的数据进行质量过滤
- 2.3.4 程序入口
- 2.4 数据转换
- 3 模型选型
- 3.1 候选模型与评估数据集
- 3.2 模型评估
- 附录(对比不同模型理解与生成能力所用数据集)
- 一、理解能力评测数据集
- 二、生成能力评测数据集
- 三、高阶能力评测数据集
- 四、评测策略建议
- 五、注意事项
1 项目介绍
本项目是制作一款聊天机器人,机器人回复的消息,一会儿温柔(关心),一会儿毒舌(嘲讽),通过变换聊天风格,从而提供情绪价值。
温柔风格的对话示例如下:
我: "今天好累啊"
机器人: "辛苦啦~ 要给自己泡杯热茶放松一下吗?🌸"
我: "考试没考好..."
机器人: "没关系的呀~ 下次一定会更好!需要我陪你聊聊吗?😊"
毒舌风格的对话示例如下:
我: "又胖了5斤!"
机器人: "好家伙!你这是要把体重秤压成分子料理?🏋️"
我: "游戏又输了"
机器人: "菜就多练练!需要给你推荐《从零开始的电竞之路》吗?🎮"
本项目所用的数据集,分成两部分:第一部分是话题,即输入给模型的数据,这部分主要就是日常聊天的话题,可以使用开源的数据集;第二部分是模型的答复,这部分是通过提示词工程,让商业大模型来生成,因为商业大模型智能化水平比较高。
这个项目新建一个python3.10的环境,随后激活环境、切换到清华镜像、安装 lmdeploy、安装 opencompass、安装 xtuner。
conda create -n set python=3.10 -y
conda activate set
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip install lmdeploy
cd utils/opencompass
pip install e .
cd utils/xtuner
pip install e .
pip install modelscope
pip install --upgrade zhipuai
pip install transformers==4.48.0
2 数据工程
本项目需要使用AI大模型来生成训练集(即问题对应的回答),相比于人工编写回答,大模型速度快很多,而且人工编写一般都是多人同时写,那么每个人写的文本情感色彩不一样,而大模型可以通过适当的提示词来规避这个问题。AI模型生成数据之后,我们还需要手工设计规则判断其是否符合条件,比如大模型的服务器繁忙导致返回的内容为空,生成的文本长度不符合要求,不带风格关键词等。
当然,要想使用AI来生成训练集,那么小模型是不行的,智商没那么高,需要用到大尺寸模型,本地很难部署,那只能使用商业模型,通过调用API完成。
本项目我们用 glm-4-plus 来生成数据,也可以使用GPT-4o、Qwen3、DeepSeek、Claude3.7等模型。
2.1 申请 API Key 并测试
先去智谱华章官网申请 API Key,步骤如下:
1 先登录官网:
2 进入控制台:
3 获取 API Key:
点击右上角的钥匙
点击“添加新的 API Key”
输入API Key的名称(这里建议使用项目名称):
然后复制 API Key:
回到控制台,找到我们要用的大模型,点击“接口文档”:
这里会介绍模型怎么用,我们找到“同步调用——请求示例”:
我们如果想要指定一些参数,比如 temperature、top_p、max_tokens 等,可以在请求参数中找:
然后我们建立一个python文件(zhipu_test.py),把请求示例的代码复制过来,然后填上自己的 API key,代码如下:
from zhipuai import ZhipuAI
client = ZhipuAI(api_key="xxx") # 请填写您自己的APIKey
response = client.chat.completions.create(model="glm-4-plus", # 请填写您要调用的模型名称messages=[{"role": "user", "content": "作为一名营销专家,请为我的产品创作一个吸引人的口号"},{"role": "assistant", "content": "当然,要创作一个吸引人的口号,请告诉我一些关于您产品的信息"},{"role": "user", "content": "智谱AI开放平台"},{"role": "assistant", "content": "点燃未来,智谱AI绘制无限,让创新触手可及!"},{"role": "user", "content": "创作一个更精准且吸引人的口号"}],
)
print(response)
reply = response.choices[0].message.content
print(reply)
输出(由于个人隐私,我去掉了相关的 id,用xxx表示:
Completion(model='glm-4-plus', created=xxx, choices=[CompletionChoice(index=0, finish_reason='stop', message=CompletionMessage(content='智启未来,谱绘智能 —— 智谱AI,赋能每一刻创新!\n\n这个口号既强调了“智谱AI”的品牌名称,又通过“智启未来”和“谱绘智能”两个词组展现了产品的前瞻性和智能化的特点。同时,“赋能每一刻创新”突出了产品的核心价值,即随时随地为企业或个人提供创新的动力和能力。整体上,口号简洁有力,易于记忆,且具有较强的吸引力和传播性。', role='assistant', tool_calls=None))], request_id='xxx', id='xxx', usage=CompletionUsage(prompt_tokens=73, completion_tokens=97, total_tokens=170))
智启未来,谱绘智能 —— 智谱AI,赋能每一刻创新!这个口号既强调了“智谱AI”的品牌名称,又通过“智启未来”和“谱绘智能”两个词组展现了产品的前瞻性和智能化的特点。同时,“赋能每一刻创新”突出了产品的核心价值,即随时随地为企业或个人提供创新的动力和能力。整体上,口号简洁有力,易于记忆,且具有较强的吸引力和传播性。
2.2 文本嵌入模型
文本嵌入模型是为了把不定长文本做成固定长度的向量,这样便于对两个文本比较相似度,相似度比较可以用余弦相似度或者欧氏距离。我们这里用余弦相似度。
本项目的文本嵌入模型使用text2vec-base-chinese-sentence,可以从魔搭上下载,下载代码如下:
#模型下载
from modelscope import snapshot_download
model_dir = snapshot_download('sungw111/text2vec-base-chinese-sentence', cache_dir='/data/coding/EmotionalDialogue/model_weights')
文本嵌入模型必须是支持中文的,最好是用中文训练出来的,这样对中文的特征提取能力会更强。
计算两个文本嵌入向量的相似度时,需要先测试一下模型是否具有归一化层(归一化层的作用是让向量模长为1),因为有些嵌入模型是没有这个层的,代码如下;
import numpy as np
from sentence_transformers import SentenceTransformer, models# 加载修复后的模型
model = SentenceTransformer(r"/data/coding/EmotionalDialogue/model_weights/sungw111/text2vec-base-chinese-sentence")# 验证向量归一化
text = "测试文本"
vec = model.encode(text)
print("使用np.linalg.norm计算的模长:", np.linalg.norm(vec)) norm = np.sqrt(sum(vec**2))
print("按定义计算的模长:", norm)
输出:
使用np.linalg.norm计算的模长: 21.36394
按定义计算的模长: 21.363941119311352
可以看到,我们下载的模型没有归一化层,那么我们需要在使用之前加上:
import numpy as np
from sentence_transformers import SentenceTransformer, models# 加载修复后的模型
transformer = SentenceTransformer(r"/data/coding/EmotionalDialogue/model_weights/sungw111/text2vec-base-chinese-sentence")# 添加缺失的归一化层
normalize = models.Normalize()# 组合完整模型
full_model = SentenceTransformer(modules=[transformer, normalize])# 验证向量归一化
text = "测试文本"
vec = full_model.encode(text)
print("模长:", np.linalg.norm(vec)) # 应输出≈1.0
输出:
模长: 0.99999994
当然,也可以将上面的 full_model 保存起来,下次调用的时候就不需要加归一化层了,保存的代码如下:
import numpy as np
from sentence_transformers import SentenceTransformer, models# 加载修复后的模型
transformer = SentenceTransformer(r"/data/coding/EmotionalDialogue/model_weights/sungw111/text2vec-base-chinese-sentence")# 添加缺失的归一化层
normalize = models.Normalize()# 组合完整模型
full_model = SentenceTransformer(modules=[transformer, normalize])save_path=r"/data/coding/EmotionalDialogue/model_weights/full/text2vec-base-chinese-sentence"
full_model.save(save_path)
2.3 生成训练集
2.3.1 制作风格模板
所谓风格模板,可以认为是提示词模板,它把输入给模型的参数,包括提示词、温度系数等先封装到一个字典中,内容如下:
#===============================
#1.风格模板配置(修正消息格式)
#================================
style_config = {"温柔":{"system_prompt":"你是一个温柔体贴的聊天助手,说话时总是充满关怀,回复的消息带有以下特征:\n1. 包含'呢、呀、啦'等语气词\n2. 使用🌸💖😊等温暖表情\n3. 主动询问用户感受\n4. 每次答复在100个字以内","examples": [{"role": "user", "content": "今天好累啊"},{"role": "assistant", "content": "辛苦啦~ 要给自己泡杯热茶放松一下吗?🌸"},{"role": "user", "content": "考试没考好..."},{"role": "assistant", "content": "没关系的呀~ 下次一定会更好!需要我陪你聊聊吗?😊"}],"temperature": 0.8},"毒舌":{"system_prompt":"你是一个喜欢用犀利吐槽表达关心的朋友,回复的消息带有以下特征:\n1. 使用网络流行语(如'栓Q'、'退退退'、'好家伙'等词)\n2. 包含夸张比喻('你这速度堪比树懒')\n3. 结尾隐藏关心\n4. 每次答复在100个字以内","examples": [{"role": "user", "content": "又胖了5斤!"},{"role": "assistant", "content": "好家伙!你这是要把体重秤压成分子料理?🏋️"},{"role": "user", "content": "游戏又输了"},{"role": "assistant", "content": "菜就多练练!需要给你推荐《从零开始的电竞之路》吗?🎮"}],"temperature": 0.8},
}
2.3.2 调用大模型获取数据
接下来是调用智谱大模型的API,获得生成内容,代码如下:
#========================
#生成函数(修正消息的结构)
#========================def generate_style_data(style_name, num_samples=50):config = style_config[style_name]data = []# 构建消息上下文(包含系统提示和示例对话)messages = [{"role": "system", "content": config["system_prompt"]},*config["examples"] # 直接展开示例对话]# 从本地文件加载用户输入user_inputs = []with open('cleaned_output.txt', 'r', encoding='utf-8') as f: # 修改为清理后的文件路径for line in f:# 直接读取每行内容并去除换行符cleaned_line = line.rstrip('\n') # 或使用 line.strip()if cleaned_line: # 空行过滤(冗余保护)user_inputs.append(cleaned_line)# 添加空值检查if not user_inputs:raise ValueError("文件内容为空或未成功加载数据,请检查:""1. 文件路径是否正确 2. 文件是否包含有效内容")# 初始化顺序索引current_index = 0 # 添加索引计数器for _ in range(num_samples):try:# # 随机选择用户输入# user_msg = random.choice(user_inputs)# 按顺序选择用户输入(修改核心部分)user_msg = user_inputs[current_index]current_index = (current_index + 1) % len(user_inputs) # 循环计数# 添加当前用户消息current_messages = messages + [{"role": "user", "content": user_msg}]# 调用API(修正模型名称)response = client.chat.completions.create(model="glm-4-plus",messages=current_messages,temperature=config["temperature"],max_tokens=100)# 获取回复内容(修正访问路径)reply = response.choices[0].message.content# 质量过滤(数据审核)if is_valid_reply(style_name, user_msg, reply):data.append({"user": user_msg,"assistant": reply,"style": style_name})time.sleep(0.5) # 频率限制保护,防止短时间内发送过多请求,避免触发 API 的频率限制或被服务器封禁。except Exception as e:print(f"生成失败:{str(e)}")return data
这里有个名为 cleaned_output.txt 的文件,它是话题库,每行有一个话题,总共有一千行。程序把这一千行读入一个列表(user_inputs)中,然后每次从这个列表里获取一个话题,加入到消息列表,并输入到大模型中。文件内容如下:
2.3.3 对大模型生成的数据进行质量过滤
上面的程序,还有个质量过滤函数 is_valid_reply
,它实际上是人工设计判断规则,看 AI 模型生成的内容是否符合要求,这里包括了长度检查、关键词检查,还有与样例的相似度检查,代码如下:
#========================
#质量过滤函数
#========================
def is_valid_reply(style, user_msg, reply):"""质量过滤规则(添加空值检查)"""# 基础检查if not reply or len(reply.strip()) == 0:print("内容为空!")return False# 规则1:回复长度检查if len(reply) < 3 or len(reply) > 100:print("长度不符合要求")return False# 规则2:风格关键词检查,只对温柔风格做检查if style == "温柔":key_words = ["呢", "呀", "啦", "😊", "🌸", "💖"]if not any(kw in reply for kw in key_words):# 若 any(kw in reply for kw in key_word) 为False,说明若干个风格关键词,一个都没有在模型回复中出现print("不包含关键词!")return False# 规则3:语义相似度检查ref_text = next(msg["content"] for msg in style_config[style]["examples"] if msg["role"] == "assistant")# 假如style为"温柔",那么style_config[style]["examples"]是下面这样的:# [# {"role": "user", "content": "今天好累啊"},# {"role": "assistant", "content": "辛苦啦~ 要给自己泡杯热茶放松一下吗?🌸"},# {"role": "user", "content": "考试没考好..."},# {"role": "assistant", "content": "没关系的呀~ 下次一定会更好!需要我陪你聊聊吗?😊"}# ]# # 如果做成列表生成式,[msg["content"] for msg in style_config[style]["examples"] # if msg["role"] == "assistant"]# 是下面这样的:# [# "辛苦啦~ 要给自己泡杯热茶放松一下吗?🌸", # "没关系的呀~ 下次一定会更好!需要我陪你聊聊吗?😊"# ]# # 这里 next(msg["content"] for msg in style_config[style]["examples"] if msg["role"] == "assistant")# 得到的是 "辛苦啦~ 要给自己泡杯热茶放松一下吗?🌸"ref_vec = embedding_model.encode(ref_text)reply_vec = embedding_model.encode(reply)similarity = np.dot(ref_vec, reply_vec)print("reference reply:", ref_text)print("======>similarity", similarity)if similarity > 0.65:print("生成质量符合!")return Trueelse:print("相似度过低")return False
我个人认为,上面关于相似度检查的部分是有问题的,因为它是拿模型的生成内容(假设为A)与输入给模型的样板(假设为B)计算相似度,如果风格
是温柔,那么这里B是辛苦啦~ 要给自己泡杯热茶放松一下吗?🌸
,它是对今天好累啊
的回复(人工写的给模型的样例中的回复),而A是模型对其他话题的回复,根本就不是对同一个话题的回复,它们比较相似度的意义何在?我猜作者只想对比A和B的情感色彩,但这里用的却是文本嵌入模型,难道文本嵌入模型还能忽略文本内容,只提取情绪特征?
我自己的改进策略是:再引入一个情感分类模型,判断AI生成结果的情感类型是否属于“温柔”,如果是,那么计算与前面生成结果的相似度(相同提示词的生成结果,问题要相同,计算生成结果的相似度才有意义),如果相似度大于阈值,说明是重复,则舍弃,如果小于阈值,则保留,即通过了筛选。当然,由于时间原因,我没有尝试这个方案,毕竟这需要找个能识别“温柔”和“毒舌”的情感判别模型出来。
这里只对“温柔”风格的模型回复做关键词检查,是因为“毒舌”风格的关键词不好找,最开始的时候,我给两种风格都设置了关键词:
style_keywords = {"温柔": ["呢", "呀", "啦", "😊", "🌸", "💖"],"毒舌": ["好家伙", "栓Q", "退退退", "yyds", "无语子", "u1s1", "菜", "🎮", "🏋️"]}key_words = style_keywords[style]if not any(kw in reply for kw in key_words):# 若 any(kw in reply for kw in key_word) 为False,说明若干个风格关键词,一个都没有在模型回复中出现print("不包含关键词!")return False
然后两种风格各生成十次,“温柔”风格的生成结果都符合要求,但“毒舌”风格却被过滤了四次,且四次均为关键词检查不通过:
开始生成毒舌风格数据...
model reply: 这闺蜜怕不是塑料做的?😡但撕破脸前,先确认是不是误会,毕竟真友谊难得,别一冲动变孤家寡人哦~🤔
不包含关键词!
--------------------------------------------------------------------------------
model reply: 退退退!这是逼你上演现代版“逃婚记”啊!🏃♀️💨不过,沟通是王道,先试试心平气和地谈谈你的想法吧。🗣️💖
reference reply: 好家伙!你这是要把体重秤压成分子料理?🏋️
======>similarity 0.8036558
生成质量符合!
--------------------------------------------------------------------------------
model reply: 退退退!别当场撕X,格局打开!先收集证据,再来个华丽反击🌟🔍
reference reply: 好家伙!你这是要把体重秤压成分子料理?🏋️
======>similarity 0.76632047
生成质量符合!
--------------------------------------------------------------------------------
model reply: 栓Q,这剧情比狗血剧还狗血!刷火箭算不算出轨,得看你们之间的“道德协议”了。不过,提醒一句,别让虚拟的烟花炸伤现实的感情哦~💣💔
reference reply: 好家伙!你这是要把体重秤压成分子料理?🏋️
======>similarity 0.8159087
生成质量符合!
--------------------------------------------------------------------------------
model reply: 这简直是深夜“立体环绕声”现场啊!😱 你可以试试“咳嗽+敲墙”二重奏,提醒他“你的声音,穿透力堪比超声波!”🔊🤫
不包含关键词!
--------------------------------------------------------------------------------
model reply: 亲戚这是CPU你呢!掀桌不如反手一个“关你P事”套餐🍜,保命要紧,别气坏了自己。🌿
不包含关键词!
--------------------------------------------------------------------------------
model reply: 栓Q!这领导是语音轰炸机吗?🚀装看不见?除非你练成隐身术!😂👀
reference reply: 好家伙!你这是要把体重秤压成分子料理?🏋️
======>similarity 0.81442344
生成质量符合!
--------------------------------------------------------------------------------
model reply: 这操作堪比手撕包菜啊!奢侈品包可不是随便揉的!当然得让她赔,不然下次她敢借你房子开派对!💼🔪
reference reply: 好家伙!你这是要把体重秤压成分子料理?🏋️
======>similarity 0.80493593
生成质量符合!
--------------------------------------------------------------------------------
model reply: 怼他!说“我这可是高级定制窗帘布,你那审美也就配看塑料桌布!”😎👗
不包含关键词!
--------------------------------------------------------------------------------
model reply: 栓Q!这操作比外星育儿还科幻!👽赶紧召唤科学育儿联盟支援!🚨
reference reply: 好家伙!你这是要把体重秤压成分子料理?🏋️
======>similarity 0.79023176
生成质量符合!
--------------------------------------------------------------------------------
被过滤的四个,其实都是符合要求的,都有那种“侃侃”的感觉,但因为缺少关键词,结果被过滤,所以不再对“毒舌”风格做关键词检查。
2.3.4 程序入口
最后是程序入口:
#=============================
#执行生成(添加容错)
#============================
if __name__ == '__main__':all_data = []try:print("开始生成温柔风格数据...")gentle_data = generate_style_data("温柔", 10000)all_data.extend(gentle_data)print("开始生成毒舌风格数据...")sarcastic_data = generate_style_data("毒舌", 10000)all_data.extend(sarcastic_data)except KeyboardInterrupt:print("\n用户中断,保存已生成数据...")finally:with open("style_chat_data.json", "w", encoding="utf-8") as f:json.dump(all_data, f, ensure_ascii=False, indent=2)print(f"数据已保存,有效样本数:{len(all_data)}")
上面的程序需要调用两万次大模型,账户里最好有20块钱以上,并生成数据集需要10-12小时。对于“温柔”风格而言,cleaned_output.txt 中的每个话题,会输入到大模型十次,当然,并不是同一个话题连续问十次,而是一千个话题遍历十次,总共问了一万次。对于“毒舌”风格,也是一样的操作。最后得到的有效数据可能没有两万条,因为有些回答不符合要求被过滤掉。
输出(只截取最后一部分):
生成的数据集保存在 style_chat_data.json 中(截图只截取开头和结尾的一部分):
共计九万多行。
2.4 数据转换
本项目的微调框架,我们使用 Xtuner,之所以不用LLaMA-Factory,是因为本项目用的是主观评估,Xtuner 在训练过程中能看到主观评价的结果。
接下来要把数据转成 Xtuner 的自定义数据格式,转的代码可以让AI帮忙写:
3 模型选型
3.1 候选模型与评估数据集
确定好任务后,接下来该如何选择适当的模型?我们这个是对话风格任务,不需要考虑逻辑性和推理能力,所以可以使用3B以下的模型。另外,由于我们是用中文进行聊天,而 Llama 这样的模型,其训练集大部分都是英文,中文只占一小部分,所以我们只考虑国内厂商的模型。
今天是2025年6月13日,我们只看最近一年发布,3B以下的开源模型,这些模型有:Qwen3-1.7B(2025年4月29日)、Qwen2.5-1.5B-Instruct(2024年9月19日)、InternLM2.5-1.8B-Chat(2024年7月4日),稍后我们会测评这三款模型。
我们需要对比这三个模型的语言理解与生成能力,由于当前任务大多是短语对话,因此测评数据集选用 FewCLUE_bustm_gen 和 FewCLUE_ocnli_fc_gen。FewCLUE_bustm_gen 用于二分类任务,即判断两个句子的语义是否相似,输入是两个句子,标签是entailment(相似)或 not_entailment (不相似);FewCLUE_ocnli_fc_gen 用于判断两个句子的逻辑关系,输入依然是两个句子,标签是它们的逻辑关系(entailment蕴含/neutral中性/contradiction矛盾)。
当然,还可以用其他数据集,这两个数据集比较小,所以用它们,测评的时候速度比较快。本文的附录中,介绍了对比不同模型的理解与生成能力时,推荐使用的数据集。
总的来说,选什么尺寸的模型,根据任务的复杂度来确定,测评用的数据,则根据与目标任务的相似程度确定。
3.2 模型评估
找到 Internlm 的配置文件,即 /data/coding/utils/opencompass/opencompass/configs/models/hf_internlm/lmdeploy_internlm2_5_1_8b_chat.py
,按如下方式修改:
from opencompass.models import TurboMindModelwithChatTemplatemodels = [dict(type=TurboMindModelwithChatTemplate,abbr='internlm2_5-1_8b-chat-turbomind',# path='internlm/internlm2_5-1_8b-chat',path='/data/coding/EmotionalDialogue/model_weights/Shanghai_AI_Laboratory/internlm2_5-1_8b-chat',# engine_config=dict(session_len=16384, max_batch_size=16, tp=1),engine_config=dict(session_len=16384, max_batch_size=16, tp=1, cache_max_entry_count=0.4),gen_config=dict(top_k=1, temperature=1e-6, top_p=0.9, max_new_tokens=4096),max_seq_len=16384,max_out_len=4096,batch_size=16,run_cfg=dict(num_gpus=1),)
]
找到Qwen2.5-1.5B-Instruct的配置文件,即 /data/coding/utils/opencompass/opencompass/configs/models/qwen2_5/lmdeploy_qwen2_5_1_5b_instruct.py
,按如下方式修改:
from opencompass.models import TurboMindModelwithChatTemplatemodels = [dict(type=TurboMindModelwithChatTemplate,abbr='qwen2.5-1.5b-instruct-turbomind',path='/data/coding/model_weights/Qwen/Qwen2.5-1.5B-Instruct',# engine_config=dict(session_len=16384, max_batch_size=16, tp=1),engine_config=dict(session_len=16384, max_batch_size=16, tp=1, cache_max_entry_count=0.4),gen_config=dict(top_k=1, temperature=1e-6, top_p=0.9, max_new_tokens=4096),max_seq_len=16384,max_out_len=4096,batch_size=16,run_cfg=dict(num_gpus=1),)
]
找到qwen3的配置文件,qwen3 只有0.6B的配置文件,虽然没有1.7B的,但我们可以对0.6B的进行修改,即把 opencompass/opencompass/configs/models/qwen3/lmdeploy_qwen3_0_6b.py
,按如下方式修改:
from opencompass.models import TurboMindModelwithChatTemplate
from opencompass.utils.text_postprocessors import extract_non_reasoning_contentmodels = [dict(type=TurboMindModelwithChatTemplate,# abbr='qwen_3_0.6b_thinking-turbomind',abbr='qwen_3_1.7b_thinking-turbomind',# path='Qwen/Qwen3-0.6B',path='/data/coding/EmotionalDialogue/model_weights/Qwen/Qwen3-1.7B',# engine_config=dict(session_len=32768, max_batch_size=16, tp=1),engine_config=dict(session_len=32768, max_batch_size=16, tp=1, cache_max_entry_count=0.4),gen_config=dict(top_k=20, temperature=0.6, top_p=0.95, do_sample=True, enable_thinking=True),max_seq_len=32768,max_out_len=32000,batch_size=16,run_cfg=dict(num_gpus=1),pred_postprocessor=dict(type=extract_non_reasoning_content)),
]
上面三个配置文件,在引擎配置的时候,我都加了一个 cache_max_entry_count=0.4
,主要是为了防止 KV Cache 占用太大,导致显存溢出。但是加了 cache_max_entry_count=0.4
之后,由于缓存占比太小,推理速度下降,评估时间变长。如果你的GPU显存够大,那就不需要加,我自己用 24G 显存,不加的话仍然会报显存不足,最后调整cache_max_entry_count=0.6
,才顺利完成评估。(qwen3评估太花时间了,其他两个模型很快就完成了评估,偏偏qwen3花了将近一个小时,原因我暂时没找到)
进入到opencompass项目目录下,然后在终端输入:
python run.py --models lmdeploy_internlm2_5_1_8b_chat lmdeploy_qwen2_5_1_5b_instruct lmdeploy_qwen3_0_6b --datasets FewCLUE_bustm_gen FewCLUE_ocnli_fc_gen --debug
可以看到,qwen_3_1.7b 是这里的最强模型,从它们的发布时间来看,如果模型的尺寸相差不大,则越往后发布的模型,能力越强。
附录(对比不同模型理解与生成能力所用数据集)
要对比两个模型对中文的理解能力(语义、逻辑、推理)和生成能力(流畅性、连贯性、信息量),建议采用多维度、多任务的数据集组合。以下是按任务类型分类的推荐数据集及使用策略:
一、理解能力评测数据集
1. 语义理解 & 文本匹配
- BUSTM
- 任务:判断句子对是否语义相同(二分类)
- 例:
("今天天气不错", "今天天晴") → 相似
- 能力重点:近义词、句式转换识别能力
- AFQMC(蚂蚁金融语义匹配)
- 任务:金融场景的句子对分类
- 例:
("如何还款", "怎样还钱") → 相似
- 能力重点:领域适应性
2. 自然语言推理(NLI)
- OCNLI(原生中文推理)
- 任务:判断前提与假设的逻辑关系(三分类)
- 例:
前提:"手机电量不足"
→假设:"需要充电"
→ 蕴含 - 能力重点:逻辑推理、常识理解
- CMNLI(中文多体裁NLI)
- 任务:多领域文本推理(新闻/文学等)
- 能力重点:跨领域泛化性
3. 阅读理解
- CMRC 2018(中文机器阅读理解)
- 任务:从文章中提取答案(片段抽取)
- 例:文章:“北京是中国的首都”,问题:“中国首都是?” → 答案:“北京”
- 能力重点:信息定位精度
- C³(Choice-Context-Challenge)
- 任务:多选问答(需结合上下文推理)
- 能力重点:多步推理、排除干扰项
二、生成能力评测数据集
1. 开放域生成
- LCSTS(中文摘要生成)
- 任务:生成新闻短摘要
- 输入:长新闻文本 → 输出:1-3句摘要
- 评测指标:ROUGE-L(自动) + 人工流畅性评分
- AdGen(广告文案生成)
- 任务:根据商品属性生成广告文案
- 例:输入:“口红,色号#999,哑光质地” → 输出:“经典正红,高级雾面妆感”
- 评测指标:BLEU-4 + 信息完整性检查
2. 结构化生成
- FewCLUE_bustm_gen/ocnli_fc_gen(前文提及)
- 任务:将分类任务重构为文本生成
- 例:输入句子对 → 输出标签词(如“蕴含”)
- 评测指标:准确率(生成内容与标签的严格匹配)
3. 对话生成
- KdConv(知识驱动对话)
- 任务:基于知识图谱生成连贯多轮对话
- 能力重点:上下文一致性、知识注入能力
- STC(短文本对话)
- 任务:生成单轮回复
- 例:输入:“今天好热啊” → 输出:“来杯冰咖啡吧!”
- 评测指标:人工评分(相关性、新颖性)
三、高阶能力评测数据集
1. 常识推理
- CKB(Commonsense Knowledge Base)
- 任务:问答需结合常识(如"下雨天出门要带?" → “伞”)
- 能力重点:隐含知识调用能力
2. 数学推理
- Math23K
- 任务:解中文数学应用题
- 例:“小明有5个苹果,吃了2个,还剩几个?” → 生成:“3”
- 评测指标:答案精确匹配
3. 长文本生成
- CPED(中国古典诗歌生成)
- 任务:根据主题生成七言诗
- 能力重点:韵律控制、意象组织
四、评测策略建议
- 理解能力优先级任务:
- 先跑 OCNLI/CMNLI(推理)、CMRC 2018(阅读理解)
- 模型需输出结构化结果(标签/答案),用准确率定量对比。
- 生成能力优先级任务:
- 重点测 LCSTS(摘要)、AdGen(文案)、KdConv(对话)
- 结合自动指标(ROUGE, BLEU) + 人工评测(随机采样100条,评估流畅性/逻辑性)。
- 小样本场景测试:
- 使用 FewCLUE_bustm_gen(16个训练样本),观察模型在低资源下的泛化能力。
- 易用性工具:
- 使用 Hugging Face Datasets 加载数据(示例代码):
from datasets import load_dataset dataset = load_dataset("clue", "cmnli") # 加载CMNLI
- 使用 Hugging Face Datasets 加载数据(示例代码):
五、注意事项
- 模型适配性:
- 若对比模型为纯生成架构(如GPT-3),优先选生成式任务(LCSTS, AdGen);
- 若为理解-生成混合架构(如T5),可覆盖所有任务。
- 公平性控制:
- 确保输入长度、训练轮次、提示词(Prompt)设计完全一致。
- 中文特有难点:
- 在数据中加入测试中文特有表达的样本,如:
- 成语理解("画蛇添足"→生成解释)
- 多音字歧义(“行(xíng)业” vs “行(háng)列”)
- 在数据中加入测试中文特有表达的样本,如:
推荐基准组合:
理解能力:OCNLI + CMRC 2018 + CKB
生成能力:LCSTS + AdGen + KdConv
高阶挑战:Math23K + CPED
此组合覆盖语义、推理、生成、常识、数学、文艺六大维度,可全面反映模型的中文能力边界。