ACP笔记(二):大模型的问答工作流程及影响大模型内容生成的随机生成参数
大模型的问答工作流程
下面以“ACP is a very”为输入文本向大模型发起一个提问,下图展示从发起提问到输出文本的完整流程。
大模型问答流程分为5个阶段:
-
第一阶段:输入文本分词化
分词(Token)是大模型处理文本的基本单元,通常是词语,词组或者符号。我们需要将"ACP is a very"这个句子分割成更小且具有独立语义的词语(Token),并且为每个Token分配一个ID。下图以通义千问示例:(通义千问的tokenizer实现细节:Tokenization)
-
第二阶段:Token向量化
计算机只能理解数字,无法直接理解Token的含义。因此需要将Token进行数字化转换(即转化为向量),使其可以被计算机所理解。Token向量化会将每个Token转化为固定维度的向量。 -
第三阶段:大模型推理
大模型通过大量已有的训练数据来学习知识,当我们输入新内容,比如“ACP is a very”时,大模型会结合所学知识进行推测。它会计算所有可能Token的概率,得到候选Token的概率集合。最后,大模型通过计算选出一个Token作为下一个输出。 -
第四阶段:输出Token
由于大模型会根据候选Token的概率进行随机挑选,这就会导致“即使问题完全相同,每次的回答都略有不同”。为了控制生成内容的随机性,目前普遍是通过temperature和top_p这来调整的。
例如,下图中大模型输出 的第一个候选Token集合为“informative(50%)”、“fun(25%)”、“enlightening(20%)”、“boring(5%)”。通过top_p参数,将影响大模型在候选Token集合中的选择倾向,如选择概率最高为“informative”。
特别地,“informative”会将继续送入大模型,用于生成候选Token。这个过程被称为自回归,它会利用到输入文本和已生成文本的信息。大模型采用这种方法依次生成候选Token。 -
输出文本
循环第三阶段和第四阶段的过程,直到输出特殊Token(如,end of sentence,即“句子结束”标记)或输出长度达到阈值,从而结束本次问答。大模型会将所有生成的内容输出。当然你可以使用大模型的流式输出能力,即预测一些Token立即进行返回。这个例子最终输出“ACP is a very informative course.”。
影响大模型内容生成的随机生成参数
假设在一个对话问答场景中,用户提问为:“在大模型ACP课程中,你可以学习什么?”。为了模拟大模型生成内容的过程,我们预设了一个候选Token集合,这些Token分别为:“RAG”、“提示词”、“模型”、“写作”、“画画”。大模型会从这5个候选Token中选择一个作为结果输出(next-token),如下所示。
用户提问:在大模型ACP课程中,你可以学习什么?
大模型回答:RAG
在这个过程中,有两个重要参数会影响大模型的输出:temperature和top_p,它们用来控制大模型生成内容的随机性和多样性。下面介绍这两个参数的工作原理和使用方式。
temperature:调整候选Token集合的概率分布
在大模型生成下一个(next-token)之前,它会先为候选Token计算一个初始概率分布。这个分布表示每个候选Token作为next-token的概率。temperature是一个调节器,它通过改变候选Token的概率分布,影响大模型的内容生成。通过调节这个参数,你可以灵活地控制生成文本的多样性和创造性。
为了更直观地理解,下图展示了不同temperature值对候选Token概率分布的影响。
图中的低、中、高温度基于通义千问Max模型的范围[0,2]划分。
由上图可知,温度从低到高(0.1->0.7->1.2),概率分布从陡峭趋于平滑,候选Token“RAG”从出现的概率0.8->0.6->0.3,虽然依然是出现概率最高的,但是已经和其它的候选Token概率接近 ,最终输出也会从相对固定到逐渐多样化。
针对不同使用场景,可参考以下建议设置temperature参数:
-
明确答案(生成代码):调低温度
-
创意多样(如广告文案):调高温度
-
无特殊需求:使用默认温度(通常为中温度范围)
需要注意的是当temperature=0时,虽然会最大限度降低随机性,但无法保证每次输出完全一致。下方示例在temperatur为0.7和1.9时的区别。如果想深入了解,可查阅(temperature的底层算法实现)
temprature为0.7
import timedef get_qwen_stream_response(user_prompt, system_prompt, temperature, top_p):response = client.chat.completions.create(model="qwen-max",messages=[{"role": "system", "content": system_prompt},{"role": "user", "content": user_prompt}],temperature=temperature,top_p=top_p,stream=True)for chunk in response:yield chunk.choices[0].delta.content# temperature,top_p的默认值使用通义千问Max模型的默认值
def print_qwen_stream_response(user_prompt, system_prompt, temperature=0.7, top_p=0.8, iterations=10):for i in range(iterations):print(f"输出 {i + 1} : ", end="")## 防止限流,添加延迟time.sleep(0.5)response = get_qwen_stream_response(user_prompt, system_prompt, temperature, top_p)output_content = ''for chunk in response:output_content += chunkprint(output_content)# 通义千问Max模型:temperature的取值范围是[0, 2),默认值为0.7
# 设置temperature=0
print_qwen_stream_response(user_prompt="马也可以叫做", system_prompt="请帮我续写内容,字数要求是4个汉字以内。", temperature=0)
输出 1 : 骏马
输出 2 : 骏马
输出 3 : 骏马
输出 4 : 骏马
输出 5 : 骏马
输出 6 : 骏马、坐骑。
输出 7 : 骏马
输出 8 : 骏马
输出 9 : 骏马
输出 10 : 骏马
temperature为1.3
# 设置temperature=1.9
print_qwen_stream_response(user_prompt="马也可以叫做", system_prompt="请帮我续写内容,字数要求是4个汉字以内。", temperature=1.9)
输出 1 : 骏马、坐骑。
输出 2 : 骏马。
输出 3 : 骏马
输出 4 : 马儿
输出 5 : 千里马。
输出 6 : 良驹、骏马
输出 7 : 骏马
输出 8 : 骏马、良驹
输出 9 : 骏马、驹。
输出 10 : 良驹或骏马。
从实验中可以明显观察到,温度值越高,模型生成的内容更具变化和多样性
top_p:控制候选Token集合的采样范围
top_p是一种筛选机制,用于从候选Token集合中选出符合特定条件的“小集合”。具体方法是:按概率从高到低排序,选取累计概率达到设定阈值的Token组成 新的候选集合,从而缩小选择范围。
下图展示了不同top_p值对候选Token集合的采样效果。
图示中蓝色部分表示累计概率达到top_p阈值(如0.5或0.9)的Token,它们组成新的候选集合;灰色部分则是未选中的Token。
当top_p=0.5时,模型优先选择最高概率的Token,即“RAG”;而当top_p=0.9时,模型会在“RAG”、“提示词”、“模型”这三个Token中随机选择一个生成输出。
由此可见,top_p值对大模型生成 内容的影响可总为:
- 值越大:候选范围越广,内容更多样化,适合创意写作、诗生成等场景。
- 值越小:候选范围越窄,输出更稳定,适合新闻初稿,代码生成等需要明确答案的场景。
- 极小值(如:0.00001):理论上模型只选择概率最高的Token,输出非常稳定。但实际上,由于分布式系统、模型输出的额外调整等因素可能引入的微小随机性,仍无法保证每次输出完全一致。
下面体验top_p的效果。通过调整top_p值,对同一问题提问10次,观察回答内容的波动情况。
# 通义千问Max模型:top_p取值范围为(0,1],默认值为0.8。
# 设置top_p=0.001
print_qwen_stream_response(user_prompt="为一款智能游戏手机取名,可以是", system_prompt="请帮我取名,字数要求是4个汉字以内。", top_p=0.001)
输出 1 : "智玩无界"
输出 2 : "智玩无界"
输出 3 : "智玩无界"
输出 4 : "智玩无界"
输出 5 : "智玩无界"
输出 6 : "智玩无界"
输出 7 : "智玩无界"
输出 8 : "智玩无界"
输出 9 : "智玩无界"
输出 10 : "智玩无界"
# 设置top_p=0.8
print_qwen_stream_response(user_prompt="为一款智能游戏手机取名,可以是",system_prompt="请帮我取名,字数要求是4个汉字以内。", top_p=0.8)
输出 1 : "智玩无界" 这个名字既突出了手机的智能化特点,又强调了游戏体验的无限可能性。"智"代表智能,"玩"代表游戏,"无界"则寓意着使用这款手机玩游戏时,用户可以享受到无边界、无限制的乐趣与自由。同时,“无界”也暗示了这款手机在性能上没有界限,能够满足各种游戏需求。整体而言,这个名字简洁明了,易于记忆,并且富有吸引力。
输出 2 : "智玩无限" 这个名字既突出了手机的智能特性,又强调了游戏的乐趣无边界。希望你喜欢!如果需要更多的建议,请随时告诉我。
输出 3 : "智游者Z1"
输出 4 : "智游者Z1"
输出 5 : "智玩无界" 这个名字既突出了手机的智能特性,也强调了游戏功能带来的无限乐趣。同时,“无界”二字还寓意着使用这款手机可以打破常规限制,享受更加自由畅快的游戏体验。希望你喜欢!如果需要进一步调整或有其他要求,请随时告诉我。
输出 6 : "智玩无界"
输出 7 : "智游精灵"
输出 8 : "智游精灵"
输出 9 : "智玩魔方"
输出 10 : "智游精灵"
根据实验结果可以发现,top_p值越高,大模型的输出结果随机性越高。
小结
- 是否需要同时调整temperature和top_p?
为了确保生成 内容的可控性,vfyq不要同时调整top_p和temperature,同时调整可能导致输出结果不可预测。你可以优先调整其中一种参数,观察其对结果的影响,再逐步微调。
知识延展:top_k
在通义千问系列模型中,参数top_k也有类似top_p的能力,可查阅通义千问API文档。它是一种采样机制,从概率排名前k的Token中随机 选择一个进行输出。一般来说,top_k越大,生成内容越多样;top_k越小,内容则更固定。当top_k设置为1时,模型仅选择概率最高的Token,输出会更加稳定,但也会导致缺乏变化和创意。
知识延展:seed
在通义千问系列模型中,参数seed也支持控制生成内容的确定性,可查阅通义千问API文档。在每次模型调用时传入相同的seed值,并保持其他参数不变,模型会尽最大可能返回相同结果,但无法保证每次结果完全致。
- 设置temperature、top_p、seed控制大模型输出,为何仍存在随机性?
即使将temprature设置为0、top_p设置为极小值(如0.00001),并使用相同的seed,同一个问题的生成结果仍可能出现不一致。这是因为一些复杂因素可能引入微小的随机性,例如大模型运行在分布式系统中,或模型输出引入了优化。
举个例子:分布式系统就像用不同的机器切面包。虽然每台机器都按照相同的设置操作,但由于设备之间的细微差异,切出来的而面包片可能还是会略有不同。