05|输出解析:用OutputParser生成鲜花推荐列表

使用Pydantic 解析器来重构第4课中的程序

LangChain 中的输出解析器

输出解析器是一种专用于处理和构建语言模型响应的类。一个基本的输出解析器类通常需要实现两个核心方法。

  • get_format_instructions:这个方法需要返回一个字符串,用于指导如何格式化语言模型的输出,告诉它应该如何组织并构建它的回答。
  • parse:这个方法接收一个字符串(也就是语言模型的输出)并将其解析为特定的数据结构或格式。这一步通常用于确保模型的输出符合我们的预期,并且能够以我们需要的形式进行后续处理。

还有一个可选的方法。

  • parse_with_prompt:这个方法接收一个字符串(也就是语言模型的输出)和一个提示(用于生成这个输出的提示),并将其解析为特定的数据结构。这样,你可以根据原始提示来修正或重新解析模型的输出,确保输出的信息更加准确和贴合要求。
class OutputParser:
    def __init__(self):
        pass

    def get_format_instructions(self):
        # 返回一个字符串,指导如何格式化模型的输出
        pass

    def parse(self, model_output):
        # 解析模型的输出,转换为某种数据结构或格式
        pass

    def parse_with_prompt(self, model_output, prompt):
        # 基于原始提示解析模型的输出,转换为某种数据结构或格式
        pass

langchain通过这个三个方法,实现了各种解析器

  1. 列表解析器(List Parser):这个解析器用于处理模型生成的输出,当需要模型的输出是一个列表的时候使用。例如,如果你询问模型“列出所有鲜花的库存”,模型的回答应该是一个列表。
  2. 日期时间解析器(Datetime Parser):这个解析器用于处理日期和时间相关的输出,确保模型的输出是正确的日期或时间格式。
  3. 枚举解析器(Enum Parser):这个解析器用于处理预定义的一组值,当模型的输出应该是这组预定义值之一时使用。例如,如果你定义了一个问题的答案只能是“是”或“否”,那么枚举解析器可以确保模型的回答是这两个选项之一。
  4. 结构化输出解析器(Structured Output Parser):这个解析器用于处理复杂的、结构化的输出。如果你的应用需要模型生成具有特定结构的复杂回答(例如一份报告、一篇文章等),那么可以使用结构化输出解析器来实现。
  5. Pydantic(JSON)解析器:这个解析器用于处理模型的输出,当模型的输出应该是一个符合特定格式的JSON对象时使用。它使用Pydantic库,这是一个数据验证库,可以用于构建复杂的数据模型,并确保模型的输出符合预期的数据模型。
  6. 自动修复解析器(Auto-Fixing Parser):这个解析器可以自动修复某些常见的模型输出错误。例如,如果模型的输出应该是一段文本,但是模型返回了一段包含语法或拼写错误的文本,自动修复解析器可以自动纠正这些错误。
  7. 重试解析器(RetryWithErrorOutputParser):这个解析器用于在模型的初次输出不符合预期时,尝试修复或重新生成新的输出。例如,如果模型的输出应该是一个日期,但是模型返回了一个字符串,那么重试解析器可以重新提示模型生成正确的日期格式。

Pydantic(JSON)解析器实战

第一步:创建模型实例

# 设置OpenAI API密钥
import os
os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'

# 创建模型实例
from langchain import OpenAI
model = OpenAI(model_name='text-davinci-003')

第二步:定义输出数据的格式

先创建了一个空的DataFrame,用于存储从模型生成的描述。接下来,通过一个名为FlowerDescription的Pydantic BaseModel类,定义了期望的数据格式(也就是数据的结构)。

# ------Part 2
# 创建一个空的DataFrame用于存储结果
import pandas as pd
df = pd.DataFrame(columns=["flower_type", "price", "description", "reason"])

# 数据准备
flowers = ["玫瑰", "百合", "康乃馨"]
prices = ["50", "30", "20"]

