使用LLAMA-2和LangChain创建自审评论系统

2023年09月19日 由 alex 发表 982 0

源码和模型


本文是基于我使用模型meta-llama/Llama-2–7b-chat-hf的笔记本。然而,还有两个笔记本实现了相同的解决方案。其中一个笔记本中,我使用了Hugging Face上可用的EleutherAI/gpt-j-6b模型,在另一个笔记本中,我使用了可以通过API访问的OpenAI模型。


使用Hugging Face的LLAMA-2


LLAMA-2是一个开源模型,但是Meta要求我们注册以授予我们对这个模型系列的访问权限。请求是通过Meta网页进行的,可以从Hugging Face的模型首页访问该网页。


1


该请求适用于Llama-2系列中的所有型号。这意味着我们将被授予对任何型号尺寸的访问权限。在请求中必须使用与我们Hugging Face账户关联的相同电子邮件。


2


收到访问确认,即可从Hugging Face网站访问该模式。请记住,你需要使用在Meta页面上请求权限时使用的相同电子邮件地址注册。


安装并加载所需的库


笔记本存储在Colab中,但我已经订阅了Colab Pro,所以可能你在该环境中无法运行它,除非你也订阅了Colab Pro。


如果遇到任何问题,该笔记本已准备在本地机器或具有Silicon芯片的Mac上的CUDA环境中运行。


在任何情况下,与OpenAI API相比,LLAMA-2的每个模型调用的执行时间不如立即。每个模型调用可能需要几分钟,具体取决于你的GPU。


我们将在Colab中安装所需的库。但如果你在自己的环境中工作并且已经使用过大型语言模型,那么你可能已经安装了langchain和transformers。


#Install de LangChain and openai libraries.
%pip install langchain
%pip install transformers
%pip install accelerate
%pip install xformers


The transformers library由Hugging Face维护,提供了访问多种开源模型和与之一起工作的工具。它是整个开源大规模语言模型革命的基础库。而Langchain则是一个较新的增加,它是我们将模型链接在一起或与不同工具配合使用的库。


现在我们可以导入所有必要的库。


from langchain import PromptTemplate
from langchain.chains import LLMChain
from langchain.llms import HuggingFacePipeline
import transformers
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, AutoModelForSeq2SeqLM
import torch
from torch import cuda, bfloat16


我已经将它们分为三个模块:来自LangChain库的类、来自transformers的类,以及一些torch库。让我们快速浏览一下每个模块:


1. PrompTemplate:允许我们创建一个包含变量的文本模板。PromptTemplate将用我们提供的值替换这些变量的值。帮助我们构建动态提示,结果将传递给模型。


2. LLMChain:这使我们能够连接使用LangChain创建的链。我们将创建两个非常简单的链,由提示和模型组成。使用LLMChain,我们将结合两者,使它们可以相互通信。


3. Transformers:我们在这里导入的类用于加载模型、其标记器并创建管道。标记器将文本转化为模型可以理解的嵌入,它还可以反向操作,将模型返回的嵌入转化为用户可以理解的文本。管道类允许我们针对它们预训练的特定任务使用模型。


4. Cuda、Bfloat16:这些是将模型加载到GPU上并提高其性能所必需的。


从Hugging Face加载LLAMA-2


加载LLAMA-2与Hugging Face上的大多数模型有些特殊和不同。因为这是一个我们需要获得访问权限的模型,所以我们需要登录到我们的Hugging Face账户才能使用它。


要登录到Hugging Face环境,你将需要一个访问令牌。你可以从你的Hugging Face配置文件的设置选项中获取它,在那里你将找到访问令牌选项。


3


%pip install huggingface_hub
hf_key = "YOUR-HF-KEY-HERE"
!huggingface-cli login --token $hf_key


通过这段代码,我们正在安装huggingface_hub库,该库用于使用我们的访问密钥登录到hugging face。

hugging face帐户的电子邮件必须与在Meta页面上请求的电子邮件相同。


#In a MAC Silicon the device must be 'mps'
# device = torch.device('mps') #to use with MAC Silicon
device = f'cuda:{cuda.current_device()}' if cuda.is_available() else 'cpu'


要在Colab或带有NVIDIA GPU的机器上运行,请保持代码不变。如果你想在搭载了Silicon芯片的Mac上加载模型, 你需要使用加载'mps'设备的语句。


现在,让我们加载模型。


#You can try with any llama model, but you will need more GPU and memory as you increase the size of the model.
model_id = "meta-llama/Llama-2-7b-chat-hf"
#model_id = "meta-llama/Llama-2-7b-hf"


我选择的模型是Llama-2–7b-chat-hf,这是Llama-2的7b版本,经过预训练以在聊天场景中表现良好。你可以尝试LLAMA系列的任何模型,但请记住,如果选择更大的模型,你将需要更多的内存和最好的处理能力。


# begin initializing HF items, need auth token for these
model_config = transformers.AutoConfig.from_pretrained(
    model_id,
    use_auth_token=hf_key
)


