LangChain 中文入门教程

2023-11-01

LangChain 中文入门教程

colab地址(包含本文所有案例)gitbook(方便阅读)github地址

  如果想把 OPENAI API 的请求根路由修改成自己的代理地址,可以通过设置环境变量 “OPENAI\_API\_BASE” 来进行修改,参考代码。或在初始化OpenAI相关模型对象时,传入“openai_api_base” 变量,参考代码

一、介绍

LangChain官方文档

1.1 背景

  众所周知 OpenAI 的 API 无法联网的,所以如果只使用自己的功能实现联网搜索并给出回答、总结 PDF 文档、基于某个 Youtube 视频进行问答等等的功能肯定是无法实现的。所以,我们来介绍一个非常强大的第三方开源库:LangChain

LangChain 是一个用于开发由语言模型驱动的应用程序的框架。他主要拥有 2 个能力:

  1. 可以将 LLM 模型(大规模语言模型)与外部数据源进行连接
  2. 允许与 LLM 模型进行交互

1.2 基础功能

  • 支持多种模型接口,比如 OpenAI、Hugging Face、AzureOpenAI …
  • Fake LLM,用于测试
  • 缓存的支持,比如 in-mem(内存)、SQLite、Redis、SQL
  • 用量记录
  • 支持流模式(就是一个字一个字的返回,类似打字效果)

Prompt管理,支持各种自定义模板

拥有大量的文档加载器,比如 Email、Markdown、PDF、Youtube …

对索引的支持

  • 文档分割器
  • 向量化
  • 对接向量存储与搜索,比如 Chroma、Pinecone、Qdrand

Chains

  • LLMChain
  • 各种工具Chain
  • LangChainHub

二、必知概念

  相信大家看完上面的介绍多半会一脸懵逼。不要担心,上面的概念其实在刚开始学的时候不是很重要,当我们讲完后面的例子之后,在回来看上面的内容会一下明白很多。但是,下面几个概念是必须知道的。

2.1 Loader 加载器

Loader文档

顾名思义,这个就是从指定源进行加载数据的。比如:

  • 文件夹 DirectoryLoader
  • Azure 存储 AzureBlobStorageContainerLoader
  • CSV文件 CSVLoader
  • 印象笔记 EverNoteLoader
  • Google网盘 GoogleDriveLoader
  • 任意的网页 UnstructuredHTMLLoader
  • PDF PyPDFLoader
  • S3 S3DirectoryLoader/S3FileLoader
  • Youtube YoutubeLoader

上面只是简单的进行列举了几个,官方提供了超级的多的加载器供你使用。

2.2 Document 文档

  当使用loader加载器读取到数据源后,数据源需要转换成 Document 对象后,后续才能进行使用。

2.3 Text Spltters 文本分割

  顾名思义,文本分割就是用来分割文本的。为什么需要分割文本?因为我们每次不管是做把文本当作 prompt 发给 openai api ,还是还是使用 openai api embedding 功能都是有字符限制的。

  比如我们将一份300页的 pdf 发给 openai api,让他进行总结,他肯定会报超过最大 Token 错。所以这里就需要使用文本分割器去分割我们 loader 进来的 Document

2.4 Vectorstores 向量数据库

Vectorstores文档

  因为数据相关性搜索其实是向量运算。所以,不管我们是使用 openai api embedding 功能还是直接通过向量数据库直接查询,都需要将我们的加载进来的数据 Document 进行向量化,才能进行向量运算搜索。转换成向量也很简单,只需要我们把数据存储到对应的向量数据库中即可完成向量的转换。官方也提供了很多的向量数据库供我们使用。

2.5 Chain(链)

Chains文档

  我们可以把 Chain 理解为任务。一个 Chain 就是一个任务,当然也可以像链条一样,一个一个的执行多个链。

2.6 Agent 代理

  我们可以简单的理解为他可以动态的帮我们选择和调用chain或者已有的工具,执行过程可以参考下面这张图:

在这里插入图片描述

2.7 Embedding

  Embedding用于衡量文本的相关性,这个也是 OpenAI API 能实现构建自己知识库的关键所在。相比 fine-tuning 最大的优势就是,不用进行训练,并且可以实时添加新的内容,而不用加一次新的内容就训练一次,并且各方面成本要比 fine-tuning 低很多。具体比较和选择可以参考此视频

三、实战

  下面使用Open AI 范例进行说明,大家也可以根据自己任务的需要换成自己需要的 LLM 模型。

3.1 单次问答

  在开始之前,我们需要先设置我们的 openai 的 key,这个 key 可以在用户管理里面创建,这里就不细说了。

import os
os.environ["OPENAI_API_KEY"] = '你的api key'

然后,我们进行导入和执行

from langchain.llms import OpenAI

llm = OpenAI(model_name="text-davinci-003",max_tokens=1024)
llm("怎么评价人工智能")

在这里插入图片描述

这时,我们就可以看到他给我们的返回结果了,怎么样,是不是很简单。

