小北的字节跳动青训营与LangChain实战课:深入解析模型I/O与提示模板(持续更新中~~~)
前言
最近,字节跳动的青训营再次扬帆起航,作为第二次参与其中的小北,深感荣幸能借此机会为那些尚未了解青训营的友友们带来一些详细介绍。青训营不仅是一个技术学习与成长的摇篮,更是一个连接未来与梦想的桥梁~
小北的青训营 X MarsCode 技术训练营——AI 加码,字节跳动青训营入营考核解答(持续更新中~~~)-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118编辑https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118
小北的字节跳动青训营与 LangChain 实战课:探索 AI 技术的新边界(持续更新中~~~)-CSDN博客编辑https://blog.csdn.net/Zhiyilang/article/details/143454165https://blog.csdn.net/Zhiyilang/article/details/143454165
小北的字节跳动青训营与LangChain系统安装和快速入门学习(持续更新中~~~)。-CSDN博客编辑https://blog.csdn.net/Zhiyilang/article/details/143455380https://blog.csdn.net/Zhiyilang/article/details/143455380
小北的字节跳动青训营用LangChain打造“易速鲜花”内部员工知识库问答系统(持续更新中~~~)-CSDN博客编辑https://blog.csdn.net/Zhiyilang/article/details/143456544https://blog.csdn.net/Zhiyilang/article/details/143456544哈喽哈喽,这里是是zyll~,北浊.欢迎来到小北的 LangChain 实战课学习笔记!
在这个充满变革的时代,技术的每一次进步都在推动着世界的快速发展。字节跳动的青训营,作为技术人才培养的重要平台,再次扬帆起航,为怀揣梦想的技术爱好者们提供了一个学习和成长的摇篮。作为青训营的一员,小北深感荣幸能够借此机会,为大家详细介绍青训营的精彩内容,并分享 LangChain 实战课的学习心得,希望能够帮助大家更好地理解和应用最前沿的 AI 技术。
今天小北将带友友们一起探索LangChain框架中的核心组件——模型(Model)。LangChain是一个强大的框架,它允许我们通过API调用大模型来解决具体问题。在这篇文章中,我们将详细讲解模型I/O(Input/Output)以及如何构建一个能够自动生成鲜花文案的应用程序。
LangChain实战课:深入解析模型I/O与提示模板
模型I/O:输入、调用与输出解析
在LangChain中,对模型的使用过程可以拆解为三个关键环节:输入提示(Format)、调用模型(Predict)和输出解析(Parse)。这三个环节形成了一个整体,被称为Model I/O。
- 输入提示:
- 提示模板:LangChain允许我们创建模板,根据实际需求动态选择不同的输入。这些模板能够针对特定的任务和应用调整输入,从而优化模型的输出。
- Prompt Engineering:提示工程的核心在于构建清晰、明确的指示,让模型能够更准确地理解并回答我们的问题。
- 调用模型:
- LangChain支持多种语言模型,包括大语言模型(LLM)、聊天模型(Chat Model)和文本嵌入模型(Embedding Model)。
- 通过LangChain的通用接口,我们可以轻松地调用不同的语言模型,而无需为每种模型编写特定的代码。
- 输出解析:
- LangChain提供了从模型输出中提取信息的功能,通过输出解析器,我们可以精确地从模型的输出中获取需要的信息。
- 输出解析器还能够将非结构化文本转换为程序可以处理的结构化数据。
构建提示模板
这里,我们希望为销售的每一种鲜花生成一段简介文案,那么每当你的员工或者顾客想了解某种鲜花时,调用该模板就会生成适合的文字。这个提示模板的生成方式如下:
# 导入LangChain中的提示模板
from langchain.prompts import PromptTemplate
# 创建原始模板
template = """您是一位专业的鲜花店文案撰写员。\n
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
"""
# 根据原始模板创建LangChain提示模板
prompt = PromptTemplate.from_template(template)
# 打印LangChain提示模板的内容
print(prompt)
提示模板的具体内容如下:
input_variables=['flower_name', 'price']
output_parser=None partial_variables={}
template='/\n您是一位专业的鲜花店文案撰写员。
\n对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?\n'
template_format='f-string'
validate_template=True
这个模板包含两个变量:{flower_name}
和 {price}
,它们将在实际使用时被具体的值替换。
调用语言模型
LangChain中支持的模型有三大类。
- 大语言模型(LLM) ,也叫Text Model,这些模型将文本字符串作为输入,并返回文本字符串作为输出。Open AI的text-davinci-003、Facebook的LLaMA、ANTHROPIC的Claude,都是典型的LLM。
- 聊天模型(Chat Model),主要代表Open AI的ChatGPT系列模型。这些模型通常由语言模型支持,但它们的 API 更加结构化。具体来说,这些模型将聊天消息列表作为输入,并返回聊天消息。
- 文本嵌入模型(Embedding Model),这些模型将文本作为输入并返回浮点数列表,也就是Embedding。而文本嵌入模型如OpenAI的text-embedding-ada-002,我们之前已经见过了。文本嵌入模型负责把文档存入向量数据库,和我们这里探讨的提示工程关系不大。
然后,我们将调用语言模型,让模型帮我们写文案,并且返回文案的结果。
我们使用这个提示模板来生成提示,并将其输入到大语言模型中。例如,对于玫瑰:
# 设置OpenAI API Key
import os
os.environ["OPENAI_API_KEY"] = '你的Open AI API Key'# 导入LangChain中的OpenAI模型接口
from langchain_openai import OpenAI
# 创建模型实例
model = OpenAI(model_name='gpt-3.5-turbo-instruct')
# 输入提示
input = prompt.format(flower_name=["玫瑰"], price='50')
# 得到模型的输出
output = model.invoke(input)
# 打印输出内容
print(output)
模型返回的输出可能是:“让你心动!50元就可以拥有这支充满浪漫气息的玫瑰花束,让TA感受你的真心爱意。”
让你心动!50元就可以拥有这支充满浪漫气息的玫瑰花束,让TA感受你的真心爱意。
复用提示模板,我们可以同时生成多个鲜花的文案:
# 导入LangChain中的提示模板
from langchain import PromptTemplate
# 创建原始模板
template = """您是一位专业的鲜花店文案撰写员。\n
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
"""
# 根据原始模板创建LangChain提示模板
prompt = PromptTemplate.from_template(template)
# 打印LangChain提示模板的内容
print(prompt)# 设置OpenAI API Key
import os
os.environ["OPENAI_API_KEY"] = '你的Open AI API Key'# 导入LangChain中的OpenAI模型接口
from langchain import OpenAI
# 创建模型实例
model = OpenAI(model_name='gpt-3.5-turbo-instruct')# 多种花的列表
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]# 生成多种花的文案
for flower, price in zip(flowers, prices):# 使用提示模板生成输入input_prompt = prompt.format(flower_name=flower, price=price)# 得到模型的输出output = model.invoke(input_prompt)# 打印输出内容print(output)
模型的输出如下:
这支玫瑰,深邃的红色,传递着浓浓的深情与浪漫,令人回味无穷!
百合:美丽的花朵,多彩的爱恋!30元让你拥有它!
康乃馨—20元,象征爱的祝福,送给你最真挚的祝福。
https://huggingface.co/joinhttps://huggingface.co/join
上面的代码是直接使用Open AI和带有 {} 占位符的提示语,同时生成了三种鲜花的文案。看起来也是相当简洁。 下面,我们用完全相同的提示模板来生成提示,并发送给HuggingFaceHub中的开源模型来创建文案。(注意:需要注册HUGGINGFACEHUB_API_TOKEN)
# 导入LangChain中的提示模板
from langchain.prompts import PromptTemplate
# 创建原始模板
template = """You are a flower shop assitiant。\n
For {price} of {flower_name} ,can you write something for me?
"""
# 根据原始模板创建LangChain提示模板
prompt = PromptTemplate.from_template(template)
# 打印LangChain提示模板的内容
print(prompt)
import os
os.environ['HUGGINGFACEHUB_API_TOKEN'] = '你的HuggingFace API Token'
# 导入LangChain中的OpenAI模型接口
from langchain_community.llms import HuggingFaceHub
# 创建模型实例
model= HuggingFaceHub(repo_id="google/flan-t5-large")
# 输入提示
input = prompt.format(flower_name=["rose"], price='50')
# 得到模型的输出
output = model(input)
# 打印输出内容
print(output)
输出:
i love you
真是一分钱一分货,当我使用较早期的开源模型T5,得到了很粗糙的文案 “i love you”(哦,还要注意T5还没有支持中文的能力,我把提示文字换成英文句子,结构其实都没变)。
当然,这里我想要向你传递的信息是:你可以重用模板,重用程序结构,通过LangChain框架调用任何模型。如果你熟悉机器学习的训练流程的话,这LangChain是不是让你联想到PyTorch和TensorFlow这样的框架——模型可以自由选择、自主训练,而调用模型的框架往往是有章法、而且可复用的。
因此,使用LangChain和提示模板的好处是:
- 代码的可读性:使用模板的话,提示文本更易于阅读和理解,特别是对于复杂的提示或多变量的情况。
- 可复用性:模板可以在多个地方被复用,让你的代码更简洁,不需要在每个需要生成提示的地方重新构造提示字符串。
- 维护:如果你在后续需要修改提示,使用模板的话,只需要修改模板就可以了,而不需要在代码中查找所有使用到该提示的地方进行修改。
- 变量处理:如果你的提示中涉及到多个变量,模板可以自动处理变量的插入,不需要手动拼接字符串。
- 参数化:模板可以根据不同的参数生成不同的提示,这对于个性化生成文本非常有用。
那我们就接着介绍模型 I/O的最后一步,输出解析。
输出解析与结构化数据
虽然上述输出看起来不错,但在实际应用中,我们可能希望获得结构化的数据。这时,输出解析器就派上了用场。
比如说,在这个文案中,如果你希望模型返回两个字段:
- description:鲜花的说明文本
- reason:解释一下为何要这样写上面的文案
下面,我们就通过LangChain的输出解析器来重构程序,让模型有能力生成结构化的回应,同时对其进行解析,直接将解析好的数据存入CSV文档。
# 导入OpenAI Key
import os
os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'# 导入LangChain中的提示模板
from langchain.prompts import PromptTemplate
# 创建原始提示模板
prompt_template = """您是一位专业的鲜花店文案撰写员。
对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?
{format_instructions}"""# 通过LangChain调用模型
from langchain_openai import OpenAI
# 创建模型实例
model = OpenAI(model_name='gpt-3.5-turbo-instruct')# 导入结构化输出解析器和ResponseSchema
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
# 定义我们想要接收的响应模式
response_schemas = [ResponseSchema(name="description", description="鲜花的描述文案"),ResponseSchema(name="reason", description="问什么要这样写这个文案")
]
# 创建输出解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)# 获取格式指示
format_instructions = output_parser.get_format_instructions()
# 根据原始模板创建提示,同时在提示中加入输出解析器的说明
prompt = PromptTemplate.from_template(prompt_template, partial_variables={"format_instructions": format_instructions}) # 数据准备
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]# 创建一个空的DataFrame用于存储结果
import pandas as pd
df = pd.DataFrame(columns=["flower", "price", "description", "reason"]) # 先声明列名for flower, price in zip(flowers, prices):# 根据提示准备模型的输入input = prompt.format(flower_name=flower, price=price)# 获取模型的输出output = model.invoke(input)# 解析模型的输出(这是一个字典结构)parsed_output = output_parser.parse(output)# 在解析后的输出中添加“flower”和“price”parsed_output['flower'] = flowerparsed_output['price'] = price# 将解析后的输出添加到DataFrame中df.loc[len(df)] = parsed_output # 打印字典
print(df.to_dict(orient='records'))# 保存DataFrame到CSV文件
df.to_csv("flowers_with_descriptions.csv", index=False)
输出:
[{'flower': '玫瑰', 'price': '50', 'description': 'Luxuriate in the beauty of this 50 yuan rose, with its deep red petals and delicate aroma.', 'reason': 'This description emphasizes the elegance and beauty of the rose, which will be sure to draw attention.'},
{'flower': '百合', 'price': '30', 'description': '30元的百合,象征着坚定的爱情,带给你的是温暖而持久的情感!', 'reason': '百合是象征爱情的花,写出这样的描述能让顾客更容易感受到百合所带来的爱意。'},
{'flower': '康乃馨', 'price': '20', 'description': 'This beautiful carnation is the perfect way to show your love and appreciation. Its vibrant pink color is sure to brighten up any room!', 'reason': 'The description is short, clear and appealing, emphasizing the beauty and color of the carnation while also invoking a sense of love and appreciation.'}]
然后,我们根据输出解析器生成了包含格式说明的新提示模板,并再次调用模型。这次,模型的输出将尽可能遵循我们定义的格式,从而方便输出解析器进行解析。解析后的输出可能也就是一个Python字典,这个字典中包含了description 和 reason 这两个字段的值。
如:
parsed_output
{'description': 'This 50-yuan rose is... feelings.', 'reason': 'The description is s...y emotion.'}
len(): 2
最后,把所有信息整合到一个pandas DataFrame对象中(需要安装Pandas库)。这个DataFrame对象中包含了flower、price、description 和 reason 这四个字段的值。其中,description 和 reason 是由 output_parser 从模型的输出中解析出来的,flower 和 price 是我们自己添加的。我们可以打印出DataFrame的内容,也方便地在程序中处理它,比如保存为下面的CSV文件。因为此时数据不再是模糊的、无结构的文本,而是结构清晰的有格式的数据。输出解析器在这个过程中的功劳很大。
到这里,友友们和小北今天的任务也就顺利完成了。LangChain的优势
- 模板管理:方便管理和复用提示模板。
- 变量提取和检查:自动提取并检查模板中的变量。
- 模型切换:轻松切换不同的模型,无需修改代码。
- 输出解析:将非结构化文本转换为结构化数据,方便后续处理。
思考题与延伸阅读
- 简述LangChain调用大语言模型的优势:
- LangChain提供了模板管理、变量提取、模型切换和输出解析等功能,简化了基于大模型的应用开发过程。
- 输出格式是如何构建并传递到提示模板中的:
- 我们通过定义输出结构(ResponseSchema)和创建输出解析器(StructuredOutputParser),生成了包含格式说明的新提示模板。这个模板在调用模型时,会指导模型生成符合格式要求的输出。
- 为什么加入输出解析器后的提示能让模型生成结构化输出:
- 输出解析器中的格式说明(format_instructions)被嵌入到提示模板中,作为模型生成输出的指导。这样,模型在生成输出时,会尽可能遵循这些格式要求。
- 使用输出解析器后是否仍然可能得不到期望的输出:
- 是的,尽管输出解析器能够大大提高输出质量,但模型仍然有可能生成不符合格式要求的输出。这可能是由于模型的局限性、输入提示的不准确或输出解析器的定义不够精确等原因造成的。
- 吴恩达老师的提示工程课程,吴老师也有LangChain的简单介绍课程呦!网上也有这些课程的中文翻译版!
- LangChain官方文档中,关于模型I/O的资料在此。
最后,如果你对提示工程和LangChain感兴趣,可以进一步学习吴恩达老师的提示工程课程以及LangChain官方文档中的相关资料。希望这篇文章对你有所帮助,期待在留言区看到你的分享!