Skip to main content

LangChain 快速入门指南

 快速入门指南

本教程为您提供了关于用LangChain构建端到端语言模型应用的快速指南。
安装

要开始使用,请用以下命令安装LangChain:
pip install langchain
# 或
conda install langchain -c conda-forge

环境设置

使用LangChain通常需要与一个或多个模型提供者、数据存储、api等进行整合。
在这个例子中,我们将使用OpenAI的API,所以我们首先需要安装他们的SDK:
pip install openai

然后我们需要在终端设置环境变量。
export OPENAI_API_KEY="..."

另外,你也可以在Jupyter笔记本(或Python脚本)中完成这项工作:
输入 os
os.environ["OPENAI_API_KEY"] = "..."

如果你想动态地设置API密钥,你可以在启动OpenAI类时使用openai_api_key参数--例如,每个用户的API密钥。
from langchain.llms import OpenAI
llm = OpenAI(openai_api_key="OPENAI_API_KEY")

构建一个语言模型应用程序: LLMs

现在我们已经安装了LangChain并设置了环境,我们可以开始构建我们的语言模型应用程序。
LangChain提供了许多模块,可用于构建语言模型应用程序。模块可以组合起来创建更复杂的应用,也可以单独用于简单的应用。
LLMs: 从语言模型中获取预测结果

LangChain最基本的构建模块是在一些输入上调用一个LLM。让我们通过一个简单的例子来了解如何做到这一点。为此,让我们假设我们正在建立一个服务,根据公司的生产情况来生成一个公司名称。
为了做到这一点,我们首先需要导入LLM包装器。
from langchain.llms import OpenAI

然后我们可以用任何参数来初始化包装器。在这个例子中,我们可能想让输出更加随机,所以我们将用一个高温度来初始化它。
llm = OpenAI(temperature=0.9)

我们现在可以在一些输入上调用它
text = "对于一家生产彩色袜子的公司来说,什么会是一个好的公司名称?"
print(llm(text))

充满乐趣的脚

关于如何在LangChain中使用LLM的更多细节,请参阅LLM入门指南。
提示模板: 管理LLM的提示语

调用LLM是一个很好的第一步,但这只是一个开始。通常情况下,当你在一个应用程序中使用LLM时,你不会直接向LLM发送用户输入。相反,你可能是在接收用户的输入并构建一个提示,然后再将其发送给LLM。
例如,在前面的例子中,我们传入的文本是硬编码的,要求提供一家生产彩色袜子的公司的名称。在这个假想的服务中,我们想做的是只接受用户的输入,描述该公司是做什么的,然后用这些信息来格式化提示。
使用LangChain很容易做到这一点
首先让我们定义提示模板:
from langchain.prompts import PromptTemplate

prompt = PromptTemplate(
input_variables=["product"]、
template="对于生产{产品}的公司来说,什么是一个好名字?
)

现在让我们看看这是如何工作的! 我们可以调用.format方法来格式化它。
print(prompt.format(product="colourful socks"))

对于一家生产彩色袜子的公司来说,什么是一个好名字呢?

更多细节,请查看提示符的入门指南。
链式: 在多步骤的工作流程中结合LLM和提示语

到目前为止,我们一直在单独使用PromptTemplate和LLM基元。但当然,真正的应用不是只有一个基元,而是它们的组合。
LangChain中的链是由链接组成的,它既可以是LLM这样的基元,也可以是其他链。
最核心的链的类型是LLMChain,它由一个PromptTemplate和一个LLM组成。
扩展前面的例子,我们可以构建一个LLMChain,它接受用户的输入,用PromptTemplate对其进行格式化,然后将格式化后的响应传递给LLM。
from langchain.prompts import PromptTemplate
从langchain.llms导入OpenAI

llm = OpenAI(temperature=0.9)
prompt = PromptTemplate(
input_variables=["product"]、
template="对于生产{产品}的公司来说,什么是一个好名字?
)

我们现在可以创建一个非常简单的链,它将接受用户的输入,用它来格式化提示,然后将其发送到LLM:
from langchain.chain import LLMChain
chain = LLMChain(llm=llm, prompt=prompt)

现在,我们可以只指定产品来运行该链了!
chain.run("colorful socks")
# -> '\n\nSocktastic!

我们走吧! 这就是第一条链--LLM链。这是一种比较简单的链,但了解它的工作原理将为你处理更复杂的链打下良好基础。
更多细节,请查看链的入门指南。
代理: 基于用户输入的动态调用链

