ToB企服应用市场:ToB评测及商务社交产业平台

标题: 小北的字节跳动青训营与LangChain实战课:深入探索输出剖析器与Pydantic解 [打印本页]

作者: 美丽的神话    时间: 5 天前
标题: 小北的字节跳动青训营与LangChain实战课:深入探索输出剖析器与Pydantic解
 前言

       近来,字节跳动的青训营再次扬帆起航,作为第二次参与其中的小北,深感荣幸能借此时机为那些尚未了解青训营的友友们带来一些具体先容。青训营不但是一个技术学习与成长的摇篮,更是一个连接未来与梦想的桥梁~
小北的青训营 X MarsCode 技术训练营——AI 加码,字节跳动青训营入营考核解答(连续更新中~~~)-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118​编辑https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118
https://blog.csdn.net/Zhiyilang/article/details/143384787?sharetype=blogdetail&sharerId=143384787&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118
小北的字节跳动青训营与 LangChain 实战课:探索 AI 技术的新边界(连续更新中~~~)-CSDN博客​编辑https://blog.csdn.net/Zhiyilang/article/details/143454165https://blog.csdn.net/Zhiyilang/article/details/143454165https://blog.csdn.net/Zhiyilang/article/details/143454165https://blog.csdn.net/Zhiyilang/article/details/143454165https://blog.csdn.net/Zhiyilang/article/details/143454165
https://blog.csdn.net/Zhiyilang/article/details/143454165
小北的字节跳动青训营与LangChain系统安装和快速入门学习(连续更新中~~~)。-CSDN博客​编辑https://blog.csdn.net/Zhiyilang/article/details/143455380https://blog.csdn.net/Zhiyilang/article/details/143455380https://blog.csdn.net/Zhiyilang/article/details/143455380https://blog.csdn.net/Zhiyilang/article/details/143455380https://blog.csdn.net/Zhiyilang/article/details/143455380
https://blog.csdn.net/Zhiyilang/article/details/143455380
小北的字节跳动青训营用LangChain打造“易速鲜花”内部员工知识库问答系统(连续更新中~~~)-CSDN博客​编辑https://blog.csdn.net/Zhiyilang/article/details/143456544https://blog.csdn.net/Zhiyilang/article/details/143456544https://blog.csdn.net/Zhiyilang/article/details/143456544https://blog.csdn.net/Zhiyilang/article/details/143456544https://blog.csdn.net/Zhiyilang/article/details/143456544
https://blog.csdn.net/Zhiyilang/article/details/143456544
小北的字节跳动青训营与提示工程(上):用少样本FewShotTemplate和ExampleSelector创建应景文案(连续更新中~~~)-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/143468624?sharetype=blogdetail&sharerId=143468624&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118https://blog.csdn.net/Zhiyilang/article/details/143468624?sharetype=blogdetail&sharerId=143468624&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118
https://blog.csdn.net/Zhiyilang/article/details/143468624?sharetype=blogdetail&sharerId=143468624&sharerefer=PC&sharesource=Zhiyilang&spm=1011.2480.3001.8118小北的字节跳动青训营与提示工程(下):用思维链和思维树提升模型思索质量(连续更新中~~~)-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/143494432
https://blog.csdn.net/Zhiyilang/article/details/143494432小北的字节跳动青训营与调用模型:调用模型:OpenAI API vs 微调开源Llama2/ChatGLM(连续更新中~~~)-CSDN博客
https://blog.csdn.net/Zhiyilang/article/details/143495077哈喽哈喽,这里是是zyll~,北浊.接待来到小北的 LangChain 实战课学习条记! 


       在这个充满厘革的期间,技术的每一次进步都在推动着天下的快速发展。在上一课中,我们学习了如何为一些花和价格生成吸引人的描述,并将这些描述和缘故原由存储到一个CSV文件中。为了实现这个目的,我们调用了OpenAI模型,并利用告终构化输出剖析器,以及一些数据处理和存储的工具。本日,我们将进一步深入研究LangChain中的输出剖析器,并用一个新的剖析器——Pydantic剖析器来重构第5课中的步伐。这也是模型I/O框架的末了一讲。
LangChain中的输出剖析器

