LangChain学习之prompt格式化与解析器使用

时间:2024-06-02 18:41:27

1. 学习背景

在LangChain for LLM应用程序开发中课程中,学习了LangChain框架扩展应用程序开发中语言模型的用例和功能的基本技能,遂做整理为后面的应用做准备。视频地址:基于LangChain的大语言模型应用开发+构建和评估高

2. 先准备尝试调用OpenAI API

本实验基于jupyternotebook进行。

2.1先安装openai包、langchain包

!pip install openai
!pip install langchain

2.2 尝试调用openai包

import openai

# 此处需要提前准备好可使用的openai KEY
openai.api_key = "XXXX"
openai.base_url = "XXXX"

def get_completion(prompt, model = "gpt-3.5-turbo"):
    messages = [{"role": "user", "content": prompt}]
    response = openai.chat.completions.create(
        model = model,
        messages = messages,
        temperature = 0,
    )
    return response.choices[0].message.content
get_completion("What is 1+1?")

输出结果:

'1 + 1 equals 2.'

3.尝试用API解决邮件对话问题

3.1 邮件内容和风格

customer_email = """
Arrr, I be fuming that me blender lid \
flew off and splattered me kitchen walls \
with smoothie! And to make matters worse,\
the warranty don't cover the cost of \
cleaning up me kitchen. I need yer help \
right now, matey!
"""

style = """American English \
in a calm and respectful tone
"""

3.2 构造成prompt

prompt = f"""Translate the text \
that is delimited by triple backticks \
into a style that is {style}. 
text: ```{customer_email}```
"""
prompt

输出如下:

"Translate the text that is delimited by triple backticks into a style that is American English in a calm and respectful tone\n. \ntext: ```\nArrr, I be fuming that me blender lid flew off and splattered me kitchen walls with smoothie! And to make matters worse,the warranty don't cover the cost of cleaning up me kitchen. I need yer help right now, matey!\n```\n"

3.3 使用上述prompt得到答案

response = get_completion(prompt)
response

输出如下:

'I must express my frustration that my blender lid unexpectedly came off and caused my kitchen walls to be covered in smoothie splatters! And unfortunately, the warranty does not cover the cleaning costs of my kitchen. I kindly request your immediate assistance, my friend.'

4. 尝试用langchain解决

4.1 用langchain调用API

from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI(
    api_key = "XXXX",
    base_url = "XXXX",
    temperature=0.0)
print(chat)

输出如下:

ChatOpenAI(client=<openai.resources.chat.completions.Completions object at 0x7f362ab4f340>, 
async_client=<openai.resources.chat.completions.AsyncCompletions object at 0x7f362aba9d80>, 
temperature=0.0, openai_api_key='sk-gGSeHiJn09Ydl6Q1655eCf128b3a42XXXXXXXXXXXXXX', 
openai_api_base='XXXX', openai_proxy='')

4.2 构造prompt模板

注意和3.2的区别,一个用了f"“”“”“,一个直接”“”“”"。

template_string = """Translate the text \
that is delimited by triple backticks \
into a style that is {style}. \
text: ```{text}```
"""

customer_style = """American English in a calm and respectful tone"""

customer_email = """
Arrr, I be fuming that me blender lid \
flew off and splattered me kitchen walls \
with smoothie! And to make matters worse, \
the warranty don't cover the cost of \
cleaning up me kitchen. I need yer help \
right now, matey!
"""

4.3 调用ChatPromptTemplate

from langchain.prompts import ChatPromptTemplate
# 将构造的prompt模板化
prompt_template = ChatPromptTemplate.from_template(template_string)
# 模板中的占位符填充的参数
customer_messages = prompt_template.format_messages(
    style = customer_style,
    text = customer_email
)
print(type(customer_messages))
print(customer_messages[0])

输出如下:

<class 'list'>
content="Translate the text that is delimited by triple backticks into a style that is American English in a calm and respectful tone\n. text: ```\nArrr, I be fuming that me blender lid flew off and splattered me kitchen walls with smoothie! And to make matters worse, the warranty don't cover the cost of cleaning up me kitchen. I need yer help right now, matey!\n```\n"

4.4 使用LLM解决问题

# Call the LLM to translate to the style of the customer message
customer_response = chat(customer_messages)
print(customer_response.content)

输出如下:

Oh man, I 'm really frustrated that my blender lid flew off and made a mess of my kitchen walls with smoothie! And on top of that, the warranty doesn't cover the cost of cleaning up my kitchen. I could really use your help right now, buddy!

5. 调用langchain对邮件回复

5.1定义回复的prompt

service_reply = """Hey there customer, \
the warranty does not cover \
cleaning expenses for your kitchen \
because it's your fault that \
you misused your blender \
by forgetting to put the lid on before \
starting the blender. \
Tough luck! See ya!
"""

service_style_pirate = """\
a polite tone \
that speaks in English Pirate\
"""

# 继续使用前面定义的prompt_template,占位符用参数填充
service_messages = prompt_template.format_messages(
    style = service_style_pirate,
    text = service_reply)

print(service_messages[0].content)

输出如下:

Translate the text that is delimited by triple backticks into a style that is a polite tone that speaks in English Pirate. 
text: ```
Hey there customer, the warranty does not cover cleaning expenses for your kitchen because it's your fault that you misused your blender by forgetting to put the lid on before starting the blender. Tough luck! See ya!```

5.2 使用LLM解决问题

service_response = chat(service_messages)
print(service_response.content)

