提示工程
从零到高级提示工程:使用Python和Langchain

大型语言模型(LLM)的一个重要方面是这些模型用于学习的参数数量。模型的参数越多,它就越能理解单词和短语之间的关系。这意味着具有数十亿参数的模型具有生成各种创意文本格式和以信息丰富的方式回答开放式和具有挑战性的问题的能力。
像ChatGPT这样的LLM,利用Transformer模型,擅长理解和生成人类语言,使其适用于需要自然语言理解的应用。然而,它们并非没有局限性,包括过时的知识、无法与外部系统交互、缺乏上下文理解,有时会生成听起来合理但实际上错误或无意义的响应等。
解决这些局限性需要将LLM与外部数据源和功能集成,这可能会带来复杂性,并需要广泛的编码和数据处理技能。这,加上理解AI概念和复杂算法的挑战,促成了使用LLM开发应用程序的学习曲线。
然而,将LLM与其他工具集成以形成LLM驱动的应用程序可以重新定义我们的数字化景观。这种应用程序的潜力是巨大的,包括提高效率和生产力,简化任务,增强决策,并提供个性化的体验。
在本文中,我们将更深入地探讨这些问题,探索Langchain的高级提示工程技术,提供清晰的解释、实用示例和逐步指南,教您如何实现它们。
Langchain是一个最先进的库,它为设计、实现和调整提示提供了便利和灵活性。随着我们解开提示工程的原理和实践,您将学习如何利用Langchain的强大功能来发挥像GPT-4这样的SOTA生成AI模型的优势。
理解提示
在深入提示工程的技术细节之前,了解提示的概念及其重要性至关重要。
“提示”是一系列用作语言模型输入的标记,指示它生成特定类型的响应。提示在引导模型的行为方面起着至关重要的作用。它们会影响生成文本的质量,当正确设计时,可以帮助模型提供有见地、准确和上下文相关的结果。在实践中,这涉及精心选择和结构化提示,以适应模型的训练和结构偏见。
提示工程是设计有效提示的艺术和科学。目标是从语言模型中获取期望的输出。通过仔细选择和结构化提示,可以引导模型生成更准确和相关的响应。提示工程的复杂性从简单的技术(例如,向模型提供相关关键字)到更高级的方法(涉及设计复杂、结构化的提示,以利用模型的内部机制)。
Langchain:最快增长的提示工具
Langchain于2022年10月由Harrison Chase推出,已成为2023年GitHub上最受欢迎的开源框架之一。它为将大型语言模型(LLM)集成到应用程序中提供了简化和标准化的接口。它还提供了一个功能丰富的接口,用于提示工程,允许开发人员尝试不同的策略并评估其结果。通过使用Langchain,您可以更有效、更直观地执行提示工程任务。
LangFlow作为一种用户界面,用于将LangChain组件编排成可执行的流程图,实现快速原型设计和实验。

