使用LangChain进行提示工程的介绍

LangChain是一个开源框架,旨在使用诸如GPT、LLaMA、Mistral等语言模型轻松构建应用程序。

LangChain最强大的功能之一是其对高级提示工程的支持。提示工程是指设计和优化提示,以从语言模型中获得最准确和相关的回复。

在这篇文章中,我们将介绍提示的基础知识,以及Langchain如何利用提示、提示模板、内存、代理和链条。对于这些核心概念,我们将在Python中提供几个代码示例,以便在本教程结束时,您能够轻松地使用LangChain框架构建自己的应用程序。

想知道如何使用LangChain和GPT来创建一个简单的AI代理吗?请查看我们的GPT和LangChain AI代码教程:

什么是Prompt工程?

作者提供的图片

我们有一份完整的指南,涵盖了提示工程,但作为一个快速复习,它是创建能够有效与生成式AI模型进行通信的文本输入的实践。这些以自然语言编写的提示指定了我们希望AI执行的任务。

它们的形式可以多种多样,从简单的问题,比如要求解释一个数学定理,到更具创意的请求,比如写一首关于特定主题的诗歌。

在即时工程中,关键不仅在于你问什么,还在于你如何问。这可能包括选择合适的措辞,设定特定的语气或风格,提供必要的背景信息,甚至定义AI的角色,比如要求它以某种语言的母语者的身份回答。

在某些情况下,提示还可以包含示例,以指导人工智能的学习过程。这种技术被称为少样本学习,对于复杂任务尤其有效。

当处理生成图像或音频的模型时,提示通常会详细描述所需的输出,从主题和风格到最终产品的构图和情绪。提示工程的艺术在于调整这些元素,以引导人工智能产生所期望的结果。

提示的基础知识

作者提供的图片

提示是提供给大型语言模型(LLM)的输入,以引发所需的响应。设计良好的提示对于从LLM获得有用的输出至关重要。提示工程的目标是精心构建提示,以获得准确、相关和有帮助的LLM响应。

一个好的提示通常包含以下四个组成部分:

  1. 指示 – 告诉模型要做什么,如何使用提供的信息,如何处理查询,并构建输出。
  2. 示例输入 – 提供示例输入,以向模型演示预期的内容。
  3. 示例输出 – 提供相应的示例输出。
  4. 查询 – 您希望模型处理的实际输入。

除了查询之外,其他内容都是可选的,但可能会显著影响响应的质量,特别是提供给LLM的指示,用于指导任务和预期响应。

示例演示了给定示例输入的期望输出格式。

查询是向LLM提出的问题或请求。

构建有效的提示涉及根据所解决的问题创造性地结合这些元素。

LangChain提示

LangChain提供了各种类和函数来帮助构建和处理提示,使得管理涉及语言模型的复杂任务更加容易。

Langchain通过`PromptTemplate`对象为即时工程提供一流的支持。

提示模板作为构建语言模型查询的结构化指南。

这些模板通常包括指令、一些示例输入(少样本示例)以及适用于特定任务的定制问题和背景。

LangChain的目标是设计与各种语言模型兼容的模板,提高在不同模型之间传输模板的便捷性。

简而言之,您可以使用PromptTemplate类来创建一个字符串提示的模板。

from langchain.prompts import PromptTemplate


prompt_template = PromptTemplate.from_template(
    "告诉我一个关于{content}的{adjective}笑话。"
)
prompt_template.format(adjective="悲伤的", content="数据科学家")

输出:

>>> “告诉我一个关于数据科学家的悲伤笑话。”

不需要有一个变量。即使没有任何变量,您也可以使用这个类创建一个提示。

from langchain.prompts import PromptTemplate
prompt_template = PromptTemplate.from_template("告诉我一个笑话")
prompt_template.format()

输出:

>>> ‘告诉我一个笑话’

如果你正在构建一个聊天应用程序,在每次用户发送新消息时都需要保存并发送消息历史记录给LLM,那该怎么办?手动完成这个过程非常耗时。

对于支持的聊天模型,您可以使用ChatPromptTemplate代替:

from langchain.prompts import ChatPromptTemplate


chat_template = ChatPromptTemplate.from_messages(
    [
        ("system", "你是一个有用的AI机器人。你的名字是{name}。"),
        ("human", "你好,你好吗?"),
        ("ai", "我很好,谢谢!"),
        ("human", "{user_input}"),
    ]
)


messages = chat_template.format_messages(name="Bob", user_input="你叫什么名字?")


print(messages)

输出:

>>> [SystemMessage(content=’你是一个有帮助的AI机器人。你的名字是Bob。’),

>>> HumanMessage(content=’你好,你好吗?’),

>>> AIMessage(content=”我过得很好,谢谢!”),

>>> HumanMessage(content=’你叫什么名字?’)]