3.2 通过 Google 搜索并返回答案

  接下来,我们就来搞点有意思的。我们来让我们的 OpenAI api 联网搜索,并返回答案给我们。

  这里我们需要借助 Serpapi 来进行实现,Serpapi 提供了 google 搜索的 api 接口。首先需要我们到 Serpapi官网上注册一个用户,并复制他给我们生成 api key。然后我们需要像上面的 openai api key 一样设置到环境变量里面去。

serpapi 貌似对中文不是很友好,所以提问的 prompt 建议使用英文。

import os
os.environ["OPENAI_API_KEY"] = '你的api key'
os.environ["SERPAPI_API_KEY"] = '你的api key'

然后,开始编写我的代码

from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.llms import OpenAI
from langchain.agents import AgentType

# 加载 OpenAI 模型
llm = OpenAI(temperature=0,max_tokens=2048) 

 # 加载 serpapi 工具
tools = load_tools(["serpapi"])

# 如果搜索完想再计算一下可以这么写
# tools = load_tools(['serpapi', 'llm-math'], llm=llm)

# 如果搜索完想再让他再用python的print做点简单的计算,可以这样写
# tools=load_tools(["serpapi","python_repl"])

# 工具加载后都需要初始化,verbose 参数为 True,会打印全部的执行详情
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

# 运行 agent
agent.run("What's the date today? What great events have taken place today in history?")

在这里插入图片描述

  我们可以看到,他正确的返回了日期(有时差),并且返回了历史上的今天。

  在 chain 和 agent 对象上都会有 verbose 这个参数,这个是个非常有用的参数,开启他后我们可以看到完整的 chain 执行过程。可以在上面返回的结果看到,他将我们的问题拆分成了几个步骤,然后一步一步得到最终的答案。

关于agent type 几个选项的含义(理解不了也不会影响下面的学习,用多了自然理解了):

  • zero-shot-react-description::根据工具的描述和请求内容的来决定使用哪个工具(最常用)
  • react-docstore::使用 ReAct 框架和 docstore 交互, 使用SearchLookup 工具, 前者用来搜, 后者寻找term, 举例: Wipipedia 工具
  • self-ask-with-search:此代理只使用一个工具: Intermediate Answer, 它会为问题寻找事实答案(指的非 gpt 生成的答案, 而是在网络中,文本中已存在的), 如 Google search API 工具
  • conversational-react-description::为会话设置而设计的代理, 它的prompt会被设计的具有会话性, 且还是会使用 ReAct 框架来决定使用来个工具, 并且将过往的会话交互存入内存

LLM 的 ReAct 模式的 Python 实现: https://til.simonwillison.net/llms/python-react-pattern

  当然,官方已经写好了 ChatGPT Plugins 的 agent,未来 chatgpt 能用啥插件,我们在 api 里面也能用插件,想想都美滋滋。不过目前只能使用不用授权的插件,期待未来官方解决这个,感兴趣的可以看此文档

Chatgpt 只能给官方赚钱,而 Openai API 能给我赚钱

3.3 对超长文本进行总结

  假如我们想要用 openai api 对一段文本进行总结,我们通常的做法就是直接发给 api 让他总结。但是如果文本超过了 api 最大的 token 限制就会报错。

  这时,我们一般会进行对文章进行分段,比如通过 tiktoken 计算并分割,然后将各段发送给 api 进行总结,最后将各段的总结再进行一个全部的总结。

   LangChain可以很好的帮我们处理这个过程,代码也很简单。

from langchain.document_loaders import UnstructuredFileLoader
from langchain.chains.summarize import load_summarize_chain
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain import OpenAI

# 导入文本
loader = UnstructuredFileLoader("/content/sample_data/data/lg_test.txt")
# 将文本转成 Document 对象
document = loader.load()
print(f'documents:{len(document)}')

# 初始化文本分割器
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 500,
    chunk_overlap = 0
)

# 切分文本
split_documents = text_splitter.split_documents(document)
print(f'documents:{len(split_documents)}')

# 加载 llm 模型
llm = OpenAI(model_name="text-davinci-003", max_tokens=1500)

# 创建总结链
chain = load_summarize_chain(llm, chain_type="refine", verbose=True)

# 执行总结链,(为了快速演示,只总结前5段)
chain.run(split_documents[:5])

  首先我们对切割前和切割后的 document 个数进行了打印,我们可以看到,切割前就是只有整篇的一个 document,切割完成后,会把上面一个 document 切成 317 个 document。

在这里插入图片描述

最终输出了对前 5 个 document 的总结。

在这里插入图片描述

这里有几个参数需要注意:

1. 文本分割器的 chunk_overlap 参数

  这个是指切割后的每个 document 里包含几个上一个 document 结尾的内容,主要作用是为了增加每个 document 的上下文关联。比如,chunk_overlap=0时, 第一个 document 为 aaaaaa,第二个为 bbbbbb;当 chunk_overlap=2 时,第一个 document 为 aaaaaa,第二个为 aabbbbbb。不过,这个也不是绝对的,要看所使用的那个文本分割模型内部的具体算法。

文本分割器参考此文档

2. chain 的 chain_type 参数

