当前位置: 首页 > news >正文

如何在langchain中对大模型的输出进行格式化

简介

我们知道在大语言模型中, 不管模型的能力有多强大,他的输入和输出基本上都是文本格式的,文本格式的输入输出虽然对人来说非常的友好,但是如果我们想要进行一些结构化处理的话还是会有一点点的不方便。

不用担心,langchain已经为我们想到了这个问题,并且提出了完满的解决方案。

langchain中的output parsers

langchain中所有的output parsers都是继承自BaseOutputParser。这个基础类提供了对LLM大模型输出的格式化方法,是一个优秀的工具类。

我们先来看下他的实现:

class BaseOutputParser(BaseModel, ABC, Generic[T]):@abstractmethoddef parse(self, text: str) -> T:"""Parse the output of an LLM call.A method which takes in a string (assumed output of a language model )and parses it into some structure.Args:text: output of language modelReturns:structured output"""def parse_with_prompt(self, completion: str, prompt: PromptValue) -> Any:"""Optional method to parse the output of an LLM call with a prompt.The prompt is largely provided in the event the OutputParser wantsto retry or fix the output in some way, and needs information fromthe prompt to do so.Args:completion: output of language modelprompt: prompt valueReturns:structured output"""return self.parse(completion)def get_format_instructions(self) -> str:"""Instructions on how the LLM output should be formatted."""raise NotImplementedError@propertydef _type(self) -> str:"""Return the type key."""raise NotImplementedError(f"_type property is not implemented in class {self.__class__.__name__}."" This is required for serialization.")def dict(self, **kwargs: Any) -> Dict:"""Return dictionary representation of output parser."""output_parser_dict = super().dict()output_parser_dict["_type"] = self._typereturn output_parser_dict

BaseOutputParser 是一个基础的类,可能被其他特定的输出解析器继承,以实现特定语言模型的输出解析。

这个类使用了Python的ABC模块,表明它是一个抽象基类(Abstract Base Class),不能被直接实例化,而是需要子类继承并实现抽象方法。

Generic[T] 表示这个类是一个泛型类,其中T 是一个类型变量,它表示解析后的输出数据的类型。

@abstractmethod 装饰器标记了 parse 方法,说明它是一个抽象方法,必须在子类中实现。parse 方法接受一个字符串参数 text,通常是语言模型的输出文本,然后将其解析成特定的数据结构,并返回。

parse_with_prompt 方法也是一个抽象方法,接受两个参数,completion 是语言模型的输出,prompt 是与输出相关的提示信息。这个方法是可选的,可以用于在需要时解析输出,可能根据提示信息来调整输出。

get_format_instructions 方法返回关于如何格式化语言模型输出的说明。这个方法可以用于提供解析后数据的格式化信息。

_type 是一个属性,可能用于标识这个解析器的类型,用于后续的序列化或其他操作。

dict 方法返回一个包含输出解析器信息的字典,这个字典可以用于序列化或其他操作。

其中子类必须要实现的方法就是parse。其他的都做为辅助作用。

langchain中有哪些Output Parser

那么langchain中有哪些Output Parser的具体实现呢?具体对应我们应用中的什么场景呢?

接下来我们将会一一道来。

List parser

ListOutputParser的作用就是把LLM的输出转成一个list。ListOutputParser也是一个基类,我们具体使用的是他的子类:CommaSeparatedListOutputParser。

看一下他的parse方法:

    def parse(self, text: str) -> List[str]:"""Parse the output of an LLM call."""return text.strip().split(", ")

还有一个get_format_instructions:

    def get_format_instructions(self) -> str:return ("Your response should be a list of comma separated values, ""eg: `foo, bar, baz`")

get_format_instructions是告诉LLM以什么样的格式进行数据的返回。

就是把LLM的输出用逗号进行分割。

下面是一个基本的使用例子:

output_parser = CommaSeparatedListOutputParser()format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(template="列出几种{subject}.\n{format_instructions}",input_variables=["subject"],partial_variables={"format_instructions": format_instructions}
)_input = prompt.format(subject="水果")
output = model(_input)
print(output)
print(output_parser.parse(output))

我们可以得到下面的输出:

Apple, Orange, Banana, Grape, Watermelon, Strawberry, Pineapple, Peach, Mango, Cherry
['Apple', 'Orange', 'Banana', 'Grape', 'Watermelon', 'Strawberry', 'Pineapple', 'Peach', 'Mango', 'Cherry']

看到这里,大家可能有疑问了, 为什么我们问的是中文,返回的却是因为呢?

这是因为output_parser.get_format_instructions就是用英文描述的,所以LLM会自然的用英文来回答。