语言模型输出的是文本,这是给人类阅读的。但很多时候,你可能想要得到的是步伐可以或许处理的布局化信息。这就是输出剖析器发挥作用的地方。
输出剖析器是一种专用于处理和构建语言模型响应的类。一个基本的输出剖析器类通常需要实现以下核心方法:
LangChain提供了多种输出剖析器,包括:

上面的各种剖析器中,前三种很容易理解,而布局化输出剖析器你已经用过了。所以接下来我们重点讲一讲Pydantic(JSON)剖析器、自动修复剖析器和重试剖析器。
Pydantic(JSON)剖析器实战

Pydantic (JSON) 剖析器应该是最常用也是最重要的剖析器,我带着你用它来重构鲜花文案生成步伐。
   Pydantic 是一个 Python 数据验证和设置管理库,主要基于 Python 范例提示。只管它不是专为 JSON 设计的,但由于 JSON 是现代 Web 应用和 API 交互中的常见数据格式,Pydantic 在处理和验证 JSON 数据时特别有效。
  接下来,我们将利用Pydantic剖析器来重构鲜花文案生成步伐。
第一步:创建模型实例
先通过情况变量设置OpenAI API密钥,然后利用LangChain库创建一个OpenAI的模型实例,选择text-davinci-003作为大语言模型。
  1. # ------Part 1
  2. # 设置OpenAI API密钥
  3. import os
  4. os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'
  5. # 创建模型实例
  6. from langchain import OpenAI
  7. model = OpenAI(model_name='gpt-3.5-turbo-instruct')
复制代码
第二步:定义输出数据的格式
创建一个空的DataFrame,用于存储从模型生成的描述。然后,通过定义一个名为FlowerDescription的Pydantic BaseModel类,来指定渴望的数据格式(即数据的布局)。
  1. # ------Part 2
  2. # 创建一个空的DataFrame用于存储结果
  3. import pandas as pd
  4. df = pd.DataFrame(columns=["flower_type", "price", "description", "reason"])
  5. # 数据准备
  6. flowers = ["玫瑰", "百合", "康乃馨"]
  7. prices = ["50", "30", "20"]
  8. # 定义我们想要接收的数据格式
  9. from pydantic import BaseModel, Field
  10. class FlowerDescription(BaseModel):
  11.     flower_type: str = Field(description="鲜花的种类")
  12.     price: int = Field(description="鲜花的价格")
  13.     description: str = Field(description="鲜花的描述文案")
  14.     reason: str = Field(description="为什么要这样写这个文案")
复制代码
Pydantic的特点包括:

第三步:创建输出剖析器
利用LangChain库中的PydanticOutputParser创建输出剖析器,该剖析器将用于剖析模型的输出,以确保其符合FlowerDescription的格式。然后,利用剖析器的get_format_instructions方法获取输出格式的指示。
  1. # ------Part 3
  2. # 创建输出解析器
  3. from langchain.output_parsers import PydanticOutputParser
  4. output_parser = PydanticOutputParser(pydantic_object=FlowerDescription)
  5. # 获取输出格式指示
  6. format_instructions = output_parser.get_format_instructions()
  7. # 打印提示
  8. print("输出格式:",format_instructions)
复制代码
步伐输出如下:
  1. 输出格式: The output should be formatted as a JSON instance that conforms to the JSON schema below.
  2. As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}}
  3. the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.
  4. Here is the output schema:
  5. {"properties": {"flower_type": {"title": "Flower Type", "description": "\u9c9c\u82b1\u7684\u79cd\u7c7b", "type": "string"}, "price": {"title": "Price", "description": "\u9c9c\u82b1\u7684\u4ef7\u683c", "type": "integer"}, "description": {"title": "Description", "description": "\u9c9c\u82b1\u7684\u63cf\u8ff0\u6587\u6848", "type": "string"}, "reason": {"title": "Reason", "description": "\u4e3a\u4ec0\u4e48\u8981\u8fd9\u6837\u5199\u8fd9\u4e2a\u6587\u6848", "type": "string"}}, "required": ["flower_type", "price", "description", "reason"]}
复制代码
下面,我们会把这个内容也传输到模型的提示中,让输入模型的提示和输出剖析器的要求相互符合,前后就呼应得上
第四步:创建提示模板