这个参数主要控制了将 document 传递给 llm 模型的方式,一共有 4 种方式:

  • stuff::这种最简单粗暴,会把所有的 document 一次全部传给 llm 模型进行总结。如果document很多的话,势必会报超出最大 token 限制的错,所以总结文本的时候一般不会选中这个。

  • map_reduce::这个方式会先将每个 document 进行总结,最后将所有 document 总结出的结果再进行一次总结。

在这里插入图片描述

  • refine::这种方式会先总结第一个 document,然后在将第一个 document 总结出的内容和第二个 document 一起发给 llm 模型在进行总结,以此类推。这种方式的好处就是在总结后一个 document 的时候,会带着前一个的 document 进行总结,给需要总结的 document 添加了上下文,增加了总结内容的连贯性。

在这里插入图片描述

  • map_rerank::这种一般不会用在总结的 chain 上,而是会用在问答的 chain 上,他其实是一种搜索答案的匹配方式。首先你要给出一个问题,他会根据问题给每个 document 计算一个这个 document 能回答这个问题的概率分数,然后找到分数最高的那个 document ,在通过把这个 document 转化为问题的 prompt 的一部分(问题+document)发送给 llm 模型,最后 llm 模型返回具体答案。

3.4 构建本地知识库问答机器人

Openai embeddings文档

  在这个例子中,我们会介绍如何从我们本地读取多个文档构建知识库,并且使用 Openai API 在知识库中进行搜索并给出答案。这个是个很有用的教程,比如可以很方便的做一个可以介绍公司业务的机器人,或是介绍一个产品的机器人。

from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain import OpenAI,VectorDBQA
from langchain.document_loaders import DirectoryLoader
from langchain.chains import RetrievalQA

# 加载文件夹中的所有txt类型的文件
loader = DirectoryLoader('/content/sample_data/data/', glob='**/*.txt')
# 将数据转成 document 对象,每个文件会作为一个 document
documents = loader.load()

# 初始化加载器
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
# 切割加载的 document
split_docs = text_splitter.split_documents(documents)

# 初始化 openai 的 embeddings 对象
embeddings = OpenAIEmbeddings()
# 将 document 通过 openai 的 embeddings 对象计算 embedding 向量信息并临时存入 Chroma 向量数据库,用于后续匹配查询
docsearch = Chroma.from_documents(split_docs, embeddings)

# 创建问答对象
qa = VectorDBQA.from_chain_type(llm=OpenAI(), chain_type="stuff", vectorstore=docsearch,return_source_documents=True)
# 进行问答
result = qa({"query": "科大讯飞今年第一季度收入是多少?"})
print(result)

在这里插入图片描述

我们可以通过结果看到,他成功的从我们的给到的数据中获取了正确的答案。

3.5 构建向量索引数据库

  我们上个案例里面有一步是将 document 信息转换成向量信息,和embeddings的信息并临时存入 Chroma 数据库。因为是临时存入,所以当我们上面的代码执行完成后,上面的向量化后的数据将会丢失。如果想下次使用,那么就还需要再计算一次embeddings,这肯定不是我们想要的。

  本案例,我们通过 ChromaPinecone 这两个数据库,来讲一下如何做向量数据持久化。更多 LangChain 数据库,参考此文档

1. Chroma
  chroma 是个本地的向量数据库,他提供的一个 persist_directory 来设置持久化目录进行持久化。读取时,只需要调取 from_document 方法加载即可。

from langchain.vectorstores import Chroma

# 持久化数据
docsearch = Chroma.from_documents(documents, embeddings, persist_directory="D:/vector_store")
docsearch.persist()

# 加载数据
docsearch = Chroma(persist_directory="D:/vector_store", embedding_function=embeddings)

2. Pinecone

  Pinecone是一个在线的向量数据库。所以,我可以第一步依旧是注册,然后拿到对应的 api key。(免费版如果索引14天不使用会被自动清除。)

然后创建我们的数据库:

  • Index Name:这个随意
  • Dimensions:OpenAI 的 text-embedding-ada-002 模型为 OUTPUT DIMENSIONS 为 1536,所以我们这里填 1536
  • Metric:默认cosine
  • Pod Type:选starter plan
    在这里插入图片描述

持久化数据和加载数据代码如下

# 持久化数据
docsearch = Pinecone.from_texts([t.page_content for t in split_docs], embeddings, index_name=index_name)

# 加载数据
docsearch = Pinecone.from_existing_index(index_name, embeddings)

一个简单从数据库获取 embeddings并回答的代码如下

from langchain.text_splitter import CharacterTextSplitter
from langchain.document_loaders import DirectoryLoader
from langchain.vectorstores import Chroma, Pinecone
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.llms import OpenAI
from langchain.chains.question_answering import load_qa_chain

import pinecone

# 初始化 pinecone
pinecone.init(
  api_key="你的api key",
  environment="你的Environment"
)

loader = DirectoryLoader('/content/sample_data/data/', glob='**/*.txt')
# 将数据转成 document 对象,每个文件会作为一个 document
documents = loader.load()

# 初始化加载器
text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0)
# 切割加载的 document
split_docs = text_splitter.split_documents(documents)

index_name="liaokong-test"