到目前为止,我们所看到的链都是按照预先确定的顺序运行的。
代理不再是这样了:他们使用LLM来决定采取哪些行动,以何种顺序进行。一个行动可以是使用一个工具并观察其输出,也可以是返回给用户。
如果使用得当,代理可以变得非常强大。在本教程中,我们将向你展示如何通过最简单、最高级别的API轻松使用代理。
为了加载代理,你应该了解以下概念:
工具: 一个执行特定职责的函数。这可以是像这样的东西: 谷歌搜索、数据库查询、Python REPL、其他链路。目前,工具的接口是一个函数,预期有一个字符串作为输入,有一个字符串作为输出。
LLM:为代理提供动力的语言模型。
代理: 要使用的代理。这应该是一个引用支持代理类的字符串。因为这本笔记本的重点是最简单、最高级的API,所以它只包括使用标准支持的代理。如果你想实现一个自定义的代理,请参阅自定义代理的文档(即将推出)。
代理: 关于支持的代理及其规格的列表,见这里。
工具: 关于预定义工具的列表和它们的规格,请看这里。
对于这个例子,你还需要安装SerpAPI Python软件包。
pip install google-search-results

并设置适当的环境变量。
输入os
os.environ["SERPAPI_API_KEY"] = "..."

现在我们可以开始行动了
from langchain.agent import load_tools
from langchain.agent import initialize_agent
从langchain.agent中导入AgentType
从langchain.llms中导入OpenAI

# 首先,让我们加载我们要用来控制代理的语言模型。
llm = OpenAI(temperature=0)

# 接下来,让我们加载一些工具来使用。注意`llm-math`工具使用LLM,所以我们需要把它传进去。
tools = load_tools(["serpapi", "llm-math"], llm=llm)


# 最后,让我们用工具、语言模型和我们想使用的代理类型来初始化一个代理。
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

# 现在我们来测试一下!
agent.run("昨天SF的最高温度是多少华氏度?这个数字提高到0.023倍是多少?")

> 进入新的AgentExecutor链...
我需要先找到温度,然后用计算器把它提高到0.023次方。
行动: 搜索
动作输入: "昨天旧金山的高温"
观察结果: 三藩市昨天的温度。昨天的最高温度: 57 °F (下午 1:56) 昨天的最低温度: 49 °F (在 1:56 am) 平均温度 ...
思考: 我现在有了温度,所以我可以用计算器把它提高到0.023次方。
行动: 计算器
动作输入: 57^.023
观察: 答案是 1.0974509573251117

思考: 我现在知道最后的答案了
最终答案: 昨天三藩市的最高温度(华氏)提高到0.023次方是1.0974509573251117。

> 完成了链。

记忆: 向链和代理添加状态

到目前为止,我们所经历的所有的链和代理都是无状态的。但通常情况下,你可能希望一个链或代理有一些 "内存 "的概念,这样它就可以记住之前的交互信息。最明显和简单的例子是在设计一个聊天机器人时--你希望它能记住以前的信息,这样它就能利用其中的上下文来进行更好的对话。这将是一种 "短期记忆"。在更复杂的方面,你可以想象一个链条/代理随着时间的推移记住关键信息--这将是一种 "长期记忆 "的形式。关于后者的更多具体想法,请看这篇很棒的论文。
LangChain提供了几个专门为这个目的而创建的链。这本笔记本介绍了如何使用这些链中的一个(ConversationChain)和两种不同类型的记忆。
默认情况下,ConversationChain有一个简单的内存类型,它可以记住所有以前的输入/输出,并将它们添加到传递的上下文中。让我们来看看如何使用这个链(设置verbose=True,这样我们就可以看到提示)。
from langchain import OpenAI, ConversationChain

llm = OpenAI(temperature=0)
conversation = ConversationChain(llm=llm, verbose=True)

output = conversation.predict(input="Hi there!")
print(output)

> 正在输入新的链...
格式化后的提示:
下面是一个人类和一个人工智能之间的友好对话。AI很健谈,从上下文中提供了很多具体的细节。如果人工智能不知道某个问题的答案,它就会如实说自己不知道。

目前的对话:

人类:你好!
人工智能:

> 完成了链。
' 你好!你今天好吗?

output = conversation.predict(input="我很好!只是在和人工智能对话。")
print(output)

> 进入新链...
格式化后的提示:
下面是一个人类和一个人工智能之间的友好对话。人工智能很健谈,从其背景中提供了很多具体的细节。如果人工智能不知道某个问题的答案,它就会如实说它不知道。

目前的对话:

人类:你好!你是谁?
人工智能:你好!你今天好吗?
人类:我很好! 只是在和人工智能进行对话。
人工智能:

> 完成了链。
" 那很好!你想谈什么?你想谈些什么?"

建立一个语言模型的应用: 聊天模型

同样地,你可以使用聊天模型来代替LLM。聊天模型是语言模型的一个变种。虽然聊天模型在引擎盖下使用语言模型,但它们暴露的接口有点不同:它们暴露的接口不是 "文本输入,文本输出",而是 "聊天信息 "作为输入和输出的接口。
聊天模型的API是相当新的,所以我们仍在摸索正确的抽象方法。
从聊天模型中获取消息完成度

您可以通过向聊天模型传递一个或多个消息来获得聊天完成度。响应将是一个消息。目前LangChain支持的消息类型有AIMessage、HumanMessage、SystemMessage和ChatMessage--ChatMessage接收一个任意的角色参数。大多数时候,你只需要处理HumanMessage、AIMessage和SystemMessage。
from langchain.chat_models import ChatOpenAI
从langchain.schema中导入(
AIMessage、
HumanMessage、
系统消息
)

chat = ChatOpenAI(temperature=0)

你可以通过传入一条信息来获得完成度。
chat([HumanMessage(content="把这句话从英语翻译成法语。我喜欢编程。"])
# -> AIMessage(content="J'aime programmer.", additional_kwargs={})

你也可以为OpenAI的gpt-3.5-turbo和gpt-4模型传入多个消息。
messages = [
SystemMessage(content="你是一个将英语翻译成法语的有用助手。")、
HumanMessage(content="我喜欢编程。")
]
chat(messages)
# -> AIMessage(content="J'aime programmer.", additional_kwargs={})

你可以更进一步,使用generate来生成多组消息的完成度。这将返回一个带有额外消息参数的LLMResult:
batch_messages = [
[
SystemMessage(content="You are a helpful assistant that translates English to French.")、
HumanMessage(content="我喜欢编程。")
],
[
SystemMessage(content="你是一个将英语翻译成法语的有用的助手。")、
HumanMessage(content="我喜欢人工智能。")
],
]
结果 = chat.generate(batch_messages)
结果
# -> LLMResult(generation=[[ChatGeneration(text="J'aime programmer.", generation_info=None, message=AIMessage(content="J'aime programmer.", additional_kwargs={}))], [ChatGeneration(text="J'aime l'intelligence artificielle. ", generation_info=None, message=AIMessage(content="J'aime l'intelligence artificielle.", additional_kwargs={})], llm_output={'token_usage': {'prompt_tokens': 57, 'completion_tokens': 20, 'total_tokens': 77}})

你可以从这个LLMResult中恢复诸如令牌使用情况的东西:
result.llm_output['token_usage'] (结果)。
# -> {'prompt_tokens': 57, 'completion_tokens': 20, 'total_tokens': 77}

聊天提示模板

与LLM类似,你可以通过使用MessagePromptTemplate来利用模板化。你可以从一个或多个MessagePromptTemplate建立一个ChatPromptTemplate。你可以使用ChatPromptTemplate的format_prompt--它返回一个PromptValue,你可以将其转换为字符串或消息对象,这取决于你是否想使用格式化的值作为输入到llm或聊天模型。
为方便起见,模板上有一个from_template方法。如果你要使用这个模板,它会是这样的:
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
ChatPromptTemplate、
SystemMessagePromptTemplate、
HumanMessagePromptTemplate、
)

chat = ChatOpenAI(temperature=0)

模板 = "你是一个有用的助手,将{输入语言}翻译成{输出语言}。"
system_message_prompt = SystemMessagePromptTemplate.from_template(模板)。
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)

chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])

#从格式化的消息中获得一个聊天完成度
chat(chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.") .to_messages()
# -> AIMessage(content="J'aime programmer.", additional_kwargs={})

带有聊天模型的链子

上节中讨论的LLMChain也可以与聊天模型一起使用:
from langchain.chat_models import ChatOpenAI
from langchain import LLMChain
from langchain.prompts.chat import (
ChatPromptTemplate、
系统信息提示模板(SystemMessagePromptTemplate)、
HumanMessagePromptTemplate、
)

chat = ChatOpenAI(temperature=0)
模板 = "你是一个有用的助手,将{input_language}翻译成{output_language}。"
system_message_prompt = SystemMessagePromptTemplate.from_template(模板)。
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt] )

chain = LLMChain(llm=chat, prompt=chat_prompt)
chain.run(input_language="English", output_language="French", text="I love programming." )
# -> "J'aime programmer."