# 定义我们想要接收的数据格式
from pydantic import BaseModel, Field
class FlowerDescription(BaseModel):
    flower_type: str = Field(description="鲜花的种类")
    price: int = Field(description="鲜花的价格")
    description: str = Field(description="鲜花的描述文案")
    reason: str = Field(description="为什么要这样写这个文案")

Pydantic有这样几个特点:

  1. 数据验证:当你向Pydantic类赋值时,它会自动进行数据验证。例如,如果你创建了一个字段需要是整数,但试图向它赋予一个字符串,Pydantic会引发异常。
  2. 数据转换:Pydantic不仅进行数据验证,还可以进行数据转换。例如,如果你有一个需要整数的字段,但你提供了一个可以转换为整数的字符串,如 “42”,Pydantic会自动将这个字符串转换为整数42。
  3. 易于使用:创建一个Pydantic类就像定义一个普通的Python类一样简单。只需要使用Python的类型注解功能,即可在类定义中指定每个字段的类型。
  4. JSON支持:Pydantic类可以很容易地从JSON数据创建,并可以将类的数据转换为JSON格式。

第三步:创建输出解析器

# ------Part 3
# 创建输出解析器
from langchain.output_parsers import PydanticOutputParser
output_parser = PydanticOutputParser(pydantic_object=FlowerDescription)

# 获取输出格式指示
format_instructions = output_parser.get_format_instructions()
# 打印提示
print("输出格式:",format_instructions)

让输入模型的提示和输出解析器的要求相互吻合,前后就呼应得上

第四步:创建提示模板

我们定义了一个提示模板,该模板将用于为模型生成输入提示。模板中包含了你需要模型填充的变量(如价格和花的种类),以及之前获取的输出格式指示。

# ------Part 4
# 创建提示模板
from langchain import PromptTemplate
prompt_template = """您是一位专业的鲜花店文案撰写员。
对于售价为 {price} 元的 {flower} ,您能提供一个吸引人的简短中文描述吗?
{format_instructions}"""

# 根据模板创建提示,同时在提示中加入输出解析器的说明
prompt = PromptTemplate.from_template(prompt_template, 
       partial_variables={"format_instructions": format_instructions}) 

# 打印提示
print("提示:", prompt)

第五步:生成提示,传入模型并解析输出

这部分是程序的主体,我们循环来处理所有的花和它们的价格。对于每种花,都根据提示模板创建了输入,然后获取模型的输出。然后使用之前创建的解析器来解析这个输出,并将解析后的输出添加到DataFrame中。最后,你打印出了所有的结果,并且可以选择将其保存到CSV文件中。

# ------Part 5
for flower, price in zip(flowers, prices):
    # 根据提示准备模型的输入
    input = prompt.format(flower=flower, price=price)
    # 打印提示
    print("提示:", input)

    # 获取模型的输出
    output = model(input)

    # 解析模型的输出
    parsed_output = output_parser.parse(output)
    parsed_output_dict = parsed_output.dict()  # 将Pydantic格式转换为字典

    # 将解析后的输出添加到DataFrame中
    df.loc[len(df)] = parsed_output.dict()

# 打印字典
print("输出的数据:", df.to_dict(orient='records'))

自动修复解析器(OutputFixingParser)实战

设计一个解析时出现的错误

# 导入所需要的库和模块
from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from typing import List

# 使用Pydantic创建一个数据格式,表示花
class Flower(BaseModel):
    name: str = Field(description="name of a flower")
    colors: List[str] = Field(description="the colors of this flower")
# 定义一个用于获取某种花的颜色列表的查询
flower_query = "Generate the charaters for a random flower."

# 定义一个格式不正确的输出
misformatted = "{'name': '康乃馨', 'colors': ['粉红色','白色','红色','紫色','黄色']}"

