介绍
生成AI目前在全球范围内广泛使用。大型语言模型能够理解提供的文本并基于此生成文本的能力,已经导致了从聊天机器人到文本分析器的众多应用。但是,这些大型语言模型通常以非结构化的方式生成文本。有时候,我们希望LLM生成的输出以结构化的形式呈现,比如JSON(JavaScript对象表示)格式。假设我们正在使用LLM来分析社交媒体帖子,并且我们需要LLM生成的输出在代码中本身作为JSON/Python变量,以执行其他任务。通过Prompt Engineering可以实现这一点,但需要花费大量时间来调整提示。为了解决这个问题,LangChain引入了输出解析功能,可以用于将LLM的输出转换为结构化格式。

学习目标
- 解释大型语言模型生成的输出
- 使用Pydantic创建自定义数据结构
- 了解提示模板的重要性,并生成一个格式化LLM输出的模板
- 学习如何使用LangChain创建LLM输出的格式化指令
- 了解如何将JSON数据解析为Pydantic对象
本文是数据科学博文马拉松的一部分。
LangChain和输出解析是什么?
LangChain是一个Python库,可以让您在短时间内构建与大型语言模型相结合的应用程序。它支持多种模型,包括OpenAI GPT LLM、Google的PaLM,甚至是Hugging Face中提供的开源模型,如Falcon、Llama等等。借助LangChain,定制大型语言模型的提示变得轻而易举,它还配备了一个开箱即用的向量存储库,可以存储输入和输出的嵌入。因此,可以使用它来创建在几分钟内查询任何文档的应用程序。
LangChain使大型语言模型能够通过代理从互联网上获取信息。它还提供了输出解析器,允许我们从大型语言模型生成的输出中结构化数据。LangChain提供了不同的输出解析器,如列表解析器、日期时间解析器、枚举解析器等等。在本文中,我们将介绍JSON解析器,它可以将LLM生成的输出解析为JSON格式。下面,我们可以观察到一个典型的流程,即将LLM输出解析为Pydantic对象,从而创建出一组可供Python变量直接使用的数据。
![]()
入门-设置模型
在本节中,我们将使用LangChain来设置模型。在本文中,我们将始终使用PaLM作为我们的大型语言模型。我们将使用Google Colab作为我们的环境。您可以将PaLM替换为任何其他大型语言模型。我们将首先导入所需的模块。
!pip install google-generativeai langchain
- 这将下载LangChain库和与PaLM模型一起使用的google-generativeai库。
- 需要langchain库来创建自定义提示并解析大型语言模型生成的输出。
- google-generativeai库将允许我们与Google的PaLM模型进行交互。
PaLM API密钥
为了使用PaLM,我们需要一个API密钥,我们可以通过注册MakerSuite网站来获得。接下来,我们将导入所有必要的库,并将API密钥传递给实例化的PaLM模型。
import os
import google.generativeai as palm
from langchain.embeddings import GooglePalmEmbeddings
from langchain.llms import GooglePalm
os.environ['GOOGLE_API_KEY'] = 'YOUR API KEY'
palm.configure(api_key=os.environ['GOOGLE_API_KEY'])
llm = GooglePalm()
llm.temperature = 0.1
prompts = ["Name 5 planets and line about them"]
llm_result = llm._generate(prompts)
print(llm_result.generations[0][0].text)
- 在这里,我们首先创建了一个Google PaLM(Pathways Language Model)的实例,并将其分配给变量llm
- 在下一个步骤中,我们将模型的温度设置为0.1,将其设置低,因为我们不希望模型产生幻觉
- 然后,我们创建了一个Prompt列表,并将其传递给变量prompts
- 为了将提示传递给PaLM,我们调用_generate()方法,然后将Prompt列表传递给它,并将结果存储在变量llm_result中
- 最后,我们通过调用.generations并通过调用.text方法将其转换为文本来打印结果
该提示的输出如下所示:
![]()
我们可以看到,大型语言模型生成了一个相对合理的输出,LLM还尝试通过添加一些陈述来为其增加一些结构。但是,如果我想将每个模型的信息分别存储在一个变量中该怎么办?如果我想将行星名称、公转周期和距离太阳的距离分别存储在一个变量中?模型生成的输出不能直接用于实现这一目标。因此,需要输出解析的需要。
创建一个Pydantic输出解析器和Prompt模板
在本节中,我们将讨论从langchain中的输出解析器输出解析给定义好的格式。在之前的例子中,输出是一个非结构化的格式。让我们看看如何将大型语言模型生成的信息存储在结构化格式中。
代码实现
让我们首先来看看下面的代码:
from pydantic import BaseModel, Field, validator
from langchain.output_parsers import PydanticOutputParser
class PlanetData(BaseModel):
planet: str = Field(description="行星的名称")
orbital_period: float = Field(description="该行星的公转周期(以地球天数为单位)")
distance_from_sun: float = Field(description="以百万千米为单位的行星距太阳的距离")
interesting_fact: str = Field(description="有关行星的有趣事实")
- 在这里,我们导入pydantic库以创建一个数据结构。在这个数据结构中,我们将通过解析LLM的输出来存储结果。
- 我们使用pydantic创建了一个名为PlanetData的数据结构,它存储了以下数据
- 行星:这是我们将作为输入传递给模型的行星名称
- 公转周期:这是一个包含特定行星的公转周期(以地球日计算)的浮点数值
- 距离太阳:这是一个浮点数,表示行星到太阳的距离
- 有趣的事实:这是一个包含了一条关于行星的有趣事实的字符串
现在,我们的目标是向大型语言模型查询有关行星的信息,并通过解析LLM的输出将所有这些数据存储在PlanetData数据结构中。为了将LLM输出解析为Pydantic数据结构,LangChain提供了一个名为PydanticOutputParser的解析器。我们将PlanetData类传递给这个解析器,可以定义如下:
planet_parser = PydanticOutputParser(pydantic_object=PlanetData)
我们将解析器存储在一个名为planet_parser的变量中。解析器对象有一个名为get_format_instructions()的方法,该方法告诉LLM如何生成输出。让我们尝试打印它
from pprint import pppp(planet_parser.get_format_instructions())
![]()
从上面我们可以看到,格式说明包含了如何格式化LLM生成的输出的信息。它告诉LLM输出数据以JSON模式,因此可以将这个JSON解析为Pydantic数据结构。它还提供了一个输出模式的示例。接下来,我们将创建一个提示模板。
提示模板
from langchain import PromptTemplate, LLMChaintemplate_string = """当涉及回答关于行星的问题时,您是一个专家\n您将会得到一个行星名称,然后输出行星的名称,它的公转周期(天)\n同时输出距离太阳的距离(百万公里)和一个有趣的事实```{planet_name}```{format_instructions}"""planet_prompt = PromptTemplate( template=template_string, input_variables=["planet_name"], partial_variables={"format_instructions": planet_parser.get_format_instructions()})
- 在我们的提示模板中,我们告诉LLM我们将提供一个行星名称作为输入,而LLM需要生成包含轨道周期、距离太阳的距离和关于该行星的有趣事实等信息的输出
- 然后我们将这个模板分配给PromptTemplate(),并将输入变量名提供给input_variables参数,对于我们的情况是planet_name
- 我们还提供之前看到的格式说明,告诉LLM如何以JSON格式生成输出
让我们尝试给出一个行星名称,并观察在发送给大型语言模型之前的提示是什么样的
input_prompt = planet_prompt.format_prompt(planet_name='mercury')pp(input_prompt.to_string())
![]()
在输出中,我们看到我们定义的模板首先出现,后面跟着输入“mercury”。接着是格式说明。这些格式说明包含了LLM用来生成JSON数据的指令。
测试大型语言模型
在本节中,我们将发送输入给LLM,并观察生成的数据。在前一节中,我们可以看到,当将输入字符串发送给LLM时,输入是什么样子的。
input_prompt = planet_prompt.format_prompt(planet_name='mercury')output = llm(input_prompt.to_string())pp(output)
![]()
我们可以看到大型语言模型生成的输出。输出确实以JSON格式生成。JSON数据包含了我们在PlanetData数据结构中定义的所有键。每个键都有一个我们期望它具有的值。
现在我们需要将这个JSON数据解析到我们之前定义的数据结构中。这可以很容易地通过我们之前定义的PydanticOutputParser来实现。让我们看一下这段代码:
parsed_output = planet_parser.parse(output)print("行星:",parsed_output.planet)print("公转周期:",parsed_output.orbital_period)print("距离太阳的距离(百万公里):",parsed_output.distance_from_sun)print("有趣的事实:",parsed_output.interesting_fact)
对于planet_parser的parse()方法的调用将接受输出,然后将其解析和转换为Pydantic对象,对于我们的情况是PlanetData对象。因此,大型语言模型生成的输出,即JSON被解析为PlannetData数据结构,我们现在可以从中访问各个数据。上述代码的输出将是
![]()
我们看到,JSON数据中的键值对被正确解析为Pydantic数据。让我们再尝试另一个行星并观察输出:
input_prompt = planet_prompt.format_prompt(planet_name='金星')output = llm(input_prompt.to_string())parsed_output = planet_parser.parse(output)print("行星:",parsed_output.planet)print("公转周期:",parsed_output.orbital_period)print("距离太阳:",parsed_output.distance_from_sun)print("有趣的事实:",parsed_output.interesting_fact)
![]()
我们看到,对于输入“金星”,LLM能够生成JSON作为输出,并且成功解析为Pydantic数据。通过输出解析,我们可以直接利用大型语言模型生成的信息。
潜在应用和用例
在这一部分,我们将介绍一些潜在的实际应用和用例,我们可以在这些输出解析技术中使用。输出解析用于信息提取或在提取后使用,即在提取任何类型的数据时,我们希望解析它,以便其他应用程序可以使用提取的信息。其中一些应用包括:
- 产品投诉提取和分析:当一个新品牌进入市场并推出新产品时,首要任务是检查产品的表现,其中评估的最佳方法之一是分析消费者在社交媒体上使用这些产品的帖子。输出解析器和LLM使得能够从消费者的社交媒体帖子中提取品牌和产品名称,甚至投诉等信息。这些大型语言模型通过输出解析将这些数据存储在Python变量中,可以用于数据可视化。
- 客户支持:在使用LLMs创建用于客户支持的聊天机器人时,一个重要的任务是从客户的聊天记录中提取信息。这些信息包含关于产品/服务的消费者面临的问题。使用LangChain的输出解析器而不是创建自定义代码来提取这些信息,可以轻松提取这些细节。
- 职位发布信息:在开发类似Indeed、LinkedIn等职位搜索平台时,可以使用LLMs从职位发布中提取详细信息,包括职位名称、公司名称、工作经验年限和职位描述。输出解析可以将此信息保存为结构化的JSON数据,用于职位匹配和推荐。通过LangChain的输出解析器直接解析LLM输出的这些信息,可以减少执行这个单独的解析操作所需的大量冗余代码。
结论
大型语言模型非常强大,因为它们可以适应各种用例,具有出色的文本生成能力。但是,在实际使用生成的输出时,它们经常不够用,我们不得不花费大量时间解析输出。在本文中,我们探讨了这个问题以及如何使用LangChain的输出解析器解决它,特别是可以解析LLM生成的JSON数据并将其转换为Pydantic对象的JSON解析器。
主要要点
本文的一些主要要点包括:
- LangChain是一个Python库,可以使用现有的大型语言模型创建应用程序。
- LangChain提供了输出解析器,可以解析大型语言模型生成的输出。
- Pydantic允许我们定义自定义数据结构,可以在解析LLMs的输出时使用。
- 除了Pydantic JSON解析器外,LangChain还提供了其他输出解析器,如列表解析器、日期时间解析器、枚举解析器等。
常见问题
本文中显示的媒体不属于Analytics Vidhya,仅供作者自行决定使用。