定义一个提示模板,该模板将用于为模型生成输入提示。模板中包罗需要模型添补的变量(如价格和花的种类),以及之前获取的输出格式指示。
  1. # ------Part 4
  2. # 创建提示模板
  3. from langchain import PromptTemplate
  4. prompt_template = """您是一位专业的鲜花店文案撰写员。
  5. 对于售价为 {price} 元的 {flower} ,您能提供一个吸引人的简短中文描述吗?
  6. {format_instructions}"""
  7. # 根据模板创建提示,同时在提示中加入输出解析器的说明
  8. prompt = PromptTemplate.from_template(prompt_template,
  9.        partial_variables={"format_instructions": format_instructions})
  10. # 打印提示
  11. print("提示:", prompt)
复制代码
输出:
  1. 提示:
  2. input_variables=['flower', 'price']
  3. output_parser=None
  4. partial_variables={'format_instructions': 'The output should be formatted as a JSON instance that conforms to the JSON schema below.\n\n
  5. As an example, for the schema {
  6. "properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}},
  7. "required": ["foo"]}}\n
  8. the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema.
  9. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.\n\n
  10. Here is the output schema:\n```\n
  11. {"properties": {
  12. "flower_type": {"title": "Flower Type", "description": "\\u9c9c\\u82b1\\u7684\\u79cd\\u7c7b", "type": "string"},
  13. "price": {"title": "Price", "description": "\\u9c9c\\u82b1\\u7684\\u4ef7\\u683c", "type": "integer"},
  14. "description": {"title": "Description", "description": "\\u9c9c\\u82b1\\u7684\\u63cf\\u8ff0\\u6587\\u6848", "type": "string"},
  15. "reason": {"title": "Reason", "description": "\\u4e3a\\u4ec0\\u4e48\\u8981\\u8fd9\\u6837\\u5199\\u8fd9\\u4e2a\\u6587\\u6848", "type": "string"}},
  16. "required": ["flower_type", "price", "description", "reason"]}\n```'}
  17. template='您是一位专业的鲜花店文案撰写员。
  18. \n对于售价为 {price} 元的 {flower} ,您能提供一个吸引人的简短中文描述吗?\n
  19. {format_instructions}'
  20. template_format='f-string'
  21. validate_template=True
复制代码
总的来说,这个提示模板是一个用于生成模型输入的工具。你可以在模板中定义需要的输入变量,以及模板字符串的格式和布局,然后利用这个模板来为每种鲜花生成一个描述。
后面,我们还要把实际的信息,循环传入提示模板,生成一个个的具体提示。下面让我们继续。
第五步:生成提示,传入模型并剖析输出
循环处理所有的花和它们的价格。对于每种花,根据提示模板创建输入,然后获取模型的输出。利用之前创建的剖析器来剖析输出,并将剖析后的输出添加到DataFrame中。
  1. # ------Part 5
  2. for flower, price in zip(flowers, prices):
  3.     # 根据提示准备模型的输入
  4.     input = prompt.format(flower=flower, price=price)
  5.     # 打印提示
  6.     print("提示:", input)
  7.     # 获取模型的输出
  8.     output = model(input)
  9.     # 解析模型的输出
  10.     parsed_output = output_parser.parse(output)
  11.     parsed_output_dict = parsed_output.dict()  # 将Pydantic格式转换为字典
  12.     # 将解析后的输出添加到DataFrame中
  13.     df.loc[len(df)] = parsed_output.dict()
  14. # 打印字典
  15. print("输出的数据:", df.to_dict(orient='records'))
复制代码
具体来说,输出的一个提示是如许的:
   提示: 您是一位专业的鲜花店文案撰写员。 对于售价为 20 元的 康乃馨 ,您能提供一个吸引人的简短中文描述吗?
  The output should be formatted as a JSON instance that conforms to the JSON schema below.
  As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}}
  the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.
  Here is the output schema:
  1. {"properties": {"flower_type": {"title": "Flower Type", "description": "\u9c9c\u82b1\u7684\u79cd\u7c7b", "type": "string"}, "price": {"title": "Price", "description": "\u9c9c\u82b1\u7684\u4ef7\u683c", "type": "integer"}, "description": {"title": "Description", "description": "\u9c9c\u82b1\u7684\u63cf\u8ff0\u6587\u6848", "type": "string"}, "reason": {"title": "Reason", "description": "\u4e3a\u4ec0\u4e48\u8981\u8fd9\u6837\u5199\u8fd9\u4e2a\u6587\u6848", "type": "string"}}, "required": ["flower_type", "price", "description", "reason"]}