# 创建一个用于解析输出的Pydantic解析器,此处希望解析为Flower格式
parser = PydanticOutputParser(pydantic_object=Flower)
# 使用Pydantic解析器解析不正确的输出
parser.parse(misformatted)

这段代码如果运行,会出现错误。因为json数据格式是不正确的
可以使用使用OutputFixingParser来帮助咱们自动解决类似的格式错误。不用人力去修改

# 从langchain库导入所需的模块
from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import OutputFixingParser

# 设置OpenAI API密钥
import os
os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'

# 使用OutputFixingParser创建一个新的解析器,该解析器能够纠正格式不正确的输出
new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())

# 使用新的解析器解析不正确的输出
result = new_parser.parse(misformatted) # 错误被自动修正
print(result) # 打印解析后的输出结果

在于,在OutputFixingParser内部,调用了原有的PydanticOutputParser,如果成功,就返回;如果失败,它会将格式错误的输出以及格式化的指令传递给大模型,并要求LLM进行相关的修复。


重试解析器(RetryWithErrorOutputParser)实战

OutputFixingParser不错,但它只能做简单的格式修复。如果出错的不只是格式,比如,输出根本不完整,有缺失内容,那么仅仅根据输出和格式本身,是无法修复它的
还是设计一个解析过程中的错误。

# 定义一个模板字符串,这个模板将用于生成提问
template = """Based on the user question, provide an Action and Action Input for what step should be taken.
{format_instructions}
Question: {query}
Response:"""

# 定义一个Pydantic数据格式,它描述了一个"行动"类及其属性
from pydantic import BaseModel, Field
class Action(BaseModel):
    action: str = Field(description="action to take")
    action_input: str = Field(description="input to the action")

# 使用Pydantic格式Action来初始化一个输出解析器
from langchain.output_parsers import PydanticOutputParser
parser = PydanticOutputParser(pydantic_object=Action)

# 定义一个提示模板,它将用于向模型提问
from langchain.prompts import PromptTemplate
prompt = PromptTemplate(
    template="Answer the user query.\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()},
)
prompt_value = prompt.format_prompt(query="What are the colors of Orchid?")

# 定义一个错误格式的字符串
bad_response = '{"action": "search"}'
parser.parse(bad_response) # 如果直接解析,它会引发一个错误

由于bad_response只提供了action字段,而没有提供action_input字段,这与Action数据格式的预期不符,所以解析会失败。

首先尝试用OutputFixingParser来解决这个错误

from langchain.output_parsers import OutputFixingParser
from langchain.chat_models import ChatOpenAI
fix_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())
parse_result = fix_parser.parse(bad_response)
print('OutputFixingParser的parse结果:',parse_result)

OutputFixingParser的parse结果:action='search' action_input='query'

解决的问题有:

  • 不完整的数据:原始的bad_response只提供了action字段而没有action_input字段。OutputFixingParser已经填补了这个缺失,为action_input字段提供了值 ‘query’。

没解决的问题有:

  • 具体性:尽管OutputFixingParser为action_input字段提供了默认值 ‘query’,但这并不具有描述性。真正的查询是 “Orchid(兰花)的颜色是什么?”。所以,这个修复只是提供了一个通用的值,并没有真正地回答用户的问题。
  • 可能的误导:‘query’ 可能被误解为一个指示,要求进一步查询某些内容,而不是作为实际的查询输入。

有更鲁棒的选择,我们最后尝试一下RetryWithErrorOutputParser这个解析器

# 初始化RetryWithErrorOutputParser,它会尝试再次提问来得到一个正确的输出
from langchain.output_parsers import RetryWithErrorOutputParser
from langchain.llms import OpenAI
retry_parser = RetryWithErrorOutputParser.from_llm(
    parser=parser, llm=OpenAI(temperature=0)
)
parse_result = retry_parser.parse_with_prompt(bad_response, prompt_value)
print('RetryWithErrorOutputParser的parse结果:',parse_result)

