在langchain实战课,作者使用了GPT4等进行API的调用,但是由于多种原因,使用了豆包API调用,在本文及接下来的序列文章将尽力还原读者代码和意图,并且交流在代码细节中的运用以及debug,与大家分享。此次针对PromptTemplate和OutputParser.
PromptTemplate
好的prompt原则:
- 给予模型清晰明确的指示
- 让模型慢慢地思考
输出解析器
语言模型输出的是文本,这是给人类阅读的。但很多时候,你可能想要获得的是程序能够处理的结构化信息。这就是输出解析器发挥作用的地方。
输出解析器是一种专用于处理和构建语言模型响应的类。一个基本的输出解析器类通常需要实现两个核心方法。
- get_format_instructions:这个方法需要返回一个字符串,用于指导如何格式化语言模型的输出,告诉它应该如何组织并构建它的回答。
- parse:这个方法接收一个字符串(也就是语言模型的输出)并将其解析为特定的数据结构或格式。这一步通常用于确保模型的输出符合我们的预期,并且能够以我们需要的形式进行后续处理。
解析器中比较复杂的是如下三种:
- Pydantic(JSON)解析器:这个解析器用于处理模型的输出,当模型的输出应该是一个符合特定格式的JSON对象时使用。它使用Pydantic库,这是一个数据验证库,可以用于构建复杂的数据模型,并确保模型的输出符合预期的数据模型。
- 自动修复解析器(Auto-Fixing Parser):这个解析器可以自动修复某些常见的模型输出错误。例如,如果模型的输出应该是一段文本,但是模型返回了一段包含语法或拼写错误的文本,自动修复解析器可以自动纠正这些错误。
- 重试解析器(RetryWithErrorOutputParser):这个解析器用于在模型的初次输出不符合预期时,尝试修复或重新生成新的输出。例如,如果模型的输出应该是一个日期,但是模型返回了一个字符串,那么重试解析器可以重新提示模型生成正确的日期格式。
Json(Pydantic) 解析器实战
ydantic有这样几个特点。
- 数据验证:当你向Pydantic类赋值时,它会自动进行数据验证。例如,如果你创建了一个字段需要是整数,但试图向它赋予一个字符串,Pydantic会引发异常。
- 数据转换:Pydantic不仅进行数据验证,还可以进行数据转换。例如,如果你有一个需要整数的字段,但你提供了一个可以转换为整数的字符串,如
"42",Pydantic会自动将这个字符串转换为整数42。 - 易于使用:创建一个Pydantic类就像定义一个普通的Python类一样简单。只需要使用Python的类型注解功能,即可在类定义中指定每个字段的类型。
- JSON支持:Pydantic类可以很容易地从JSON数据创建,并可以将类的数据转换为JSON格式。
# 设置OpenAI API 密钥
import os
from langchain_openai import OpenAI
import pandas as pd
os.environ['OPENAI_API_KEY'] = ''
# 创建模型实例
model = OpenAI(
model='gpt-3.5-turbo-instruct',
temperature=0,
max_retries=2,
api_key=os.environ['OPENAI_API_KEY'],
)
# 创建一个空的DataFrame用于存储结果
df = pd.DataFrame(columns=['flower_type', 'price', 'description', 'reason'])
# 数据准备
flowers = ['玫瑰', '百合', '康乃馨']
prices = ['50', '30', '20']
# 定义我们想要接收的数据格式
from pydantic import BaseModel, Field
class FlowerDescription(BaseModel):
flower_type: str = Field(description='鲜花的种类')
price: int = Field(description='鲜花的价格')
description: str = Field(description='鲜花的描述文案')
reason: str = Field(description='为什么要写这个文案')
# 创建输出解析器
from langchain.output_parsers import PydanticOutputParser
output_parser = PydanticOutputParser(pydantic_object=FlowerDescription)
# 获取输出格式指示
format_instructions = output_parser.get_format_instructions()
# print(format_instructions)
# 创建提示模版
from langchain_core.prompts import PromptTemplate
prompt_template = '''您是一位专业的鲜花店文案撰写员。
对于售价为{price}元的{flower}, 您能提供一个吸引人的简短中文描述吗?
{format_instructions}'''
# 根据模版提示,同时在提示中加入输出解析器的说明
prompt = PromptTemplate.from_template(prompt_template,
partial_variables={"format_instructions": format_instructions})
#print(prompt)
# 根据提示输入变量
for flower, price in zip(flowers, prices):
input1 = prompt.format(flower=flower, price=price)
# print(input1)
output = model.invoke(input1)
# 解析模型的输出
parsed_output = output_parser.parse(output)
parsed_output_dict = parsed_output.dict()
# 解析后的输出添加到DataFrame中
df.loc[len(df)] = parsed_output.dict()
# 打印字典
print(df.to_dict(orient='records'))
Bug解析:主要在有几个库在调用过程中更换了新的,openai的调用方式也发生了一点改变,和掘金小册中略有不同,得到结果如下:
[{'flower_type': '玫瑰', 'price': 50, 'description': '这束玫瑰花色鲜艳,花朵饱满,散发着迷人的花香。它象征着爱情和浪漫,是送给心爱的人最完美的礼物。无论是情人节、生日还是纪念日,都是最佳的选择。', 'reason': '鲜花店需要吸引顾客购买,这个文案能够吸引顾客的眼球,让他们更有购买的欲望。'}, {'flower_type': '百合', 'price': 30, 'description': '这束百合花散发着清新的花香,花瓣洁白如雪,象征着纯洁和美好的爱情。无论是送给恋人、朋友还是家人,都能传达出您对他们的真挚情感。', 'reason': '作为一位专业的鲜花店文案撰写员,我深知百合花的美妙之处,希望通过这段简短的描述,能够吸引更多人选择百合花作为礼物。'}, {'flower_type': '康乃馨', 'price': 20, 'description': '这束康乃馨,花朵饱满,色彩鲜艳,散发着淡淡的花香,是表达爱意、感谢和祝福的最佳选择。无论是送给爱人、朋友还是家人,都能传递出您的真挚情感。', 'reason': '康乃馨是一种受欢迎的鲜花,它的美丽和芳香能够打动人心,因此我们特别为这束康乃馨撰写了这段吸引人的描述文案,希望能够帮助您更好地表达您的情感。'}]