复制代码
下面,步伐剖析模型的输出。在这一步中,你利用你之前定义的输出剖析器(output_parser)将模型的输出剖析成了一个FlowerDescription的实例。FlowerDescription是你之前定义的一个Pydantic类,它包罗了鲜花的范例、价格、描述以及描述的来由。
然后,将剖析后的输出添加到DataFrame中。在这一步中,你将剖析后的输出(即FlowerDescription实例)转换为一个字典,并将这个字典添加到你的DataFrame中。这个DataFrame是你用来存储所有鲜花描述的。
末了,打印出所有的结果,并可以选择将其生存到CSV文件中。
  1. 输出的数据:
  2. [{'flower_type': 'Rose', 'price': 50, 'description': '玫瑰是最浪漫的花,它具有柔和的粉红色,有着浓浓的爱意,价格实惠,50元就可以拥有一束玫瑰。', 'reason': '玫瑰代表着爱情,是最浪漫的礼物,以实惠的价格,可以让您尽情体验爱的浪漫。'},
  3. {'flower_type': '百合', 'price': 30, 'description': '这支百合,柔美的花蕾,在你的手中摇曳,仿佛在与你深情的交谈', 'reason': '营造浪漫氛围'},
  4. {'flower_type': 'Carnation', 'price': 20, 'description': '艳丽缤纷的康乃馨,带给你温馨、浪漫的气氛,是最佳的礼物选择!', 'reason': '康乃馨是一种颜色鲜艳、芬芳淡雅、具有浪漫寓意的鲜花,非常适合作为礼物,而且20元的价格比较实惠。'}]
复制代码

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

自动修复剖析器主要用于纠正小的格式错误。当输出格式不正确时,它会尝试修复格式错误,而不是重新生成输出。
首先,让我们来设计一个剖析时出现的错误。
  1. # 导入所需要的库和模块
  2. from langchain.output_parsers import PydanticOutputParser
  3. from pydantic import BaseModel, Field
  4. from typing import List
  5. # 使用Pydantic创建一个数据格式,表示花
  6. class Flower(BaseModel):
  7.     name: str = Field(description="name of a flower")
  8.     colors: List[str] = Field(description="the colors of this flower")
  9. # 定义一个用于获取某种花的颜色列表的查询
  10. flower_query = "Generate the charaters for a random flower."
  11. # 定义一个格式不正确的输出
  12. misformatted = "{'name': '康乃馨', 'colors': ['粉红色','白色','红色','紫色','黄色']}"
  13. # 创建一个用于解析输出的Pydantic解析器,此处希望解析为Flower格式
  14. parser = PydanticOutputParser(pydantic_object=Flower)
  15. # 使用Pydantic解析器解析不正确的输出
  16. parser.parse(misformatted)
复制代码
这段代码如果运行,会出现错误。 
  1. 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)
复制代码
不过,这里我并不想如许解决题目,而是尝试利用OutputFixingParser来帮助咱们自动解决类似的格式错误。
  1. # 从langchain库导入所需的模块
  2. from langchain.chat_models import ChatOpenAI
  3. from langchain.output_parsers import OutputFixingParser
  4. # 设置OpenAI API密钥
  5. import os
  6. os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'
  7. # 使用OutputFixingParser创建一个新的解析器,该解析器能够纠正格式不正确的输出
  8. new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())
  9. # 使用新的解析器解析不正确的输出
  10. result = new_parser.parse(misformatted) # 错误被自动修正
  11. print(result) # 打印解析后的输出结果
复制代码
用上面的新的new_parser来代替Parser进行剖析,你会发现,JSON格式的错误题目被解决了,步伐不再出错。
输出如下:
  1. name='Rose' colors=['red', 'pink', 'white']
复制代码
这里的秘密在于,在OutputFixingParser内部,调用了原有的PydanticOutputParser,如果乐成,就返回;如果失败,它会将格式错误的输出以合格式化的指令传递给大模型,并要求LLM进行相关的修复。
神奇吧,大模型不但给我们提供知识,还随时帮助分析并解决步伐出错的信息。
我们通过一个示例来演示如何利用自动修复剖析器。假设我们有一个格式错误的JSON字符串,利用PydanticOutputParser剖析时会引发错误。此时,我们可以利用OutputFixingParser来尝试自动修复格式错误。
重试剖析器(RetryWithErrorOutputParser)实战

