小北的字节跳动青训营与提示工程(上):用少样本FewShotTemplate和ExampleSelector创建应景文案(持续更新中~~~)

 前言

       最近,字节跳动的青训营再次扬帆起航,作为第二次参与其中的小北,深感荣幸能借此机会为那些尚未了解青训营的友友们带来一些详细介绍。青训营不仅是一个技术学习与成长的摇篮,更是一个连接未来与梦想的桥梁~

小北的青训营 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.8118icon-default.png?t=O83Ahttps://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/143454165icon-default.png?t=O83Ahttps://blog.csdn.net/Zhiyilang/article/details/143454165
小北的字节跳动青训营与LangChain系统安装和快速入门学习(持续更新中~~~)。-CSDN博客​编辑https://blog.csdn.net/Zhiyilang/article/details/143455380https://blog.csdn.net/Zhiyilang/article/details/143455380icon-default.png?t=O83Ahttps://blog.csdn.net/Zhiyilang/article/details/143455380

小北的字节跳动青训营用LangChain打造“易速鲜花”内部员工知识库问答系统(持续更新中~~~)-CSDN博客​编辑https://blog.csdn.net/Zhiyilang/article/details/143456544https://blog.csdn.net/Zhiyilang/article/details/143456544icon-default.png?t=O83Ahttps://blog.csdn.net/Zhiyilang/article/details/143456544小北的字节跳动青训营与LangChain实战课:深入解析模型I/O与提示模板(持续更新中~~~)-CSDN博客https://blog.csdn.net/Zhiyilang/article/details/143464481icon-default.png?t=O83Ahttps://blog.csdn.net/Zhiyilang/article/details/143464481哈喽哈喽,这里是是zyll~,北浊.欢迎来到小北的 LangChain 实战课学习笔记!

       在这个充满变革的时代,技术的每一次进步都在推动着世界的快速发展。字节跳动的青训营,作为技术人才培养的重要平台,再次扬帆起航,为怀揣梦想的技术爱好者们提供了一个学习和成长的摇篮。作为青训营的一员,小北深感荣幸能够借此机会,为大家详细介绍青训营的精彩内容,并分享 LangChain 实战课的学习心得,希望能够帮助大家更好地理解和应用最前沿的 AI 技术。

深入探索LangChain提示模板与提示工程

        在之前的博客中,小北给大家留下了一个思考题:为什么在提示模板的构建过程中加入了partial_variables(即输出解析器指定的format_instructions)之后,模型能够生成结构化的输出?当我们打印出最终传递给大模型的提示时,这个谜团就迎刃而解了。

您是一位专业的鲜花店文案撰写员。
对于售价为 50 元的 玫瑰 ,您能提供一个吸引人的简短描述吗?
The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":

