β Back to Cookbook
haystack chat with docs
Details
File: third_party/Haystack/haystack_chat_with_docs.ipynb
Type: Jupyter Notebook
Use Cases: Documents, RAG
Integrations: Haystack
Content
Notebook content (JSON format):
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Using Mistral AI with Haystack\n",
"\n",
"In this cookbook, we will use Mistral embeddings and generative models in 2 [Haystack](https://github.com/deepset-ai/haystack) pipelines:\n",
"\n",
"1) We will build an indexing pipeline that can create embeddings for the contents of URLs and indexes them into a vector database\n",
"2) We will build a retrieval-augmented chat pipeline to chat with the contents of the URLs\n",
"\n",
"First, we install our dependencies"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!pip install mistral-haystack\n",
"!pip install trafilatura"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'2.10.3'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from haystack import version\n",
"version.__version__"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we need to set the `MISTRAL_API_KEY` environment variable π"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"from getpass import getpass\n",
"\n",
"os.environ[\"MISTRAL_API_KEY\"] = getpass(\"Mistral API Key:\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Index URLs with Mistral Embeddings\n",
"\n",
"Below, we are using `mistral-embed` in a full Haystack indexing pipeline. We create embeddings for the contents of the chosen URLs with `mistral-embed` and write them to an [`InMemoryDocumentStore`](https://docs.haystack.deepset.ai/v2.0/docs/inmemorydocumentstore) using the [`MistralDocumentEmbedder`](https://docs.haystack.deepset.ai/v2.0/docs/mistraldocumentembedder). \n",
"\n",
"> π‘This document store is the simplest to get started with as it has no requirements to setup. Feel free to change this document store to any of the [vector databases available for Haystack 2.0](https://haystack.deepset.ai/integrations?type=Document+Store) such as **Weaviate**, **Chroma**, **AstraDB** etc."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<haystack.core.pipeline.pipeline.Pipeline object at 0x1370196a0>\n",
"π
Components\n",
" - fetcher: LinkContentFetcher\n",
" - converter: HTMLToDocument\n",
" - embedder: MistralDocumentEmbedder\n",
" - writer: DocumentWriter\n",
"π€οΈ Connections\n",
" - fetcher.streams -> converter.sources (List[ByteStream])\n",
" - converter.documents -> embedder.documents (List[Document])\n",
" - embedder.documents -> writer.documents (List[Document])"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from haystack import Pipeline\n",
"from haystack.components.converters import HTMLToDocument\n",
"from haystack.components.fetchers import LinkContentFetcher\n",
"from haystack.components.writers import DocumentWriter\n",
"from haystack.document_stores.in_memory import InMemoryDocumentStore\n",
"from haystack_integrations.components.embedders.mistral.document_embedder import MistralDocumentEmbedder\n",
"\n",
"\n",
"document_store = InMemoryDocumentStore()\n",
"fetcher = LinkContentFetcher()\n",
"converter = HTMLToDocument()\n",
"embedder = MistralDocumentEmbedder()\n",
"writer = DocumentWriter(document_store=document_store)\n",
"\n",
"indexing = Pipeline()\n",
"\n",
"indexing.add_component(name=\"fetcher\", instance=fetcher)\n",
"indexing.add_component(name=\"converter\", instance=converter)\n",
"indexing.add_component(name=\"embedder\", instance=embedder)\n",
"indexing.add_component(name=\"writer\", instance=writer)\n",
"\n",
"indexing.connect(\"fetcher\", \"converter\")\n",
"indexing.connect(\"converter\", \"embedder\")\n",
"indexing.connect(\"embedder\", \"writer\")\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Calculating embeddings: 1it [00:00, 3.69it/s]\n"
]
},
{
"data": {
"text/plain": [
"{'embedder': {'meta': {'model': 'mistral-embed',\n",
" 'usage': {'prompt_tokens': 1658,\n",
" 'total_tokens': 1658,\n",
" 'completion_tokens': 0}}},\n",
" 'writer': {'documents_written': 2}}"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"urls = [\"https://mistral.ai/news/la-plateforme/\", \"https://mistral.ai/news/mixtral-of-experts\"]\n",
"\n",
"indexing.run({\"fetcher\": {\"urls\": urls}})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Chat With the URLs with Mistral Generative Models\n",
"\n",
"Now that we have indexed the contents and embeddings of various URLs, we can create a RAG pipeline that uses the [`MistralChatGenerator`](https://docs.haystack.deepset.ai/v2.0/docs/mistralchatgenerator) component with `mistral-small`.\n",
"A few more things to know about this pipeline:\n",
"\n",
"- We are using the [`MistralTextEmbdder`](https://docs.haystack.deepset.ai/v2.0/docs/mistraltextembedder) to embed our question and retrieve the most relevant 1 document\n",
"- We are enabling streaming responses by providing a `streaming_callback`\n",
"- `documents` is being provided to the chat template by the retriever, while we provide `query` to the pipeline when we run it."
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"from haystack.dataclasses import ChatMessage\n",
"\n",
"chat_template = \"\"\"Answer the following question based on the contents of the documents.\\n\n",
" Question: {{query}}\\n\n",
" Documents: {{documents[0].content}}\n",
" \"\"\"\n",
"user_message = ChatMessage.from_user(chat_template)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<haystack.core.pipeline.pipeline.Pipeline object at 0x13705e2d0>\n",
"π
Components\n",
" - text_embedder: MistralTextEmbedder\n",
" - retriever: InMemoryEmbeddingRetriever\n",
" - prompt_builder: ChatPromptBuilder\n",
" - llm: MistralChatGenerator\n",
"π€οΈ Connections\n",
" - text_embedder.embedding -> retriever.query_embedding (List[float])\n",
" - retriever.documents -> prompt_builder.documents (List[Document])\n",
" - prompt_builder.prompt -> llm.messages (List[ChatMessage])"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from haystack import Pipeline\n",
"from haystack.components.builders import ChatPromptBuilder\n",
"from haystack.components.generators.utils import print_streaming_chunk\n",
"from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever\n",
"from haystack_integrations.components.embedders.mistral.text_embedder import MistralTextEmbedder\n",
"from haystack_integrations.components.generators.mistral import MistralChatGenerator\n",
"\n",
"text_embedder = MistralTextEmbedder()\n",
"retriever = InMemoryEmbeddingRetriever(document_store=document_store, top_k=1)\n",
"prompt_builder = ChatPromptBuilder(template=user_message, variables=[\"query\", \"documents\"], required_variables=[\"query\", \"documents\"])\n",
"llm = MistralChatGenerator(model='mistral-small', streaming_callback=print_streaming_chunk)\n",
"\n",
"rag_pipeline = Pipeline()\n",
"rag_pipeline.add_component(\"text_embedder\", text_embedder)\n",
"rag_pipeline.add_component(\"retriever\", retriever)\n",
"rag_pipeline.add_component(\"prompt_builder\", prompt_builder)\n",
"rag_pipeline.add_component(\"llm\", llm)\n",
"\n",
"\n",
"rag_pipeline.connect(\"text_embedder.embedding\", \"retriever.query_embedding\")\n",
"rag_pipeline.connect(\"retriever.documents\", \"prompt_builder.documents\")\n",
"rag_pipeline.connect(\"prompt_builder.prompt\", \"llm.messages\")\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"The Mistral platform has three generative endpoints: mistral-tiny, mistral-small, and mistral-medium. Each endpoint serves a different model with varying performance and language support. Mistral-tiny serves Mistral 7B Instruct v0.2, which is the most cost-effective and only supports English. Mistral-small serves Mixtral 8x7B, which supports English, French, Italian, German, Spanish, and code. Mistral-medium serves a prototype model with higher performance, also supporting the same languages and code as Mistral-small. Additionally, the platform offers an embedding endpoint called Mistral-embed, which serves an embedding model with a 1024 embedding dimension designed for retrieval capabilities."
]
}
],
"source": [
"question = \"What generative endpoints does the Mistral platform have?\"\n",
"\n",
"messages = [ChatMessage.from_user(chat_template)]\n",
"\n",
"result = rag_pipeline.run(\n",
" {\n",
" \"text_embedder\": {\"text\": question},\n",
" \"prompt_builder\": {\"template\": messages, \"query\": question},\n",
" \"llm\": {\"generation_kwargs\": {\"max_tokens\": 165}},\n",
" },\n",
" include_outputs_from=[\"text_embedder\", \"retriever\", \"llm\"],\n",
")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "mistral",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.9"
}
},
"nbformat": 4,
"nbformat_minor": 2
}