重试剖析器在模型的初次输出不符合预期时,会尝试重新生成新的输出。它通过重新与模型交互,利用模型的推理能力来找回相关信息,使得输出更加完备和符合预期。
首先照旧设计一个剖析过程中的错误。
  1. # 定义一个模板字符串,这个模板将用于生成提问
  2. template = """Based on the user question, provide an Action and Action Input for what step should be taken.
  3. {format_instructions}
  4. Question: {query}
  5. Response:"""
  6. # 定义一个Pydantic数据格式,它描述了一个"行动"类及其属性
  7. from pydantic import BaseModel, Field
  8. class Action(BaseModel):
  9.     action: str = Field(description="action to take")
  10.     action_input: str = Field(description="input to the action")
  11. # 使用Pydantic格式Action来初始化一个输出解析器
  12. from langchain.output_parsers import PydanticOutputParser
  13. parser = PydanticOutputParser(pydantic_object=Action)
  14. # 定义一个提示模板,它将用于向模型提问
  15. from langchain.prompts import PromptTemplate
  16. prompt = PromptTemplate(
  17.     template="Answer the user query.\n{format_instructions}\n{query}\n",
  18.     input_variables=["query"],
  19.     partial_variables={"format_instructions": parser.get_format_instructions()},
  20. )
  21. prompt_value = prompt.format_prompt(query="What are the colors of Orchid?")
  22. # 定义一个错误格式的字符串
  23. bad_response = '{"action": "search"}'
  24. parser.parse(bad_response) # 如果直接解析,它会引发一个错误
复制代码
由于bad_response只提供了action字段,而没有提供action_input字段,这与Action数据格式的预期不符,所以剖析会失败。
我们首先尝试用OutputFixingParser来解决这个错误。
  1. from langchain.output_parsers import OutputFixingParser
  2. from langchain.chat_models import ChatOpenAI
  3. fix_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())
  4. parse_result = fix_parser.parse(bad_response)
  5. print('OutputFixingParser的parse结果:',parse_result)
复制代码
我们来看看这个尝试解决了什么题目,没解决什么题目。
解决的题目有:

没解决的题目有:

当然,另有更鲁棒的选择,我们末了尝试一下RetryWithErrorOutputParser这个剖析器。

  1. # 初始化RetryWithErrorOutputParser,它会尝试再次提问来得到一个正确的输出
  2. from langchain.output_parsers import RetryWithErrorOutputParser
  3. from langchain.llms import OpenAI
  4. retry_parser = RetryWithErrorOutputParser.from_llm(
  5.     parser=parser, llm=OpenAI(temperature=0)
  6. )
  7. parse_result = retry_parser.parse_with_prompt(bad_response, prompt_value)
  8. print('RetryWithErrorOutputParser的parse结果:',parse_result)
复制代码
我们通过一个示例来演示如何利用重试剖析器。假设我们有一个输出不完备的响应,利用OutputFixingParser无法完全修复。此时,我们可以利用RetryWithErrorOutputParser来尝试重新生成完备的输出。这个剖析器没有让我们失望,乐成地还原了格式,甚至也根据传入的原始提示,还原了action_input字段的内容。RetryWithErrorOutputParser的parse结果:action='search' action_input='colors of Orchid'

总结

布局化剖析器和Pydantic剖析器都旨在从大型语言模型中获取格式化的输出。布局化剖析器更适合简单的文本响应,而Pydantic剖析器则提供了对复杂数据布局和范例的支持。选择哪种剖析器取决于应用的具体需求和输出的复杂性。
自动修复剖析器主要适用于纠正小的格式错误,而重试剖析器则可以处理更复杂的题目,包括格式错误和内容缺失。
在选择剖析器时,需要考虑具体的应用场景。如果仅面对格式题目,自动修复剖析器可能充足;但如果输出的完备性和准确性至关重要,那么重试剖析器可能是更好的选择。
思索题

题目较多,可以选择性思索,期待在留言区看到你的分享。如果你觉得内容对你有帮助,也接待分享给有需要的朋侪!
延伸阅读



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4