LLAMA系列附带了一个预设置存储在Hugging Face中,我们需要在加载模型时检索它以备后用。Hugging Face上的大多数模型都没有这种预配置,所以如果你之前有使用其他模型的经验,可能对这种工作方式不太熟悉。


model = AutoModelForCausalLM.from_pretrained(
    model_id,
    trust_remote_code=True,
    config=model_config,
    device_map='auto',
    use_auth_token=hf_key
)
model.eval()


在前两个参数中,我们指定要加载的模型的名称,该名称存储在变量model_id中,并且我们通过调用transformers.AutoConfig.from_pretrained检索到的配置。


我们指示它使用最合适的设备。如果我们想要强制其使用新实例化的GPU,我们可以将其传递给分配的编号。要检查它在哪个插槽中,我们只需要打印device的内容,然后我们将看到其占用的名称和位置。


device


‘cuda:0’


现在我们已经将模型加载到GPU上,并存储在变量model中。


接下来的步骤是加载tokenizer并创建pipeline。由于加载tokenizer可能非常耗时,我更喜欢在笔记本中的单独单元格中加载它,这样如果我想对pipeline进行更改,就不需要再执行它了。


tokenizer = AutoTokenizer.from_pretrained(model_id,
                                          use_aut_token=hf_key) 


pipe = pipeline(
    "text-generation",
    model=model,
    tokenizer=tokenizer,
    max_new_tokens=128,
    temperature=0.3,
    repetition_penalty=1.1,
    return_full_text=True,
    device_map='auto'
)
assistant_llm = HuggingFacePipeline(pipeline=pipe)


这样,我们创建了执行模型的流水线。正如你所见,我们为它提供了任务:文本生成、模型和标记器。这些参数不需要太多解释;我们来看看其他参数:


1. max_new_tokens:表示模型生成的文本的最大长度。它在达到这个数字之前可能会停止,但不会超过它。


2. temperature:这个参数控制模型生成的回应的随机性。数值越大,变化越大。如果你用模型生成代码,可以保持为0;如果你的用例需要高度想象力但不一定准确的回应,可以尝试更高的值,如1.0。我将它设置为0.3,以便模型提供更多富有想象力的例子。尝试不同的值,你会看到随着数值增大,回应的变化更多。


3. repetition_penalty:在某些情况下,模型在生成回应时可能陷入循环,导致无休止且毫无意义的对话,直到达到max_tokens。这个参数通过惩罚词语重复来防止这种情况发生。


4. return_full_text:为了与LangChain正常工作,我们需要模型返回完整的回应,不截断或裁剪。


这样,assistant_llm将包含我们的流水线,可以随时使用。


创建我们的第一个链


我们的第一个链将负责为用户的评论拟定一个初始回应。它包含一个提示和刚刚加载的流水线。


首先,我们将使用一个模板和我们提供的变量构建提示,然后将其传递给模型,模型将执行提示的指令。


# Instruction how the LLM must respond the comments,
assistant_template = """
You are {sentiment} social media post commenter, you will respond to the following post
Post: "{customer_request}"
Comment:
"""
#Create the prompt template to use in the Chain for the first Model.
assistant_prompt_template = PromptTemplate(
    input_variables=["sentiment", "customer_request"],
    template=assistant_template
)


提供的提示文本内容保存在变量assistant_template中。正如你所见,它包含两个参数:情感(sentiment)和客户请求(customer_request)。情感参数设置助手在创建回答时所采用的个性。客户请求参数包含了助手应该回应的文本。


提示模板使用之前从langchain库中导入的PromptTemplate创建。该模板接收输入参数,这些参数连同接收到的文本将形成要发送给模型的提示。


现在我们可以使用LangChain创建第一个链。正如我之前提到的,这个链只会将提示模板和模型连接起来。换句话说,它将接收参数,使用assistant_prompt_template构建提示,一旦构建完成,将其传递给模型。


assistant_chain = LLMChain(
    llm=assistant_llm,
    prompt=assistant_prompt_template,
    output_key="assistant_response",
    verbose=False
)
#the output of the formatted prompt will pass directly to the LLM.


这个链条将作为我们小型评论系统的第一部分。我们将与包含第二个模型的链条一起使用,负责对第一个模型的回应进行审核。但是我们也可以单独运行它。


让我们测试一下这个链条!


# This the customer comment in the forum moderated by the agent.
# feel free to update it.
customer_request = """Your product is a piece of shit. I want my money back!"""
# Our assistatnt working in 'nice' mode.
assistant_response=create_dialog(customer_request, "nice")
print(f"assistant response: {assistant_response}")


助理回复:"很抱歉听到你对我们的产品不满意!你可以告诉我更多关于你不喜欢的部分吗?也许我们可以帮你解决问题或提供退款。你的反馈对我们非常重要。"


#Our assistant running in rude mode.
assistant_response = create_dialog(customer_request, "rude")
print(f"assistant response: {assistant_response}")


助理回复:“很抱歉听到你对我们的产品不满意!你可以告诉我们更多你不喜欢的地方吗?我们非常重视你的反馈,并乐意进行改进。请私信给我们以获得退款或进一步讨论。”


事实上,获得的两个回答非常相似并且完全可被发布。很明显,Llama-2是一个经过训练以提供礼貌回答的现代模型。