带聊天模型的代理

代理也可以与聊天模型一起使用,你可以使用AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION作为代理类型来初始化一个。
from langchain.agent import load_tools
from langchain.agent import initialize_agent
from langchain.agent import AgentType
from langchain.chat_models import ChatOpenAI
从langchain.llms中导入OpenAI

# 首先,让我们加载我们要用来控制代理的语言模型。
chat = ChatOpenAI(temperature=0)

# 接下来,让我们加载一些工具来使用。注意,`llm-math`工具使用LLM,所以我们需要把它传进去。
llm = OpenAI(temperature=0)
tools = load_tools(["serpapi", "llm-math"], llm=llm)


# 最后,让我们用工具、语言模型和我们想使用的代理类型来初始化一个代理。
agent = initialize_agent(tools, chat, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

# 现在我们来测试一下!
agent.run("Olivia Wilde的男朋友是谁?他现在的年龄是多少,提高到0.23倍?")


> 进入新的AgentExecutor链...
思考: 我需要用搜索引擎找到奥利维亚-王尔德的男朋友,用计算器把他的年龄提高到0.23次方。
行动:
{
"action": "搜索"、
"action_input": "奥利维亚-王尔德的男朋友"
}

观察一下: Sudeikis和王尔德的关系在2020年11月结束。王尔德在2022年CinemaCon上展示《别担心,亲爱的》时,被公开送达了有关孩子监护权的法庭文件。2021年1月,王尔德在拍摄《Don't Worry Darling》时认识了歌手哈里-斯泰尔斯,并开始约会。
想法:我需要用搜索引擎来查找哈里-斯泰尔斯现在的年龄。
行动:
{
"行动": "搜索"、
"action_input": "Harry Styles年龄"
}

观察结果:29岁
思考:现在我需要计算出29岁,并将其提高到0.23倍。
行动:
{
"行动": "计算器"、
"action_input": "29^0.23"
}

观察: 答案:2.169459462491557

思考:我现在知道最终答案了。
最终答案:2.169459462491557

> 完成的链条。
'2.169459462491557'

记忆: 为链和代理添加状态

你可以用聊天模型初始化的链和代理来使用Memory。这与LLM的Memory的主要区别在于,我们可以将所有之前的消息浓缩成一个字符串,而不是将它们作为自己独特的内存对象。
from langchain.prompts import (
ChatPromptTemplate、 
MessagesPlaceholder、 
SystemMessagePromptTemplate、 
HumanMessagePromptTemplate
)
from langchain.chain import ConversationChain
从langchain.chat_models导入ChatOpenAI
从langchain.memory导入ConversationBufferMemory

prompt = ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template("下面是一个人类和一个人工智能之间的友好对话。人工智能很健谈,从上下文中提供了很多具体细节。如果人工智能不知道某个问题的答案,它就会如实说它不知道。")、
MessagesPlaceholder(variable_name="history")、
HumanMessagePromptTemplate.from_template("{input}")
])

llm = ChatOpenAI(温度=0)
内存 = ConversationBufferMemory(return_messages=True)
conversation = ConversationChain(memory=memory, prompt=prompt, llm=llm)

conversation.predict(input="Hi there!")
# -> "你好!今天我能为你提供什么帮助?


conversation.predict(input="我做得很好!只是在和一个人工智能进行对话。")
#-> "这听起来很有趣! 我很高兴能和你聊天。你有什么特别想谈的吗?"

conversation.predict(input="告诉我你的情况。")
# -> "当然!我是OpenAI创建的一个人工智能语言模型。我是在互联网上的大型文本数据集上训练出来的,这使我能够理解并产生类似人类的语言。我可以回答问题,提供信息,甚至像这样进行对话。关于我,你还有什么想知道的吗?"





Comments

Popular posts from this blog

Think in 2B SaaS