别急,我们可以稍微修改下运行代码,如下:

output_parser = CommaSeparatedListOutputParser()format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(template="列出几种{subject}.\n{format_instructions}",input_variables=["subject"],partial_variables={"format_instructions": format_instructions + "用中文回答"}
)_input = prompt.format(subject="水果")
output = model(_input)
print(output)
print(output_parser.parse(output))

我们在format_instructions之后,提示LLM需要用中文来回答问题。这样我们就可以得到下面的结果:

苹果,橘子,香蕉,梨,葡萄,芒果,柠檬,桃
['苹果,橘子,香蕉,梨,葡萄,芒果,柠檬,桃']

是不是很棒?

Datetime parser

DatetimeOutputParser用来将LLM的输出进行时间的格式化。

class DatetimeOutputParser(BaseOutputParser[datetime]):format: str = "%Y-%m-%dT%H:%M:%S.%fZ"def get_format_instructions(self) -> str:examples = comma_list(_generate_random_datetime_strings(self.format))return f"""Write a datetime string that matches the following pattern: "{self.format}". Examples: {examples}"""def parse(self, response: str) -> datetime:try:return datetime.strptime(response.strip(), self.format)except ValueError as e:raise OutputParserException(f"Could not parse datetime string: {response}") from e@propertydef _type(self) -> str:return "datetime"

在get_format_instructions中,他告诉LLM返回的结果是一个日期的字符串。

然后在parse方法中对这个LLM的输出进行格式化,最后返回datetime。

我们看下具体的应用:

output_parser = DatetimeOutputParser()
template = """回答下面问题:
{question}
{format_instructions}"""
prompt = PromptTemplate.from_template(template,partial_variables={"format_instructions": output_parser.get_format_instructions()},
)
chain = LLMChain(prompt=prompt, llm=model)
output = chain.run("中华人民共和国是什么时候成立的?")
print(output)
print(output_parser.parse(output))
1949-10-01T00:00:00.000000Z
1949-10-01 00:00:00

回答的还不错,给他点个赞。

Enum parser

如果你有枚举的类型,那么可以尝试使用EnumOutputParser.

EnumOutputParser的构造函数需要传入一个Enum,我们主要看下他的两个方法:

    @propertydef _valid_values(self) -> List[str]:return [e.value for e in self.enum]def parse(self, response: str) -> Any:try:return self.enum(response.strip())except ValueError:raise OutputParserException(f"Response '{response}' is not one of the "f"expected values: {self._valid_values}")def get_format_instructions(self) -> str:return f"Select one of the following options: {', '.join(self._valid_values)}"

parse方法接收一个字符串 response,尝试将其解析为枚举类型的一个成员。如果解析成功,它会返回该枚举成员;如果解析失败,它会抛出一个 OutputParserException 异常,异常信息中包含了所有有效值的列表。

get_format_instructions告诉LLM需要从Enum的有效value中选择一个输出。这样parse才能接受到正确的输入值。

具体使用的例子可以参考前面两个parser的用法。篇幅起见,这里就不列了。

Pydantic (JSON) parser

JSON可能是我们在日常代码中最常用的数据结构了,这个数据结构很重要。

在langchain中,提供的JSON parser叫做:PydanticOutputParser。

既然要进行JSON转换,必须得先定义一个JSON的类型对象,然后告诉LLM将文本输出转换成JSON格式,最后调用parse方法把json字符串转换成JSON对象。

我们来看一个例子:


class Student(BaseModel):name: str = Field(description="学生的姓名")age: str = Field(description="学生的年龄")student_query = "告诉我一个学生的信息"parser = PydanticOutputParser(pydantic_object=Student)prompt = PromptTemplate(template="回答下面问题.\n{format_instructions}\n{query}\n",input_variables=["query"],partial_variables={"format_instructions": parser.get_format_instructions()+"用中文回答"},
)_input = prompt.format_prompt(query=student_query)output = model(_input.to_string())
print(output)
print(parser.parse(output))

这里我们定义了一个Student的结构体,然后让LLM给我一个学生的信息,并用json的格式进行返回。

之后我们使用parser.parse来解析这个json,生成最后的Student信息。

我们可以得到下面的输出:

示例输出:{"name": "张三", "age": "18"}
name='张三' age='18'

Structured output parser

虽然PydanticOutputParser非常强大, 但是有时候我们只是需要一些简单的结构输出,那么可以考虑StructuredOutputParser.

我们看一个具体的例子:

response_schemas = [ResponseSchema(name="name", description="学生的姓名"),ResponseSchema(name="age", description="学生的年龄")
]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(template="回答下面问题.\n{format_instructions}\n{question}",input_variables=["question"],partial_variables={"format_instructions": format_instructions}
)_input = prompt.format_prompt(question="给我一个女孩的名字?")
output = model(_input.to_string())
print(output)
print(output_parser.parse(output))

这个例子是上面的PydanticOutputParser的改写,但是更加简单。

我们可以得到下面的结果:

 ` ` `json
{"name": "Jane","age": "18"
}` ` `
{'name': 'Jane', 'age': '18'}

output返回的是一个markdown格式的json字符串,然后通过output_parser.parse得到最后的json。

其他的一些parser

除了json,xml格式也是比较常用的格式,langchain中提供的XML parser叫做XMLOutputParser。

另外,如果我们在使用parser的过程中出现了格式问题,langchain还贴心的提供了一个OutputFixingParser。也就是说当第一个parser报错的时候,或者说不能解析LLM输出的时候,就会换成OutputFixingParser来尝试修正格式问题:

from langchain.output_parsers import OutputFixingParsernew_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())new_parser.parse(misformatted)

如果错误不是因为格式引起的,那么langchain还提供了一个RetryOutputParser,来尝试重试:

from langchain.output_parsers import RetryWithErrorOutputParserretry_parser = RetryWithErrorOutputParser.from_llm(parser=parser, llm=OpenAI(temperature=0)
)retry_parser.parse_with_prompt(bad_response, prompt_value)

这几个parser都非常有用,大家可以自行尝试。

总结

虽然langchain中的有些parser我们可以自行借助python语言的各种工具来实现。但是有一些parser实际上是要结合LLM一起来使用的,比如OutputFixingParser和RetryOutputParser。

所以大家还是尽可能的使用langchain提供的parser为好。毕竟轮子都给你造好了,还要啥自行车。

相关文章:

如何在langchain中对大模型的输出进行格式化

简介 我们知道在大语言模型中, 不管模型的能力有多强大,他的输入和输出基本上都是文本格式的,文本格式的输入输出虽然对人来说非常的友好,但是如果我们想要进行一些结构化处理的话还是会有一点点的不方便。 不用担心,langchain已…...

【送书活动二期】Java和MySQL数据库中关于小数的保存问题

之前总结过一篇文章mysql数据库:decimal类型与decimal长度用法详解,主要是个人学习期间遇到的mysql中关于decimal字段的详解,最近在群里遇到一个小伙伴提出的问题,也有部分涉及,今天就再大致总结一下Java和MySQL数据库…...

11月21日,每日信息差

今天是2023年11月21日,以下是为您准备的16条信息差 第一、国内首条PPP模式市域铁路台州S1线客运量破900万人次。PPP(Public-Private Partnership)是公共基础设施的一种项目运作模式,指社会资本与政府合作,参与公共基础…...

极速整理文件!Python自动化办公新利器

更多资料获取 📚 个人网站:ipengtao.com 当涉及到自动化办公和文件整理,Python确实是一个强大的工具。在这篇博客文章中,我将深入探讨《极速整理文件!Python自动化办公新利器》这个话题,并提供更加丰富和全…...

电机控制学习

电机开发板...

leetcode 1670