# 持久化数据
# docsearch = Pinecone.from_texts([t.page_content for t in split_docs], embeddings, index_name=index_name)

# 加载数据
docsearch = Pinecone.from_existing_index(index_name,embeddings)

query = "科大讯飞今年第一季度收入是多少?"
docs = docsearch.similarity_search(query, include_metadata=True)

llm = OpenAI(temperature=0)
chain = load_qa_chain(llm, chain_type="stuff", verbose=True)
chain.run(input_documents=docs, question=query)

在这里插入图片描述

3.6 使用GPT3.5模型构建油管频道问答机器人

  在 chatgpt api(也就是 GPT-3.5-Turbo)模型出来后,因钱少活好深受大家喜爱,所以 LangChain 也加入了专属的链和模型,我们来跟着这个例子看下如何使用他。

import os

from langchain.document_loaders import YoutubeLoader
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains import ChatVectorDBChain, ConversationalRetrievalChain

from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
  ChatPromptTemplate,
  SystemMessagePromptTemplate,
  HumanMessagePromptTemplate
)

# 加载 youtube 频道
loader = YoutubeLoader.from_youtube_url('https://www.youtube.com/watch?v=Dj60HHy-Kqk')
# 将数据转成 document
documents = loader.load()

# 初始化文本分割器
text_splitter = RecursiveCharacterTextSplitter(
  chunk_size=1000,
  chunk_overlap=20
)

# 分割 youtube documents
documents = text_splitter.split_documents(documents)

# 初始化 openai embeddings
embeddings = OpenAIEmbeddings()

# 将数据存入向量存储
vector_store = Chroma.from_documents(documents, embeddings)
# 通过向量存储初始化检索器
retriever = vector_store.as_retriever()

system_template = """
Use the following context to answer the user's question.
If you don't know the answer, say you don't, don't try to make it up. And answer in Chinese.
-----------
{context}
-----------
{chat_history}
"""

# 构建初始 messages 列表,这里可以理解为是 openai 传入的 messages 参数
messages = [
  SystemMessagePromptTemplate.from_template(system_template),
  HumanMessagePromptTemplate.from_template('{question}')
]

# 初始化 prompt 对象
prompt = ChatPromptTemplate.from_messages(messages)


# 初始化问答链
qa = ConversationalRetrievalChain.from_llm(ChatOpenAI(temperature=0.1,max_tokens=2048),retriever,condense_question_prompt=prompt)


chat_history = []
while True:
  question = input('问题:')
  # 开始发送问题 chat_history 为必须参数,用于存储对话历史
  result = qa({'question': question, 'chat_history': chat_history})
  chat_history.append((question, result['answer']))
  print(result['answer'])

我们可以看到他能很准确的围绕这个油管视频进行问答

在这里插入图片描述

使用流式回答也很方便

from langchain.callbacks.base import CallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler

chat = ChatOpenAI(streaming=True, callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]), verbose=True, temperature=0)
resp = chat(chat_prompt_with_values.to_messages())

3.7 用 OpenAI 连接万种工具

  我们主要是结合使用 zapier来实现将万种工具连接起来。所以我们第一步依旧是需要申请账号和他的自然语言 api key。zapier api key 填入基础信息后,基本可以秒在邮箱里看到审核通过的邮件。

  然后,我们通过右键里面的连接打开我们的api 配置页面。我们点击右侧的 Manage Actions 来配置我们要使用哪些应用。我在这里配置了 Gmail 读取和发邮件的 action,并且所有字段都选的是通过 AI 猜。

在这里插入图片描述

在这里插入图片描述

配置好后,我们开始写代码

import os
os.environ["ZAPIER_NLA_API_KEY"] = ''
from langchain.llms import OpenAI
from langchain.agents import initialize_agent
from langchain.agents.agent_toolkits import ZapierToolkit
from langchain.utilities.zapier import ZapierNLAWrapper


llm = OpenAI(temperature=.3)
zapier = ZapierNLAWrapper()
toolkit = ZapierToolkit.from_zapier_nla_wrapper(zapier)
agent = initialize_agent(toolkit.get_tools(), llm, agent="zero-shot-react-description", verbose=True)

# 我们可以通过打印的方式看到我们都在 Zapier 里面配置了哪些可以用的工具
for tool in toolkit.get_tools():
  print (tool.name)
  print (tool.description)
  print ("\n\n")

agent.run('请用中文总结最后一封"******@qq.com"发给我的邮件。并将总结发送给"******@qq.com"')

在这里插入图片描述

  我们可以看到他成功读取了******@qq.com给他发送的最后一封邮件,并将总结的内容又发送给了******@qq.com。这是我发送给 Gmail 的邮件:

在这里插入图片描述

这是他发送给 QQ 邮箱的邮件:
在这里插入图片描述

  这只是个小例子,因为 zapier 有数以千计的应用,所以我们可以轻松结合 openai api 搭建自己的工作流。

  主要知识点已经讲完了,下面用一些比较有趣的小例子,当作拓展延伸。

四、小例子

4.1 执行多个chain

LangChain是链式的,所以他也可以按顺序依次去执行多个 chain:

from langchain.llms import OpenAI
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.chains import SimpleSequentialChain

# location 链
llm = OpenAI(temperature=1)
template = """Your job is to come up with a classic dish from the area that the users suggests.
% USER LOCATION
{user_location}

YOUR RESPONSE:
"""
prompt_template = PromptTemplate(input_variables=["user_location"], template=template)
location_chain = LLMChain(llm=llm, prompt=prompt_template)

# meal 链
template = """Given a meal, give a short and simple recipe on how to make that dish at home.
% MEAL
{user_meal}

YOUR RESPONSE:
"""
prompt_template = PromptTemplate(input_variables=["user_meal"], template=template)
meal_chain = LLMChain(llm=llm, prompt=prompt_template)

# 通过 SimpleSequentialChain 串联起来,第一个答案会被替换第二个中的user_meal,然后再进行询问
overall_chain = SimpleSequentialChain(chains=[location_chain, meal_chain], verbose=True)
review = overall_chain.run("Rome")

在这里插入图片描述

4.2 结构化输出

有时候我们希望输出的内容不是文本,而是像 json 那样结构化的数据。

from langchain.output_parsers import StructuredOutputParser, ResponseSchema
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI

llm = OpenAI(model_name="text-davinci-003")

# 告诉他我们生成的内容需要哪些字段,每个字段类型式啥
response_schemas = [
    ResponseSchema(name="bad_string", description="This a poorly formatted user input string"),
    ResponseSchema(name="good_string", description="This is your response, a reformatted response")
]

# 初始化解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)

# 生成的格式提示符
# {
#	"bad_string": string  // This a poorly formatted user input string
#	"good_string": string  // This is your response, a reformatted response
#}
format_instructions = output_parser.get_format_instructions()

template = """
You will be given a poorly formatted string from a user.
Reformat it and make sure all the words are spelled correctly

{format_instructions}

% USER INPUT:
{user_input}

YOUR RESPONSE:
"""

# 将我们的格式描述嵌入到 prompt 中去,告诉 llm 我们需要他输出什么样格式的内容
prompt = PromptTemplate(
    input_variables=["user_input"],
    partial_variables={"format_instructions": format_instructions},
    template=template
)

promptValue = prompt.format(user_input="welcom to califonya!")
llm_output = llm(promptValue)

# 使用解析器进行解析生成的内容
output_parser.parse(llm_output)

在这里插入图片描述

4.3 爬取网页并输出JSON数据

  有些时候我们需要爬取一些结构性比较强的网页,并且需要将网页中的信息以JSON的方式返回回来。我们就可以使用 LLMRequestsChain 类去实现,具体可以参考下面代码

为了方便理解,我在例子中直接使用了Prompt的方法去格式化输出结果,而没用使用上个案例中用到的 StructuredOutputParser去格式化,也算是提供了另外一种格式化的思路

from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
from langchain.chains import LLMRequestsChain, LLMChain

llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0)

template = """在 >>> 和 <<< 之间是网页的返回的HTML内容。
网页是新浪财经A股上市公司的公司简介。
请抽取参数请求的信息。

>>> {requests_result} <<<
请使用如下的JSON格式返回数据
{{
  "company_name":"a",
  "company_english_name":"b",
  "issue_price":"c",
  "date_of_establishment":"d",
  "registered_capital":"e",
  "office_address":"f",
  "Company_profile":"g"

}}
Extracted:"""

prompt = PromptTemplate(
    input_variables=["requests_result"],
    template=template
)

chain = LLMRequestsChain(llm_chain=LLMChain(llm=llm, prompt=prompt))
inputs = {
  "url": "https://vip.stock.finance.sina.com.cn/corp/go.php/vCI_CorpInfo/stockid/600519.phtml"
}

response = chain(inputs)
print(response['output'])

我们可以看到,他很好的将格式化后的结果输出了出来

在这里插入图片描述

4.4 自定义agent中所使用的工具

from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
from langchain.tools import BaseTool
from langchain.llms import OpenAI
from langchain import LLMMathChain, SerpAPIWrapper

llm = OpenAI(temperature=0)

# 初始化搜索链和计算链
search = SerpAPIWrapper()
llm_math_chain = LLMMathChain(llm=llm, verbose=True)

# 创建一个功能列表,指明这个 agent 里面都有哪些可用工具,agent 执行过程可以看必知概念里的 Agent 那张图
tools = [
    Tool(
        name = "Search",
        func=search.run,
        description="useful for when you need to answer questions about current events"
    ),
    Tool(
        name="Calculator",
        func=llm_math_chain.run,
        description="useful for when you need to answer questions about math"
    )
]

# 初始化 agent
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

# 执行 agent
agent.run("Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?")

在这里插入图片描述

  自定义工具里面有个比较有意思的地方,使用哪个工具的权重是靠 工具中描述内容 来实现的,和我们之前编程靠数值来控制权重完全不同。

  比如 Calculator 在描述里面写到,如果你问关于数学的问题就用他这个工具。我们就可以在上面的执行过程中看到,他在我们请求的 prompt 中数学的部分,就选用了Calculator 这个工具进行计算。