然而,第二个回答的风格稍微更正式。


创建主持人链


就像对助理模型创建提示模板一样,我们需要为该链条创建一个提示模板。然而,这一次它只会收到一个参数:由第一个模型生成的回复。


#The moderator prompt template
moderator_template = """
You are the moderator of an online forum, you are strict and will not tolerate any negative comments.
You will look at this next comment and, if it is negative, you will transform it to positive. Avoid any negative words.
If it is nice, you will let it remain as is and repeat it word for word.
###
Original comment: {comment_to_moderate}
###
Edited comment:"""
# We use the PromptTemplate class to create an instance of our template that will use the prompt from above and store variables we will need to input when we make the prompt.
moderator_prompt_template = PromptTemplate(
    input_variables=["comment_to_moderate"],
    template=moderator_template
)


提示词更长,但机制相同:一段充满参数的文本。在这种情况下,参数是一句话,将成为第一链的响应。


moderator_llm = assistant_llm
#We build the chain for the moderator.
moderator_chain = LLMChain(
    llm=moderator_llm, prompt=moderator_prompt_template, verbose=False
)  # the output of the prompt will pass to the LLM.


现在我们可以执行这个第二个链条,并将从第一个上运行得到的结果传递给它。


# To run our chain we use the .run() command
moderator_says = moderator_chain.run({"comment_to_moderate": assistant_response})
print(f"moderator_says: {moderator_says}")


moderator_says:“感谢你分享你对我们产品的想法!我们感谢你的反馈,并一直在寻找改进的方法。你的意见对我们来说非常宝贵。如果你能提供有关你喜欢或不喜欢什么的更多详细信息,我们将不胜感激。再次感谢你!”


创建一个调节器连接两个LangChain链


让我们将这两个链一起工作,并构建我们的系统;我将再次创建它们,因为我想要将Verbose参数修改为True,这样在执行链时我们就可以看到中间步骤。


#The optput of the first chain must coincide with one of the parameters of the second chain.
#The parameter is defined in the prompt_template.
assistant_chain = LLMChain(
    llm=assistant_llm,
    prompt=assistant_prompt_template,
    output_key="comment_to_moderate",
    verbose=False,
)
#verbose True because we want to see the intermediate messages.
moderator_chain = LLMChain(
    llm=moderator_llm,
    prompt=moderator_prompt_template,
    verbose=True
)


如果你注意到,第一个链条的输出:comment_to_moderate,与第二个链条的提示模板中的参数一致。这样,在将它们合并时,可以自动将第一个链条的结果传递给第二个链条。


要创建连接两个模型的链条,我们需要合并包含提示和模型的两个链条。为此,我们将使用LangChain库中的SequentialChain类。


from langchain.chains import SequentialChain
# Creating the SequentialChain class indicating chains and parameters.
assistant_moderated_chain = SequentialChain(
    chains=[assistant_chain, moderator_chain],
    input_variables=["sentiment", "customer_request"],
    verbose=True,
)


让我们测试这一连串。


# We can now run the chain.
assistant_moderated_chain.run({"sentiment": "rude", "customer_request": customer_request})


进入新的SequentialChain链...


进入新的LLMChain链...


格式化后的提问:


你是一个在线论坛的版主,你要求严格,不容忍任何负面评论。你将查看下面的评论,如果它是负面的,你将把它转化为积极的。避免使用任何负面词汇。如果评论很好,你会让它保持原样,并逐字重复。


原评论:“很抱歉听到你对我们的产品不满意!你能告诉我们更多你不喜欢的地方吗?也许我们可以帮助解决问题或提供退款。没有必要粗鲁,让我们携手寻找解决方案。” ### 编辑后的评论:


链结束。“感谢你对我们产品的看法!我们非常感谢你的反馈,并将尽力解决你可能有的任何疑虑。你的意见帮助我们改进并提供更好的产品。让我们共同寻找解决方案!”


这个审查工作得非常完美!在原始评论中,第一个模型有一个轻微的失当言论,而模型告诉用户不需要无礼。第二个模型注意到了这一点,并在不改变其意义的情况下修改了评论。


结论


我们创建自动化评论审查系统的过程非常简单,结果令人满意。


审查系统的主要组成部分是两个链条,由一个模型和一个提示模板组成。这些链条非常简单,主要是构建提示并将其传递给模型。


一旦我们有了这两个链条,我们只需要将它们组合起来。我们只需要确保第一个链条的输出与第二个链条的输入匹配。


通过这些简单的步骤,我们创建了一个可以自动回复用户并比允许单个模型在没有任何审查的情况下回复要安全得多的系统。


请记住,即使 ChatGPT 也可以被黑客入侵,提供不符合政治正确的回复。我们都知道 BadGPT 的例子,它成功生成了高度不合适的回复。


总之,通过将负责最终回复的模型与用户输入分离,我们显著降低了系统产生粗鲁或不恰当回复的可能性。




文章来源:https://medium.com/gitconnected/create-a-self-moderated-comment-system-with-llama-2-and-langchain-656f482a48be
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消