leetcode 1670 解题思路 使用2个deque作为类的成员变量 code class FrontMiddleBackQueue { public:deque<int> left;deque<int> right;FrontMiddleBackQueue() {}void pushFront(int val) {left.push_front(val);if(left.size() right.size()2){right.push_fr…...

Nginx热部署

快捷查看指令 ctrlf 进行搜索会直接定位到需要的知识点和命令讲解&#xff08;如有不正确的地方欢迎各位小伙伴在评论区提意见&#xff0c;小编会及时修改&#xff09; Nginx热部署 首先来讲一下为什么要进行热部署 nginx 支持热加载 热部署 &#xff0c;在不打断用户请求的情…...

京东数据运营-京东数据平台-京东店铺数据分析-2023年10月京东烘干机品牌销售榜

鲸参谋监测的京东平台10月份烘干机市场销售数据已出炉&#xff01; 10月份&#xff0c;烘干机市场整体销售上涨。鲸参谋数据显示&#xff0c;今年10月份&#xff0c;京东平台上烘干机的销量将近5万件&#xff0c;环比增长约77%&#xff0c;同比增长约22%&#xff1b;销售额将近…...

java中的方法引用和Stream流

知识模块&#xff1a; 一.方法引用a.方法概述b.方法引用格式 二.Stream流1.Stream流概述2.Stream流操作步骤一.方法引用a.方法概述/*方法引用概述&#xff1a;当我们使用已有类中的方法作为Lambda表达式对应的接口中的抽象方法实现我们可以用方法引用来简化Lambda表达式*/impor…...

《第一行代码:Android》第三版-3.4.4体验Activity的生命周期

本文的代码是在主Activity中&#xff0c;重载了几个生命周期函数&#xff0c;在日志中打印出对应的日志信息&#xff0c;有两个按钮&#xff0c;负责启动另外的Activity&#xff0c;并回到主Activity 由此查看日志&#xff0c;来体会生命周期。 MainActivity.kt 文件如下 pac…...

用java编写一个网络聊天室

网络聊天室 服务器&#xff1a; 1.启动服务器&#xff0c;在服务器端循环监听客户端的连接 try {ServerSocket serverSocketnew ServerSocket(6622);System.out.println("服务器已启动");while(true){//把客户端实例添加到sockets里Socket socketserverSocket.acc…...

Opencv颜色追踪

废话不多说直接上代码&#xff01;&#xff01; # 这是一个示例 Python 脚本。 import cv2 import numpy as npdef track_object():# 打开摄像头外接cap cv2.VideoCapture(0)while True:# 读取摄像头帧# ret&#xff08;Return Value&#xff09;是一个布尔值&#xff0c;表示…...

计算机网络——网络可靠性及网络出口配置

1. 前言&#xff1a; 学习目标&#xff1a; 1.了解链路聚合的作用 2. 了解ACL的工作原理 3. 了解NAT的工作原理和配置 2. 网络可靠性方案 网络可靠性是指网络在面对各种异常情况或故障时&#xff0c;能够维持正常运行和提供服务的能力。这包括防止网络中断、减小数据丢失的可能…...

在虚拟机搭建nignx,和使用本地访问nginx的情况

下载nginx yum install nginx 查看nginx是否安装成功。 nginx -v nginx的配置文件的目录和资源的目录。 先到nginx.conf的目录下&#xff0c;在 /etc/nginx/nginx.conf&#xff0c;编辑它。 vi /etc/nginx/nginx.conf 可以看到默认的html的目录。在 /usr/share/nginx/html 下面…...

Java数据结构之《直接插入排序》问题

一、前言&#xff1a; 这是怀化学院的&#xff1a;Java数据结构中的一道难度中等的一道编程题(此方法为博主自己研究&#xff0c;问题基本解决&#xff0c;若有bug欢迎下方评论提出意见&#xff0c;我会第一时间改进代码&#xff0c;谢谢&#xff01;) 后面其他编程题只要我写完…...

向量场中的几个恒等式

向量场中的几个恒等式 1. ∇ 2 A ∇ ∇ ⋅ A − ∇ ∇ A \nabla ^2 A \nabla \nabla\cdot A-\nabla \times\nabla\times A ∇2A∇∇⋅A−∇∇A 2. ∇ ⋅ ∇ A 0 \nabla \cdot \nabla \times A 0 ∇⋅∇A0 3. ∇ ∇ ϕ 0 \nabla \times \nabla \phi0 ∇∇ϕ0...

异行星低代码平台--第三方插件对接:钉钉平台对接(一)

异行星低代码平台可以集成钉钉&#xff0c;实现单点登录、消息推送和组织机构同步。 提示 此功能需要企业版授权才能使用。 钉钉集成​ 单点登录 异行星低代码平台集成到钉钉后&#xff0c;只要使用钉钉账户登录钉钉客户端&#xff0c;即可在钉钉中直接使用管理后台&#…...

MyBatis使用教程详解<下>

回顾上一篇博文,我们讲了如何使用注解/XML的方式来操作数据库,实际上,一个Mapper接口的实现,这两种方式是可以并存的. 上一篇博文中,我们演示的都是比较简单的SQL语句,没有设计到复杂的逻辑,本篇博文会讲解复杂SQL的实现及一些细节处理.话不多说,让我们开始吧. 一. #{}和${} …...

C++基础 -17-继承中 基类与派生构造和析构调用顺序

首先声明 定义了派生类会同时调用基类和派生的构造函数 定义了派生类会同时调用基类和派生的析构函数 那么顺序如何如下图 构造由上往下顺序执行 析构则完全相反 #include "iostream"using namespace std;class base {public:base(){cout << "base-bui…...

uniapp实现表单弹窗

uni.showModal({title: 删除账户,confirmColor:#3A3A3A,cancelColor:#999999,confirmText:确定,editable:true,//显示content:请输入“delete”删除账户,success: function (res) {console.log(res)if(res.confirm){if(res.contentdelete){console.log(123123123213)uni.setSto…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...