这数年2B SaaS创业经历,让我自己从一个对2B SaaS有着盲目疯狂热情的人,变的逐渐趋于冷静。如何推动建立一个健康的SaaS产品和公司,成了我特别想去思考和解决的问题。 这几年,个人和公司一直都是在野蛮生长,销售驱动的模型下,产品,销售,交付,客户成功都在疲于奔命完成财务业绩。在没有坚持跑出一套聚焦于SaaS领域,可以合力的运作体系下,争执和冲突便成了家常便饭。 销售往往因产品没有某个功能,吐槽产品不给力。因为研发不能按时做出一个客户要的功能,吐槽产品无能,因为找不到客户,所以开始盯着老客户的增购业绩,盯着传统实施项目规模带来的业绩收益。 交付因为销售的过度承诺,卖出产品没有的功能,或者实施过程中细节点产品不支持的能力,吐槽销售,吐槽研发,实施过程变得举步维艰。 CS因为交付质量,产品功能,系统服务的稳定性,导致客户关系紧张,出问题后花费大量时间灭火。或者处理因为bug带来的系统数据不一致的问题。在发生了集成对接的情况下,甚至要协调下游各个系统修复数据,带来的服务成本的增长。增购也就自然而然变得困难。 产研觉得产品功能自己都无法进行规划管理,总是被动的被销售和交付过程中客户的紧急需求干扰,仓促设计的结果就是应用架构设计上的疏忽,开发的bug,业务场景的缺失。 上述的过程,可能很多初始的SaaS创业团队都会碰到,特别是2B领域的。协同的不好,矛盾冲突屡屡发生,不产生合力的情况下,为了维持高业绩增长的要求,内部的负担愈发严重,跑的越来越慢,整体的服务质量情况却没有一个明显的提升。由此引发的各个职能的一线的员工的工作感受也越来越差。推诿,委屈,困惑,气忿等负面情绪也与日俱增。 因此,如何科学的构建一个可以上下协同的组织,如何管理需求,如何管理迭代,如何找到目标客户,如何快速的实施落地,如何更好的保持客户粘性,给客户带来持续不断的新鲜感,配合客户业务的发展需要,就需要进行一套科学的管理办法。无序和杂乱只会让增长越来越缓慢。

MAC Homebrew安装了zookeeper 但是stop时报错

执行下面的命令的时候报错,找不到对应路径下的pid文件。 zkserver stop /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/etc/zookeeper/zoo.cfg Stopping zookeeper ... no zookeeper to stop (could not find file /usr/local/var/run/zookeeper/data/zookeeper_server.pid) 查了网上很多地方,很多人说是data路径中的空格问题,但是查了配置文件发现并不是。 错误信息里面说是pid文件找不到路径,所以,怀疑是读写权限或者是别的什么异常原因导致当时pid文件没有生成。 试着用sudo权限重新执行 sudo zkserver restart Password: /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/etc/zookeeper/zoo.cfg /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/etc/zookeeper/zoo.cfg Stopping zookeeper ... no zookeeper to stop (could not find file /usr/local/var/run/zookeeper/data/zookeeper_server.pid) /usr/bin/java ZooKeeper JMX enabled by default 结果在目录下找到了对应的pid文件。 查看pid文件内容,发现就是一个进程id。这时候考虑修改pid文件的内容,把当前停不下来的进程编号写进去。 然后重新执行了zkserver stop命令。 sudo zkserver stop /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/etc/zookeeper/zoo.cfg Stopping zookeeper ... STOPPED 搞定...

FAISS Vector DB 学习笔记(一)

 1. 安装Faiss: 按照Faiss官方资源库提供的安装说明,确保你有必要的依赖和兼容的硬件(如果使用GPU加速)。 2. 2.准备好你的数据: Faiss使用密集向量工作,所以确保你的数据以浮点数组或矩阵的形式表示,其中每一行对应一个向量。确保你的向量的尺寸是一致的。 3. 导入必要的模块: 在你的Python脚本中,导入所需的Faiss模块: ``python import faiss import numpy as np ``` 4. 创建一个索引: 根据你的需要,选择适当的索引类型。下面是一个创建IndexFlatL2索引的例子: ```python d = 128  # Dimension of your vectors index = faiss.IndexFlatL2(d)  # Initialize the index ``` 你可以探索其他的索引类型,比如IndexIVFFlat或IndexHNSW,这取决于你愿意做出的折衷。 5. 为索引添加向量: 一旦你初始化了你的索引,使用`add'方法将你的向量添加到它里面。传入一个NumPy数组或一个兼容的数据结构: ``python vectors = np.random.random((1000, d)).astype('float32')  # Example vectors index.add(vectors)  # Add the vectors to the index ``` 6. 进行相似性搜索: 要为一个查询向量找到最近的邻居,可以使用`search`方法。传入查询向量和需要检索的近邻数量: ``python k = 5  # Number of nearest neighbors to retrieve query_vector = np.random.random((1, d)).astype('float32')  # Example query vector D, I = index.search(query_vector, k)  # Perform the search ``` 返回的`D`数组包含与最近的邻居的距离,`I`数组包含它们在原始数据集中的相应索引。 7. 自定义和优化: Faiss...