输出如下:

Ahoy there, me heartie! Unfortunately, the warranty be not coverin' the cost of cleanin' yer kitchen, as tis yer own fault for misusin' yer blender by forgettin' to put on the lid afore startin' the blendin'. Aye, 'tis a tough break indeed! Fare thee well, matey!

至此我们就完成了使用langchain去实现prompt的构造、转换和调用。

6. 用langchain转化回答为JSON格式

6.1 构造模板

# 顾客对产品的评论
customer_review = """\
This leaf blower is pretty amazing.  It has four settings:\
candle blower, gentle breeze, windy city, and tornado. \
It arrived in two days, just in time for my wife's \
anniversary present. \
I think my wife liked it so much she was speechless. \
So far I've been the only one using it, and I've been \
using it every other morning to clear the leaves on our lawn. \
It's slightly more expensive than the other leaf blowers \
out there, but I think it's worth it for the extra features.
"""

# 顾客意见形成模板
review_template = """\
For the following text, extract the following information:

gift: Was the item purchased as a gift for someone else? \
Answer True if yes, False if not or unknown.

delivery_days: How many days did it take for the product \
to arrive? If this information is not found, output -1.

price_value: Extract any sentences about the value or price,\
and output them as a comma separated Python list.

Format the output as JSON with the following keys:
gift
delivery_days
price_value

text: {text}
"""


from langchain.prompts import ChatPromptTemplate
# 构造模板,占位符信息用prompt填充
prompt_template = ChatPromptTemplate.from_template(review_template)
messages = prompt_template.format_messages(text=customer_review)
# 调用LLM,输入为prompt
response = chat(messages)
print(response.content)

输出如下:

{
  "gift": true,
  "delivery_days": 2,
  "price_value": "It's slightly more expensive than the other leaf blowers out there, but I think it's worth it for the extra features."
}

6.2 构造合适的prompt

print(type(response.content))

输出如下:

str

可以看到输出内容是字符串类型的,为了方便处理数据,我们需要的是JSON格式,因此还需要进行转化。

from langchain.output_parsers import ResponseSchema
from langchain.output_parsers import StructuredOutputParser


gift_schema = ResponseSchema(name="gift",  description="Was the item purchased as a gift for someone else? Answer True if yes, False if not or unknown.")
delivery_days_schema = ResponseSchema(name="delivery_days", description="How many days did it take for the product to arrive? If this information \
                                      is not found, output -1.")
price_value_schema = ResponseSchema(name="price_value", description="Extract any sentences about the value or price, and output them as a comma \
                                    separated Python list.")

response_schemas = [gift_schema, 
                    delivery_days_schema,
                    price_value_schema]
# 构造转换器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
format_instructions = output_parser.get_format_instructions()
print(format_instructions)

输出如下:

The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":

```json
{
	"gift": string  // Was the item purchased as a gift for someone else? Answer True if yes, False if not or unknown.
	"delivery_days": string  // How many days did it take for the product to arrive? If this information                                       is not found, output -1.
	"price_value": string  // Extract any sentences about the value or price, and output them as a comma                                     separated Python list.
}```

LLM会根据构造的prompt进行回答,生成最终的回答结果。接着构造完整的prompt:

review_template_2 = """\
For the following text, extract the following information:

gift: Was the item purchased as a gift for someone else? \
Answer True if yes, False if not or unknown.

delivery_days: How many days did it take for the product\
to arrive? If this information is not found, output -1.

price_value: Extract any sentences about the value or price,\
and output them as a comma separated Python list.

text: {text}

{format_instructions}
"""

prompt = ChatPromptTemplate.from_template(template=review_template_2)
messages = prompt.format_messages(text=customer_review, 
                                format_instructions=format_instructions)
print(messages[0].content)

输出如下:

For the following text, extract the following information:

gift: Was the item purchased as a gift for someone else? Answer True if yes, False if not or unknown.

delivery_days: How many days did it take for the productto arrive? If this information is not found, output -1.

price_value: Extract any sentences about the value or price,and output them as a comma separated Python list.

text: This leaf blower is pretty amazing.  It has four settings:candle blower, gentle breeze, windy city, and tornado. It arrived in two days, just in time for my wife's anniversary present. I think my wife liked it so much she was speechless. So far I've been the only one using it, and I've been using it every other morning to clear the leaves on our lawn. It's slightly more expensive than the other leaf blowers out there, but I think it's worth it for the extra features.


The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":

```json
{
	"gift": string  // Was the item purchased as a gift for someone else? Answer True if yes, False if not or unknown.
	"delivery_days": string  // How many days did it take for the product to arrive? If this information                                       is not found, output -1.
	"price_value": string  // Extract any sentences about the value or price, and output them as a comma                                     separated Python list.
}```

6.3 使用LLM解决问题

response = chat(messages)
print(response.content)

输出如下:

```json
{
	"gift": "True",
	"delivery_days": "2",
	"price_value": "It's slightly more expensive than the other leaf blowers out there, but I think it's worth it for the extra features."
}```

进行格式转换

output_dict = output_parser.parse(response.content)
print(output_dict)

输出如下:

{'gift': 'True', 'delivery_days': '2', 'price_value': "It's slightly more expensive than the other leaf blowers out there, but I think it's worth it for the extra features."}

接下来查看输出类型:

type(output_dict)

输出如下:

dict

接下来就可以愉快的使用输出数据了。

总的来说,langchain对于格式化输出和prompt构造拥有较好的效果,可以很好使用。