官方教程非常长,我看了很认可,但是看完了之后呢就需要一些整理得当的笔记让我自己能更快地找到需求。所以有了这篇文章。【写给自己看的,里面半句废话的解释都没有,如果看不懂的话直接看官方教程再看我的】
我是不打算一开始就用OpenAI的,打算先用一下开源模型。之后我还会写一篇OpenAI的速通版。
文章目录
- 前置准备
- 用Prompt模板
- 增加context:自定义文档内容
- 增加context:从网页中获取文档内容
- 增加context:从PDF中获取文档内容
- 用文档检索器 (RAG方法)
- 增加chat_history:利用MessagesPlaceholder
- 切换LLM model
- 后话
前置准备
pip install langchain
curl -fsSL https://ollama.com/install.sh | sh # linux装llama2的指令
# 如果用的是Windows或者MacOS,前往这里下载:https://ollama.com/
用Prompt模板
from langchain_community.llms import Ollama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParseroutput_parser = StrOutputParser()llm = Ollama(model="llama2")
prompt = ChatPromptTemplate.from_messages([("system", "You are world class technical documentation writer."),("user", "{input}")
])
chain = prompt | llm | output_parserprint(chain.invoke({"input": "how can langsmith help with testing?"}))
增加context:自定义文档内容
from langchain_community.llms import Ollama
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chainllm = Ollama(model="llama2")prompt = ChatPromptTemplate.from_template("""Answer the following question based only on the provided context:<context>
{context}
</context>Question: {input}""")document_chain = create_stuff_documents_chain(llm, prompt)from langchain_core.documents import Document
docs = [Document(page_content="langsmith can let you visualize test results")]document_chain.invoke({"input": "how can langsmith help with testing?","context": docs
})
增加context:从网页中获取文档内容
下面这个代码会读网页的内容到docs里,可以替代上一节的docs = Document(page_content="langsmith can let you visualize test results")
部分。
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader("https://bbs.csdn.net/topics/618378840")docs = loader.load()
增加context:从PDF中获取文档内容
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("3399.pdf")docs = loader.load()
注意,根据我的观察,LangChain的PDF loader 是基于 pypdf 的,而实际上pypdf 不是很好用,对表格之类的信息更是一塌糊涂,我更喜欢自己解析一下PDF文件。详情可以看这篇文章:【记录】Python|处理PDF的第三方库的对比大全(2024年)
用文档检索器 (RAG方法)
文档检索器的作用是根据一些加权,来判断所有的文档列表中哪一个文档是最适合当前的提问的。
下面的代码中增加了矢量检索器,详细的原理介绍见这里(具体原理我也没看,直觉上就是给文本加权重然后算一算这样)。根据官方说,它还可以加SQL 表、互联网等,我也没看懂。
from langchain_community.llms import Ollama
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chainllm = Ollama(model="llama2")prompt = ChatPromptTemplate.from_template("""Answer the following question based only on the provided context:<context>
{context}
</context>Question: {input}""")document_chain = create_stuff_documents_chain(llm, prompt)from langchain_core.documents import Document
docs = [Document(page_content="langsmith can let you visualize test results")]from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)from langchain_community.embeddings import OllamaEmbeddings
embeddings = OllamaEmbeddings()
from langchain_community.vectorstores import FAISS
vector = FAISS.from_documents(documents, embeddings)from langchain_community.embeddings import OllamaEmbeddings
embeddings = OllamaEmbeddings()
from langchain_community.vectorstores import FAISS
vector = FAISS.from_documents(documents, embeddings)from langchain.chains import create_retrieval_chainretriever = vector.as_retriever()
retrieval_chain = create_retrieval_chain(retriever, document_chain)response = retrieval_chain.invoke({"input": "how can langsmith help with testing?"})
print(response["answer"])
增加chat_history:利用MessagesPlaceholder
总之就是改了Prompt结构,再多引入了一个create_history_aware_retriever函数。
from langchain_community.llms import Ollama
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chainllm = Ollama(model="llama2")from langchain_core.prompts import MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([("system", """Answer the user's questions based on the below context:<context>
{context}
</context>"""),MessagesPlaceholder(variable_name="chat_history"),("user", "{input}"),
]) ## Add MessagesPlaceholderdocument_chain = create_stuff_documents_chain(llm, prompt)from langchain_core.documents import Document
docs = [Document(page_content="langsmith can let you visualize test results")]from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)from langchain_community.embeddings import OllamaEmbeddings
embeddings = OllamaEmbeddings()
from langchain_community.vectorstores import FAISS
vector = FAISS.from_documents(documents, embeddings)from langchain_community.embeddings import OllamaEmbeddings
embeddings = OllamaEmbeddings()
from langchain_community.vectorstores import FAISS
vector = FAISS.from_documents(documents, embeddings)from langchain.chains import create_retrieval_chain##-- Start changing --##
retriever = vector.as_retriever()from langchain.chains import create_history_aware_retriever
retriever_chain = create_history_aware_retriever(llm, retriever, prompt)from langchain.chains import create_retrieval_chain
retrieval_chain = create_retrieval_chain(retriever_chain, document_chain)from langchain_core.messages import HumanMessage, AIMessagechat_history = [HumanMessage(content="Can LangSmith help test my LLM applications?"), AIMessage(content="Yes!")]
response = retrieval_chain.invoke({"chat_history": chat_history,"input": "Tell me how","context": "" # I don't know why the 'context' variable is needed here, but it is required by the 'prompt' variable.
})print(response)
运行结果:
切换LLM model
ollama中包含了许多开源大模型,llama2只是其中的只有3.8G的一个小模型llama2:7b罢了。
为了实现更好的效果,建议用更大的模型比如13b或者70b。
运行大模型只需要对应的内存满足要求就可以了,不需要像训练那样需要太多的GPU开销啥的,挺划算的也挺好部署的,你们也可以试试用比较大的开源模型而不是用初始的那个llama2:7b。
切换模型很简单,步骤如下:
- 打开https://ollama.com/library找到你想要的模型。
- 以llama2:13b为例。切换分支到13b,关注指令pull后接的名称(这里是
llama2:13b
)。 - 复制pull指令并粘贴到终端:
ollama run llama2:13b
。 - 修改代码,把model=后面的llama2改成对应的名称即可,如下所示:
from langchain_community.llms import Ollama llm = Ollama(model="llama2:13b")
后话
代理那一节,官方说本地模型的代理不可靠,而且这个也只是调用一些其他工具API,有需求的话自己看一下,我对这个没需求。
至于后面的 langserve 的介绍,对我挺有用的但是暂时不需要写这个部分的代码,所以我寻思着以后要用了再写下一篇博客吧,这篇博客差不多长度了。