AutoGen、LangChain、LlamaIndex玩了一圈,越来越感觉Prompt Engineering 才是核心。欢迎大家一起学习AIGC、AGI,欢迎点赞,评论区讨论。
前言
吴恩达老师在他的ChatGPT Prompt Engineering for Developers公开课中,分享了关于Prompt 工程的两条原则:一是清晰且具体的prompt, 二是给大模型思考的时间(推理或计算过程)。
建议大家刷一下这个公开课,里面展示了以下6大策略:
- 写清晰的提示
- 给模型提供参考 Few Shot
- 将复杂任务拆分成子任务
- 给GPT时间思考
- 使用外部工具(agent)
- 反复迭代问题
我在之前刷的时候,focus在语法层。当写这篇文章时,边二刷,边感觉这些策略如太极一般简单。这些策略不只反映大模型的工作流程,也跟我们解决问题时的思考过程是一样的。
我们来看下这个demo:
c
你是一位专业的老喻干货店小编,负责文案的撰写。
对于远近闻名的赣南板鸭,是江西年夜饭的一道佳肴,您能写一篇吸引人的推广文章吗?
The output should be a markdown code snippet formatted in the following schema, including the leading and tailing "```json" and "```"
```json
{
"description": string // 板鸭的描述文案,
"reason": string // 推荐理由
}
LLM返回如下:
json
{ "description": "赣南板鸭,江西年夜饭的瑰宝,以酥脆的皮、嫩滑的肉质和独特的香味而闻名。经过精心烹制的板鸭,口感丰富,美味无比。",
"reason": "这篇推广文章突出了赣南板鸭的独特口感和美味,同时提到它是江西年夜饭的一道传统佳肴,吸引读者的兴趣并激发他们品尝的欲望。" }
Model I/O
假如说LangChain
这个AI框架是车的话,LLM就是这台车的发动机。LLM的使用分成三步:输入提示(Prompt)、调用模型(Predict)和输出解析(Parse),LangChain
把这个过程称为Model I/O。
要开发AI应用的我们,必须得研究这台发动机啊。不然等到华为鸿蒙智仓一发力,冰箱彩电大沙发就没得玩了。在输入提示环节,LangChain
为我们提供了PromptTemplate;调用模型环节,LangChain
为不同的大模型提供了统一的接口,方便我们切换高度各种大模型;输出解析环节提供了各种Parser,可以精确地从模型输出中获取需要的信息。将大模型返回的非结构化文本,转换成程序方便处理的结构化数据。
提示模板
老喻干货店有很多干货、地方特色,如果我们要为每一种干货写一段简介文案,就可以使用PromptTemplate。
ini
# 引入LangChain提示模板
from langchain import PromptTemplate
# 新建模板
template = """您是一位专业的老喻干货店小编,负责文案编写。\n
对于售价为 {price} 元的 {food_name} ,您能写一段吸引人的简短描述吗?
"""
# 根据原始模板创建LangChain提示模板
prompt = PromptTemplate.from_template(template)
# 打印LangChain提示模板的内容
print(prompt)
上述的代码其实生成的prompt具体内容是:
ini
input_variables=['food_name', 'price']
output_parser=None
partial_variables={}
template='/\n您是一位专业的老喻干货店小编,负责文案编写。
\n对于售价为 {price} 元的 {food_name} ,您能写一段吸引人的简短描述吗?\n'
template_format='f-string'
validate_template=True
f-string的意思是它是一个模板字符串,有两个变量{food_name}和{price}表示干货的名称和价格,在模板中占位,在最后生成prompt时会被相应的值替换。
from_template
表示可以从一个模板创建一个PromptTemplate实例。所以PromptTemplate
的from_template
方法就是将一个模板字符串转化为包含input_variables、output_parser、partial_variables、template、template_format、validate_template的更好操作的PromptTemplate对象,产品经理会根据各种应用场景预设很多内置模板,它们也是应用的核心。
模型分类
常用的LLM分成三在类:
-
LLM
比如 text-davinci-003、LlaMa、Claude都是典型的文本大模型。OpenAI最近还推出了GPT-4V多模态大模型、Google 的Gemini也是。LLM负责根据Prompt,生成输出并返回。
-
聊天模型 Chat Model 相比上面的模型,类似于ChatGPT的聊天模型有比较固定的role和结构,背后还是由上面的语言模型支持。
-
文本嵌入模型 Embedding Model OpenAI 的 text-embedding-ada-002会将文本转变成LLM更好理解和计算的浮点数(检索的相似cosine计算)。存入向量数据库,做RAG应用。
模型调用
python
# 设置OpenAI API Key
import os
os.environ["OPENAI_API_KEY"] = '你的Open AI API Key'
# 引入LangChain中的OpenAI模型接口
from langchain import OpenAI
# 新建模型实例
model = OpenAI(model_name='gpt-3.5-turbo')
# 输入提示
input = prompt.format(food_name=["赣南板鸭"], price='40')
# 得到模型的输出
output = model(input)
# 打印输出内容
print(output)
prompt.format
会将food_name替换为"赣南板鸭",price替换为'40',得到的prompt就是:"您是一位专业的老喻干货店小编,负责文案编写。\n对于售价为 40 元的 赣南板鸭 ,您能写一段吸引人的简短描述吗?", 大模型返回如下:
品味正宗赣南板鸭,尽享美食的极致享受!香脆外皮、嫩滑肉质,每一口都散发着浓郁的鸭香,让您的味蕾沉醉其中。无论是家庭聚会还是节日盛宴,赣南板鸭都是不可错过的美味选择。
提示词模板可以复用,如下:
ini
foods = ["三江萝卜腌菜", "高安腐竹", "黑木耳"]
prices = ["15", "20", "65"]
for food, price in zip(foods, prices): # 使用提示模板生成输入
input_prompt = prompt.format(flower_name=food, price=price) # 得到模型的输出
output = model(input_prompt) # 打印输出内容
print(output)
三江萝卜腌菜,清爽可口的美味选择!新鲜的萝卜经过精心腌制,口感酥脆,带有微妙的酸甜味道,让您一口接一口停不下来。无论是作为开胃菜还是伴碟佐餐,三江萝卜腌菜都能为您的餐桌增添一抹美味风情。
替换LLM
LangChain提供了统一的LLM调用接口,方便灵活替换各种模型。Hugging Face 社区有很多开源的大模型,我们来试下:
python
# 引入提示模板
from langchain import PromptTemplate
# 创建模板
template = """/\n您是一位专业的老喻干货店小编,负责文案编写。
\n对于售价为 {price} 元的 {food_name} ,您能写一段吸引人的简短描述吗?\n
"""
# 根据模板创建LangChain提示模板
prompt = PromptTemplate.from_template(template)
# 打印LangChain提示模板的内容
print(prompt)
import os
os.environ['HUGGINGFACEHUB_API_TOKEN'] = '你的HuggingFace API Token'
# 引入LangChain中的OpenAI模型接口
from langchain import HuggingFaceHub
# 创建模型实例
model= HuggingFaceHub(repo_id="google/flan-t5-large")
# 输入提示
input = prompt.format(food_name=["赣南板鸭"], price='40')
# 得到模型的输出
output = model(input)
# 打印输出内容
print(output)
所以,我们可以总结LangChain
中的PromptTemplate
的好处:
- 可读性更好
- 可复用
- 好维护
一类模板解决一类问题,
- 变量处理
- 参数化
输出解析
LangChain 提供的解析模型输出的功能,使你能够更容易地从模型输出中获取结构化的信息,这将大大加快基于语言模型进行应用开发的效率。
接下来,我们就通过 LangChain 的输出解析器来重写,让模型生成结构化的输出,同时对其进行解析,将解析好的数据存入 CSV 文档。
ini
from langchain import PromptTemplate, OpenAI
#OpenAI Key
import os
os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'
# 创建提示模板 多加了fomat_instructions
prompt_template = """您是一位专业的干货店小编,负责写文案。
对于售价为 {price} 元的 {food_name} ,您能写一段吸引人的简短描述吗?
{format_instructions}"""
# 新建模型实例
model = OpenAI(model_name='gpt-3.5-turbo')
# 导入结构化输出解析器和ResponseSchema
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
# 定义我们想要接收的响应模式
response_schemas = [
ResponseSchema(name="description", description="干货的描述文案"),
ResponseSchema(name="reason", description="问什么要这样写这个文案")
]
# 根据响应schema 创建输出解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
# 获取格式指示
format_instructions = output_parser.get_format_instructions()
# 根据模板创建提示,同时在提示中加入输出解析器的说明 对应用partial_variables
prompt = PromptTemplate.from_template(prompt_template,
partial_variables={"format_instructions": format_instructions})
# 数据准备
foods = ["三江萝卜腌菜", "高安腐竹", "黑木耳"]
prices = ["15", "20", "65"]
# 创建一个空的DataFrame用于存储结果
import pandas as pd
df = pd.DataFrame(columns=["food", "price", "description", "reason"]) # 先声明列名
for food, price in zip(foods, prices):
# 根据提示准备模型的输入
input = prompt.format(food_name=food, price=price)
# 获取模型的输出
output = model(input)
# 解析模型的输出(这是一个字典结构)
parsed_output = output_parser.parse(output)
# 在解析后的输出中添加"flower"和"price"
parsed_output['food'] = food
parsed_output['price'] = price
# 将解析后的输出添加到DataFrame中
df.loc[len(df)] = parsed_output
# 打印字典
print(df.to_dict(orient='records'))
# 保存DataFrame到CSV文件
df.to_csv("foods_with_descriptions.csv", index=False)
总结
- model I/O
- 三个流程里的工具
- 贴合的实战
参考资料
- 黄佳老师的LangChain课