所以你一定在想,为什么我们需要PromptTemplates?为什么我们不能直接将字符串提示传递给LLM?以下是使用LangChain的PromptTemplate的一些好理由:

  • 提示模板是可重复使用的,允许您创建一次提示并在多种情况下使用,例如在不重写提示的情况下总结不同的文章。
  • 它们将提示的格式与实际模型调用分离,使代码更模块化,并允许对模板或模型进行独立更新。
  • 使用模板可以提高代码的可读性,因为它们将复杂逻辑封装在更简单、更清晰、有命名的变量格式中。
  • 使用提示模板可以更轻松地进行维护,因为只需在一个中心位置进行提示逻辑的更改,而不是在每个单独的提示中进行更改。

LangChain记忆

在涉及聊天的语言模型应用中,系统记住过去的对话非常重要。

就像在普通聊天中一样,系统应该能够回顾之前说过的内容。

简单来说,这意味着系统可以看到一些先前的消息。但更先进的系统将记住更多细节,比如不同主题的事实以及它们之间的联系。

这种记住过去聊天记录的能力被称为“记忆”。LangChain帮助为这些聊天系统添加记忆功能。

LangChain中的一个内存有两个主要功能:

  1. 在将查询发送给LLM之前,系统会从内存中读取数据,以增强用户输入的初始提示。
  2. 一旦LLM返回响应,系统会将其写入内存以供将来的交互使用,然后将最终输出返回给用户。

LangChain中的内存(图片来源

要在LangChain中使用Memory功能,您可以使用ConversationBufferMemory类。

from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory(return_messages=True)
memory.chat_memory.add_user_message("hi!")
memory.chat_memory.add_ai_message("what's up?")
memory.chat_memory.add_user_message("how are you doing?")
memory.chat_memory.add_ai_message("I am fine, thank you and you?")


# 检查变量历史记录
memory.load_memory_variables({})

输出:

>>> {‘history’: [HumanMessage(content=’hi!’),

>>> AIMessage(content=”怎么了?”),

>>> HumanMessage(content=’你好吗?’),

>>> AIMessage(content=’我很好,谢谢你,你呢?’)]}

它返回一个字典,默认情况下键是history。这个键指向一个消息列表,这些消息可以是来自人类的(HumanMessage),也可以是来自LLM的(AIMessage)。

LangChain 链

对于简单的任务,使用单个 LLM(大型语言模型)效果很好。然而,对于更复杂的任务,通常需要链式多个步骤和/或模型。

在LangChain中,使用Chains的传统方式是通过Chain接口。

较新且推荐的方法是LangChain表达式语言(LCEL)。虽然LCEL更适用于新项目,但Chain方法仍然有用且受支持。

from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser


model = ChatOpenAI(openai_api_key = “...”)


prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "您是一位专业的数据科学家和机器学习工程师,能够提供专业的知识并准确地回答问题。",
        ),
        ("human", "{question}"),
    ]
)
runnable = prompt | model | StrOutputParser()


for chunk in runnable.stream({"question": "机器学习和深度学习有什么不同之处?"}):
    print(chunk, end="", flush=True)

输出

>>> 机器学习和深度学习是人工智能(AI)的子领域,涉及训练模型根据数据进行预测或决策。虽然两者之间存在重叠,但它们……

创建runnable的方式对于Python来说并不是很标准,但是这个|是一个管道操作符。Prompt | model | StrOutputParser()的意思是Prompt通过model传递,然后将其输出传递给StrOutputParser()。链中的每个部分都以某种方式转换数据。

想要了解更多关于使用LangChain构建的有趣用例和应用程序吗?请查看我们的工程和数据应用用例博客。

LangChain代理

代理的基本概念是利用语言模型来选择一系列的动作。

与链式不同,其中一系列动作是预先确定并嵌入在代码中,代理使用语言模型作为决策工具来识别适当的动作及其顺序。

在LangChain的Agents中有三个关键概念:

  1. 工具:LLM可用工具的描述
  2. 用户输入:任务的高级目标
  3. 中间步骤:为了实现用户输入而先前执行的任何(动作,工具输出)对

工具代表代理可以激活的功能。工具设计的两个关键方面包括:

  • 确保代理人能够使用适当的工具。
  • 以最大化对代理人有用的方式定义这些工具。

对于各种常规活动,代理人需要一系列相互关联的工具。为了解决这个问题,LangChain引入了工具包的概念。LangChain提供了广泛的工具包供您开始使用。

要了解更多关于Agents的信息,请查看这个官方LangChain指南

来源:本博客中的一些示例是使用官方的LangChain文档生成的。

结论

通过提供一种结构化的设计提示方法,LangChain不仅简化了与不同语言模型交互的过程,还最大限度地提高了其输出的效率和相关性。LangChain中的PromptTemplateMemory等功能展示了在提示工程中灵活性和精确性的深思熟虑的整合,适用于从简单查询到复杂对话环境的各种任务。

LangChain的ChainsAgents中的高级功能进一步提升了使用LangChain构建应用程序的潜力,只需几行代码即可选择任何底层的LLM进行开发,而可供选择的选项有很多。

无论是简单的任务还是复杂的应用,LangChain对于提示工程的方法都非常简单、清晰且易于采用。

想要了解更多吗?请查看DataCamp上如何使用LangChain构建LLM应用程序的第一部分。