RetryWithErrorOutputParser的parse结果:action='search' action_input='colors of Orchid'

总结

结构化解析器和Pydantic解析器都旨在从大型语言模型中获取格式化的输出。结构化解析器更适合简单的文本响应,而Pydantic解析器则提供了对复杂数据结构和类型的支持。选择哪种解析器取决于应用的具体需求和输出的复杂性。
在选择哪种解析器时,需要考虑具体的应用场景。如果仅面临格式问题,自动修复解析器可能足够;但如果输出的完整性和准确性至关重要,那么重试解析器可能是更好的选择。

  1. 工具:Pydantic 是一个Python库,用于数据验证,可以确保数据符合特定的格式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/273514.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用JAXB生成XML的Java对象

文章目录 标题使用JAXB生成XML的Java对象根据xml生成xsd文件:下载trang.jar:使用trang.jar生成xml的xsd文件: 使用JAXB的xjc生成java对象: 标题使用JAXB生成XML的Java对象 根据xml生成xsd文件: 下载trang.jar&#x…

Hive:数据仓库利器

1. 简介 Hive是一个基于Hadoop的开源数据仓库工具,可以用来存储、查询和分析大规模数据。Hive使用SQL-like的HiveQL语言来查询数据,并将其结果存储在Hadoop的文件系统中。 2. 基本概念 介绍 Hive 的核心概念,例如表、分区、桶、HQL 等。 …

关系数据库标准语言SQL

1.SQL概述 1.1基本表(Base table) 实际存储在数据库中的表SQL中一个关系就对应一个基本表基本表可以有若干个索引基本表的集合组成关系模式,即全局概念模式(数据的整体逻辑结构) 1.2 存储文件 存储文件和相关索引组…

Ubuntu软件开发环境搭建

Ubuntu软件开发环境搭建 安装VMware Tools网络桥接更新软件源常用功能配置时间同步共享文件夹双向复制粘贴终端初始大小和字体设置安装必要的工具 常用指令 安装VMware Tools 点击虚拟机->安装VMware Tools… 打开终端,cd到/media/用户名/VMware Tools/下&#…

苍穹外卖-day13:vue基础回顾+进阶

vue基础回顾进阶 课程内容 VUE 基础回顾路由 Vue-Router状态管理 vuexTypeScript 1. VUE 基础回顾 1.1 基于脚手架创建前端工程 1.1.1 环境要求 要想基于脚手架创建前端工程,需要具备如下环境要求: ​ node.js 前端项目的运行环境 学习web阶段已安…

qt开发记录

文章目录 1、QT介绍2、信号和槽机制3、提升类4、播放媒体5、增加新的组件6、联合vscode开发 1、QT介绍 打开的主页面介绍,下面是一张新的工程的QT编辑栏,我这里大致分为三类,分别标注如下: 下面对这三个进行分别说明&#xff1a…

idea远程试调jar、远程试调war

idea远程试调jar、远程试调war 目的&#xff1a;测试运行时与ide开发时是否一致。 配置jar Maven中添加 <packaging>jar</packaging>将其打包为jar。 设置运行入口main 编译jar 看到jar输出 配置试调 添加jar运行 远程试调 先在源码中打好断点试调 debug运行…

智能合约 - 部署ERC20

Remix介绍 Remix是一个由以太坊社区开发的在线集成开发环境&#xff08;IDE&#xff09;&#xff0c;旨在帮助开发者编写、测试和部署以太坊智能合约。它提供了一个简单易用的界面&#xff0c;使得开发者可以在浏览器中直接进行智能合约的开发&#xff0c;而无需安装任何额外的…

C++进阶之路---手撕“红黑树”

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、红黑树的概念与性质 1.概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点…

ZnO 阀片的非线性 U-I特性