LangChain填补了人工智能开发的空白。它使得NLP应用(如虚拟助手、内容生成器、问答系统等)能够解决现实世界的问题。
LangChain不是一个独立的模型或提供者,而是简化了与多种模型的交互,扩展了LLM应用的能力,超越了简单API调用。
LangChain的架构
LangChain的主要组件包括模型I/O、提示模板、内存、代理和链。
模型I/O
LangChain通过一个名为模型I/O的标准化接口与各种语言模型实现无缝连接。这使得模型切换变得容易,适用于优化或更好的性能。LangChain支持多种语言模型提供商,包括OpenAI、HuggingFace、Azure、Fireworks等。
提示模板
这些模板用于管理和优化与LLM的交互,提供简洁的指令或示例。优化提示可以提高模型的性能,其灵活性也对输入过程做出了重大贡献。
一个简单的提示模板示例:
<p>from langchain.prompts import PromptTemplate
prompt = PromptTemplate(input_variables=["subject"],
template="What are the recent advancements in the field of {subject}?")
print(prompt.format(subject="Natural Language Processing"))</p>
当我们深入复杂性时,我们在LangChain中遇到了更复杂的模式,例如Reason和Act(ReAct)模式。ReAct是一种用于执行操作的重要模式,其中代理将任务分配给合适的工具,自定义输入并解析其输出以完成任务。以下Python示例展示了ReAct模式,展示了如何在LangChain中结构提示,使用一系列的思考和操作来推理问题并产生最终答案:
PREFIX = """Answer the following question using the given tools:"""
FORMAT_INSTRUCTIONS = """Follow this format:
Question: {input_question}
Thought: your initial thought on the question
Action: your chosen action from [{tool_names}]
Action Input: your input for the action
Observation: the action's outcome"""
SUFFIX = """Start!
Question:{input}
Thought:{agent_scratchpad}"""
内存
内存是LangChain中的一个关键概念,允许LLM和工具随着时间的推移保留信息。这种有状态的行为通过存储以前的响应、用户交互、环境状态和代理的目标来提高LangChain应用程序的性能。ConversationBufferMemory和ConversationBufferWindowMemory策略有助于跟踪对话的全部或最近部分。对于更复杂的方法,ConversationKGMemory策略允许将对话编码为知识图,知识图可以反馈到提示中或用于预测响应而无需调用LLM。
代理
代理通过执行操作和任务与世界交互。在LangChain中,代理将工具和链结合起来执行任务。它可以与外部世界建立连接以检索信息,从而克服LLM的固有局限性。代理可以决定根据情况将计算传递给计算器或Python解释器。
代理具有以下子组件:
- 工具:这些是功能组件。
- 工具包:工具的集合。
- 代理执行器:这是允许在工具之间进行选择的执行机制。
LangChain中的代理还遵循零次ReAct模式,其中决策仅基于工具的描述。该机制可以通过考虑完整的对话历史来扩展内存。使用ReAct,代理不会要求LLM完成文本,而是提示LLM以思考/行动/观察循环响应。
链
链是LangChain库处理语言模型输入和输出的操作序列。这些LangChain的基本组件本质上由链接组成,可以是其他链或原始的提示、语言模型或实用程序。
想象一个链条就像一个工厂的输送带。输送带上的每一步代表某个操作,可以是调用语言模型、将Python函数应用于文本,甚至以特定方式提示模型。
LangChain将其链分为三种类型:实用链、通用链和合并文档链。我们将深入探讨实用链和通用链。
- 实用链专门设计用于从语言模型中提取特定任务的精确答案。例如,让我们看一下LLMMathChain。这个实用链使语言模型能够执行数学计算。它接受自然语言问题,语言模型生成Python代码片段,然后执行以产生答案。
- 通用链则作为构建块用于其他链,但不能直接独立使用。这些链,如LLMChain,是基础链,通常与其他链组合来完成复杂任务。例如,LLMChain经常用于通过格式化输入(基于提供的提示模板)并将其传递给语言模型来查询语言模型对象。
使用Langchain的提示工程逐步实现
我们将指导您完成使用Langchain实现提示工程的过程。在继续之前,请确保您已安装必要的软件和包。
您可以利用流行的工具,如Docker、Conda、Pip和Poetry,来设置LangChain。这些方法的相关安装文件可以在LangChain存储库中找到,包括Docker的Dockerfile、Pip的requirements.txt、Poetry的pyproject.toml和Conda的langchain_ai.yml文件。
在我们的文章中,我们将使用Pip,即Python的标准包管理器,来安装和管理第三方库。如果Pip不包含在您的Python发行版中,您可以按照https://pip.pypa.io/上的说明安装Pip。
要使用Pip安装库,请使用命令pip install library_name。
但是,Pip本身并不管理环境。为了处理不同的环境,我们使用工具virtualenv。
在下一节中,我们将讨论模型集成。
步骤1:设置Langchain
首先,您需要安装Langchain包。我们使用Windows操作系统。在终端中运行以下命令来安装它:
pip install langchain
步骤2:导入Langchain和其他必要模块
接下来,导入Langchain以及其他必要的模块。在这里,我们还导入了transformers库,该库在NLP任务中被广泛使用。
<p>import langchain from transformers import AutoModelWithLMHead, AutoTokenizer
步骤3:加载预训练模型
Open AI
OpenAI模型可以通过LangChain库或OpenAI Python客户端库方便地接口。值得注意的是,OpenAI提供了一个用于文本嵌入模型的嵌入类。两个关键的LLM模型是GPT-3.5和GPT-4,主要区别在于令牌长度。每个模型的定价可以在OpenAI的网站上找到。虽然有更复杂的模型,如GPT-4-32K,它们具有更高的令牌接受度,但其API可用性并非总是保证的。

