欢迎参加本次研讨会,使用检索增强生成、本地推理器 DataStax Enterprise v7 和本地开放大型语言模型 Mistral 来构建和部署您自己的 Enterprise Co-Pilot。
该存储库通过将您的敏感数据保留在防火墙内来专注于安全性!
为什么?
它利用 DataStax RAGStack,这是一个精选的最佳开源软件堆栈,用于在使用 DataStax Enterprise、Astra Vector DB 或 Apache Cassandra 作为矢量存储的生产就绪应用程序中简化 RAG 模式的实施。
你将学到什么:
?如何利用 DataStax RAGStack 实现以下组件的生产就绪使用:
?如何使用 Ollama 作为本地推理引擎
?如何使用 Mistral 作为问答式聊天机器人的本地开放大型语言模型 (LLM)
?如何使用 Streamlit 轻松部署您出色的应用程序!
演示文稿的幻灯片可以在这里找到
本研讨会假设您有权访问:
在接下来的步骤中,我们将准备存储库、DataStax Enterprise、Jupyter Notebook 和带有 Ollama 的 Ollama 推理引擎。
首先,我们需要将此存储库克隆到您的本地开发笔记本电脑。
打开 build-your-local-ragstack-chatbot 存储库
单击Use this template
-> Ceate new repository
,如下所示:
现在选择您的 github 帐户并命名新存储库。最好还设置描述。单击Create repository
凉爽的!您刚刚在自己的 Gihub 帐户中创建了一个副本!
cd
到一个合理的目录(如 /projects 等);git clone <url-to-your-repo>
cd
到您的新目录!你已经准备好摇滚了! ?
创建虚拟环境很有用。使用以下内容进行设置:
python3 -m venv myenv
然后按如下方式激活它:
source myenv/bin/activate # on Linux/Mac
myenvScriptsactivate.bat # on Windows
现在您可以开始安装所需的软件包:
pip3 install -r requirements.txt
从新的终端窗口通过以下两种方式之一运行 DSE 7:
docker-compose up
这使用了该存储库根目录中的 docker-compose.yml 文件,该文件也可以方便地启动 Jupyter 解释器。
DataStax 将在 http://localhost:9042 上运行,Jupyter 将通过浏览 http://localhost:8888 进行访问
有许多推理引擎。你可以选择 LM Studio,它有一个很好的 UI。在此笔记本中,我们将使用 Ollama。
ollama run mistral
下载 Mistral (~4GB)如果这一切都失败了,由于 RAM 限制,您可以选择使用tinyllama 作为模型。
为了开始本次研讨会,我们将首先尝试提供的笔记本中的概念。我们假设您将从 Jupyter Docker 容器中运行,如果不是,请将主机名从host.docker.internal
更改为localhost
。
本笔记本展示了使用 DataStax Enterprise Vector Store 作为使 LLM 交互有意义且不产生幻觉的方法所需采取的步骤。这里采用的方法是检索增强生成。
你将学到:
浏览到 http://localhost:8888 并打开根目录中名为Build_Your_Own_RAG_Meetup.ipnb
的笔记本。
在本次研讨会中,我们将使用 Streamlit,这是一个非常简单易用的框架来创建前端 Web 应用程序。
首先,让我们创建一个hello world应用程序,如下所示:
import streamlit as st
# Draw a title and some markdown
st . markdown ( """# Your Enterprise Co-Pilot
Generative AI is considered to bring the next Industrial Revolution.
Why? Studies show a **37% efficiency boost** in day to day work activities!
### Security and safety
This Chatbot is safe to work with sensitive data. Why?
- First of all it makes use of [Ollama, a local inference engine](https://ollama.com);
- On top of the inference engine, we're running [Mistral, a local and open Large Language Model (LLM)](https://mistral.ai/);
- Also the LLM does not contain any sensitive or enterprise data, as there is no way to secure it in a LLM;
- Instead, your sensitive data is stored securely within the firewall inside [DataStax Enterprise v7 Vector Database](https://www.datastax.com/blog/get-started-with-the-datastax-enterprise-7-0-developer-vector-search-preview);
- And lastly, the chains are built on [RAGStack](https://www.datastax.com/products/ragstack), an enterprise version of Langchain and LLamaIndex, supported by [DataStax](https://www.datastax.com/).""" )
st . divider ()
第一步是导入streamlit 包。然后我们调用st.markdown
来编写标题,最后我们向网页写入一些内容。
要在本地启动此应用程序,您需要安装 Streamlit 依赖项,如下所示(这应该已经作为先决条件的一部分完成):
pip install streamlit
现在运行应用程序:
streamlit run app_1.py
这将启动应用程序服务器并将您带到刚刚创建的网页。
很简单,不是吗? ?
在此步骤中,我们将开始准备应用程序以允许聊天机器人与用户交互。我们将使用以下 Streamlit 组件: 1. 2. st.chat_input
以便用户允许输入问题 2. st.chat_message('human')
绘制用户的输入 3. st.chat_message('assistant')
绘制聊天机器人的响应
这会产生以下代码:
# Draw the chat input box
if question := st . chat_input ( "What's up?" ):
# Draw the user's question
with st . chat_message ( 'human' ):
st . markdown ( question )
# Generate the answer
answer = f"""You asked: { question } """
# Draw the bot's answer
with st . chat_message ( 'assistant' ):
st . markdown ( answer )
使用 app_2.py 进行尝试并按如下方式启动。
如果您以前的应用程序仍在运行,只需提前按ctrl-c
来终止它即可。
streamlit run app_2.py
现在输入一个问题,然后再次输入另一个问题。您会看到只保留了最后一个问题。
为什么???
这是因为 Streamlit 会根据最新的输入一次又一次地重绘整个屏幕。由于我们不记得问题,因此只显示最后一个问题。
在此步骤中,我们将确保跟踪问题和答案,以便每次重画时都会显示历史记录。
为此,我们将采取以下步骤:
messages
的st.session_state
中添加问题messages
的st.session_state
中for message in st.session_state.messages
循环打印历史记录此方法之所以有效,是因为session_state
在 Streamlit 运行中是有状态的。
查看app_3.py中的完整代码。
正如您将看到的,我们使用字典来存储role
(可以是人类或人工智能)和question
或answer
。跟踪角色很重要,因为它将在浏览器中绘制正确的图片。
运行它:
streamlit run app_3.py
现在添加多个问题,您将看到每次 Streamlit 重新运行时这些问题都会重新绘制到屏幕上。 ?
在这里,我们将链接回我们使用 Jupyter Notebook 所做的工作,并将问题与对 Mistral 聊天模型的调用集成起来。
还记得每次用户交互时 Streamlit 都会重新运行代码吗?因此,我们将利用 Streamlit 中的数据和资源缓存,以便仅建立一次连接。我们将使用@st.cache_data()
和@st.cache_resource()
来定义缓存。 cache_data
通常用于数据结构。 cache_resource
主要用于数据库等资源。
这会产生以下代码来设置提示和聊天模型:
# Cache prompt for future runs
@ st . cache_data ()
def load_prompt ():
template = """You're a helpful AI assistent tasked to answer the user's questions.
You're friendly and you answer extensively with multiple sentences. You prefer to use bulletpoints to summarize.
QUESTION:
{question}
YOUR ANSWER:"""
return ChatPromptTemplate . from_messages ([( "system" , template )])
prompt = load_prompt ()
# Cache Mistral Chat Model for future runs
@ st . cache_resource ()
def load_chat_model ():
# parameters for ollama see: https://api.python.langchain.com/en/latest/chat_models/langchain_community.chat_models.ollama.ChatOllama.html
# num_ctx is the context window size
return ChatOllama (
model = "mistral:latest" ,
num_ctx = 18192 ,
base_url = st . secrets [ 'OLLAMA_ENDPOINT' ]
)
chat_model = load_chat_model ()
我们现在将改为调用链,而不是在前面的示例中使用静态答案:
# Generate the answer by calling Mistral's Chat Model
inputs = RunnableMap ({
'question' : lambda x : x [ 'question' ]
})
chain = inputs | prompt | chat_model
response = chain . invoke ({ 'question' : question })
answer = response . content
查看app_4.py中的完整代码。
在继续之前,我们必须在./streamlit/secrets.toml
中提供OLLAMA_ENDPOINT
。 secrets.toml.example
中提供了一个示例:
# Ollama/Mistral Endpoint
OLLAMA_ENDPOINT = " http://localhost:11434 "
要在本地启动此应用程序,您需要安装 RAGStack,其中包含稳定版本的 LangChain 和所有依赖项(这应该已经作为先决条件的一部分完成):
pip install ragstack
现在运行应用程序:
streamlit run app_4.py
您现在可以开始与聊天机器人进行问答互动。当然,由于没有与 DataStax Enterprise Vector Store 集成,因此不会有上下文相关的答案。由于尚未内置流媒体功能,请给客服人员一些时间,以便立即给出完整的答案。
我们先从问题开始:
What does Daniel Radcliffe get when he turns 18?
正如您将看到的,您将收到一个非常通用的答案,而无需 CNN 数据中提供的信息。
现在事情变得非常有趣!在此步骤中,我们将集成 DataStax Enterprise Vector Store,以便为聊天模型提供实时上下文。实施检索增强生成所采取的步骤:
我们将重用通过笔记本插入的 CNN 数据。
为了实现这一点,我们首先必须建立与 DataStax Enterprise Vector Store 的连接:
# Cache the DataStax Enterprise Vector Store for future runs
@ st . cache_resource ( show_spinner = 'Connecting to Datastax Enterprise v7 with Vector Support' )
def load_vector_store ():
# Connect to DSE
cluster = Cluster (
[ st . secrets [ 'DSE_ENDPOINT' ]]
)
session = cluster . connect ()
# Connect to the Vector Store
vector_store = Cassandra (
session = session ,
embedding = HuggingFaceEmbeddings (),
keyspace = st . secrets [ 'DSE_KEYSPACE' ],
table_name = st . secrets [ 'DSE_TABLE' ]
)
return vector_store
vector_store = load_vector_store ()
# Cache the Retriever for future runs
@ st . cache_resource ( show_spinner = 'Getting retriever' )
def load_retriever ():
# Get the retriever for the Chat Model
retriever = vector_store . as_retriever (
search_kwargs = { "k" : 5 }
)
return retriever
retriever = load_retriever ()
我们唯一需要做的另一件事是更改链以包含对向量存储的调用:
# Generate the answer by calling Mistral's Chat Model
inputs = RunnableMap ({
'context' : lambda x : retriever . get_relevant_documents ( x [ 'question' ]),
'question' : lambda x : x [ 'question' ]
})
查看app_5.py中的完整代码。
在继续之前,我们必须在./streamlit/secrets.toml
中提供DSE_ENDPOINT
、 DSE_KEYSPACE
和DSE_TABLE
。 secrets.toml.example
中提供了一个示例:
# DataStax Enterprise Endpoint
DSE_ENDPOINT = " localhost "
DSE_KEYSPACE = " default_keyspace "
DSE_TABLE = " dse_vector_table "
并运行应用程序:
streamlit run app_5.py
我们再问一个问题:
What does Daniel Radcliffe get when he turns 18?
正如您将看到的,现在您将收到一个非常上下文相关的答案,因为矢量存储为聊天模型提供了相关的 CNN 数据。
如果答案生成后出现在屏幕上,那该多酷啊!嗯,这很容易。
首先,我们将创建一个流回调处理程序,在每次新令牌生成时都会调用该处理程序,如下所示:
# Streaming call back handler for responses
class StreamHandler ( BaseCallbackHandler ):
def __init__ ( self , container , initial_text = "" ):
self . container = container
self . text = initial_text
def on_llm_new_token ( self , token : str , ** kwargs ):
self . text += token
self . container . markdown ( self . text + "▌" )
然后我们解释聊天模型以使用 StreamHandler:
response = chain . invoke ({ 'question' : question }, config = { 'callbacks' : [ StreamHandler ( response_placeholder )]})
上面代码中的response_placeholer
定义了需要写入token的位置。我们可以通过调用int st.empty()
来创建该空间,如下所示:
# UI placeholder to start filling with agent response
with st . chat_message ( 'assistant' ):
response_placeholder = st . empty ()
查看app_6.py中的完整代码。
并运行应用程序:
streamlit run app_6.py
现在您将看到响应将实时写入浏览器窗口。
当然,最终目标是将您自己公司的背景添加到代理中。为此,我们将添加一个上传框,允许您上传 PDF 文件,然后使用该文件提供有意义的上下文响应!
首先,我们需要一个使用 Streamlit 创建的上传表单:
# Include the upload form for new data to be Vectorized
with st . sidebar :
with st . form ( 'upload' ):
uploaded_file = st . file_uploader ( 'Upload a document for additional context' , type = [ 'pdf' ])
submitted = st . form_submit_button ( 'Save to DataStax Enterprise' )
if submitted :
vectorize_text ( uploaded_file )
现在我们需要一个函数来加载 PDF 并将其引入 DataStax Enterprise,同时对内容进行矢量化。
# Function for Vectorizing uploaded data into DataStax Enterprise
def vectorize_text ( uploaded_file , vector_store ):
if uploaded_file is not None :
# Write to temporary file
temp_dir = tempfile . TemporaryDirectory ()
file = uploaded_file
temp_filepath = os . path . join ( temp_dir . name , file . name )
with open ( temp_filepath , 'wb' ) as f :
f . write ( file . getvalue ())
# Load the PDF
docs = []
loader = PyPDFLoader ( temp_filepath )
docs . extend ( loader . load ())
# Create the text splitter
text_splitter = RecursiveCharacterTextSplitter (
chunk_size = 1500 ,
chunk_overlap = 100
)
# Vectorize the PDF and load it into the DataStax Enterprise Vector Store
pages = text_splitter . split_documents ( docs )
vector_store . add_documents ( pages )
st . info ( f" { len ( pages ) } pages loaded." )
查看app_7.py中的完整代码。
要在本地启动此应用程序,您需要安装 PyPDF 依赖项,如下所示(这应该已经作为先决条件的一部分完成):
pip install pypdf
并运行应用程序:
streamlit run app_7.py
现在上传与您相关的 PDF 文档(越多越好)并开始询问有关该文档的问题。您会发现答案是相关的、有意义的并且符合上下文! ?见证奇迹发生!