PydanticOutputParser 解析器
本篇文章介绍了如何使用 pydantic 库来执行 PydanticOutputParser 操作。
PydanticOutputParser 是一个用于将语言模型的输出转换为 结构化信息 的类。该类能够以清晰且有序的形式提供您所需的信息,而非仅仅给出简单的文本回复。
通过使用这个类,您可以将语言模型的输出转换为符合特定数据模型的形式,从而更便于处理和利用这些信息。
电子邮件对话示例
email_conversation = """
发件人:John (John@bikecorporation.me)
收件人:Kim (Kim@teddyinternational.me)
主题:"ZENESIS"自行车分销合作及会议日程提议
尊敬的Kim先生:
我是John,Bike Corporation的高级执行总监。我最近通过贵公司的新闻稿了解到您的新款自行车型号"ZENESIS"。Bike Corporation是一家在自行车制造和分销领域处于领先地位的公司,拥有长期的经验和专业知识。
我们希望能获取ZENESIS型号的详细产品手册。特别是关于技术规格、电池性能和设计方面的信息。这些信息将帮助我们进一步完善我们的分销策略和营销计划。
此外,为了更详细地讨论合作的可能性,我建议在下周二(1月15日)上午10:00进行会面。是否可以在您的办公室进行这次讨论?
谢谢。
此致
敬礼,
John
高级执行总监
Bike Corporation
"""
使用 StrOutputParser 解析器将电子邮件对话转换为字符串输出(基础使用)
创建一个链式结构,该结构将使用基本的 StrOutputParser 组件。
from langchain_core.prompts import PromptTemplate
from langchain_core.messages import AIMessageChunk # 用于处理AI模型的输出数据块
from langchain_core.output_parsers import StrOutputParser
prompt = PromptTemplate.from_template(
"请提取以下邮件中的关键内容.\n\n{email_conversation}"
)
chain = prompt | Qwen2_5_7B_Instruct_llm | StrOutputParser()
answer = chain.invoke({"email_conversation": email_conversation})
# 用于实时输出(流式输出)的函数
def stream_response(response,return_output=False):
"""
从AI模型中流式输出响应,处理并打印每个数据块。
此函数遍历'response'迭代器中的每个项目。如果项目是AIMessageChunk实例,则提取并打印其内容。
如果项目是字符串,则直接打印该字符串。
可选择是否返回所有响应数据块的连接字符串。
参数:
- response (iterable): 响应数据块的迭代器,可以是AIMessageChunk对象或字符串。
- return_output (bool, 可选): 如果为True,函数将返回连接后的响应字符串。默认为False。
返回:
- str: 如果```return_output```为True,返回连接后的响应字符串。否则不返回任何内容。
"""
answer = ""
for item in response:
if isinstance(item, AIMessageChunk):
answer += item.content
print(item.content, end="")
elif isinstance(item, str):
answer += item
print(item, end="")
if return_output:
return answer
output= stream_response(answer,return_output=True)
打印输出:
以下是邮件的关键内容提取:
- **发件人**:John,Bike Corporation的高级执行总监
- **收件人**:Kim,Teddy International的收件人
- **主题**:"ZENESIS"自行车分销合作及会议日程提议
- **主要内容**:
- Bike Corporation希望获取ZENESIS型号的详细产品手册,特别是技术规格、电池性能和设计方面的信息。
- 建议在下周二(1月15日)上午10:00进行会面讨论合作可能性。
- 建议在Kim的办公室进行这次讨论。
使用 PydanticOutputParser 将电子邮件对话转换为结构化输出(高级基础使用)
当接收到如上文所示的电子邮件内容时,我们可以使用下面以“Pydantic”风格定义的类来解析电子邮件信息。
作为参考,位于Field内部的description内容用于指导从基于文本的回复中提取关键信息。语言模型依靠此描述来提取所需信息。
因此,该描述必须准确且清晰,这一点至关重要。
设置数据结构时,我们需要考虑以下几个方面:
- 数据模型的定义:根据电子邮件内容的结构,我们需要定义一个符合要求的数据模型。
- 字段描述的准确性:每个字段的
description内容必须准确反映该字段的含义和预期值。 - 数据验证:在解析数据后,我们需要对其进行验证,确保其符合预期的格式和范围。(可选)
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
class EmailSummary(BaseModel):
person: str = Field(description="邮件发送人")
email: str = Field(description="发送人的邮箱地址")
subject: str = Field(description="邮件主题")
summary: str = Field(description="邮件内容摘要")
date: str = Field(
description="邮件内容中提到的会议日期和时间"
)
parser = PydanticOutputParser(pydantic_object=EmailSummary)
PydanticOutputParser 主要方法,
一个 PydanticOutputParser 类主要需要实现两个核心方法。
-
get_format_instructions():提供定义语言模型应输出信息格式的说明。 例如,您可以以字符串形式返回这些说明,其中描述了语言模型应输出的数据字段及其格式要求。 这些说明对于语言模型组织输出内容并将其调整以适应您的特定数据模型至关重要。 -
parse():该函数接收语言模型的输出(假定为字符串),对其进行分析并转换为特定的结构。 可以使用像Pydantic这样的工具,将输入字符串与预定义的模式进行比对并转换为符合该模式的数据结构。
定义接口密钥
from dotenv import load_dotenv
import os
load_dotenv()
os.environ["SILICONFLOW_API_KEY"] = "sk-iicnuzmyqazacwyxiuvrssabsntjornquscpjahkroumtrejlm"
定义模型
from langchain_openai import ChatOpenAI
from dotenv import load_dotenv
import os
load_dotenv()
# 创建ChatOpenAI对象,配置为使用硅基流动API
Qwen2_5_7B_Instruct_llm = ChatOpenAI(
temperature=0.1, # 控制输出的随机性和创造性,值越低输出越稳定可预测,值越高输出越有创意但可能偏离预期 (范围: 0.0 ~ 2.0)
model_name="Qwen/Qwen2.5-7B-Instruct", # 硅基流动支持的模型名称
openai_api_key=os.getenv("SILICONFLOW_API_KEY"), # 从环境变量获取API密钥
openai_api_base="https://api.siliconflow.cn/v1" # 硅基流动API的基础URL
)
设置上下文电子邮件内容
email_conversation = """
发件人:John (John@bikecorporation.me)
收件人:Kim (Kim@teddyinternational.me)
主题:"ZENESIS"自行车分销合作及会议日程提议
尊敬的Kim先生:
我是John,Bike Corporation的高级执行总监。我最近通过贵公司的新闻稿了解到您的新款自行车型号"ZENESIS"。Bike Corporation是一家在自行车制造和分销领域处于领先地位的公司,拥有长期的经验和专业知识。
我们希望能获取ZENESIS型号的详细产品手册。特别是关于技术规格、电池性能和设计方面的信息。这些信息将帮助我们进一步完善我们的分销策略和营销计划。
此外,为了更详细地讨论合作的可能性,我建议在下周二(1月15日)上午10:00进行会面。是否可以在您的办公室进行这次讨论?
谢谢。
此致
敬礼,
John
高级执行总监
Bike Corporation
"""
测试get_format_instructions方法
format_instructions = parser.get_format_instructions()
print(format_instructions)
打印结果
The output should be formatted as a JSON instance that conforms to the JSON schema below.
As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.
Here is the output schema:
{"properties": {"person": {"description": "邮件发送人", "title": "Person", "type": "string"}, "email": {"description": "发送人的邮箱地址", "title": "Email", "type": "string"}, "subject": {"description": "邮件主题", "title": "Subject", "type": "string"}, "summary": {"description": "邮件内容摘要", "title": "Summary", "type": "string"}, "date": {"description": "邮件内容中提到的会议日期和时间", "title": "Date", "type": "string"}}, "required": ["person", "email", "subject", "summary", "date"]}
定义提示模板
让我们定义一个包含以下变量的提示:
question: 接收用户的问题。email_conversation: 输入电子邮件对话的内容。format: 指定格式。
prompt = PromptTemplate.from_template(
"""
你是一个帮助人的助手.
问题:
{question}
邮件对话:
{email_conversation}
格式:
{format}
"""
)
# 使用partial方法预先填充 ```format``` 变量
prompt = prompt.partial(format=parser.get_format_instructions())
chain = prompt | Qwen2_5_7B_Instruct_llm
response = chain.stream(
{
"email_conversation": email_conversation,
"question": "提取邮件的主要内容。",
}
)
# 结果以 JSON 格式返回。
output = stream_response(response, return_output=True)
执行链并查看结果
{
"person": "John",
"email": "John@bikecorporation.me",
"subject": "ZENESIS自行车分销合作及会议日程提议",
"summary": "John是Bike Corporation的高级执行总监,最近通过公司的新闻稿了解到ZENESIS型号的新车型。他希望获取ZENESIS型号的详细产品手册,特别是关于技术规格、电池性能和设计方面的信息。此外,他建议在下周二(1月15日)上午10:00在公司办公室进行一次会议,以更详细地讨论合作的可能性。",
"date": "1月15日上午10:00"
}
最后,使用解析器来解析结果并将其转换为 EmailSummary 对象
structured_output = parser.parse(output)
print(structured_output)
打印解析后的结果
person='John'
email='John@bikecorporation.me'
subject='ZENESIS自行车分销合作及会议日程提议'
summary='Bike Corporation希望获取ZENESIS型号的详细产品手册,特别是关于技术规格、电池性能和设计方面的信息。建议在下周二(1月15日)上午10:00进行会面讨论合作可能性。'
date='1月15日上午10:00'
创建包含 PydanticOutputParser 的链
你可以将输出生成为你定义的 Pydantic 对象。
chain = prompt | Qwen2_5_7B_Instruct_llm | parser
执行链并查看结果
result = chain.invoke(
{
"email_conversation": email_conversation,
"question": "提取邮件的主要内容。",
}
)
print(result)
打印结果
person='John'
email='John@bikecorporation.me'
subject='ZENESIS自行车分销合作及会议日程提议'
summary='John希望获取ZENESIS型号的详细产品手册,特别是技术规格、电池性能和设计方面的信息。他建议在1月15日上午10:00与Kim会面讨论合作可能性。'
date='1月15日上午10:00'
添加输出解析器 .with_structured_output(Pydantic)
通过添加输出解析器使用 .with_structured_output(Pydantic),
你可以将输出转换为 Pydantic 对象。
注意
需要注意的是,.with_structured_output() 方法不支持 stream() 方法。
llm_with_structured = ChatOpenAI(
temperature=0.1, # 控制输出的随机性和创造性,值越低输出越稳定可预测,值越高输出越有创意但可能偏离预期 (范围: 0.0 ~ 2.0)
model_name="Qwen/Qwen2.5-7B-Instruct", # 硅基流动支持的模型名称
openai_api_key=os.getenv("SILICONFLOW_API_KEY"), # 从环境变量获取API密钥
openai_api_base="https://api.siliconflow.cn/v1" # 硅基流动API的基础URL
).with_structured_output(EmailSummary)
answer = llm_with_structured.invoke(email_conversation)
answer
打印结果:
EmailSummary(
person='Kim',
email='John@bikecorporation.me',
subject='ZENESIS自行车分销合作及会议日程提议',
summary='Bike Corporation的高级执行总监John希望获取ZENESIS型号的详细产品手册,并提议在1月15日上午10点于Kim的办公室进行会面讨论合作可能性。',
date='2024-01-15'
)