EAK氧化锌阀片的非线性电压-电流(U-I)特性是它在作为限压元件的实际应用中最为重要的性能。 U-I特性曲线中有一个明显的转折点,即拐点。当作用在阀片上的电压低于拐点电压时,流过阀片的电流密度很小&#xff0c;一般小于1μA/cm”,电压与电流接近线性关系;当电压高于拐点电压时…

基于时空上下文(STC)的运动目标跟踪算法,Matlab实现

博主简介&#xff1a; 专注、专一于Matlab图像处理学习、交流&#xff0c;matlab图像代码代做/项目合作可以联系&#xff08;QQ:3249726188&#xff09; 个人主页&#xff1a;Matlab_ImagePro-CSDN博客 原则&#xff1a;代码均由本人编写完成&#xff0c;非中介&#xff0c;提供…

cf火线罗技鼠标宏最细教程(鬼跳,上箱,一键顺,usp速点,雷神三连发及压枪,AK火麒麟压枪.lua脚本)

一.前言 因为我发现火线的鼠标宏非常多&#xff0c;想着自己也有罗技鼠标&#xff0c;看能不能自己写一写让游玩的时候更方便操作一些&#xff0c;可能不一定有什么帮助&#xff0c;但也是一个学习的过程&#xff0c;下面就把我自己的心得和代码详细的记录下来&#xff0c;好多…

springboot整合springsecurity,从数据库中认证

概述&#xff1a;springsecurity这个东西太容易忘了&#xff0c;这里写点东西&#xff0c;避免忘掉 目录 第一步&#xff1a;引入依赖 第二步&#xff1a;创建user表 第三步&#xff1a;创建一个用户实体类&#xff08;User&#xff09;和一个用于访问用户数据的Repository…

小程序搜索排名优化二三事

小程序的优化主要是排名优化和性能优化两个版块。性能优化这方面主要靠开发者自己完善&#xff0c;我们团队提供的服务就是把产品的排名打上去&#xff0c;获得更多的自然流量&#xff0c;实现盈利。 如何提升小程序的搜索排名主要从如下几个方面出发&#xff1a; 首先要知道…

数据结构——lesson10排序之插入排序

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

配置视图解析器

配置视图解析器&#xff1a; 我们在指定视图的时候路径是有重复的&#xff0c;重复的操作可以用视图解析器&#xff0c;让框架帮我们&#xff1a; mv.setViewName("/WEB-INF/view/show.jsp");mv.setViewName("/WEB-INF/VIEW/other.jsp"); ​​​​​​​ …

Tomcat:Session ID保持会话

目录 前言 ​一、部署环境 二、部署nginx反向代理服务器 三、部署tomcat服务器1 四、部署tomcat服务器2 五、客户端测试&#xff08;Session ID不断变动&#xff09; 六、配置Session ID会话保持 七、客户端测试&#xff08;Session ID保持&#xff09; 前言 此次实验…

DockerFile遇到的坑

CMD 命令的坑 dockerfile 中的 CMD 命令在docker run -it 不会执行 CMD 命令。 FROM golang WORKDIR / COPY . ./All-in-one CMD ["/bin/sh","-c","touch /kkk.txt && ls -la"] RUN echo alias ll"ls -la" > ~/.bashrc(不…

Linux:Gitlab:16.9.2 (rpm包) 部署及基础操作(1)

1.基础环境 我只准备了一台gitlab服务器&#xff0c;访问就用真机进行访问&#xff0c;接下来介绍一下详细配置 centos7 内网ip:192.168.6.7 外网ip:172.20.10.4 运行内存&#xff1a;4G CPU:4核 先去配置基础环境 关闭防火墙以及selinux 再去下载基础的运行…

注册个人小程序

访问地址 https://mp.weixin.qq.com/ 立即注册 选择小程序 注册 填写信息 登录邮箱 访问邮箱的链接激活账号 选择个人&#xff0c;填写信息 注册完成&#xff0c;即可登录进入填写信息
最新文章