LangChain的介绍和入门
💥 什么是LangChain
LangChain由 Harrison Chase 创建于2022年10月,它是围绕LLMs(大语言模型)建立的一个框架,LLMs使用机器学习算法和海量数据来分析和理解自然语言,GPT3.5、GPT4是LLMs最先进的代表,国内百度的文心一言、阿里的通义千问也属于LLMs。LangChain自身并不开发LLMs,它的核心理念是为各种LLMs实现通用的接口,把LLMs相关的组件“链接”在一起,简化LLMs应用的开发难度,方便开发者快速地开发复杂的LLMs应用。
LangChain目前有两个语言的实现:python、nodejs。
我们从两个方面全面介绍LangChain:一个是LangChain组件的基本概念和应用;另一个是LangChain常见的使用场景。
参考官网介绍:https://python.langchain.com/docs/integrations/text_embedding/huggingfacehub
2 LangChain主要组件
一个LangChain的应用是需要多个组件共同实现的,LangChain主要支持6种组件:
- Models:模型,各种类型的模型和模型集成,比如GPT-4
- Prompts:提示,包括提示管理、提示优化和提示序列化
- Memory:记忆,用来保存和模型交互时的上下文状态
- Indexes:索引,用来结构化文档,以便和模型交互
- Chains:链,一系列对各种组件的调用
- Agents:代理,决定模型采取哪些行动,执行并且观察流程,直到完成为止
2.1 Models
现在市面上的模型多如牛毛,各种各样的模型不断出现,LangChain模型组件提供了与各种模型的集成,并为所有模型提供一个精简的统一接口。
LangChain目前支持三种类型的模型:LLMs、Chat Models(聊天模型)、Embeddings Models(嵌入模型).
- LLMs: 大语言模型接收文本字符作为输入,返回的也是文本字符.
- 聊天模型: 基于LLMs, 不同的是它接收聊天消(一种特定格式的数据)作为输入,返回的也是聊天消息.
- 文本嵌入模型: 文本嵌入模型接收文本作为输入, 返回的是浮点数列表.
LangChain支持的三类模型,它们的使用场景不同,输入和输出不同,开发者需要根据项目需要选择相应。
2.1.1 LLMs (大语言模型)
LLMs使用场景最多,常用大模型的下载库:https://huggingface.co/models:
接下来我们以「文心一言」模型为例, 使用该类模型的组件:
- 第一步:安装必备的工具包:langchain和openai
pip install openai==0.28 pip install langchain pip install qianfan
注意,在使用openai模型之前,必须开通OpenAI API服务,需要获得API Token。
- 第二步:借助百度智能云–千帆大模型平台:申请API Key 以及Secret Key
想请见附件手册
- 第三部:代码实现
import os from langchain.llms import QianfanLLMEndpoint os.environ['QIANFAN_AK'] = "SPPejIX4r2mEUdjdkVNwxTHc" os.environ['QIANFAN_SK'] = "hOGdXomPZu8FRL51dkBZrEee4tqaS6PM" llm = QianfanLLMEndpoint(streaming=True, model="ERNIE-Bot-turbo") res = llm("帮我讲个笑话吧") print(res) 当然可以!这是一个有趣的笑话: 有一天,一只小鸟飞到一栋大房子前,大声喊道:“卖报!卖报!”可是没有人回应。它继续喊道:“嘿,有人在吗?卖报!”这次还是没有人回应。小鸟想了想,于是说:“对不起,打扰了!我只是想知道,这里有人想买天堂吗?”听到这个笑话,我希望你也能开心起来!
2.1.2 Chat Models (聊天模型)
聊天消息包含下面几种类型,使用时需要按照约定传入合适的值:
- AIMessage: 就是 AI 输出的消息,可以是针对问题的回答.
- HumanMessage: 人类消息就是用户信息,由人给出的信息发送给LLMs的提示信息,比如“实现一个快速排序方法”.
- SystemMessage: 可以用于指定模型具体所处的环境和背景,如角色扮演等。你可以在这里给出具体的指示,比如“作为一个代码专家”,或者“返回json格式”.
- ChatMessage: Chat 消息可以接受任意角色的参数,但是在大多数时间,我们应该使用上面的三种类型.
LangChain支持的常见聊天模型有:
模型 | 描述 |
ChatOpenAI | OpenAI聊天模型 |
AzureChatOpenAI | Azure提供的OpenAI聊天模型 |
PromptLayerChatOpenAI | 基于OpenAI的提示模版平台 |
举例说明:
import os from langchain.chat_models import QianfanChatEndpoint from langchain.chat_models.base import HumanMessage os.environ['QIANFAN_AK'] = "SPPejIX4r2mEUdjdkVNwxTHc" os.environ['QIANFAN_SK'] = "hOGdXomPZu8FRL51dkBZrEee4tqaS6PM" chat = QianfanChatEndpoint( streaming=True,model="ERNIE-Bot-turbo" ) messages = [ HumanMessage(content="给我写一首唐诗") ] res = chat(messages) print(res) ''' content='好的,以下是我为您创作的唐诗:\n\n青山依旧在,几度夕阳红。\n白发渔樵江渚上,惯看秋月春风。\n一壶浊酒喜相逢,古今多少事,都付笑谈中。' '''
2.1.3 提示模板
在上面的例子中,模型默认是返回纯文本结果的,如果想让模型返回想要的数据格式(比如json格式),可以使用提示模版。
提示模板就是把一些常见的提示整理成模板,用户只需要修改模板中特定的词语,就能快速准确地告诉模型自己的需求。我们看个例子:
import os from langchain.chat_models import QianfanChatEndpoint from langchain.prompts import ChatPromptTemplate os.environ['QIANFAN_AK'] = "SPPejIX4r2mEUdjdkVNwxTHc" os.environ['QIANFAN_SK'] = "hOGdXomPZu8FRL51dkBZrEee4tqaS6PM" template_str = """您是一位专业的鲜花店文案撰写员。\n 对于售价为 {price} 元的 {flower_name} ,您能提供一个吸引人的简短描述吗? 注意: 文字不要超过50个字符 """ promp_emplate = ChatPromptTemplate.from_template(template_str) prompt = promp_emplate.format_messages(flower_name=["玫瑰"], price='50') print('prompt-->', prompt) ''' prompt--> [HumanMessage(content="您是一位专业的鲜花店文案撰写员。\n\n对于售价为 50 元的 ['玫瑰'] ,您能提供一个吸引人的简短描述吗?\n注意: 文字不要超过50个字符\n# ")] ''' chat = QianfanChatEndpoint( streaming=True,model="ERNIE-Bot-turbo" ) result = chat(prompt) print(result) ''' content='玫瑰鲜花 售价50元\n纯手工编织花束,顶级玫瑰品种\n散发浓郁香气,温暖人心扉\n白色或粉红色,娇艳欲滴\n让爱情与浪漫伴随你每一天!#' '''
2.1.4 Embeddings Models(嵌入模型)
Embeddings Models特点:将字符串作为输入,返回一个浮动数的列表。在NLP中,Embedding的作用就是将数据进行文本向量化。
Embeddings Models可以为文本创建向量映射,这样就能在向量空间里去考虑文本,执行诸如语义搜索之类的操作,比如说寻找相似的文本片段。
接下来我们以一个OpenAI文本嵌入模型的例子进行说明:
import os from langchain.embeddings import QianfanEmbeddingsEndpoint os.environ['QIANFAN_AK'] = "SPPejIX4r2mEUdjdkVNwxTHc" os.environ['QIANFAN_SK'] = "hOGdXomPZu8FRL51dkBZrEee4tqaS6PM" embed = QianfanEmbeddingsEndpoint() res1 = embed.embed_query('这是第一个测试文档') print(res1) ''' [0.039765920490026474, 0.02263435162603855, -0.01889650709927082, ...., ''' res2 = embed.embed_documents(['这是第一个测试文档', '这是第二个测试文档']) print(res2) ''' [[0.03977284952998161, 0.022625437006354332, -0.01892162673175335, ...., '''
上述代码中,我们分别使用了两种方法来进行文本的向量表示,他们最大不同在于:embed_query()接收一个字符串的输入,而embed_documents可以接收一组字符串。
LangChain集成的文本嵌入模型有:
- AzureOpenAI、Baidu Qianfan、Hugging Face Hub、OpenAI、Llama-cpp、SentenceTransformers
2.2 Prompts
Prompt是指当用户输入信息给模型时加入的提示,这个提示的形式可以是zero-shot或者few-shot等方式,目的是让模型理解更为复杂的业务场景以便更好的解决问题。
提示模板:如果你有了一个起作用的提示,你可能想把它作为一个模板用于解决其他问题,LangChain就提供了PromptTemplates组件,它可以帮助你更方便的构建提示。
zero-shot提示方式:
from langchain import PromptTemplate from langchain.llms import QianfanLLMEndpoint import os os.environ['QIANFAN_AK'] = "SPPejIX4r2mEUdjdkVNwxTHc" os.environ['QIANFAN_SK'] = "hOGdXomPZu8FRL51dkBZrEee4tqaS6PM" template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字" prompt = PromptTemplate( input_variables=["lastname"], template=template, ) prompt_text = prompt.format(lastname="王") print(prompt_text) llm = QianfanLLMEndpoint() result = llm(prompt_text) print(result) ''' 给邻居的儿子起名字是一件非常棒的事情!在考虑名字时,通常会考虑一些基本的因素,比如名字的含义、读音、书写等。以下是一些建议: 如果您想要一个简单的名字,那么可以考虑王煦宇。这个名字寓意着阳光和宽广的宇宙,表示孩子应该像太阳一样温暖、明朗,又如宇宙般宽广包容。 另一个选择是王谦嘉。这个名字意为谦虚、高尚,同时也表示嘉奖和庆祝。如果邻居有特别期望他的儿子将来成为有道德、有修养的人,这个名字可能是一个不错的选择。 当然,这只是一些建议,最终的决定应该基于王先生的个人喜好和期望。请确保名字易于书写和发音,并且与您和邻居的姓氏搭配得当。祝王先生和他的儿子一切顺利! '''
few-shot提示方式:
from langchain import PromptTemplate, FewShotPromptTemplate from langchain.llms import QianfanLLMEndpoint import os os.environ['QIANFAN_AK'] = "SPPejIX4r2mEUdjdkVNwxTHc" os.environ['QIANFAN_SK'] = "hOGdXomPZu8FRL51dkBZrEee4tqaS6PM" examples = [ {"word": "开心", "antonym": "难过"}, {"word": "高", "antonym": "矮"}, ] example_template = """ 单词: {word} 反义词: {antonym}\\n """ example_prompt = PromptTemplate( input_variables=["word", "antonym"], template=example_template, ) few_shot_prompt = FewShotPromptTemplate( examples=examples, example_prompt=example_prompt, prefix="给出每个单词的反义词", suffix="单词: {input}\\n反义词:", input_variables=["input"], example_separator="\\n", ) prompt_text = few_shot_prompt.format(input="粗") print(prompt_text) print('*'*80) llm = QianfanLLMEndpoint(temperature=0.9) print(llm(prompt_text))
2.3 Chains(链)
在LangChain中,Chains描述了将LLM与其他组件结合起来完成一个应用程序的过程.
针对上一小节的提示模版例子,zero-shot里面,我们可以用链来连接提示模版组件和模型,进而可以实现代码的更改:
from langchain import PromptTemplate from langchain.llms import QianfanLLMEndpoint from langchain.chains import LLMChain import os os.environ['QIANFAN_AK'] = "SPPejIX4r2mEUdjdkVNwxTHc" os.environ['QIANFAN_SK'] = "hOGdXomPZu8FRL51dkBZrEee4tqaS6PM" template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字" prompt = PromptTemplate( input_variables=["lastname"], template=template, ) llm = QianfanLLMEndpoint() chain = LLMChain(llm = llm, prompt = prompt) print(chain.run("王")) ''' 给邻居家的新生儿起名字是一件非常重要的事情,需要考虑到很多因素,包括家庭传统、父母的偏好、名字的含义等等。在这个情况下,王先生和太太可能会想要一个既传统又具有现代感的名字。 基于这些考虑,以下是一些适合男孩的名字: 1. 王梓轩(Zi Xuan):这个名字既有传统的含义(梓是树木的意思,轩是高远的意思),又具有现代感。 2. 王宇翔(Yu Xiang):这个名字既包含了宇宙的含义(宇是宇宙的意思,翔是飞翔的意思),又有希望他儿子能像鸟儿一样自由飞翔的寓意。 3. 王宇轩(Yu Xuan):这个名字也有同样的含义,而且也有一种稳重和宽广的感觉。 4. 王博远(Bo Yuan):这个名字的含义是博学而远志,既体现了父母的期望,又有一种清新明快的感觉。 请注意,在选择名字时,还需要考虑名字在社区中的受欢迎程度,以确保这个名字不会引起任何问题或误解。此外,如果王先生和太太有任何特定的偏好或期望,他们也应该在这个过程中发挥重要作用。 以上就是我为王先生的儿子提出的一些名字建议,希望能帮助到你们。 '''
如果你想将第一个模型输出的结果,直接作为第二个模型的输入,还可以使用LangChain的SimpleSequentialChain, 代码如下:
from langchain import PromptTemplate from langchain.llms import QianfanLLMEndpoint from langchain.chains import LLMChain, SimpleSequentialChain import os os.environ['QIANFAN_AK'] = "SPPejIX4r2mEUdjdkVNwxTHc" os.environ['QIANFAN_SK'] = "hOGdXomPZu8FRL51dkBZrEee4tqaS6PM" template = "我的邻居姓{lastname},他生了个儿子,给他儿子起个名字" first_prompt = PromptTemplate( input_variables=["lastname"], template=template, ) llm = QianfanLLMEndpoint(temperature=0.9) first_chain = LLMChain(llm = llm, prompt = first_prompt) second_prompt = PromptTemplate( input_variables=["child_name"], template="邻居的儿子名字叫{child_name},给他起一个小名", ) second_chain = LLMChain(llm=llm, prompt=second_prompt) overall_chain = SimpleSequentialChain(chains=[first_chain, second_chain], verbose=True) print(overall_chain) catchphrase = overall_chain.run("王") print(catchphrase) ''' 当然,给邻居的孩子起小名也是一个很好的方式,可以更加亲近和亲切。考虑到上述名字的含义和音韵,以下是一些小名的建议: 1. 梓轩宝宝:对应“王梓轩”这个名字,可以叫他“宝宝”,表示亲切和喜爱。 2. 宇帆小子:对应“王宇帆”这个名字,可以叫他“小子”,显得活泼可爱。 3. 瑞阳小宝:对应“王瑞阳”这个名字,可以叫他“小宝”,显得亲切温暖。 4. 博文宝贝:对应“王博文”这个名字,可以叫他“宝贝”,表示对他的喜爱和呵护。 5. 浩宇小星:对应“王浩宇”这个名字,可以叫他“小星”,显得充满活力和希望。 '''
大模型应用框架-LangChain(二)+https://developer.aliyun.com/article/1544760?spm=a2c6h.13148508.setting.17.22454f0eHFZZj3