制作一个可实时联网的gpt机器人

LangChain 的中文入门教程 : https://liaokong.gitbook.io/llm-kai-fa-jiao-cheng#tong-guo-google-sou-suo-bing-fan-hui-da-an

用过我的AI工具(https://ai.quanyouhulian.com/)的人都发现了,我的GPTs里面有个gpt-4-all可实时联网的模型!openai本身是没有gpt-4-all这个模型的,该模型在后端做了层封装,主要依赖的是一个langchain4j包!

今天,带大家详细了解下如何实现LLM开发

什么是LangChain?

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

  1. 可以将 LLM 模型与外部数据源进行连接
  2. 允许与 LLM 模型进行交互

LangChain框架中的一些专属词汇

在讲解LangChian框架前,先和大家讲下一些大数据常用的专属词汇,当了解这些词汇后再来做LangChain开发思路会更清晰些

Loader 加载器

顾名思义,这个就是从指定源进行加载数据的。比如:文件夹 DirectoryLoader、Azure 存储 AzureBlobStorageContainerLoader、CSV文件 CSVLoader、印象笔记 EverNoteLoader、网盘 DriveLoader、任意的网页 UnstructuredHTMLLoader、PDF PyPDFLoader、S3 S3DirectoryLoader/S3FileLoader

Document 文档

在做LangChain开发时,使用loader加载器读取完数据源后,需要将数据源转换成 Document 对象后才能进行使用。

Text Spltters 文本分割

不管是OpenAI还是国产大模型,所有API接口都会有tokens数限制,比如我们发送一份500页pdf文件给chatgpt进行文件总结,它就会报超出token最大限制异常。这时候就需要使用Text Spltters对我们加载进来的Document文档进行文本分割!

Vectorstores 向量数据库

不管我们使用OpenAI API Embedding功能还是通过向量数据库查询,都需要将我们加载的Document文档数据进行向量化,这样才能进行向量运算及搜索!

Chain链

chain链可以理解为任务,一个chain就是一个任务,也可一个一个的执行多个链。

Agent 代理

可以动态的帮我们选择和调用chain,执行过程可以参考下图:

Embedding

这个是用于衡量文本的相关联性,这个也是 OpenAI API 能实现构建自己知识库的关键!

他比 fine-tuning 最大的优势就是,不用进行训练,并且可以实时添加新的内容,而不用加一次新的内容就训练一次,并且各方面成本要比 fine-tuning 低很多。

LangChain实战使用

通过前面的必备概念,相信大家已经对 LangChain 有了一定的了解,但可能还有些许疑惑。别担心,这都是小问题!我相信,经过接下来的实战演练,你们会彻底理解这些内容,并真正感受到这个库的强大之处。

因为我们将使用 OpenAI API 的进阶功能,所以后面的范例中使用的 LLM 主要是 OpenAI,大家可以根据自己的需求替换成其他 LLM 模型。

1. 完成一次问答

首先,我们来个最简单的例子:使用 LangChain 加载 OpenAI 模型,并完成一次问答。

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

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

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

1
2
3
4
from langchain.llms import OpenAI

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

这样,我们就可以看到返回的结果了

2. 通过 Google 搜索并返回答案

接下来,我们来点有趣的:让 OpenAI API 联网搜索,并返回答案。这里我们需要借助 Serpapi 来实现,Serpapi 提供了 Google 搜索的 API 接口。

首先,我们需要到 Serpapi 官网上注册一个用户,并复制生成的 API key。然后像设置 OpenAI API key 一样设置到环境变量中。

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

接下来,编写代码:

1
2
3
4
5
6
7
8
from langchain.agents import load_tools, initialize_agent
from langchain.llms import OpenAI
from langchain.agents import AgentType

llm = OpenAI(temperature=0, max_tokens=2048)
tools = load_tools(["serpapi"])
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
agent.run("What's the date today? What great events have taken place today in history?")

我们可以看到,他正确返回了日期,并且列出了历史上的今天发生的重大事件。

3. 对超长文本进行总结

假如我们想用 OpenAI API 对一段文本进行总结,但文本超过了 API 最大的 token 限制,这时我们可以使用 LangChain 来处理。

LangChain 会自动分段并总结每段内容,最后再进行一次总体总结。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
split_documents = text_splitter.split_documents(document)

llm = OpenAI(model_name="text-davinci-003", max_tokens=1500)
chain = load_summarize_chain(llm, chain_type="refine", verbose=True)
print(chain.run(split_documents[:5]))

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

在这个例子中,我们将介绍如何从本地读取多个文档构建知识库,并使用 OpenAI API 在知识库中进行搜索并回答问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain import OpenAI
from langchain.document_loaders import DirectoryLoader
from langchain.chains import RetrievalQA

loader = DirectoryLoader('/content/sample_data/data/', glob='**/*.txt')
documents = loader.load()

text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
split_docs = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()
docsearch = Chroma.from_documents(split_docs, embeddings)

qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type="stuff", retriever=docsearch.as_retriever(), return_source_documents=True)
result = qa({"query": "科大讯飞今年第一季度收入是多少?"})
print(result)

5. 构建向量索引数据库

我们可以使用 Chroma 或 Pinecone 来实现向量数据持久化。以下是 Chroma 的代码示例:

1
2
3
4
5
6
7
8
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)

Pinecone 的代码示例:

1
2
3
4
5
6
7
import pinecone

pinecone.init(api_key="你的api key", environment="你的Environment")

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)

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

通过使用 GPT-3.5-Turbo 模型,我们可以构建一个针对特定油管视频的问答机器人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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 ConversationalRetrievalChain
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate

loader = YoutubeLoader.from_youtube_url('https://www.youtube.com/watch?v=Dj60HHy-Kqk')
documents = loader.load()

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=20)
documents = text_splitter.split_documents(documents)

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.
-----------
{question}
-----------
{chat_history}
"""

messages = [
SystemMessagePromptTemplate.from_template(system_template),
HumanMessagePromptTemplate.from_template('{question}')
]

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('问题:')
result = qa({'question': question, 'chat_history': chat_history})
chat_history.append((question, result['answer']))
print(result['answer'])

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


也可以很方便的使用流式回答

1
2
3
4
5
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())

7. 用 OpenAI 连接万种工具

我们可以结合使用 Zapier 来实现将万种工具连接起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

总结

本篇文章对LangChain进行了一个初级讲解,因为 LangChain 迭代极快,所以后面肯定会随着AI继续的发展,还会迭代出更好用的功能,个人非常看好这个开源库。

LangChain源码开源地址:https://github.com/langchain-ai/langchain


制作一个可实时联网的gpt机器人
http://example.com/2024/09/15/后端技术互联/制作一个可实时联网的gpt机器人/
作者
技术Z先生
发布于
2024年9月15日
许可协议