简介
在学习 LangChain 的过程中,第一个核心概念就是 PromptsModelsParsers,也有人叫做 ModelsIO,他们代表了对一次大模型请求的完整周期。如下图所示
Prompts:负责请求数据的准备步骤。
Model:负责具体请求和参数。
Parser:负责请求结果返回后的处理步骤。
三者共同作用,完整的覆盖了整个大模型请求。
使用价值
很多人疑惑的一点可能在于明明基于官方的 API 也可以实现请求响应的一系列过程,为何还要多此一举使用这三个模块呢?
首先先来看一个官方的示例:
OpenAI 官方库示例
先来看一个直接使用官方 API 发起的请求,示例代码如下:
# OpenAI提供的python公共库
import openai
key = 'open_ai_key'
# 设置OpenAI Token
openai.api_key = key
response = openai.ChatCompletion.create(
# 声明调用的模型名称
model='gpt-3.5-turbo',
# temperature用来设置大模型返回数据的随机性和创造性,较低的数值返回的数据就更贴近现实。
temperature=0.0,
# 消息内容,可以包含上下文信息,列表数据中的顺序就是对话发生的顺序
messages=[{'role': 'user', 'content': '1+1等于几?'}]
)
# 从返回数据中拿到具体的答案信息
answer = response['choices'][0]['message']['content']
# 打印调试信息
print(answer)
复制代码
从以上代码中可以看出以下几个问题:
官方提供的主要功能为请求的发送,具体发送的数据 messages 部分需要用户自己组织和维护。
返回的数据 response 部分也只是简单的组装了一个结构。有过开发经验的同学都深有感触,如果每次给到的返回信息从结构到内容都是不一样的,作为调用方,则需要编写无数行代码去处理这些异常。
而 LangChain 的 Prompts、Models、Parsers 则通过了很强的抽象设计解决了这个问题。
实践演练
接下来将分为 2 个模块讲解这三个部分分别起到的作用,最后在展示一下它们合并到一起的效果。
Prompts 与 Models
在学习写作文的过程中,我们的老师常常会教各种句式和结构,目的就是为了让我们的作文更加的清晰明了。
包括在工作之后,我们也会通过学习 STAR 法则,5W1H 等各种方法论让我们的表达更加清晰。
而 Prompt 也是这个作用,让输入提示词的人可以根据一个清晰的结构明确自己要表述的内容。
所以为了实现这个目的,通常会使用 ChatPromptTemplate,可以自行定义让用户输入提示词的结构。
# LangChain相关模块的导入
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
key = "OpenAIToken"
# 创建OpenAI调用实例
# temperature用来设置大模型返回数据的随机性和创造性,较低的数值返回的数据就更贴近现实。
chat = ChatOpenAI(temperature=0.0, openai_api_key=key)
# 可复用的模板字符串,注意不要使用 f字符串 ,LangChain会在运行时自动替换
template_str = """将三个反引号内的文本内容转换成{style}风格的文本```{text}```"""
# 创建一个针对模板字符串的prompt模板实例
prompt_template = ChatPromptTemplate.from_template(template_str)
# 用prompt模板实例+参数,生成具体的请求消息列表
custom_message = prompt_template.format_messages(
style="标准文言文",
text="2023年8月23日下午18:19分,我在盘锦坐在沙发上忽悠两下,感觉到了地震震,房子在晃动两下,窗帘在动,厨房灯在抖动,我连忙打开手机发现大连在地震,而我们是余震,可吓死我了"
)
# 调用chat发送消息,从ChatGPT中获取相应信息
customer_res = chat(custom_message)
# 相应信息中的content是具体的返回消息体
print(customer_res.content)
复制代码
Parsers
在前文中已经提到过,ChatGPT 直接返回的文本信息是无格式的,会让调用方在后续编码过程中非常痛苦。
根据业务需求,开发者通常需要大模型返回一个结构化的数据,方便后续的逻辑可以根据这个数据进行进一步的处理。
而这一个问题,可以通过在 Prompt 中给出相应的要求,让返回值达到预期的格式来解决,代码如下所示:
# LangChain相关模块的导入
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
key = 'open_ai_key'
# 创建OpenAI调用实例
# temperature用来设置大模型返回数据的随机性和创造性,较低的数值返回的数据就更贴近现实。
chat = ChatOpenAI(temperature=0.0, openai_api_key=key)
# 可复用的模板字符串,注意不要使用 f字符串 ,LangChain会在运行时自动替换
template_str = """\
对于给出的text数据,从中提取出下列数据
时间: 事件发生的准确时间
地点: 事情发生时,讲述人所处的城市名称
事件: 文中主要讲述的具体事件是发生了什么事件
现象: 列举出事件发生时,出现的每个现象,每个现象作为单独的句子记录
将提取出的数据,按照json的格式显示出来,json的key分别为以下几个字段
时间
地点
事件
现象
text: {text}
"""
# 创建一个针对模板字符串的prompt模板实例
prompt_template = ChatPromptTemplate.from_template(template_str)
# 用prompt模板实例+参数,生成具体的请求消息列表
custom_message = prompt_template.format_messages(
text="2023年8月23日下午18:19分,我在盘锦坐在沙发上忽悠两下,感觉到了地震,房子在晃动两下,窗帘在动,厨房灯在抖动,我连忙打开手机发现大连在地震,而我们是余震,可吓死我了"
)
# 调用chat发送消息,从ChatGPT中获取相应信息
customer_res = chat(custom_message)
# 相应信息中的content是具体的返回消息体
print(customer_res.content)
print(type(customer_res.content))
复制代码
但是!现有的这个输出无法满足我们的需求,因为它实际的返回是 string,但是需求要求为 dict 格式数据。
可以通过 ResponseSchema 将返回值信息彻底转换为我们需要的结构信息。
1.针对 prompt 中的每个想要提取的属性,创建 ResponseSchema 记录字段名称和描述,用于后续解析返回数据:
# LangChain相关模块的导入
from langchain.output_parsers import ResponseSchema, StructuredOutputParser
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
key = 'open_ai_key'
# 创建OpenAI调用实例
# temperature用来设置大模型返回数据的随机性和创造性,较低的数值返回的数据就更贴近现实。
chat = ChatOpenAI(temperature=0.0, openai_api_key=key)
# 可复用的模板字符串,注意不要使用 f字符串 ,LangChain会在运行时自动替换
template_str = """\
text: {text}
{format_instructions}
"""
# 针对prompt中的每个想要提取的属性,创建ResponseSchema记录字段名称和描述,用于后续解析返回数据
time_schema = ResponseSchema(name="时间", description="事件发生的准确时间")
location_schema = ResponseSchema(name="地点", description="事情发生时,讲述人所处的城市名称")
event_schema = ResponseSchema(name="事件", description="文中主要讲述的具体事件是发生了什么事件")
situation_schema = ResponseSchema(
name="现象",
description="列举出事件发生时,出现的每个现象,每个现象作为列表中的单独一项"
)
复制代码
2.将所有 schema 组装成列表,生成响应值结构化解析器,并根据 schema 格式定义,自动生成一个支持格式化输出的 Prompt:
response_schemas = [time_schema, location_schema, event_schema, situation_schema]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
# 根据schema格式定义,自动生成一个支持格式化输出的prompt
format_instructions = output_parser.get_format_instructions()
# 输出生成的prompt查看格式
print(format_instructions)
复制代码
3.根据模板和数据,生成完整成 Prompt 请求数据:
prompt_template = ChatPromptTemplate.from_template(template_str)
custom_message = prompt_template.format_messages(
text="2023年8月23日下午18:19分,我在盘锦坐在沙发上忽悠两下,感觉到了地震,房子在晃动两下,窗帘在动,厨房灯在抖动,我连忙打开手机发现大连在地震,而我们是余震,可吓死我了",
format_instructions=format_instructions
)
# 根据结构化解析器,解析返回数据,获取类型正确的数据结果
result = output_parser.parse(resp.content)
print(result)
print(type(result))
复制代码
完整代码为:
# LangChain相关模块的导入
from langchain.output_parsers import ResponseSchema, StructuredOutputParser
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
key = 'open_ai_key'
# 创建OpenAI调用实例
# temperature用来设置大模型返回数据的随机性和创造性,较低的数值返回的数据就更贴近现实。
chat = ChatOpenAI(temperature=0.0, openai_api_key=key)
# 可复用的模板字符串,注意不要使用 f字符串 ,LangChain会在运行时自动替换
template_str = """\
text: {text}
{format_instructions}
"""
# 针对prompt中的每个想要提取的属性,创建ResponseSchema记录字段名称和描述,用于后续解析返回数据
time_schema = ResponseSchema(name="时间", description="事件发生的准确时间")
location_schema = ResponseSchema(name="地点", description="事情发生时,讲述人所处的城市名称")
event_schema = ResponseSchema(name="事件", description="文中主要讲述的具体事件是发生了什么事件")
situation_schema = ResponseSchema(
name="现象",
description="列举出事件发生时,出现的每个现象,每个现象作为列表中的单独一项"
)
# 将全部的属性描述schema组装成列表,生成相应值结构化解析器
response_schemas = [time_schema, location_schema, event_schema, situation_schema]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
# 根据schema格式定义,自动生成一个支持格式化输出的prompt
format_instructions = output_parser.get_format_instructions()
# 输出生成的prompt查看格式
print(format_instructions)
# 根据模板和数据,生成完整成prompt请求数据
prompt_template = ChatPromptTemplate.from_template(template_str)
custom_message = prompt_template.format_messages(
text="2023年8月23日下午18:19分,我在盘锦坐在沙发上忽悠两下,感觉到了地震,房子在晃动两下,窗帘在动,厨房灯在抖动,我连忙打开手机发现大连在地震,而我们是余震,可吓死我了",
format_instructions=format_instructions
)
# 调用大模型发起请求
customer_res = chat(custom_message)
# 根据结构化解析器,解析返回数据,获取类型正确的数据结果
result = output_parser.parse(customer_res.content)
print(result)
print(type(result))
复制代码
返回结果示例如图:
如此一来,通过解析器解析之后的数据,格式已经转为了 Python 中支持的 dict 格式,可以直接给后续的逻辑中使用。
更多Python基础语法趣味学习视频,请点击!
评论