admin管理员组

文章数量:1616673

文章目录

  • 一、概述
  • 二、Model I/O
  • 三、提示模板
  • 四、语言模型
  • 五、输出解析
  • 六、输出解析器背后的原理


一、概述

 从这节课开始,我们将对 LangChain 中的六大核心组件一一进行详细的剖析。
 Model 模型,位于 LangChain 框架的最底层,它是基于语言模型构建的应用的核心元素,因为所谓 LangChain 应用开发,就是以 LangChain 作为框架,通过 API 调用大模型来解决具体问题的过程。


二、Model I/O

 可以把对模型的使用过程拆解成三块,分别是 输入提示 (对应图中的 Format)、调用模型 (对应图中的 Predict)、输出解析 (对应图中的 Parse)。这三块形成了一个整体,因此在 LangChain 中这个过程被统称为 Model I/O (Input/Output)。
 在模型 I/O 的每个环节,LangChain 都为咱们提供了模板和工具,快捷地形成调用各种语言模型的接口。

  1. 提示模板,使用模型的第一个环节是把提示信息输入到模型中,你可以创建 LangChain 模板,根据实际需求动态选择不同的输入,针对特定的任务和应用调整输入。
  2. 语言模型,LangChain 允许你通过通用接口来调用语言模型。这意味着无论你要使用的是哪种语言模型,都可以通过同一种方式进行调用,这样就提高了灵活性和便利性。
  3. 输出解析,LangChain 还提供了从模型输出中提取信息的功能。通过 输出解析器,你可以 精确地从模型的输出中获取需要的信息,而不需要处理冗余或不相关的数据,更重要的是还可以 把大模型给回的非结构化文本,转换成程序可以处理的结构化数据

三、提示模板

 现在“提示工程”这个词特别流行,所谓 Prompt Engineering,就是专门研究对大语言模型的提示构建。
 那其中的具体原则,不外乎吴恩达老师在他的提示工程课程中所说的:

  1. 给予模型清晰明确的指示
  2. 让模型慢慢地思考

 例如,假设现在我们在销售鲜花,并希望为销售的每一种鲜花生成一段简介文案,那么每当你的员工或者顾客想了解某种鲜花时,调用该模板就会生成适合的文字。这个提示模板的生成方式如下:

# 导入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
"""

 在这里,所谓“模板”就是一段描述某种鲜花的文本格式,它是一个 f-string,其中有两个变量 {flower_name} 和 {price} 表示花的名称和价格,这两个值是模板里面的 占位符,在实际使用模板生成提示时会被具体的值替换。

 打印出这个 PromptTemplate 对象,你可以看到这个对象中的信息包括 输入的变量 (在这个例子中就是 flower_name 和 price)、输出解析器 (这个例子中没有指定)、模板的格式 (这个例子中为’f-string’)、是否验证模板 (这个例子中设置为 True)。

PromptTemplate 的 from_template 方法 就是将一个原始的模板 字符串 转化为一个更丰富、更方便操作的 PromptTemplate 对象,这个对象就是 LangChain 中的 提示模板
 LangChain 提供了多个类和函数,也 为各种应用场景设计了很多内置模板,使构建和使用提示变得容易。下一章还会对提示工程的基本原理和 LangChain 中的各种提示模板做更深入的讲解。


四、语言模型

 LangChain 中支持的模型有三大类:

  1. 大语言模型,LLM,ext Model
     这些模型将文本字符串作为输入,并返回文本字符串作为输出。
  2. 聊天模型,Chat Model
     主要代表 Open AI 的 ChatGPT 系列模型。这些模型通常由语言模型支持,但它们的 API 更加结构化。具体来说,这些模型将 聊天消息列表 作为 输入,并返回 聊天消息 (输入一个列表,即很多消息,然后输出一条消息)。
  3. 文本嵌入模型,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感受你的真心爱意。
"""

 input = prompt.format(flower_name=[“玫瑰”], price=‘50’) 这行代码的作用是将模板实例化,此时将 {flower_name} 替换为 “玫瑰”,{price} 替换为 ‘50’。

 最后合在一起,复用提示模板,我们可以同时生成多个鲜花的文案:

# 导入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)
"""
input_variables=['flower_name', 'price'] 
output_parser=None partial_variables={} 
template='/\n您是一位专业的鲜花店文案撰写员。
\n对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗?\n'
template_format='f-string' 
validate_template=True

这支玫瑰,深邃的红色,传递着浓浓的深情与浪漫,令人回味无穷!
百合:美丽的花朵,多彩的爱恋!30元让你拥有它!
康乃馨—20元,象征爱的祝福,送给你最真挚的祝福。
"""

 更重要的是,在 LangChain 中我们可以随意地更换 model,而不需要修改任何提示相关的代码。例如,现在我们调用 HuggingFace 中的 Model:

# 导入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
"""

 总结下来,使用 LangChain 和 提示模板 的好处在于:

  1. 代码的可读性,使用模板的话,提示文本更易于阅读和理解,特别是对于复杂的提示或多变量的情况。
  2. 可复用性,模板可以在多个地方被复用,让你的代码更简洁,不需要在每个需要生成提示的地方重新构造提示字符串。
  3. 维护,如果你在后续需要修改提示,使用模板的话,只需要修改模板就可以了,而不需要在代码中查找所有使用到该提示的地方进行修改。
  4. 变量处理,如果你的提示中涉及到多个变量,模板可以自动处理变量的插入,不需要手动拼接字符串。
  5. 参数化,模板可以根据不同的参数生成不同的提示,这对于个性化生成文本非常有用。

总结下来,到目前为止见到了调用大语言模型的方法有:

  1. response = client.chatpletions.create(model=“gpt-4”, message=…, temperature=0.8, max_tokens=60)
  2. chat = ChatOpenAI(model=“gpt-4”, temperature=0.8, max_tokens=60)
    response = chat(messages)
  3. output = model.invoke(input_prompt)
  4. output = model(input)

五、输出解析

 LangChain 提供的解析模型输出的功能,使你能够更容易地从模型输出中获取 结构化的信息,这将大大加快基于语言模型进行应用开发的效率。

 比如,假设我们希望的到两个字段:description 文案,reason 原因。即,我们希望返回的文本从一个 简单的 string “让你心动!50 元就可以拥有这支充满浪漫气息的玫瑰花束,让 TA 感受你的真心爱意。为什么这样说呢?因为爱情是无价的,50 元对应热恋中的情侣也会觉得值得。” 变成一个 python 字典 “{description: “让你心动!50 元就可以拥有这支充满浪漫气息的玫瑰花束,让 TA 感受你的真心爱意。” ; reason: “因为爱情是无价的,50 元对应热恋中的情侣也会觉得值得。”}”

 那么从 A 的笼统言语,到 B 这种结构清晰的数据结构,如何自动实现?这就需要 LangChain 中的 输出解析器 上场了。
 下面,我们就通过 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'] = flower
    parsed_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.'}]
"""
  • 这段代码中,首先定义 输出结构,我们希望模型生成的答案包含两部分:descriptionreason。所以我们定义了一个名为 response_schemas 的列表,其中包含 两个 ResponseSchema 对象,分别对应这两部分的输出。
  • 根据这个列表,我通过 StructuredOutputParser.from_response_schemas 方法创建了一个 输出解析器
  • 然后,我们通过 输出解析器对象的 get_format_instructions() 方法 获取输出的 格式说明 format_instructions,再根据 原始的字符串模板输出解析器格式说明 创建新的 提示模板 (这个模板就整合了输出解析结构信息)。再通过新的模板生成模型的输入,得到模型的输出。此时模型的输出结构将尽最大可能遵循我们的指示,以 便于输出解析器进行解析
  • 对于每一个鲜花和价格组合,我们都用 output_parser.parse(output) 把模型输出的文案解析成之前定义好的数据格式,也就是一个 Python 字典,这个字典中包含了 description 和 reason 这两个字段的值。
  • 最后,把所有信息整合到一个 pandas DataFrame 对象 中。这个 DataFrame 对象中包含了 flower、price、description 和 reason 这四个字段的值。其中,description 和 reason由 output_parser 从模型的输出中解析出来的flower 和 price 是我们 自己添加的

六、输出解析器背后的原理

在提示模板的构建过程中加入了 partial_variables,也就是输出解析器指定的 format_instructions 之后,为什么能够让模型生成结构化的输出?

 当你用 print 语句打印出最终传递给大模型的提示时,一切就变得非常明了。

您是一位专业的鲜花店文案撰写员。
对于售价为 50 元的 玫瑰 ,您能提供一个吸引人的简短描述吗?
The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":

```json
{
        "description": string  // 鲜花的描述文案
        "reason": string  // 问什么要这样写这个文案
}

 秘密在于,LangChain 的输出解析器偷偷的在提示中加了一段话,也就是 {format_instructions} 中的内容。这段由 LangChain 自动添加的文字,就清楚地指示着我们希望得到什么样的回答以及回答的具体格式。
 提示指出,模型需要根据一个 schema 来格式化输出文本,这个 schema 从 ```json 开始,到 ```结束
 这就是在告诉模型,你就 follow 这个 schema(schema,可以理解为对数据结构的描述)的格式,就行啦!这就是一个很棒、很典型的提示工程。有了这样清晰的提示,智能程度比较高的模型(比如 GPT3.5 及以上版本),肯定能够输出可以被解析的数据结构,如 JSON 格式的数据。

本文标签: 模型提示LangChain