4.5 使用Memory实现一个带记忆的对话机器人

  上一个例子我们使用的是通过自定义一个列表来存储对话的方式来保存历史的。当然,你也可以使用自带的 memory 对象来实现这一点。

from langchain.memory import ChatMessageHistory
from langchain.chat_models import ChatOpenAI

chat = ChatOpenAI(temperature=0)

# 初始化 MessageHistory 对象
history = ChatMessageHistory()

# 给 MessageHistory 对象添加对话内容
history.add_ai_message("你好!")
history.add_user_message("中国的首都是哪里?")

# 执行对话
ai_response = chat(history.messages)
print(ai_response)

4.6 使用 Hugging Face 模型

使用 Hugging Face 模型之前,需要先设置环境变量

import os
os.environ['HUGGINGFACEHUB_API_TOKEN'] = ''

使用在线的 Hugging Face 模型

from langchain import PromptTemplate, HuggingFaceHub, LLMChain

template = """Question: {question}
Answer: Let's think step by step."""

prompt = PromptTemplate(template=template, input_variables=["question"])
llm = HuggingFaceHub(repo_id="google/flan-t5-xl", model_kwargs={"temperature":0, "max_length":64})
llm_chain = LLMChain(prompt=prompt, llm=llm)

question = "What NFL team won the Super Bowl in the year Justin Beiber was born?"
print(llm_chain.run(question))

将 Hugging Face 模型直接拉到本地使用

from langchain import PromptTemplate, LLMChain
from langchain.llms import HuggingFacePipeline
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, AutoModelForSeq2SeqLM

model_id = 'google/flan-t5-large'
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForSeq2SeqLM.from_pretrained(model_id)

pipe = pipeline(
    "text2text-generation",
    model=model,
    tokenizer=tokenizer,
    max_length=100
)

local_llm = HuggingFacePipeline(pipeline=pipe)
print(local_llm('What is the capital of France? '))


template = """Question: {question} Answer: Let's think step by step."""
prompt = PromptTemplate(template=template, input_variables=["question"])

llm_chain = LLMChain(prompt=prompt, llm=local_llm)
question = "What is the capital of England?"
print(llm_chain.run(question))

将模型拉到本地使用的好处:

  • 训练模型
  • 可以使用本地的 GPU
  • 有些模型无法在 Hugging Face 运行

4.7 通过自然语言执行SQL命令

参考教程《Spark SQL Agent》《SQL Database Agent》

我们通过 SQLDatabaseToolkit 或者 SQLDatabaseChain 都可以实现执行SQL命令的操作

from langchain.agents import create_sql_agent
from langchain.agents.agent_toolkits import SQLDatabaseToolkit
from langchain.sql_database import SQLDatabase
from langchain.llms.openai import OpenAI

db = SQLDatabase.from_uri("sqlite:///../notebooks/Chinook.db")
toolkit = SQLDatabaseToolkit(db=db)

agent_executor = create_sql_agent(
    llm=OpenAI(temperature=0),
    toolkit=toolkit,
    verbose=True
)

agent_executor.run("Describe the playlisttrack table")
from langchain import OpenAI, SQLDatabase, SQLDatabaseChain

db = SQLDatabase.from_uri("mysql+pymysql://root:root@127.0.0.1/chinook")
llm = OpenAI(temperature=0)

db_chain = SQLDatabaseChain(llm=llm, database=db, verbose=True)
db_chain.run("How many employees are there?")

