当前位置:   article > 正文

(16-2)输出解析器(Output Parsers)(2)_jsonkeyoutputfunctionsparser

jsonkeyoutputfunctionsparser

4.5  JSON解析

在LangChain中,JSON解析器用于将大型语言模型(LLM)的输出解析为JSON格式。JSON解析器允许用户指定任意的JSON模式,并查询LLM以获取符合该模式的输出。这对于需要从LLM获取结构化数据的场景非常有用。

在使用JSON解析器时,需要注意大型语言模型是“有漏洞的抽象”(leaky abstractions),这意味着它们可能无法总是生成完全符合预期的JSON格式的输出。因此,选择具有足够能力生成格式良好的JSON的LLM是很重要的,在此有如下所示的建议。

  1. 在OpenAI的产品线中,DaVinci模型可以可靠地生成JSON,而Curie模型在这方面的能力则有所下降。
  2. 可以选择使用库Pydantic来声明数据模型,Python库Pydantic用于实现数据验证和设置管理功能,它可以帮助确保数据的准确性和一致性。

实例4-1使用JSON解析器(源码路径:codes\4\json01.py

实例文件json01.py的具体实现代码如下所示。

  1. from typing import List
  2. from langchain.prompts import PromptTemplate
  3. from langchain_core.output_parsers import JsonOutputParser
  4. from langchain_core.pydantic_v1 import BaseModel, Field
  5. from langchain_openai import ChatOpenAI
  6. # 创建一个ChatOpenAI模型实例
  7. model = ChatOpenAI(temperature=0)
  8. # 定义你希望的数据结构
  9. class Joke(BaseModel):
  10. setup: str = Field(description="question to set up a joke")
  11. punchline: str = Field(description="answer to resolve the joke")
  12. # 定义一个查询意图,用于提示语言模型填充数据结构
  13. joke_query = "Tell me a joke."
  14. # 设置一个解析器,并在提示模板中注入指令
  15. parser = JsonOutputParser(pydantic_object=Joke)
  16. # 创建一个提示模板
  17. prompt = PromptTemplate(
  18. template="Answer the user query.\n{format_instructions}\n{query}",
  19. input_variables=["query"],
  20. partial_variables={"format_instructions": parser.get_format_instructions()},
  21. )
  22. # 创建一个处理链:提示模板 -> 模型 -> 解析器
  23. chain = prompt | model | parser
  24. # 调用处理链,获取一个笑话
  25. output = chain.invoke({"query": joke_query})
  26. print(output)
  27. # 使用流式方法逐个打印输出
  28. for s in chain.stream({"query": joke_query}):
  29. print(s)

上述代码的实现流程如下所示:

  1. 首先,定义了类Joke,它继承自Pydantic的BaseModel,并指定了两个字段:setup和punchline。
  2. 然后,创建了一个JSON解析器实例,并将Joke类作为参数传递给它。
  3. 接下来,创建了一个提示模板,并将其与模型和解析器连接起来,形成一个处理链。通过调用这个处理链,我们得到了一个符合Joke数据结构的JSON对象。
  4. 最后,使用流式方法逐个打印输出,展示逐步获取和处理LLM生成的数据的过程。

如果不使用Pydantic,也可以创建一个JSON解析器实例,但不指定具体的模式。这将提示LLM返回JSON格式的输出,但不会提供关于模式的具体信息。在这种情况下,LLM生成的JSON可能会有不同的结构,这需要开发者根据实际情况进行处理。

执行上述代码后将得到两种类型的输出:一种是直接调用chain.invoke方法得到的完整JSON对象,另一种是通过流式调用chain.stream方法逐步得到的JSON片段。

1. 完整输出(使用chain.invoke)

当使用chain.invoke方法时,将得到一个完整的JSON对象,它包含了LLM生成的数据,下面是输出结果:

  1. {
  2.   "setup": "Why don't scientists trust atoms?",
  3.   "punchline": "Because they make up everything!"
  4. }

这个JSON对象对应于Joke Pydantic模型,其中setup字段包含了笑话的铺垫,punchline字段包含了笑话的笑点。

2. 流式输出(使用chain.stream)

当使用chain.stream方法时,将逐步得到LLM生成的数据片段。这是因为流式输出支持逐步处理输出,而不是等待整个输出生成完毕。下面是流式输出结果:

  1. {'setup': ''}
  2. {'setup': 'Why'}
  3. {'setup': 'Why don'}
  4. {'setup': "Why don't"}
  5. {'setup': "Why don't scientists"}
  6. {'setup': "Why don't scientists trust"}
  7. {'setup': "Why don't scientists trust atoms"}
  8. {'setup': "Why don't scientists trust atoms?", 'punchline': ''}
  9. {'setup': "Why don't scientists trust atoms?", 'punchline': 'Because'}
  10. {'setup': "Why don't scientists trust atoms?", 'punchline': 'Because they'}
  11. {'setup': "Why don't scientists trust atoms?", 'punchline': 'Because they make'}
  12. {'setup': "Why don't scientists trust atoms?", 'punchline': 'Because they make up'}
  13. {'setup': "Why don't scientists trust atoms?", 'punchline': 'Because they make up everything'}

上面的输出结果展示了LLM生成的笑话是如何逐步构建的,每个片段都是一个包含部分或全部笑话的JSON对象。

注意:这些输出结果是基于假设LLM能够准确地理解提示并生成符合预期格式的响应。在实际应用中,LLM的输出可能会有所不同,并且需要根据实际情况进行验证和调整。此外,流式输出的顺序和内容可能会根据LLM的具体实现和响应而有所不同。

4.6  OpenAI函数解析

OpenAI函数解析器是一组特殊的输出解析器,它们利用OpenAI的语言模型的功能调用来结构化和解析输出。这些解析器设计用来与支持函数调用功能的OpenAI模型一起工作,如DaVinci。它们允许用户定义请求的预期格式,并从模型生成的文本中提取和验证数据。

在LangChain中,常用的OpenAI函数解析器如下所示。

  1. JsonOutputFunctionsParser:这个解析器将OpenAI模型的功能调用输出作为JSON对象返回,适用于需要将输出转换为JSON格式以便进一步处理的场景。
  2. PydanticOutputFunctionsParser:此解析器将功能调用的输出作为Pydantic模型返回,Pydantic是一个数据验证和设置管理库,它可以确保数据的准确性和一致性。通过使用Pydantic模型,可以提供额外的验证和类型安全。
  3. JsonKeyOutputFunctionsParser:这个解析器从功能调用的JSON输出中提取特定键的值,适用于当你需要从结构化的输出中提取单个字段时。
  4. PydanticAttrOutputFunctionsParser:类似于JsonKeyOutputFunctionsParser,但它返回的是Pydantic模型的属性。这允许直接与模型的特定字段交互,而不需要处理整个JSON对象。

在使用这些解析器时,需要定义一个函数调用模板,这个模板将告诉OpenAI模型你期望的输出格式。然后,LangChain会将这个模板与模型的输出结合起来,生成结构化的数据。例如,如果想要获取一个笑话,可以定义一个Joke Pydantic模型,并创建一个函数调用模板来请求这个笑话。当模型生成输出时,OpenAI函数解析器会根据你定义的模板来解析和验证数据,确保它符合Joke模型的预期格式。

OpenAI函数解析器提供了一种强大的方式来处理和验证从OpenAI模型中生成的数据,使得与这些模型的交互更加灵活和可靠。通过使用OpenAI函数解析器,开发者可以确保他们得到的数据是结构化和可用的,从而更容易地集成到各种应用程序中。

假设有一个大型语言模型(LLM),它能够回答用户提出的关于天气的问题。请看下面的例子,解析模型的输出结果,提取其中的关键信息,比如温度和天气状况,此时可以使用OpenAI函数解析器来实现这一目标。

实例4-1:获取北京的天气信息(源码路径:codes\4\open01.py

实例文件open01.py的具体实现代码如下所示。

  1. from langchain_core.pydantic_v1 import BaseModel, Field
  2. from langchain_openai import ChatOpenAI
  3. from langchain.prompts import PromptTemplate
  4. from langchain.output_parsers.openai_functions import PydanticOutputFunctionsParser
  5. from langchain_community.utils.openai_functions import convert_pydantic_to_openai_function
  6. # 定义天气信息的Pydantic模型
  7. class Weather(BaseModel):
  8. temperature: float = Field(description="当前温度(摄氏度)")
  9. condition: str = Field(description="天气状况")
  10. # 设置OpenAI模型
  11. weather_model = ChatOpenAI(temperature=0)
  12. # 定义提示模板
  13. prompt = PromptTemplate.from_template(
  14. """请问您想了解哪个城市的天气?
  15. """
  16. )
  17. # 将Pydantic模型转换为OpenAI函数
  18. openai_functions = [convert_pydantic_to_openai_function(Weather)]
  19. # 创建OpenAI函数解析器
  20. parser = PydanticOutputFunctionsParser(pydantic_schema=Weather)
  21. # 创建处理链
  22. chain = prompt | weather_model.bind(functions=openai_functions) | parser
  23. # 调用处理链并传入用户提出的问题,以获取天气信息
  24. output = chain.invoke({"input": "明天北京的天气如何?"})
  25. print(output)

上述代码的实现流程如下所示:

  1. 首先,定义了一个 Pydantic 模型 WeatherForecast,用于描述天气预报的数据结构,包括日期 (date)、温度 (temperature) 和天气状况 (condition)。
  2. 然后,创建了一个 OpenAI 函数 Weather,该函数将返回一个包含天气预报信息的 JSON 格式。
  3. 接着,使用 OpenAI 函数解析器 PydanticOutputFunctionsParser 将函数的输出转换为 Pydantic 模型。最后,调用处理链,传入用户的查询,以获取天气预报信息。执行后会输出:
{"date": "2024-04-12", "temperature": "22°C", "condition": "晴"}

4.7  修正解析器(Output-fixing parser)

在LangChain中,修正解析器(Output-fixing parser)是LangChain中一种特殊的输出解析器,它包裹了另一个输出解析器。如果原始解析器失败,它将调用另一个大型语言模型(LLM)来修复任何格式错误。可以将格式错误的输出以及格式指令一起传递给模型,并要求它修复这些错误。例如在下面代码中定义了一个Pydantic模型来表示演员及其电影作品,并尝试使用Pydantic输出解析器来解析一个格式错误的JSON字符串。

  1. from typing import List
  2. from langchain.output_parsers import PydanticOutputParser
  3. from langchain_core.pydantic_v1 import BaseModel, Field
  4. from langchain_openai import ChatOpenAI
  5. # 定义一个Pydantic模型来表示演员和他们的电影作品
  6. class Actor(BaseModel):
  7. name: str = Field(description="演员的名字")
  8. film_names: List[str] = Field(description="他们主演的电影名称列表")
  9. # 定义一个查询,要求生成一个随机演员的电影作品列表
  10. actor_query = "为一个随机演员生成电影作品列表。"
  11. # 创建一个Pydantic输出解析器实例
  12. parser = PydanticOutputParser(pydantic_object=Actor)
  13. # 一个格式错误的JSON字符串
  14. misformatted = "{'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}"
  15. # 尝试使用Pydantic输出解析器解析格式错误的JSON字符串
  16. try:
  17. parser.parse(misformatted)
  18. except Exception as e:
  19. print(f"解析错误:{e}")

执行这段代码后,由于JSON字符串格式错误,将抛出异常,并在控制台中打印出异常信息:

解析错误:Failed to parse Actor from completion {'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}. Got: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

这条异常信息表明,Pydantic输出解析器无法将给定的JSON字符串解析为Actor模型,因为JSON字符串中的属性名称没有用双引号包围。如果使用修正解析器OutputFixingParser进行及处理,它将尝试使用另一个LLM来修复格式错误,例如下面的代码。

  1. from langchain.output_parsers import OutputFixingParser
  2. # 创建一个输出修正解析器实例,传入原始的Pydantic输出解析器和LLM
  3. new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())
  4. # 使用输出修正解析器尝试解析格式错误的JSON字符串
  5. try:
  6. fixed_actor = new_parser.parse(misformatted)
  7. print(fixed_actor)
  8. except Exception as e:
  9. print(f"修复失败:{e}")

在上述代码中,OutputFixingParser将接收到格式错误的JSON字符串,并尝试使用ChatOpenAI LLM来修复它。如果LLM能够理解问题并生成正确的格式,OutputFixingParser将返回一个符合Actor模型的结构化数据,那么最终的输出将是一个符合Actor Pydantic模型的结构化数据对象。具体来说,输出将是:

Actor(name='Tom Hanks', film_names=['Forrest Gump'])

这个输出表示已经成功地将原始的格式错误的JSON字符串 {'name': 'Tom Hanks', 'film_names': ['Forrest Gump']} 修正为一个Actor对象,其中包含了演员的名字和他们主演的电影名称列表。

如果LLM无法正确地修复格式错误,OutputFixingParser会抛出一个异常,表明修复失败。在这种情况下,输出将不是预期的Actor对象,而是异常信息。因此,在使用OutputFixingParser时,应该准备好处理可能出现的异常情况。

4.8  Pandas DataFrame解析器

Pandas DataFrame 是 Python 编程中常用的数据结构,用于数据操作和分析。它提供了丰富的工具,用于处理结构化数据,如数据清洗、转换和分析。Pandas DataFrame解析器是LangChain中用于处理和分析结构化数据的一个输出解析器,它允许用户指定一个任意的Pandas DataFrame,并查询LLM以获取格式化字典形式的数据,这些数据从相应的DataFrame中提取。

Pandas DataFrame解析器允许用户指定一个 Pandas DataFrame,并查询大型语言模型(LLMs)以从 DataFrame 中提取数据,并以字典格式返回。在使用过程中,需要确保选择具有足够容量的 LLM,以生成符合指定格式的查询结果。使用类PandasDataFrameOutputParser来解析 Pandas DataFrame 的输出。使用类PromptTemplate 类来设置查询的提示模板,注入解析器的格式指令,并与 ChatOpenAI 模型一起使用。

Pandas DataFrame解析器可以执行多种操作,如对列和行进行操作,以及对数据进行汇总操作。如果查询格式不正确,将会引发 OutputParserException 错误,需要在处理代码中进行错误处理。例如下面是一个使用 Pandas DataFrame 解析器的例子,假设有一个包含动物信息的 Pandas DataFrame,包括动物的名称、腿的数量和是否能飞,在实例中想要查询该 DataFrame 中的数据,例如获取动物的名称和腿的数量。

实例4-1获取动物的名称和腿的数量(源码路径:codes\4\fra.py

实例文件fra.py的具体实现代码如下所示。

  1. import pprint
  2. from typing import Any, Dict
  3. import pandas as pd
  4. from langchain.output_parsers import PandasDataFrameOutputParser
  5. from langchain.prompts import PromptTemplate
  6. from langchain_openai import ChatOpenAI
  7. # 创建 Pandas DataFrame 包含动物信息
  8. df = pd.DataFrame({
  9. "名称": ["狗", "猫", "鸟", "蛇"],
  10. "腿的数量": [4, 4, 2, 0],
  11. "能飞吗": [False, False, True, False]
  12. })
  13. # 设置解析器,指定使用 PandasDataFrameOutputParser,并传入 DataFrame
  14. parser = PandasDataFrameOutputParser(dataframe=df)
  15. # 设置提示模板
  16. prompt = PromptTemplate(
  17. template="查询动物的信息:\n{format_instructions}\n{query}\n",
  18. input_variables=["query"],
  19. partial_variables={"format_instructions": parser.get_format_instructions()},
  20. )
  21. # 创建 ChatOpenAI 模型实例
  22. model = ChatOpenAI(temperature=0)
  23. # 定义用于格式化解析结果的函数
  24. def format_parser_output(parser_output: Dict[str, Any]) -> None:
  25. for key in parser_output.keys():
  26. parser_output[key] = parser_output[key].to_dict()
  27. return pprint.PrettyPrinter(width=4, compact=True).pprint(parser_output)
  28. # 执行查询
  29. df_query = "获取动物名称和腿的数量。"
  30. chain = prompt | model | parser
  31. parser_output = chain.invoke({"query": df_query})
  32. # 格式化并打印解析结果
  33. format_parser_output(parser_output)

在上述代码中,定义了一个包含动物信息的 Pandas DataFrame,并设置了一个查询,以获取动物的名称和腿的数量。然后,使用 Pandas DataFrame 解析器执行查询,并格式化输出结果。执行后会根据给定的查询"获取动物名称和腿的数量。",输出结果是一个字典,包含动物的名称和对应的腿的数量执行后会输出:

  1. {'名称': {'0': '狗', '1': '猫', '2': '鸟', '3': '蛇'},
  2.  '腿的数量': {'0': 4, '1': 4, '2': 2, '3': 0}}

这个字典表示了查询结果,其中包含了动物的名称和对应的腿的数量。

4.9  XML解析器

LangChain中的XML解析器是一种特殊的输出解析器,其主要作用是将大型语言模型(LLM)的文本输出转换为XML(可扩展标记语言)格式。XML是一种用于存储和传输数据的标准文本格式,它通过使用标签(tags)来描述数据的结构和语义。XML解析器的主要特点如下所示:

  1. 结构化输出:XML解析器能够将LLM生成的自由文本转换为结构化的XML数据,使得数据更易于机器解析和人类阅读。
  2. 灵活性:用户可以自定义XML的标签和结构,以适应不同的数据需求和应用场景。
  3. 错误容忍:尽管LLM被称为“有漏洞的抽象”,但XML解析器可以指导LLM生成符合预期格式的输出,减少格式错误的可能性。
  4. 数据整合:生成的XML数据可以轻松地与其他系统和应用程序集成,便于数据的进一步处理和分析。

使用XML解析器的步骤如下所示:

(1)定义数据结构:首先,需要定义希望从LLM获取的数据的结构。这通常涉及到创建一个XML模式(schema),它描述了数据的预期布局和格式。

(2)设置提示模板:创建一个提示模板(PromptTemplate),它将指导LLM如何生成符合你定义的数据结构的输出。提示模板可以包含特定的格式指令,告诉LLM如何使用XML标签来格式化其响应。

(3)创建解析器实例:实例化XMLOutputParser类,并将XML模式或其他相关参数传递给它。

(4)构建处理链:将提示模板、LLM模型和XML解析器连接起来,形成一个处理链,这个处理链将负责生成、格式化和解析数据。

(5)调用解析器:通过调用处理链的invoke方法,可以获取LLM的输出,并将其转换为XML格式。如果LLM的输出不符合预期格式,你可能需要调整提示模板或数据结构。

例如下面是一个使用XML解析器的例子,创建一个能够从大型语言模型(LLM)获取数据并以XML格式输出的系统,这个系统可以用于生成产品信息、新闻摘要信息等场景。

实例4-1生成手机产品信息(源码路径:codes\4\xml01.py

实例文件xml01.py的具体实现代码如下所示。

  1. from langchain.output_parsers import XMLOutputParser
  2. from langchain.prompts import PromptTemplate
  3. from langchain_openai import ChatOpenAI
  4. # 创建一个LLM模型实例,这里我们使用OpenAI的Chat模型
  5. model = ChatOpenAI(temperature=0)
  6. # 定义一个查询,要求生成一个产品的简要信息
  7. product_query = "请提供一款智能手机的详细信息。"
  8. # 创建一个XML解析器实例,用于将LLM的输出解析为XML格式
  9. parser = XMLOutputParser()
  10. # 设置提示模板,包含查询和格式指令
  11. prompt_template = PromptTemplate(
  12. template="""{query}
  13. 请将产品信息以以下XML标签格式化:<product>, <name>, <brand>, <price>, <features>。""",
  14. input_variables=["query"],
  15. partial_variables={"format_instructions": parser.get_format_instructions()}
  16. )
  17. # 构建处理链:提示模板 -> LLM模型 -> XML解析器
  18. chain = prompt_template | model | parser
  19. # 调用处理链并获取输出
  20. output = chain.invoke({"query": product_query})
  21. # 打印XML格式的输出
  22. print(output)

上述代码的实现流程如下所示:

  1. 创建LLM模型实例:使用 ChatOpenAI 创建了一个温度为0的LLM模型实例。
  2. 定义查询:product_query 包含了一个简单的查询,要求生成一款智能手机的详细信息。
  3. 创建XML解析器实例:使用 XMLOutputParser 创建了一个XML解析器实例,用于将LLM的输出解析为XML格式。
  4. 设置提示模板:使用 PromptTemplate 创建了一个提示模板,其中包含了查询和格式指令,指示用户以特定的XML标签格式化产品信息。
  5. 构建处理链:将提示模板、LLM模型和XML解析器连接成一个处理链。
  6. 调用处理链并获取输出:使用 chain.invoke() 方法调用处理链,并传入查询作为输入。
  7. 打印XML格式的输出:输出的信息为XML格式的字符串,包含了从语言模型生成的产品信息,根据提示模板中指定的XML标签格式进行了格式化。

执行后会输出:

  1. <product>
  2. <name>小米11</name>
  3. <brand>小米</brand>
  4. <price>3999元</price>
  5. <features>120Hz屏幕刷新率, 108MP主摄像头, 55W快充</features>
  6. </product>

这个XML数据可以直接用于网页展示、数据交换或其他需要XML格式的场合。通过使用XML解析器,可以确保从LLM获得的数据是结构化和格式化的,这样就可以在应用程序中轻松使用这些数据。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/682980
推荐阅读
相关标签
  

闽ICP备14008679号