LangChain 中文入门教程-实例

针对 帖子 LangChain 中文入门教程 中的实战应用代码可能会遇到的问题进行总结

1、完成第一次问答:

  • 安装依赖 pip3 install openai langchain

  • code:

import os
from langchain_openai import OpenAI

os.environ["OPENAI_API_KEY"]='你自己的key'

llm = OpenAI(model_name='gpt-3.5-turbo-instruct',max_tokens=1024)

res = llm("怎么评价人工智能")
print(res)

可能会遇到问题:
NotOpenSSLWarning: urllib3 v2 only supports OpenSSL 1.1.1+, currently the ‘ssl’ module is compiled with ‘LibreSSL 2.8.3’. See: https://github.com/urllib3/urllib3/issues/3020
解决办法:pip3 install ‘urllib3<2.0’

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

  • 依赖 pip3 install google-search-results serpapi

  • code:

import os

os.environ["OPENAI_API_KEY"]='你自己的key'
os.environ["SERPAPI_API_KEY"] = '你自己serpapi的key'

from langchain_community.agent_toolkits.load_tools import load_tools
from langchain.agents import initialize_agent
from langchain_openai import OpenAI
from langchain.agents import AgentType

llm = OpenAI(temperature = 0, max_tokens = 2048)

tools = load_tools(["serpapi"])

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

# 工具加载后都需要初始化,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?")

3、对超长文本进行总结

  • 安装依赖:pip3 install unstructured

  • code:

import os

os.environ["OPENAI_API_KEY"]='YOU_KEY'

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

loader = UnstructuredFileLoader("./dlh_test.txt")

document = loader.load()
print(f'documents:{len(document)}')

# 初始化文本分割器
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size = 500,
    chunk_overlap = 0 #是指切割后的每个 document 里包含几个上一个 document 结尾的内容,主要作用是为了增加每个 document 的上下文关联
)

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

# 加载 llm 模型
llm = OpenAI(model_name="gpt-3.5-turbo-instruct", max_tokens=1500)

# 创建总结链
chain = load_summarize_chain(llm, chain_type="refine", verbose=True)
""" 
chain_type 有四个方式:
- 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 模型返回具体答案

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

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

  • 安装依赖:pip3 install chromadb

  • code:

import os

os.environ["OPENAI_API_KEY"]='YOU_KEY'

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain_openai import OpenAI
from langchain.chains import VectorDBQA
from langchain_community.document_loaders import DirectoryLoader
from langchain.chains import RetrievalQA

# 加载文件夹中的所有txt类型的文件
loader = DirectoryLoader('./', glob='data.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)

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

  • 依赖:pip3 install youtube-transcript-api

  • code:

import os

os.environ["OPENAI_API_KEY"]='YOU_KEY'

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

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

# 加载 youtube 频道
loader = YoutubeLoader('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.
-----------
{question}
-----------
{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,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'])