自动修复解析器(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)
这段代码如果运行,会出现错误。
langchain.schema.output_parser.OutputParserException: Failed to parse Flower from completion {'name': '康乃馨', 'colors': ['粉红色','白色']}. Got: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
这个错误消息来自Python的内建JSON解析器发现输入的JSON格式不正确。程序尝试用PydanticOutputParser来解析JSON字符串时,Python期望属性名称被双引号包围,但在给定的JSON字符串中是单引号。
当这个错误被触发后,程序进一步引发了一个自定义异常:OutputParserException,它提供了更多关于错误的上下文。这个自定义异常的消息表示在尝试解析flower对象时遇到了问题。
问题在于misformatted字符串的内容:
"{'name': '康乃馨', 'colors': ['粉红色','白色','红色','紫色','黄色']}"
应该改为:
'{"name": "康乃馨", "colors": ["粉红色","白色","红色","紫色","黄色"]}'
这样,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) # 打印解析后的输出结果
用上面的新的new_parser来代替Parser进行解析,JSON格式的错误问题被解决了,程序不再出错。
输出如下:
name='Rose' colors=['red', 'pink', 'white']
在OutputFixingParser内部,调用了原有的PydanticOutputParser,如果成功,就返回;如果失败,它会将格式错误的输出以及格式化的指令传递给大模型,并要求LLM进行相关的修复。
重试解析器(RetryWithErrorOutputParser)实战
OutputFixingParser不错,但它只能做简单的格式修复。如果出错的不只是格式,比如,输出根本不完整,有缺失内容,那么仅仅根据输出和格式本身,是无法修复它的。
此时,通过实现输出解析器中parse_with_prompt方法,LangChain提供的重试解析器可以帮助我们利用大模型的推理能力根据原始提示找回相关信息。
我们通过分析一个重试解析器的用例来理解上面的这段话。
首先还是设计一个解析过程中的错误。
# 定义一个模板字符串,这个模板将用于生成提问
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)
这个解析器没有让我们失望,成功地还原了格式,甚至也根据传入的原始提示,还原了action_input字段的内容。
RetryWithErrorOutputParser的parse结果:action='search' action_input='colors of Orchid'