五、总结

  所有的案例都基本已经结束了,希望大家能通过这篇文章的学习有所收获。这篇文章只是对 LangChain 一个初级的讲解,高级的功能希望大家继续探索。希望大家能结合 LangChain 开发出更有创意的产品,而不仅仅只搞一堆各种一键搭建chatgpt聊天客户端的那种产品。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LangChain 中文入门教程 的相关文章

  • Erlang:到 Python 实例的端口没有响应

    我正在尝试通过 Erlang 端口与外部 python 进程进行通信 首先 打开一个端口 然后通过 stdin 将消息发送到外部进程 我期待在进程的标准输出上得到相应的答复 我的尝试如下所示 open a port Port open po
  • Flask-SocketIO redis 订阅

    我在用着https github com miguelgrinberg Flask SocketIO https github com miguelgrinberg Flask SocketIO实现 WebSocket 服务器 我需要从另一
  • 从所有数据帧列中删除子字符串

    我有一个单词列表 大约 1000 个单词 我称之为负面单词 CAST ARTICLES SANITARY JAN CLAUSES SPECIAL ENDORSEMENT 我很快就会用这个单词列表制作一个数据框 我还有一个数据框 看起来像 F
  • 如何替换Python字符串中的正确字母

    任务是 您的任务是纠正数字化文本中的错误 您只需处理以下错误 S 被误解为 5 O 被误解为 0 I 被误解为 1 我的代码 def correct string for i in string if 5 in string string
  • pyCUDA无法打印结果

    最近 我使用 pip 为我的 python3 4 3 安装 pyCUDA 但我在测试示例代码时发现 https documen tician de pycuda tutorial html getting started https doc
  • Python 不考虑 distutils.cfg

    我已经尝试了给出的所有内容 并且所有教程都指向相同的方向 即使用 mingw 作为 python 而不是 Visual C 中的编译器 我确实有 Visual C 和 mingw 当我想使用 pip 安装时 问题开始出现 它总是给Unabl
  • Python:json_normalize pandas 系列给出 TypeError

    我在 pandas 系列中有数万行像这样的 json 片段df json IDs lotId 1 Id 123456 date 2009 04 17 bidsCount 2 IDs lotId 2 Id 123456 date 2009 0
  • Python 内置对象的 __enter__() 和 __exit__() 在哪里定义?

    我读到每次使用 with 时都会调用该对象的 enter 和 exit 方法 我知道对于用户定义的对象 您可以自己定义这些方法 但我不明白这对于 打开 等内置对象 函数甚至测试用例是如何工作的 这段代码按预期工作 我假设它使用 exit 关
  • 获取 Keras model.summary() 作为表

    我在 Keras 中创建了相当大的模型 我正在用 LaTeX 写一篇关于它的文章 为了很好地描述 LaTeX 中的 keras 模型 我想用它创建一个 LaTeX 表 我可以手动实现它 但我想知道是否有任何 更好 的方法来实现这一点 我四处
  • Eclipse/PyDev 中未使用导入警告,尽管已使用

    我正在我的文件中导入一个绘图包 如下所示 import matplotlib pyplot as plt 稍后我会在我的代码中成功使用此导入 fig plt figure figsize 16 10 然而 Eclipse 告诉我 未使用的导
  • 哪种方式最适合Python工厂注册?

    这是一个关于这些方法中哪一种被认为是最有效的问题 Pythonic 我不是在寻找个人意见 而是在寻找惯用的观点 我的背景不是Python 所以这会对我有帮助 我正在开发一个可扩展的 Python 3 项目 这个想法类似于工厂模式 只不过它是
  • 如何通过selenium中弹出的身份验证?

    我正在尝试使用带有 Selenium 的 Python 脚本加载需要身份验证的网页 options webdriver ChromeOptions prefs download default directory r download de
  • 数据损坏 C++ 和 Python 之间的管道

    我正在编写一些代码 从 Python 获取二进制数据 将其通过管道传输到 C 对数据进行一些处理 在本例中计算互信息度量 然后将结果通过管道传输回 Python 在测试时 我发现如果我发送的数据是一组尺寸小于 1500 X 1500 的 2
  • 根据标点符号列表替换数据框中的标点符号[重复]

    这个问题在这里已经有答案了 使用 Canopy 和 Pandas 我有数据框 a 其定义如下 a pd read csv text txt df pd DataFrame a df columns test test txt 是一个单列文件
  • 如何在引发异常时将变量传递给异常并在异常时检索它?

    现在我只有一个空白的异常类 我想知道如何在引发变量时给它一个变量 然后在 try except 中处理它时检索该变量 class ExampleException Exception pass 为其构造函数提供一个参数 将其存储为属性 然后
  • 类返回语句不打印任何输出

    我正在学习课程 但遇到了问题return语句 它是语句吗 我希望如此 程序什么也没有打印出来 它只是结束而不做任何事情 class className def createName self name self name name def
  • tf.print() vs Python print vs tensor.eval()

    看来在Tensorflow中 至少有三种方法可以打印出张量的值 我一直在读here https www freecodecamp org news debugging tensorflow a starter e6668ce72617 an
  • AWS 将 MQTT 消息存储到 DynamoDB

    我构建了一个定期发送 MQTT 消息的 python 脚本 这是发送到后端的 JSON 字符串 Id 1234 Ut 1488395951 Temp 22 86 Rh 48 24 在后端 我想将 MQTT 消息存储到 DynamoDB 表中
  • 用 pandas DataFrame 替换 mysql 数据库表中的行

    Python 版本 2 7 6 熊猫版本 0 17 1 MySQLdb 版本 1 2 5 在我的数据库中 PRODUCT 我有一张桌子 XML FEED 表 XML FEED 很大 数百万条记录 我有一个 pandas DataFrame
  • 使用 python 将 CSV 文件上传到 Microsoft Azure 存储帐户

    我正在尝试上传一个 csv使用 python 将文件写入 Microsoft Azure 存储帐户 我已经发现C sharp https blogs msdn microsoft com jmstall 2012 08 03 convert