访问这些模型需要OpenAI API密钥。这可以通过在OpenAI平台上创建帐户、设置计费信息并生成新的密钥来完成。
<p>import os os.environ["OPENAI_API_KEY"] = 'your-openai-token'</p>
创建密钥后,可以将其设置为环境变量(OPENAI_API_KEY)或在类实例化期间将其作为参数传递以进行OpenAI调用。
考虑一个LangChain脚本来演示与OpenAI模型的交互:
from langchain.llms import OpenAI llm = OpenAI(model_name="text-davinci-003") # LLM接受提示作为输入并输出完成 prompt = "who is the president of the United States of America?" completion = llm(prompt)
<p>美国现任总统是乔·拜登。</p>
在这个例子中,初始化一个代理来执行计算。代理接受输入(一个简单的加法任务),使用提供的OpenAI模型处理它,并返回结果。
Hugging Face
Hugging Face是一个免费使用的Transformers Python库,兼容PyTorch、TensorFlow和JAX,包括BERT、T5等模型的实现。
Hugging Face还提供Hugging Face Hub,一个用于托管代码仓库、机器学习模型、数据集和Web应用程序的平台。
要使用Hugging Face作为模型的提供者,您需要一个帐户和API密钥,可以从他们的网站获取。令牌可以作为环境变量HUGGINGFACEHUB_API_TOKEN提供。
考虑以下Python代码段,使用Google开发的开源Flan-T5-XXL模型:
from langchain.llms import HuggingFaceHub
<p>llm = HuggingFaceHub(model_kwargs={"temperature": 0.5, "max_length": 64}, repo_id="google/flan-t5-xxl")
prompt = "In which country is Tokyo?"
completion = llm(prompt)
print(completion)</p>
这个脚本接受一个问题作为输入并返回一个答案,展示了模型的知识和预测能力。
步骤4:基本提示工程
首先,我们将生成一个简单的提示并查看模型如何响应。
prompt = 'Translate the following English text to French: "{0}"'
input_text = 'Hello, how are you?'
input_ids = tokenizer.encode(prompt.format(input_text), return_tensors='pt')
<p>generated_ids = model.generate(input_ids, max_length=100, temperature=0.9)
print(tokenizer.decode(generated_ids[0], skip_special_tokens=True))</p>
在上面的代码片段中,我们提供一个提示来将英语文本翻译成法语。语言模型然后尝试根据提示翻译给定的文本。
步骤5:高级提示工程
虽然上面的方法有效,但它并没有充分利用提示工程的力量。让我们通过引入更复杂的提示结构来改进它。
prompt = 'As a highly proficient French translator, translate the following English text to French: "{0}"'
input_text = 'Hello, how are you?'
input_ids = tokenizer.encode(prompt.format(input_text), return_tensors='pt')
<p>generated_ids = model.generate(input_ids, max_length=100, temperature=0.9)
print(tokenizer.decode(generated_ids[0], skip_special_tokens=True))</p>
在这个代码片段中,我们修改了提示来表明翻译是由一名“精通法语的翻译人员”完成的。提示的变化可以带来更好的翻译,因为模型现在假设自己是一名专家。
使用Langchain构建学术文献问答系统
我们将使用LangChain构建一个可以回答有关最近发表的学术论文的问题的学术文献问答系统。

