LangChain
LangChain是一个软件开发框架,可以更轻松地使用大型语言模型(LLM)创建应用程序。它是一个具有 Python 和 JavaScript 代码库的开源工具。LangChain 允许开发人员将 GPT-4 等 LLM 与外部数据相结合,为聊天机器人、代码理解、摘要等各种应用程序开辟了可能性。
LangChain模块
LangChain将其功能分组到以下模块中:
- 模型
- 提示
- 链
- 代理
- 记忆
- 文档加载程序和索引
提示
提示是指模型输入。在前面的部分中,您将提示硬编码为 LLM 和聊天模型。此技术不适用,因为在生产环境中不会收到硬编码的完整文本提示。相反,您将收到来自用户的简洁输入,您将希望将其转换为提示。
模型
LangChain支持三种类型的模型:
- 大型语言模型
- 聊天模型
- 文本嵌入模型
链
链允许您同时运行多个LangChain模块。例如,使用链,您可以同时运行提示符和 LLM,从而避免了首先格式化 LLM 模型的提示,然后使用模型在单独的步骤中执行它。
LangChain支持三种主要类型的链:
- 简单的 LLM 链
- 顺序链
- 定制链
代理
LangChain代理涉及LLM来执行以下步骤:
- 根据用户输入或其先前的输出确定要执行的操作。
- 执行操作。
- 观察输出。
- 重复前三个步骤,直到它尽其所能完成用户输入中定义的任务。
RAG Architecture
典型的 RAG 应用程序有两个主要组件:
- 索引(Indexing)
用于从源获取数据并为其建立索引的管道。这通常发生在离线状态。
- 提取和生成(Retriever and generation)
实际的 RAG 链,它在运行时接受用户查询并从索引中检索相关数据,然后将其传递给模型。
索引(Indexing)
- Load
首先需要加载数据,通过DocumentLoaders完成
- Split
Text splitters将large Documents分成更小的chunks。这对于索引数据和将其传递到模型都很有用,因为大块更难搜索并且不适合模型的有限上下文窗口。
- Store
存储和索引我们的分割,这通常是使用 VectorStore 和 Embeddings 模型来完成的。
矢量数据库
Chroma 是一个用于构建具有嵌入的 AI 应用程序的数据库。
数据量庞大的知识、新闻、文献、语料等先通过嵌入(embedding)算法转变为向量数据,然后存储在Chroma等向量数据库中。当用户在大模型输入问题后,将问题本身也embedding,转化为向量,在向量数据库中查找与之最匹配的相关知识,组成大模型的上下文,将其输入给大模型,最终返回大模型处理后的文本给用户,这种方式不仅降低大模型的计算量,提高响应速度,也降低成本,并避免了大模型的tokens限制,是一种简单高效的处理手段。
主流的向量数据库对比如下所示:
向量数据库 | URL | GitHub Star | Language |
---|---|---|---|
chroma | https://github.com/chroma-core/chroma | 7.4K | Python |
milvus | https://github.com/milvus-io/milvus | 21.5K | Go/Python/C++ |
pinecone | https://www.pinecone.io/ | ❌ | ❌ |
qdrant | https://github.com/qdrant/qdrant | 11.8K | Rust |
typesense | https://github.com/typesense/typesense | 12.9K | C++ |
weaviate | https://github.com/weaviate/weaviate | 6.9K | Go |
在这里我们使用chroma
提取和生成(Retrieval and generation)
- Retrieve:给定用户输入,使用检索器从存储中检索相关分割。
- Generate:
ChatModel / LLM
使用包含问题和检索到的数据的提示生成答案
实例
import os
import bs4
from langchain import hub
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader
# Load, chunk and index the contents of the blog.
print("Starting..........")
os.environ['OPENAI_API_KEY'] ="sk-xxxxxxxx"
os.environ['OPENAI_BASE_URL'] ="https://api.chatanywhere.tech/v1"
print("Loading.....")
#loader = WebBaseLoader(
# web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
# bs_kwargs=dict(
# parse_only=bs4.SoupStrainer(
# class_=("post-content", "post-title", "post-header")
# )
# ),
#)
loader = PyPDFLoader("example_data/计算机信息模型导论2024.pdf")
docs = loader.load()
print("Loadded....")
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings(),persist_directory="./vector_store")
# Retrieve and generate using the relevant snippets of the blog.
retriever = vectorstore.as_retriever()
prompt = hub.pull("rlm/rag-prompt")
print("RAG....")
llm = ChatOpenAI(model_name="gpt-3.5-turbo",base_url="https://api.chatanywhere.tech/v1", temperature=0)
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
print(rag_chain.invoke("what is OPCUA 变量类型? 请中文回答"))
# cleanup
#vectorstore.delete_collection()
计算机信息模型导论2024.pdf是我正在写的一本书。介绍计算机信息模型,其中包含了OPCUA 的基本知识。
Chroma 矢量数据库默认是存储在内存中的。如果设置了永久存储目录的位置persist_directory,它会存放在指定的目录中。一旦文档的矢量数据存储在文件中,提问可以不需要每次读pdf文件,程序简化为:
import os
from langchain import hub
from langchain_community.vectorstores import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI,OpenAIEmbeddings
# Load, chunk and index the contents of the blog.
os.environ['OPENAI_API_KEY'] ="sk-xxxxxxxxx"
os.environ['OPENAI_BASE_URL'] ="https://api.chatanywhere.tech/v1"
embedding = OpenAIEmbeddings(openai_api_key=os.environ['OPENAI_API_KEY'] )
vectorstore = Chroma(persist_directory="./vector_store",embedding_function=embedding)
# Retrieve and generate using the relevant snippets of the blog.
retriever = vectorstore.as_retriever()
prompt = hub.pull("rlm/rag-prompt")
print("RAG....")
llm = ChatOpenAI(model_name="gpt-3.5-turbo",base_url="https://api.chatanywhere.tech/v1", temperature=0)
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
print(rag_chain.invoke("what is OPCUA 变量类型? 请中文回答"))