随机推荐

  • 安装mysql中遇到的错误:

    1 安装报错 Install Remove of the Service Denied 解决方案如下 2 安装报错 The service already exists 解决方案如下 3 安装报错 Can t create test fil
  • 真机上,微信小程序弹出层中使用textarea组件无法显示文本的问题

    真机上 微信小程序弹出层中使用textarea组件无法显示文本的问题 解决思路 文章链接 最近开发微信小程序发现了一个BUG 最后莫名奇妙地解决了 隐隐约约地感觉和微信小程序地textarea组件的z index层级有关 没有去深究其中原理
  • 【前端知识之Vue】diff算法流程

    前言 本系列主要整理前端面试中需要掌握的知识点 本节介绍diff算法流程以及相关例子 如果想看源码推荐YK菌的 Vue源码 图解 diff算法 与 虚拟DOM snabbdom 最小量更新原理解析 手写源码 updateChildren哦
  • IntelliJ IDEA-配置文件位置

    关于配置文件的位置 一旦开始使用IDEA之后 就需要做很多的配置相关工作 使得IDEA越来越符合你的个人习惯 让你使用起来得心应手 而这些配置信息 都保存在C盘 比如我的就会默认保存在如图所示的位置 C Documents and Sett
  • flutter loading前一个界面关闭后一个界面的loading

    import package flutter cupertino dart import package flutter material dart import package flutter easyloading flutter ea
  • H5 架构和原生架构的区别

    1 App 的 3 种开发方式 表面上看 手机 App 都是同样的东西 就是手机上的应用程序 点击图标就能运行 但是它们的底层技术不一样 按照开发技术 App 可以分成三大类 原生应用 简称 nativeApp Web 应用 简称 WebA
  • 阿里云轻量应用服务器mysql远程连接教程

    阿里云轻量应用服务器mysql远程连接教程 打开轻量应用服务器控制台 打开防火墙 点击添加规则 打开服务器命令行 可以使用Xshell等软件 在阿里云控制台开放3306端口后后在linux系统中也要开放3306端口 在服务器中开放防火墙33
  • esp32搭建lvgl

    platformio 下载两个库 TFT eSPI lv arduino 3 0 1对应lvgl 7 2 7 5对应lvgl6 pio libdeps tft espi user Setup h 驱动芯片选择 颜色顺序 分辨率选择 不同芯片
  • Nginx反向代理配置流式响应

    Nginx 是通过缓存响应内容来处理请求的 也就是说 当 Nginx 接收到完整的响应后 才会将其发送给客户端 所以默认不支持流式响应 这里讲讲 Nginx 反向代理中怎么配置流式响应 一 使用背景 最近使用 Egg js 搭建自动化部署服
  • MyEclipse提示过期,MyEclipse Subscription Expired解决方案

    一 错误描述 某一天打开MyEclipse 突然发现出现如下提示框 1 错误日志 Thank you for choosing MyEclipse Your license expired 1091 days ago To continue
  • @Valid和@Validated在service层的应用及问题汇总

    1 背景 实际开发中 很多时候要对参数校验 比如为空等 除了要在接口的入口处使用 很多普通方法也需要检查 比如service方法 那么如何在service上使用这个参数校验呢 2 使用方式 步骤一 在service接口上加上 Validat
  • [CF1149C](Tree Generator)

    题意 给出一颗树的括号序 有m个操作 每次交换两个括号 保证交换后括号序仍然合法 输出每次操作后 包括未操作时 树的直径 solution 首先转化题目 对于一棵树的括号序 我们找到一段子串 满足将其中匹配的括号消去后剩下的括号最多 那么剩
  • STM32 Flash操作(擦写)过程中器件复位导致数据丢失问题

    1 问题描述 产品在运行过程中需要保存一些断电不丢失的数据 为此将数据保存在STM32内部的flash中 但是测试人员在测试的过程中 修改了数据参数 直接断电重启机器 并没有等待flash的操作时间 导致原有的数据丢失 2 原理分析 本产品
  • 理解准确率(accuracy)、精度(precision)、查全率(recall)、F1

    Precision又叫查准率 Recall又叫查全率 这两个指标共同衡量才能评价模型输出结果 TP TN FP FN的定义 在二分类问题中 Real 1 Real 0 Predict 1 TP FP Predict 0 FN TN TP 预
  • 记录用Anaconda搭建Tensorflow1.13环境

    上文才搭建好了Pytorch环境 这次获得了一篇论文源码 其中用到的是Tensorflow环境 为了复现论文结果 只好再搭建一个Tensorflow环境 首先论文中给出的环境信息是 Tensorflow 1 13 以及 Python 3 这
  • [第六篇]——云服务器之Spring Cloud直播商城 b2b2c电子商务技术总结

    云服务器 云服务器 Elastic Compute Service ECS 是一种简单高效 安全可靠 处理能力可弹性伸缩的计算服务 云服务器管理方式比物理服务器更简单高效 我们无需提前购买昂贵的硬件 即可迅速创建或删除云服务器 云服务器费用
  • flutter强制横屏竖屏设置

    void main 强制横屏 SystemChrome setPreferredOrientations DeviceOrientation landscapeLeft DeviceOrientation landscapeRight ru
  • Latex 约等于符号

    approx
  • 深入理解Python 中的特殊常量None

    False 不同 它不表示 0 也不表示空字符串 而表示没有值 也就是空值 None 有自己的数据类型 我们可以在 IDLE 中使用 type 函数查看它的类型 执行代码如下 gt gt gt type None
  • LangChain 中文入门教程

    文章目录 LangChain 中文入门教程 一 介绍 1 1 背景 1 2 基础功能 二 必知概念 2 1 Loader 加载器 2 2 Document 文档 2 3 Text Spltters 文本分割 2 4 Vectorstores