```json
{
        "description": string  // 鲜花的描述文案
        "reason": string  // 问什么要这样写这个文案
}
揭秘结构化输出的秘密

想象一下,你是一位专业的鲜花店文案撰写员,需要为售价为50元的玫瑰提供一个吸引人的简短描述。同时,你被告知输出应该是一个符合特定格式的markdown代码片段,如下所示:

	{  

	    "description": "string",  // 鲜花的描述文案  

	    "reason": "string"  // 为什么要这样写这个文案  

	}

秘密在于,LangChain的输出解析器在提示中巧妙地加入了一段文字,即{format_instructions}中的内容。这段由LangChain自动添加的文字,清晰地指示了模型应该按照什么样的格式来生成回答。它告诉模型:“你就按照这个schema(可以理解为对数据结构的描述)的格式来生成文本吧!”

这就是一个典型的提示工程应用。有了这样明确的提示,智能程度较高的模型(如GPT 3.5及以上版本)就能轻松输出可以被解析的数据结构,如JSON格式的数据。

无独有偶,在Open AI的官方文档 GPT 最佳实践中,也给出了和上面这两大原则一脉相承的6大策略。分别是:

  1. 写清晰的指示
  2. 给模型提供参考(也就是示例)
  3. 将复杂任务拆分成子任务
  4. 给GPT时间思考
  5. 使用外部工具
  6. 反复迭代问题
深入提示工程

在上一篇博客中,小北提到了吴恩达老师在ChatGPT Prompt Engineering for Developers公开课中给出的两个大原则:写出清晰而具体的指示,以及给模型思考的时间。OpenAI的GPT最佳实践也提出了类似的六大策略。

现在,让我们进一步探讨如何利用LangChain中的提示模板来做好提示工程。

提示的结构

一个实用的提示框架通常包含以下几个部分:

  1. 指令(Instruction):告诉模型任务的大致内容和操作方法,比如如何使用提供的外部信息、如何处理查询以及如何构造输出。
  2. 上下文(Context):作为模型的额外知识来源,这些信息可以手动插入,也可以通过矢量数据库检索或其他方式获取。
  3. 提示输入(Prompt Input):通常是具体的问题或需要模型做的具体事情,这个部分和指令部分也可以合并。但拆分成独立组件后,模板更加结构化,便于复用。
  4. 输出指示器(Output Indicator):标记要生成的文本的开始。
LangChain提示模板的类型

LangChain提供了String(StringPromptTemplate)和Chat(BaseChatPromptTemplate)两种基本类型的模板,并基于它们构建了不同类型的提示模板。这些模板的导入方式如下:


from langchain.prompts.prompt import PromptTemplate
from langchain.prompts import FewShotPromptTemplate
from langchain.prompts.pipeline import PipelinePromptTemplate
from langchain.prompts import ChatPromptTemplate
from langchain.prompts import (
    ChatMessagePromptTemplate,
    SystemMessagePromptTemplate,
    AIMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

我发现有时候不指定 .prompts,直接从LangChain包也能导入模板。 

from langchain import PromptTemplate
  • 使用PromptTemplate:通过占位符和format方法,可以生成适用于不同场景的提示。
    from langchain import PromptTemplate
    
    template = """\
    你是业务咨询顾问。
    你给一个销售{product}的电商公司,起一个好的名字?
    """
    prompt = PromptTemplate.from_template(template)
    
    print(prompt.format(product="鲜花"))
    

    输出:

    你是业务咨询顾问。
    你给一个销售鲜花的电商公司,起一个好的名字?
    
  • 当然,也可以通过提示模板类的构造函数,在创建模板时手工指定input_variables,示例如下:
    prompt = PromptTemplate(
        input_variables=["product", "market"], 
        template="你是业务咨询顾问。对于一个面向{market}市场的,专注于销售{product}的公司,你会推荐哪个名字?"
    )
    print(prompt.format(product="鲜花", market="高端"))
    
    输出:
    你是业务咨询顾问。对于一个面向高端市场的,专注于销售鲜花的公司,你会推荐哪个名字?
    
    上面的方式直接生成了提示模板,并没有通过from_template方法从字符串模板中创建提示模板。二者效果是一样的。
  • 下面代码展示了OpenAI的Chat Model中的各种消息角色。
    import openai
    openai.ChatCompletion.create(
      model="gpt-3.5-turbo",
      messages=[
            {"role": "system", "content": "You are a helpful assistant."},
            {"role": "user", "content": "Who won the world series in 2020?"},
            {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
            {"role": "user", "content": "Where was it played?"}
        ]
    )
    

    OpenAI对传输到gpt-3.5-turbo和GPT-4的messsage格式说明如下:

    消息必须是消息对象的数组,其中每个对象都有一个角色(系统、用户或助理)和内容。对话可以短至一条消息,也可以来回多次。  

    通常,对话首先由系统消息格式化,然后是交替的用户消息和助理消息。  

    系统消息有助于设置助手的行为。例如,你可以修改助手的个性或提供有关其在整个对话过程中应如何表现的具体说明。但请注意,系统消息是可选的,并且没有系统消息的模型的行为可能类似于使用通用消息,例如“你是一个有用的助手”。  

    用户消息提供助理响应的请求或评论。  

    助理消息存储以前的助理响应,但也可以由你编写以给出所需行为的示例。

  • 使用ChatPromptTemplate:针对聊天模型,如ChatGPT,设计了带有角色的消息格式。
  • 重点介绍FewShotPromptTemplate,下面,我给出一个示例:

    # 导入聊天消息类模板
    from langchain.prompts import (
        ChatPromptTemplate,
        SystemMessagePromptTemplate,
        HumanMessagePromptTemplate,
    )
    # 模板的构建
    template="你是一位专业顾问,负责为专注于{product}的公司起名。"
    system_message_prompt = SystemMessagePromptTemplate.from_template(template)
    human_template="公司主打产品是{product_detail}。"
    human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
    prompt_template = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
    
    # 格式化提示消息生成提示
    prompt = prompt_template.format_prompt(product="鲜花装饰", product_detail="创新的鲜花设计。").to_messages()
    
    # 下面调用模型,把提示传入模型,生成结果
    import os
    os.environ["OPENAI_API_KEY"] = '你的OpenAI Key'
    from langchain.chat_models import ChatOpenAI
    chat = ChatOpenAI()
    result = chat(prompt)
    print(result)
    

    输出:

    content='1. 花语创意\n2. 花韵设计\n3. 花艺创新\n4. 花漾装饰\n5. 花语装点\n6. 花翩翩\n7. 花语之美\n8. 花馥馥\n9. 花语时尚\n10. 花之魅力' 
    additional_kwargs={} 
    example=False
    

FewShot的思想起源

下图就是OpenAI的GPT-3论文给出的GPT-3在翻译任务中,通过FewShot提示完成翻译的例子。Few-Shot(少样本)学习是提示工程中非常重要的部分。在Few-Shot学习设置中,模型会被给予几个示例,以帮助模型理解任务并生成正确的响应。以上,就是ZeroShot、OneShot、FewShot这些重要概念的起源。

使用 FewShotPromptTemplate

下面,就让我们来通过LangChain中的FewShotPromptTemplate构建出最合适的鲜花文案。

  1. 创建示例样本:构建包含输入变量和对应值的字典列表,作为提示的样本。
    # 1. 创建一些示例
    samples = [
      {
        "flower_type": "玫瑰",
        "occasion": "爱情",
        "ad_copy": "玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。"
      },
      {
        "flower_type": "康乃馨",
        "occasion": "母亲节",
        "ad_copy": "康乃馨代表着母爱的纯洁与伟大,是母亲节赠送给母亲的完美礼物。"
      },
      {
        "flower_type": "百合",
        "occasion": "庆祝",
        "ad_copy": "百合象征着纯洁与高雅,是你庆祝特殊时刻的理想选择。"
      },
      {
        "flower_type": "向日葵",
        "occasion": "鼓励",
        "ad_copy": "向日葵象征着坚韧和乐观,是你鼓励亲朋好友的最好方式。"
      }
    ]
    

    samples这个列表,它包含了四个字典,每个字典代表了一种花的类型、适合的场合,以及对应的广告文案。 这些示例样本,就是构建FewShotPrompt时,作为例子传递给模型的参考信息。

  2. 创建提示模板:使用PromptTemplate对象将示例格式化为字符串。
    # 2. 创建一个提示模板
    from langchain.prompts.prompt import PromptTemplate
    template="鲜花类型: {flower_type}\n场合: {occasion}\n文案: {ad_copy}"
    prompt_sample = PromptTemplate(input_variables=["flower_type", "occasion", "ad_copy"], 
                                   template=template)
    print(prompt_sample.format(**samples[0]))
    

    提示模板的输出如下:

    鲜花类型: 玫瑰
    场合: 爱情
    文案: 玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。
    
  3. 创建FewShotPromptTemplate对象:结合示例和提示模板,生成更复杂的提示。
    # 3. 创建一个FewShotPromptTemplate对象
    from langchain.prompts.few_shot import FewShotPromptTemplate
    prompt = FewShotPromptTemplate(
        examples=samples,
        example_prompt=prompt_sample,
        suffix="鲜花类型: {flower_type}\n场合: {occasion}",
        input_variables=["flower_type", "occasion"]
    )
    print(prompt.format(flower_type="野玫瑰", occasion="爱情"))
    

    输出:

    鲜花类型: 玫瑰
    场合: 爱情
    文案: 玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。
    
    鲜花类型: 康乃馨
    场合: 母亲节
    文案: 康乃馨代表着母爱的纯洁与伟大,是母亲节赠送给母亲的完美礼物。
    
    鲜花类型: 百合
    场合: 庆祝
    文案: 百合象征着纯洁与高雅,是你庆祝特殊时刻的理想选择。
    
    鲜花类型: 向日葵
    场合: 鼓励
    文案: 向日葵象征着坚韧和乐观,是你鼓励亲朋好友的最好方式。
    
    鲜花类型: 野玫瑰
    场合: 爱情
    
  4. 调用大模型创建新文案:将生成的提示传递给大模型,得到所需的文案。
    # 4. 把提示传递给大模型
    import os
    os.environ["OPENAI_API_KEY"] = '你的Open AI Key'
    from langchain.llms import OpenAI
    model = OpenAI(model_name='gpt-3.5-turbo-instruct')
    result = model(prompt.format(flower_type="野玫瑰", occasion="爱情"))
    print(result)
    

    输出:

    文案: 野玫瑰代表着爱情的坚贞,是你向心爱的人表达爱意的最佳礼物。
    

使用示例选择器

如果示例很多,可以使用LangChain提供的示例选择器(如SemanticSimilarityExampleSelector),根据语义相似性选择最相关的示例,以节省Token用量并提高效率。

# 5. 使用示例选择器
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings

# 初始化示例选择器
example_selector = SemanticSimilarityExampleSelector.from_examples(
    samples,
    OpenAIEmbeddings(),
    Chroma,
    k=1
)

# 创建一个使用示例选择器的FewShotPromptTemplate对象
prompt = FewShotPromptTemplate(
    example_selector=example_selector, 
    example_prompt=prompt_sample, 
    suffix="鲜花类型: {flower_type}\n场合: {occasion}", 
    input_variables=["flower_type", "occasion"]
)
print(prompt.format(flower_type="红玫瑰", occasion="爱情"))

输出:

鲜花类型: 玫瑰
场合: 爱情
文案: 玫瑰,浪漫的象征,是你向心爱的人表达爱意的最佳选择。

鲜花类型: 红玫瑰
场合: 爱情

通过这样详细的步骤和策略,我们能够充分利用LangChain中的提示模板和示例选择器来构建高质量的提示,从而引导模型生成符合期望的文本。希望这篇文章能帮助你更好地理解提示工程和LangChain的应用!

总结

好的,到这里,今天小北绍了提示工程的原理,几种提示模板的用法,以及最重要的FewShot的思路。其实说白了,就是给模型一些示例做参考,模型才能明白你要什么。

总的来说,提供示例对于解决某些任务至关重要,通常情况下,FewShot的方式能够显著提高模型回答的质量。不过,当少样本提示的效果不佳时,这可能表示模型在任务上的学习不足。在这种情况下,小北建议对模型进行微调或尝试更高级的提示技术。

下一篇博客,小北将与友友们在探讨输出解析的同时,讲解另一种备受关注的提示技术,被称为“思维链提示”(Chain of Thought,简称CoT)。这种技术因其独特的应用方式和潜在的实用价值而引人注目。

思考题

  1. 如果你观察LangChain中的prompt.py中的PromptTemplate的实现代码,你会发现除了我们使用过的input_variables、template等初始化参数之外,还有template_format、validate_template等参数。举例来说,template_format可以指定除了f-string之外,其它格式的模板,比如jinja2。请你查看LangChain文档,并尝试使用这些参数。
template_format: str = "f-string"
"""The format of the prompt template. Options are: 'f-string', 'jinja2'."""

validate_template: bool = True
"""Whether or not to try validating the template."""
  1. 请你尝试使用PipelinePromptTemplate和自定义Template。  
  2. 请你构想一个关于鲜花店运营场景中客户服务对话的少样本学习任务。在这个任务中,模型需要根据提供的示例,学习如何解答客户的各种问题,包括询问花的价格、推荐鲜花、了解鲜花的保养方法等。最好是用ChatModel完成这个任务。
from langchain.chat_models import ChatOpenAI
from langchain import PromptTemplate
from langchain.prompts.chat import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    AIMessagePromptTemplate,
    HumanMessagePromptTemplate)

题目较多,可以选择性思考,期待在留言区看到你的分享。如果你觉得内容对你有帮助,也欢迎分享给有需要的朋友!最后如果你学有余力,可以进一步学习下面的延伸阅读。

延伸阅读

  1. 论文: Open AI的GPT-3模型:大模型是少样本学习者, Brown, T. B., Mann, B., Ryder, N., Subbiah, M., Kaplan, J., Dhariwal, P., ... & Agarwal, S. (2020). Language models are few-shot learners. arXiv preprint arXiv:2005.14165.
  2. 论文:单样本学习的匹配网络,Vinyals, O., Blundell, C., Lillicrap, T., & Wierstra, D. (2016). Matching networks for one shot learning. In Advances in neural information processing systems (pp. 3630-3638).
  3. 论文:用语义输出编码做零样本学习,Palatucci, M., Pomerleau, D., Hinton, G. E., & Mitchell, T. M. (2009). Zero-shot learning with semantic output codes. In Advances in neural information processing systems (pp. 1410-1418).
  4. 论文:对示例角色的重新思考:是什么使得上下文学习有效?Min, S., Lyu, X., Holtzman, A., Artetxe, M., Lewis, M., Hajishirzi, H., & Zettlemoyer, L. (2022). Rethinking the Role of Demonstrations: What Makes In-Context Learning Work? Proceedings of the 2022 Conference on Empirical Methods in Natural Language Processing (EMNLP 2022).
  5. 论文:微调后的语言模型是零样本学习者,Wei, J., Bosma, M., Zhao, V. Y., Guu, K., Yu, A. W., Lester, B., Du, N., Dai, A. M., & Le, Q. V. (2022). Finetuned Language Models Are Zero-Shot Learners. Proceedings of the International Conference on Learning Representations (ICLR 2022).

猜你喜欢

转载自blog.csdn.net/Zhiyilang/article/details/143468624