首先,我们需要设置环境。我们安装必要的依赖项:
pip install langchain arxiv openai transformers faiss-cpu
安装后,我们创建一个新的Python笔记本并导入必要的库:
from langchain.llms import OpenAI from langchain.chains.qa_with_sources import load_qa_with_sources_chain from langchain.docstore.document import Document import arxiv
我们的问答系统的核心是能够获取与特定领域相关的相关学术论文,在这里我们考虑自然语言处理(NLP)。我们定义一个函数get_arxiv_data(max_results=10)来收集arXiv中NLP的最新论文摘要,并将它们封装在LangChain文档对象中,使用摘要作为内容,唯一的条目ID作为源。
我们使用arXiv API来获取与NLP相关的最新论文:
<p>def get_arxiv_data(max_results=10):
search = arxiv.Search(
query="NLP",
max_results=max_results,
sort_by=arxiv.SortCriterion.SubmittedDate,
)</p>
documents = []
<p>for result in search.results():
documents.append(Document(
page_content=result.summary,
metadata={"source": result.entry_id},
))</p>
return documents
这个函数从arXiv中检索NLP的最新论文摘要,并将它们转换为LangChain文档对象。我们使用论文的摘要和其唯一的条目ID(URL到论文)作为内容和源。
def print_answer(question):
print(
chain(
{
"input_documents": sources,
"question": question,
},
return_only_outputs=True,
)["output_text"]
)
让我们定义我们的语料库并设置LangChain:
sources = get_arxiv_data(2) chain = load_qa_with_sources_chain(OpenAI(temperature=0))
现在我们的问答系统已经准备好了,我们可以通过询问一个问题来测试它:
print_answer("What are the recent advancements in NLP?")
输出将是对您问题的答案,引用从中提取信息的来源。例如:
<p>最近在NLP方面的进展包括使用基于检索的指令执行模型和用于解决交替电流最优电力流问题的新计算框架。 来源:http://arxiv.org/abs/2307.16877v1,http://arxiv.org/abs/2307.16830v1</p>
您可以轻松切换模型或修改系统以满足您的需求。例如,我们切换到GPT-4,这给出了更好、更详细的回应。
sources = get_arxiv_data(2) chain = load_qa_with_sources_chain(OpenAI(model_name="gpt-4", temperature=0))
<p>自然语言处理(NLP)的最近进展包括开发用于信息检索任务(如问答)的基于检索的指令执行模型。这些模型可以适应各种信息域和任务,而无需额外的微调。然而,它们通常难以坚持提供的知识,并可能在其响应中产生幻觉。另一个进展是引入用于解决交替电流最优电力流问题的计算框架,该框架利用单指令多数据(SIMD)抽象的非线性程序(NLP)并采用带有不等式放松策略的凝缩空间内点法(IPM)。此策略允许在不进行数值枢轴的情况下对KKT矩阵进行因式分解,这以前曾阻碍了IPM算法的并行化。 来源:http://arxiv.org/abs/2307.16877v1,http://arxiv.org/abs/2307.16830v1</p>
GPT-4中的一个令牌可以是单个字符或单个单词。例如,GPT-4-32K可以在单次运行中处理多达32,000个令牌,而GPT-4-8K和GPT-3.5-turbo分别支持8,000和4,000个令牌。然而,必须注意的是,每次与这些模型交互都会产生直接与处理的令牌数量成比例的成本,无论是输入还是输出。
在我们的问答系统的背景下,如果一篇学术文献超过最大令牌限制,系统将无法处理它,从而影响响应的质量和完整性。为了解决这个问题,可以将文本分解为符合令牌限制的较小部分。
FAISS(Facebook AI相似性搜索)有助于快速找到与用户查询最相关的文本块。它创建每个文本块的向量表示,并使用这些向量来检索与给定问题的向量表示最相似的块。
但是,使用工具如FAISS,即使将文本分解为较小的块,也有时会导致上下文丢失,从而影响答案的质量。因此,仔细管理和优化令牌的使用对于使用这些大型语言模型至关重要。
pip install faiss-cpu langchain CharacterTextSplitter
安装上述库后,运行
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores.faiss import FAISS
from langchain.text_splitter import CharacterTextSplitter
documents = get_arxiv_data(max_results=10) # 现在我们可以使用更多数据
document_chunks = []
splitter = CharacterTextSplitter(separator=" ", chunk_size=1024, chunk_overlap=0)
for document in documents:
for chunk in splitter.split_text(document.page_content):
document_chunks.append(Document(page_content=chunk, metadata=document.metadata))
<p>search_index = FAISS.from_documents(document_chunks, OpenAIEmbeddings())</p>
<p>chain = load_qa_with_sources_chain(OpenAI(temperature=0))</p>
<p>def print_answer(question):
print(
chain(
{
"input_documents": search_index.similarity_search(question, k=4),
"question": question,
},
return_only_outputs=True,
)["output_text"]
)
代码完成后,我们现在拥有一个功能强大的工具来查询NLP领域的最新学术文献。
NLP的最近进展包括使用深度神经网络(DNN)进行自动文本分析和NLP任务,例如拼写检查、语言检测、实体提取、作者检测、问答等。 来源:http://arxiv.org/abs/2307.10652v1,http://arxiv.org/abs/2307.07002v1,http://arxiv.org/abs/2307.12114v1,http://arxiv.org/abs/2307.16217v1
结论
将大型语言模型(LLM)集成到应用程序中的采用正在加速。提示工程是最大限度地发挥这些模型潜力的有力工具,而Langchain正以其简化和标准化的接口、灵活的提示模板、强大的模型集成以及创新的代理和链的使用而领先于这一领域。
然而,尽管有了这些进步,仍有一些需要牢记的提示。使用Langchain时,了解输出质量严重依赖于提示的措辞至关重要。尝试不同的提示风格和结构可以带来更好的结果。此外,虽然Langchain支持多种语言模型,但每个模型都有其优缺点。为特定任务选择合适的模型至关重要。此外,使用这些模型会带来成本考虑,因为令牌处理直接影响交互成本。
如步骤指南所示,Langchain可以支持强大的应用程序,例如学术文献问答系统。拥有日益增长的用户社区和在开源领域日益增长的影响力,Langchain有望成为发挥LLM(如GPT-4)全部潜力的关键工具。
与LLM的交互,如在我们的问答系统中所示,展示了这些模型的知识和预测能力。通过利用Langchain的功能,开发人员可以创建更复杂、更强大的应用程序,以满足用户不断增长的需求,并推动人工智能领域的创新。














