mirror of
https://github.com/hwchase17/langchain.git
synced 2025-08-10 21:35:08 +00:00
community: Vectara summarization (#14970)
Description: Adding Summarization to Vectara, to reflect it provides not only vector-store type functionality but also can return a summary. Also added: MMR capability (in the Vectara platform side) Updated templates Updated documentation and IPYNB examples Tag maintainer: @baskaryan Twitter handle: @ofermend --------- Co-authored-by: Ofer Mendelevitch <ofermend@gmail.com>
This commit is contained in:
parent
cf6951a0c9
commit
75ba22793f
@ -1,14 +1,13 @@
|
||||
# Vectara
|
||||
|
||||
>[Vectara](https://docs.vectara.com/docs/) is a GenAI platform for developers. It provides a simple API to build Grounded Generation
|
||||
>(aka Retrieval-augmented-generation or RAG) applications.
|
||||
>[Vectara](https://vectara.com/) is the trusted GenAI platform for developers. It provides a simple API to build GenAI applications
|
||||
> for semantic search or RAG (Retreieval augmented generation).
|
||||
|
||||
**Vectara Overview:**
|
||||
- `Vectara` is developer-first API platform for building GenAI applications
|
||||
- `Vectara` is developer-first API platform for building trusted GenAI applications.
|
||||
- To use Vectara - first [sign up](https://vectara.com/integrations/langchain) and create an account. Then create a corpus and an API key for indexing and searching.
|
||||
- You can use Vectara's [indexing API](https://docs.vectara.com/docs/indexing-apis/indexing) to add documents into Vectara's index
|
||||
- You can use Vectara's [Search API](https://docs.vectara.com/docs/search-apis/search) to query Vectara's index (which also supports Hybrid search implicitly).
|
||||
- You can use Vectara's integration with LangChain as a Vector store or using the Retriever abstraction.
|
||||
|
||||
## Installation and Setup
|
||||
|
||||
@ -21,7 +20,7 @@ Once you have these, you can provide them as arguments to the Vectara vectorstor
|
||||
- export `VECTARA_API_KEY`="your-vectara-api-key"
|
||||
|
||||
|
||||
## Vector Store
|
||||
## Vectara as a Vector Store
|
||||
|
||||
There exists a wrapper around the Vectara platform, allowing you to use it as a vectorstore, whether for semantic search or example selection.
|
||||
|
||||
@ -59,18 +58,35 @@ To query the vectorstore, you can use the `similarity_search` method (or `simila
|
||||
```python
|
||||
results = vectara.similarity_score("what is LangChain?")
|
||||
```
|
||||
The results are returned as a list of relevant documents, and a relevance score of each document.
|
||||
|
||||
`similarity_search_with_score` also supports the following additional arguments:
|
||||
In this case, we used the default retrieval parameters, but you can also specify the following additional arguments in `similarity_search` or `similarity_search_with_score`:
|
||||
- `k`: number of results to return (defaults to 5)
|
||||
- `lambda_val`: the [lexical matching](https://docs.vectara.com/docs/api-reference/search-apis/lexical-matching) factor for hybrid search (defaults to 0.025)
|
||||
- `filter`: a [filter](https://docs.vectara.com/docs/common-use-cases/filtering-by-metadata/filter-overview) to apply to the results (default None)
|
||||
- `n_sentence_context`: number of sentences to include before/after the actual matching segment when returning results. This defaults to 2.
|
||||
- `mmr_config`: can be used to specify MMR mode in the query.
|
||||
- `is_enabled`: True or False
|
||||
- `mmr_k`: number of results to use for MMR reranking
|
||||
- `diversity_bias`: 0 = no diversity, 1 = full diversity. This is the lambda parameter in the MMR formula and is in the range 0...1
|
||||
|
||||
The results are returned as a list of relevant documents, and a relevance score of each document.
|
||||
## Vectara for Retrieval Augmented Generation (RAG)
|
||||
|
||||
Vectara provides a full RAG pipeline, including generative summarization.
|
||||
To use this pipeline, you can specify the `summary_config` argument in `similarity_search` or `similarity_search_with_score` as follows:
|
||||
|
||||
- `summary_config`: can be used to request an LLM summary in RAG
|
||||
- `is_enabled`: True or False
|
||||
- `max_results`: number of results to use for summary generation
|
||||
- `response_lang`: language of the response summary, in ISO 639-2 format (e.g. 'en', 'fr', 'de', etc)
|
||||
|
||||
## Example Notebooks
|
||||
|
||||
For a more detailed examples of using Vectara, see the following examples:
|
||||
* [this notebook](/docs/integrations/vectorstores/vectara.html) shows how to use Vectara as a vectorstore for semantic search
|
||||
* [this notebook](/docs/integrations/providers/vectara/vectara_chat.html) shows how to build a chatbot with Langchain and Vectara
|
||||
* [this notebook](/docs/integrations/providers/vectara/vectara_summary.html) shows how to use the full Vectara RAG pipeline, including generative summarization
|
||||
* [this notebook](/docs/integrations/retrievers/self_query/vectara_self_query.html) shows the self-query capability with Vectara.
|
||||
|
||||
|
||||
For a more detailed examples of using the Vectara wrapper, see one of these two sample notebooks:
|
||||
* [Chat Over Documents with Vectara](./vectara_chat.html)
|
||||
* [Vectara Text Generation](./vectara_text_generation.html)
|
||||
|
||||
|
||||
|
@ -7,12 +7,51 @@
|
||||
"source": [
|
||||
"# Chat Over Documents with Vectara\n",
|
||||
"\n",
|
||||
"This notebook is based on the [chat_vector_db](https://github.com/langchain-ai/langchain/blob/master/docs/modules/chains/index_examples/chat_vector_db) notebook, but using Vectara as the vector database."
|
||||
"This notebook is based on the [chat_vector_db](https://github.com/hwchase17/langchain/blob/master/docs/modules/chains/index_examples/chat_vector_db.html) notebook, but using Vectara as the vector database."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "56372c5b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Setup\n",
|
||||
"\n",
|
||||
"You will need a Vectara account to use Vectara with LangChain. To get started, use the following steps:\n",
|
||||
"1. [Sign up](https://www.vectara.com/integrations/langchain) for a Vectara account if you don't already have one. Once you have completed your sign up you will have a Vectara customer ID. You can find your customer ID by clicking on your name, on the top-right of the Vectara console window.\n",
|
||||
"2. Within your account you can create one or more corpora. Each corpus represents an area that stores text data upon ingest from input documents. To create a corpus, use the **\"Create Corpus\"** button. You then provide a name to your corpus as well as a description. Optionally you can define filtering attributes and apply some advanced options. If you click on your created corpus, you can see its name and corpus ID right on the top.\n",
|
||||
"3. Next you'll need to create API keys to access the corpus. Click on the **\"Authorization\"** tab in the corpus view and then the **\"Create API Key\"** button. Give your key a name, and choose whether you want query only or query+index for your key. Click \"Create\" and you now have an active API key. Keep this key confidential. \n",
|
||||
"\n",
|
||||
"To use LangChain with Vectara, you'll need to have these three values: customer ID, corpus ID and api_key.\n",
|
||||
"You can provide those to LangChain in two ways:\n",
|
||||
"\n",
|
||||
"1. Include in your environment these three variables: `VECTARA_CUSTOMER_ID`, `VECTARA_CORPUS_ID` and `VECTARA_API_KEY`.\n",
|
||||
"\n",
|
||||
"> For example, you can set these variables using os.environ and getpass as follows:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import os\n",
|
||||
"import getpass\n",
|
||||
"\n",
|
||||
"os.environ[\"VECTARA_CUSTOMER_ID\"] = getpass.getpass(\"Vectara Customer ID:\")\n",
|
||||
"os.environ[\"VECTARA_CORPUS_ID\"] = getpass.getpass(\"Vectara Corpus ID:\")\n",
|
||||
"os.environ[\"VECTARA_API_KEY\"] = getpass.getpass(\"Vectara API Key:\")\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"2. Add them to the Vectara vectorstore constructor:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"vectorstore = Vectara(\n",
|
||||
" vectara_customer_id=vectara_customer_id,\n",
|
||||
" vectara_corpus_id=vectara_corpus_id,\n",
|
||||
" vectara_api_key=vectara_api_key\n",
|
||||
" )\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"execution_count": 2,
|
||||
"id": "70c4e529",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -36,7 +75,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": 3,
|
||||
"id": "01c46e92",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -45,7 +84,7 @@
|
||||
"source": [
|
||||
"from langchain.document_loaders import TextLoader\n",
|
||||
"\n",
|
||||
"loader = TextLoader(\"../../../modules/state_of_the_union.txt\")\n",
|
||||
"loader = TextLoader(\"state_of_the_union.txt\")\n",
|
||||
"documents = loader.load()"
|
||||
]
|
||||
},
|
||||
@ -54,19 +93,19 @@
|
||||
"id": "239475d2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We now split the documents, create embeddings for them, and put them in a vectorstore. This allows us to do semantic search over them."
|
||||
"Since we're using Vectara, there's no need to chunk the documents, as that is done automatically in the Vectara platform backend. We just use `from_document()` to upload the text loaded from the file, and directly ingest it into Vectara:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 4,
|
||||
"id": "a8930cf7",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"vectorstore = Vectara.from_documents(documents, embedding=None)"
|
||||
"vectara = Vectara.from_documents(documents, embedding=None)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -79,7 +118,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 5,
|
||||
"id": "af803fee",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@ -94,42 +133,71 @@
|
||||
"id": "3c96b118",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We now initialize the `ConversationalRetrievalChain`"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "7b4110f3",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"openai_api_key = os.environ[\"OPENAI_API_KEY\"]\n",
|
||||
"llm = OpenAI(openai_api_key=openai_api_key, temperature=0)\n",
|
||||
"retriever = vectorstore.as_retriever(lambda_val=0.025, k=5, filter=None)\n",
|
||||
"d = retriever.get_relevant_documents(\n",
|
||||
" \"What did the president say about Ketanji Brown Jackson\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"qa = ConversationalRetrievalChain.from_llm(llm, retriever, memory=memory)"
|
||||
"We now initialize the `ConversationalRetrievalChain`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "e8ce4fe9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"id": "7b4110f3",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[Document(page_content='Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence. A former top litigator in private practice.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '29486', 'len': '97'}), Document(page_content='Groups of citizens blocking tanks with their bodies. Everyone from students to retirees teachers turned soldiers defending their homeland. In this struggle as President Zelenskyy said in his speech to the European Parliament “Light will win over darkness.” The Ukrainian Ambassador to the United States is here tonight. Let each of us here tonight in this Chamber send an unmistakable signal to Ukraine and to the world.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '1083', 'len': '117'}), Document(page_content='All told, we created 369,000 new manufacturing jobs in America just last year. Powered by people I’ve met like JoJo Burgess, from generations of union steelworkers from Pittsburgh, who’s here with us tonight. As Ohio Senator Sherrod Brown says, “It’s time to bury the label “Rust Belt.” It’s time. \\n\\nBut with all the bright spots in our economy, record job growth and higher wages, too many families are struggling to keep up with the bills. Inflation is robbing them of the gains they might otherwise feel.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '14257', 'len': '77'}), Document(page_content='This is personal to me and Jill, to Kamala, and to so many of you. Cancer is the #2 cause of death in America–second only to heart disease. Last month, I announced our plan to supercharge \\nthe Cancer Moonshot that President Obama asked me to lead six years ago. Our goal is to cut the cancer death rate by at least 50% over the next 25 years, turn more cancers from death sentences into treatable diseases. More support for patients and families.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '36196', 'len': '122'}), Document(page_content='Six days ago, Russia’s Vladimir Putin sought to shake the foundations of the free world thinking he could make it bend to his menacing ways. But he badly miscalculated. He thought he could roll into Ukraine and the world would roll over. Instead he met a wall of strength he never imagined. He met the Ukrainian people.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '664', 'len': '68'}), Document(page_content='I understand. \\n\\nI remember when my Dad had to leave our home in Scranton, Pennsylvania to find work. I grew up in a family where if the price of food went up, you felt it. That’s why one of the first things I did as President was fight to pass the American Rescue Plan. Because people were hurting. We needed to act, and we did.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '8042', 'len': '97'}), Document(page_content='He rejected repeated efforts at diplomacy. He thought the West and NATO wouldn’t respond. And he thought he could divide us at home. We were ready. Here is what we did. We prepared extensively and carefully.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '2100', 'len': '42'}), Document(page_content='He thought he could roll into Ukraine and the world would roll over. Instead he met a wall of strength he never imagined. He met the Ukrainian people. From President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world. Groups of citizens blocking tanks with their bodies.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '788', 'len': '28'}), Document(page_content='Putin’s latest attack on Ukraine was premeditated and unprovoked. He rejected repeated efforts at diplomacy. He thought the West and NATO wouldn’t respond. And he thought he could divide us at home. We were ready. Here is what we did.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '2053', 'len': '46'}), Document(page_content='A unity agenda for the nation. We can do this. \\n\\nMy fellow Americans—tonight , we have gathered in a sacred space—the citadel of our democracy. In this Capitol, generation after generation, Americans have debated great questions amid great strife, and have done great things. We have fought for freedom, expanded liberty, defeated totalitarianism and terror. And built the strongest, freest, and most prosperous nation the world has ever known.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '36968', 'len': '131'})]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"query = \"What did the president say about Ketanji Brown Jackson\"\n",
|
||||
"result = qa({\"question\": query})"
|
||||
"openai_api_key = os.environ[\"OPENAI_API_KEY\"]\n",
|
||||
"llm = OpenAI(openai_api_key=openai_api_key, temperature=0)\n",
|
||||
"retriever = vectara.as_retriever()\n",
|
||||
"d = retriever.get_relevant_documents(\n",
|
||||
" \"What did the president say about Ketanji Brown Jackson\", k=2\n",
|
||||
")\n",
|
||||
"print(d)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "44ed803e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"bot = ConversationalRetrievalChain.from_llm(\n",
|
||||
" llm, retriever, memory=memory, verbose=False\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5b6deb16",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"And can have a multi-turn conversation with out new bot:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "e8ce4fe9",
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"query = \"What did the president say about Ketanji Brown Jackson\"\n",
|
||||
"result = bot({\"question\": query})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "4c79862b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@ -139,7 +207,7 @@
|
||||
"\" The president said that Ketanji Brown Jackson is one of the nation's top legal minds and a former top litigator in private practice, and that she will continue Justice Breyer's legacy of excellence.\""
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -150,28 +218,28 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"execution_count": 10,
|
||||
"id": "c697d9d1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"query = \"Did he mention who she succeeded\"\n",
|
||||
"result = qa({\"question\": query})"
|
||||
"query = \"Did he mention who she suceeded\"\n",
|
||||
"result = bot({\"question\": query})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"execution_count": 11,
|
||||
"id": "ba0678f3",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"' Ketanji Brown Jackson succeeded Justice Breyer.'"
|
||||
"' Ketanji Brown Jackson succeeded Justice Breyer on the United States Supreme Court.'"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -192,15 +260,15 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"execution_count": 12,
|
||||
"id": "1b41a10b-bf68-4689-8f00-9aed7675e2ab",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"qa = ConversationalRetrievalChain.from_llm(\n",
|
||||
" OpenAI(temperature=0), vectorstore.as_retriever()\n",
|
||||
"bot = ConversationalRetrievalChain.from_llm(\n",
|
||||
" OpenAI(temperature=0), vectara.as_retriever()\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
@ -214,7 +282,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"execution_count": 13,
|
||||
"id": "bc672290-8a8b-4828-a90c-f1bbdd6b3920",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -223,12 +291,12 @@
|
||||
"source": [
|
||||
"chat_history = []\n",
|
||||
"query = \"What did the president say about Ketanji Brown Jackson\"\n",
|
||||
"result = qa({\"question\": query, \"chat_history\": chat_history})"
|
||||
"result = bot({\"question\": query, \"chat_history\": chat_history})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"execution_count": 14,
|
||||
"id": "6b62d758-c069-4062-88f0-21e7ea4710bf",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -240,7 +308,7 @@
|
||||
"\" The president said that Ketanji Brown Jackson is one of the nation's top legal minds and a former top litigator in private practice, and that she will continue Justice Breyer's legacy of excellence.\""
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -259,7 +327,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"execution_count": 15,
|
||||
"id": "9c95460b-7116-4155-a9d2-c0fb027ee592",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -267,13 +335,13 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chat_history = [(query, result[\"answer\"])]\n",
|
||||
"query = \"Did he mention who she succeeded\"\n",
|
||||
"result = qa({\"question\": query, \"chat_history\": chat_history})"
|
||||
"query = \"Did he mention who she suceeded\"\n",
|
||||
"result = bot({\"question\": query, \"chat_history\": chat_history})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"execution_count": 16,
|
||||
"id": "698ac00c-cadc-407f-9423-226b2d9258d0",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -282,10 +350,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"' Ketanji Brown Jackson succeeded Justice Breyer.'"
|
||||
"' Ketanji Brown Jackson succeeded Justice Breyer on the United States Supreme Court.'"
|
||||
]
|
||||
},
|
||||
"execution_count": 14,
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -305,21 +373,21 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"execution_count": 17,
|
||||
"id": "562769c6",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"qa = ConversationalRetrievalChain.from_llm(\n",
|
||||
" llm, vectorstore.as_retriever(), return_source_documents=True\n",
|
||||
"bot = ConversationalRetrievalChain.from_llm(\n",
|
||||
" llm, vectara.as_retriever(), return_source_documents=True\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"execution_count": 18,
|
||||
"id": "ea478300",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -328,12 +396,12 @@
|
||||
"source": [
|
||||
"chat_history = []\n",
|
||||
"query = \"What did the president say about Ketanji Brown Jackson\"\n",
|
||||
"result = qa({\"question\": query, \"chat_history\": chat_history})"
|
||||
"result = bot({\"question\": query, \"chat_history\": chat_history})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"execution_count": 19,
|
||||
"id": "4cb75b4e",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -342,10 +410,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Document(page_content='Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence. A former top litigator in private practice.', metadata={'source': '../../../modules/state_of_the_union.txt'})"
|
||||
"Document(page_content='Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence. A former top litigator in private practice.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '29486', 'len': '97'})"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -356,74 +424,16 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "669ede2f-d69f-4960-8468-8a768ce1a55f",
|
||||
"id": "99b96dae",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ConversationalRetrievalChain with `search_distance`\n",
|
||||
"If you are using a vector store that supports filtering by search distance, you can add a threshold value parameter."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"id": "f4f32c6f-8e49-44af-9116-8830b1fcc5f2",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"vectordbkwargs = {\"search_distance\": 0.9}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "1e251775-31e7-4679-b744-d4a57937f93a",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"qa = ConversationalRetrievalChain.from_llm(\n",
|
||||
" OpenAI(temperature=0), vectorstore.as_retriever(), return_source_documents=True\n",
|
||||
")\n",
|
||||
"chat_history = []\n",
|
||||
"query = \"What did the president say about Ketanji Brown Jackson\"\n",
|
||||
"result = qa(\n",
|
||||
" {\"question\": query, \"chat_history\": chat_history, \"vectordbkwargs\": vectordbkwargs}\n",
|
||||
")"
|
||||
"## ConversationalRetrievalChain with `map_reduce`\n",
|
||||
"LangChain supports different types of ways to combine document chains with the ConversationalRetrievalChain chain."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"id": "24ebdaec",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" The president said that Ketanji Brown Jackson is one of the nation's top legal minds and a former top litigator in private practice, and that she will continue Justice Breyer's legacy of excellence.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(result[\"answer\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "99b96dae",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ConversationalRetrievalChain with `map_reduce`\n",
|
||||
"We can also use different types of combine document chains with the ConversationalRetrievalChain chain."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"id": "e53a9d66",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -437,7 +447,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"execution_count": 21,
|
||||
"id": "bf205e35",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -448,7 +458,7 @@
|
||||
"doc_chain = load_qa_chain(llm, chain_type=\"map_reduce\")\n",
|
||||
"\n",
|
||||
"chain = ConversationalRetrievalChain(\n",
|
||||
" retriever=vectorstore.as_retriever(),\n",
|
||||
" retriever=vectara.as_retriever(),\n",
|
||||
" question_generator=question_generator,\n",
|
||||
" combine_docs_chain=doc_chain,\n",
|
||||
")"
|
||||
@ -456,7 +466,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"execution_count": 22,
|
||||
"id": "78155887",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -470,7 +480,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"execution_count": 23,
|
||||
"id": "e54b5fa2",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -482,7 +492,7 @@
|
||||
"\" The president said that he nominated Circuit Court of Appeals Judge Ketanji Brown Jackson, who is one of the nation's top legal minds and a former top litigator in private practice.\""
|
||||
]
|
||||
},
|
||||
"execution_count": 24,
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -503,7 +513,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"execution_count": 24,
|
||||
"id": "d1058fd2",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -515,7 +525,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"execution_count": 25,
|
||||
"id": "a6594482",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -526,7 +536,7 @@
|
||||
"doc_chain = load_qa_with_sources_chain(llm, chain_type=\"map_reduce\")\n",
|
||||
"\n",
|
||||
"chain = ConversationalRetrievalChain(\n",
|
||||
" retriever=vectorstore.as_retriever(),\n",
|
||||
" retriever=vectara.as_retriever(),\n",
|
||||
" question_generator=question_generator,\n",
|
||||
" combine_docs_chain=doc_chain,\n",
|
||||
")"
|
||||
@ -534,9 +544,10 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 27,
|
||||
"execution_count": 26,
|
||||
"id": "e2badd21",
|
||||
"metadata": {
|
||||
"scrolled": false,
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
@ -548,7 +559,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 28,
|
||||
"execution_count": 27,
|
||||
"id": "edb31fe5",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -557,10 +568,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\" The president said that Ketanji Brown Jackson is one of the nation's top legal minds and a former top litigator in private practice.\\nSOURCES: ../../../modules/state_of_the_union.txt\""
|
||||
"\" The president said that Ketanji Brown Jackson is one of the nation's top legal minds and a former top litigator in private practice.\\nSOURCES: langchain\""
|
||||
]
|
||||
},
|
||||
"execution_count": 28,
|
||||
"execution_count": 27,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -581,7 +592,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 29,
|
||||
"execution_count": 28,
|
||||
"id": "2efacec3-2690-4b05-8de3-a32fd2ac3911",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -609,8 +620,8 @@
|
||||
"question_generator = LLMChain(llm=llm, prompt=CONDENSE_QUESTION_PROMPT)\n",
|
||||
"doc_chain = load_qa_chain(streaming_llm, chain_type=\"stuff\", prompt=QA_PROMPT)\n",
|
||||
"\n",
|
||||
"qa = ConversationalRetrievalChain(\n",
|
||||
" retriever=vectorstore.as_retriever(),\n",
|
||||
"bot = ConversationalRetrievalChain(\n",
|
||||
" retriever=vectara.as_retriever(),\n",
|
||||
" combine_docs_chain=doc_chain,\n",
|
||||
" question_generator=question_generator,\n",
|
||||
")"
|
||||
@ -618,7 +629,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 30,
|
||||
"execution_count": 29,
|
||||
"id": "fd6d43f4-7428-44a4-81bc-26fe88a98762",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -635,12 +646,12 @@
|
||||
"source": [
|
||||
"chat_history = []\n",
|
||||
"query = \"What did the president say about Ketanji Brown Jackson\"\n",
|
||||
"result = qa({\"question\": query, \"chat_history\": chat_history})"
|
||||
"result = bot({\"question\": query, \"chat_history\": chat_history})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 31,
|
||||
"execution_count": 30,
|
||||
"id": "5ab38978-f3e8-4fa7-808c-c79dec48379a",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -650,14 +661,14 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" Justice Breyer"
|
||||
" Ketanji Brown Jackson succeeded Justice Breyer on the United States Supreme Court."
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chat_history = [(query, result[\"answer\"])]\n",
|
||||
"query = \"Did he mention who she succeeded\"\n",
|
||||
"result = qa({\"question\": query, \"chat_history\": chat_history})"
|
||||
"query = \"Did he mention who she suceeded\"\n",
|
||||
"result = bot({\"question\": query, \"chat_history\": chat_history})"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -671,7 +682,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 32,
|
||||
"execution_count": 31,
|
||||
"id": "a7ba9d8c",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -685,14 +696,14 @@
|
||||
" return \"\\n\".join(res)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"qa = ConversationalRetrievalChain.from_llm(\n",
|
||||
" llm, vectorstore.as_retriever(), get_chat_history=get_chat_history\n",
|
||||
"bot = ConversationalRetrievalChain.from_llm(\n",
|
||||
" llm, vectara.as_retriever(), get_chat_history=get_chat_history\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 33,
|
||||
"execution_count": 32,
|
||||
"id": "a3e33c0d",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -701,12 +712,12 @@
|
||||
"source": [
|
||||
"chat_history = []\n",
|
||||
"query = \"What did the president say about Ketanji Brown Jackson\"\n",
|
||||
"result = qa({\"question\": query, \"chat_history\": chat_history})"
|
||||
"result = bot({\"question\": query, \"chat_history\": chat_history})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 34,
|
||||
"execution_count": 33,
|
||||
"id": "936dc62f",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@ -718,7 +729,7 @@
|
||||
"\" The president said that Ketanji Brown Jackson is one of the nation's top legal minds and a former top litigator in private practice, and that she will continue Justice Breyer's legacy of excellence.\""
|
||||
]
|
||||
},
|
||||
"execution_count": 34,
|
||||
"execution_count": 33,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -726,14 +737,6 @@
|
||||
"source": [
|
||||
"result[\"answer\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b8c26901",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
304
docs/docs/integrations/providers/vectara/vectara_summary.ipynb
Normal file
304
docs/docs/integrations/providers/vectara/vectara_summary.ipynb
Normal file
@ -0,0 +1,304 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "559f8e0e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Vectara\n",
|
||||
"\n",
|
||||
">[Vectara](https://vectara.com/) is the trusted GenAI platform that provides an easy-to-use API for document indexing and querying. \n",
|
||||
"\n",
|
||||
"Vectara provides an end-to-end managed service for Retrieval Augmented Generation or [RAG](https://vectara.com/grounded-generation/), which includes:\n",
|
||||
"1. A way to extract text from document files and chunk them into sentences.\n",
|
||||
"2. The state-of-the-art [Boomerang](https://vectara.com/how-boomerang-takes-retrieval-augmented-generation-to-the-next-level-via-grounded-generation/) embeddings model. Each text chunk is encoded into a vector embedding using Boomerang, and stored in the Vectara internal knowledge (vector+text) store\n",
|
||||
"3. A query service that automatically encodes the query into embedding, and retrieves the most relevant text segments (including support for [Hybrid Search](https://docs.vectara.com/docs/api-reference/search-apis/lexical-matching) and [MMR](https://vectara.com/get-diverse-results-and-comprehensive-summaries-with-vectaras-mmr-reranker/))\n",
|
||||
"4. An option to create [generative summary](https://docs.vectara.com/docs/learn/grounded-generation/grounded-generation-overview), based on the retrieved documents, including citations.\n",
|
||||
"\n",
|
||||
"See the [Vectara API documentation](https://docs.vectara.com/docs/) for more information on how to use the API.\n",
|
||||
"\n",
|
||||
"This notebook shows how to use functionality related to the `Vectara`'s integration with langchain.\n",
|
||||
"Specificaly we will demonstrate how to use chaining with [LangChain's Expression Language](https://python.langchain.com/docs/expression_language/) and using Vectara's integrated summarization capability."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e97dcf11",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Setup\n",
|
||||
"\n",
|
||||
"You will need a Vectara account to use Vectara with LangChain. To get started, use the following steps:\n",
|
||||
"1. [Sign up](https://www.vectara.com/integrations/langchain) for a Vectara account if you don't already have one. Once you have completed your sign up you will have a Vectara customer ID. You can find your customer ID by clicking on your name, on the top-right of the Vectara console window.\n",
|
||||
"2. Within your account you can create one or more corpora. Each corpus represents an area that stores text data upon ingest from input documents. To create a corpus, use the **\"Create Corpus\"** button. You then provide a name to your corpus as well as a description. Optionally you can define filtering attributes and apply some advanced options. If you click on your created corpus, you can see its name and corpus ID right on the top.\n",
|
||||
"3. Next you'll need to create API keys to access the corpus. Click on the **\"Authorization\"** tab in the corpus view and then the **\"Create API Key\"** button. Give your key a name, and choose whether you want query only or query+index for your key. Click \"Create\" and you now have an active API key. Keep this key confidential. \n",
|
||||
"\n",
|
||||
"To use LangChain with Vectara, you'll need to have these three values: customer ID, corpus ID and api_key.\n",
|
||||
"You can provide those to LangChain in two ways:\n",
|
||||
"\n",
|
||||
"1. Include in your environment these three variables: `VECTARA_CUSTOMER_ID`, `VECTARA_CORPUS_ID` and `VECTARA_API_KEY`.\n",
|
||||
"\n",
|
||||
"> For example, you can set these variables using os.environ and getpass as follows:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"import os\n",
|
||||
"import getpass\n",
|
||||
"\n",
|
||||
"os.environ[\"VECTARA_CUSTOMER_ID\"] = getpass.getpass(\"Vectara Customer ID:\")\n",
|
||||
"os.environ[\"VECTARA_CORPUS_ID\"] = getpass.getpass(\"Vectara Corpus ID:\")\n",
|
||||
"os.environ[\"VECTARA_API_KEY\"] = getpass.getpass(\"Vectara API Key:\")\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"2. Add them to the Vectara vectorstore constructor:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"vectorstore = Vectara(\n",
|
||||
" vectara_customer_id=vectara_customer_id,\n",
|
||||
" vectara_corpus_id=vectara_corpus_id,\n",
|
||||
" vectara_api_key=vectara_api_key\n",
|
||||
" )\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "aac7a9a6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.embeddings import FakeEmbeddings\n",
|
||||
"from langchain.prompts import ChatPromptTemplate\n",
|
||||
"from langchain.schema.output_parser import StrOutputParser\n",
|
||||
"from langchain.schema.runnable import RunnableLambda, RunnablePassthrough\n",
|
||||
"from langchain.vectorstores import Vectara"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "875ffb7e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"First we load the state-of-the-union text into Vectara. Note that we use the `from_files` interface which does not require any local processing or chunking - Vectara receives the file content and performs all the necessary pre-processing, chunking and embedding of the file into its knowledge store."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "be0a4973",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"vectara = Vectara.from_files([\"state_of_the_union.txt\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "22a6b953",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We now create a Vectara retriever and specify that:\n",
|
||||
"* It should return only the 3 top Document matches\n",
|
||||
"* For summary, it should use the top 5 results and respond in English"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "19cd2f86",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"summary_config = {\"is_enabled\": True, \"max_results\": 5, \"response_lang\": \"eng\"}\n",
|
||||
"retriever = vectara.as_retriever(\n",
|
||||
" search_kwargs={\"k\": 3, \"summary_config\": summary_config}\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c49284ed",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"When using summarization with Vectara, the retriever responds with a list of `Document` objects:\n",
|
||||
"1. The first `k` documents are the ones that match the query (as we are used to with a standard vector store)\n",
|
||||
"2. With summary enabled, an additional `Document` object is apended, which includes the summary text. This Document has the metadata field `summary` set as True.\n",
|
||||
"\n",
|
||||
"Let's define two utility functions to split those out:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "e5100654",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def get_sources(documents):\n",
|
||||
" return documents[:-1]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_summary(documents):\n",
|
||||
" return documents[-1].page_content\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"query_str = \"what did Biden say?\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f2a74368",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we can try a summary response for the query:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "ee4759c4",
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'The returned results did not contain sufficient information to be summarized into a useful answer for your query. Please try a different search or restate your query differently.'"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"(retriever | get_summary).invoke(query_str)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dd7c4593",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"And if we would like to see the sources retrieved from Vectara that were used in this summary (the citations):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "0eb66034",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[Document(page_content='When they came home, many of the world’s fittest and best trained warriors were never the same. Dizziness. \\n\\nA cancer that would put them in a flag-draped coffin. I know. \\n\\nOne of those soldiers was my son Major Beau Biden. We don’t know for sure if a burn pit was the cause of his brain cancer, or the diseases of so many of our troops. But I’m committed to finding out everything we can.', metadata={'lang': 'eng', 'section': '1', 'offset': '34652', 'len': '60', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
|
||||
" Document(page_content='The U.S. Department of Justice is assembling a dedicated task force to go after the crimes of Russian oligarchs. We are joining with our European allies to find and seize your yachts your luxury apartments your private jets. We are coming for your ill-begotten gains. And tonight I am announcing that we will join our allies in closing off American air space to all Russian flights – further isolating Russia – and adding an additional squeeze –on their economy. The Ruble has lost 30% of its value.', metadata={'lang': 'eng', 'section': '1', 'offset': '3807', 'len': '42', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
|
||||
" Document(page_content='He rejected repeated efforts at diplomacy. He thought the West and NATO wouldn’t respond. And he thought he could divide us at home. We were ready. Here is what we did. We prepared extensively and carefully.', metadata={'lang': 'eng', 'section': '1', 'offset': '2100', 'len': '42', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"(retriever | get_sources).invoke(query_str)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8f16bf8d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Vectara's \"RAG as a service\" does a lot of the heavy lifting in creating question answering or chatbot chains. The integration with LangChain provides the option to use additional capabilities such as query pre-processing like `SelfQueryRetriever` or `MultiQueryRetriever`. Let's look at an example of using the [MultiQueryRetriever](https://python.langchain.com/docs/modules/data_connection/retrievers/MultiQueryRetriever).\n",
|
||||
"\n",
|
||||
"Since MQR uses an LLM we have to set that up - here we choose `ChatOpenAI`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "e14325b9",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"President Biden has made several notable quotes and comments. He expressed a commitment to investigate the potential impact of burn pits on soldiers' health, referencing his son's brain cancer [1]. He emphasized the importance of unity among Americans, urging us to see each other as fellow citizens rather than enemies [2]. Biden also highlighted the need for schools to use funds from the American Rescue Plan to hire teachers and address learning loss, while encouraging community involvement in supporting education [3].\""
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain.chat_models import ChatOpenAI\n",
|
||||
"from langchain.retrievers.multi_query import MultiQueryRetriever\n",
|
||||
"\n",
|
||||
"llm = ChatOpenAI(temperature=0)\n",
|
||||
"mqr = MultiQueryRetriever.from_llm(retriever=retriever, llm=llm)\n",
|
||||
"\n",
|
||||
"(mqr | get_summary).invoke(query_str)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "fa14f923",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[Document(page_content='When they came home, many of the world’s fittest and best trained warriors were never the same. Dizziness. \\n\\nA cancer that would put them in a flag-draped coffin. I know. \\n\\nOne of those soldiers was my son Major Beau Biden. We don’t know for sure if a burn pit was the cause of his brain cancer, or the diseases of so many of our troops. But I’m committed to finding out everything we can.', metadata={'lang': 'eng', 'section': '1', 'offset': '34652', 'len': '60', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
|
||||
" Document(page_content='The U.S. Department of Justice is assembling a dedicated task force to go after the crimes of Russian oligarchs. We are joining with our European allies to find and seize your yachts your luxury apartments your private jets. We are coming for your ill-begotten gains. And tonight I am announcing that we will join our allies in closing off American air space to all Russian flights – further isolating Russia – and adding an additional squeeze –on their economy. The Ruble has lost 30% of its value.', metadata={'lang': 'eng', 'section': '1', 'offset': '3807', 'len': '42', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
|
||||
" Document(page_content='And, if Congress provides the funds we need, we’ll have new stockpiles of tests, masks, and pills ready if needed. I cannot promise a new variant won’t come. But I can promise you we’ll do everything within our power to be ready if it does. Third – we can end the shutdown of schools and businesses. We have the tools we need.', metadata={'lang': 'eng', 'section': '1', 'offset': '24753', 'len': '82', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
|
||||
" Document(page_content='The returned results did not contain sufficient information to be summarized into a useful answer for your query. Please try a different search or restate your query differently.', metadata={'summary': True}),\n",
|
||||
" Document(page_content='Danielle says Heath was a fighter to the very end. He didn’t know how to stop fighting, and neither did she. Through her pain she found purpose to demand we do better. Tonight, Danielle—we are. The VA is pioneering new ways of linking toxic exposures to diseases, already helping more veterans get benefits.', metadata={'lang': 'eng', 'section': '1', 'offset': '35502', 'len': '58', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
|
||||
" Document(page_content='Let’s stop seeing each other as enemies, and start seeing each other for who we really are: Fellow Americans. We can’t change how divided we’ve been. But we can change how we move forward—on COVID-19 and other issues we must face together. I recently visited the New York City Police Department days after the funerals of Officer Wilbert Mora and his partner, Officer Jason Rivera. They were responding to a 9-1-1 call when a man shot and killed them with a stolen gun.', metadata={'lang': 'eng', 'section': '1', 'offset': '26312', 'len': '89', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'}),\n",
|
||||
" Document(page_content='The American Rescue Plan gave schools money to hire teachers and help students make up for lost learning. I urge every parent to make sure your school does just that. And we can all play a part—sign up to be a tutor or a mentor. Children were also struggling before the pandemic. Bullying, violence, trauma, and the harms of social media.', metadata={'lang': 'eng', 'section': '1', 'offset': '33227', 'len': '61', 'X-TIKA:Parsed-By': 'org.apache.tika.parser.csv.TextAndCSVParser', 'Content-Encoding': 'UTF-8', 'Content-Type': 'text/plain; charset=UTF-8', 'source': 'vectara'})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"(mqr | get_sources).invoke(query_str)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "16853820",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"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.10.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Vectara Text Generation\n",
|
||||
"\n",
|
||||
"This notebook is based on [text generation](https://github.com/langchain-ai/langchain/blob/master/docs/modules/chains/index_examples/vector_db_text_generation.ipynb) notebook and adapted to Vectara."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Prepare Data\n",
|
||||
"\n",
|
||||
"First, we prepare the data. For this example, we fetch a documentation site that consists of markdown files hosted on Github and split them into small enough Documents."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import pathlib\n",
|
||||
"import subprocess\n",
|
||||
"import tempfile\n",
|
||||
"\n",
|
||||
"from langchain.docstore.document import Document\n",
|
||||
"from langchain.llms import OpenAI\n",
|
||||
"from langchain.prompts import PromptTemplate\n",
|
||||
"from langchain.text_splitter import CharacterTextSplitter\n",
|
||||
"from langchain.vectorstores import Vectara"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Cloning into '.'...\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def get_github_docs(repo_owner, repo_name):\n",
|
||||
" with tempfile.TemporaryDirectory() as d:\n",
|
||||
" subprocess.check_call(\n",
|
||||
" f\"git clone --depth 1 https://github.com/{repo_owner}/{repo_name}.git .\",\n",
|
||||
" cwd=d,\n",
|
||||
" shell=True,\n",
|
||||
" )\n",
|
||||
" git_sha = (\n",
|
||||
" subprocess.check_output(\"git rev-parse HEAD\", shell=True, cwd=d)\n",
|
||||
" .decode(\"utf-8\")\n",
|
||||
" .strip()\n",
|
||||
" )\n",
|
||||
" repo_path = pathlib.Path(d)\n",
|
||||
" markdown_files = list(repo_path.glob(\"*/*.md\")) + list(\n",
|
||||
" repo_path.glob(\"*/*.mdx\")\n",
|
||||
" )\n",
|
||||
" for markdown_file in markdown_files:\n",
|
||||
" with open(markdown_file, \"r\") as f:\n",
|
||||
" relative_path = markdown_file.relative_to(repo_path)\n",
|
||||
" github_url = f\"https://github.com/{repo_owner}/{repo_name}/blob/{git_sha}/{relative_path}\"\n",
|
||||
" yield Document(page_content=f.read(), metadata={\"source\": github_url})\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"sources = get_github_docs(\"yirenlu92\", \"deno-manual-forked\")\n",
|
||||
"\n",
|
||||
"source_chunks = []\n",
|
||||
"splitter = CharacterTextSplitter(separator=\" \", chunk_size=1024, chunk_overlap=0)\n",
|
||||
"for source in sources:\n",
|
||||
" for chunk in splitter.split_text(source.page_content):\n",
|
||||
" source_chunks.append(chunk)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Set Up Vector DB\n",
|
||||
"\n",
|
||||
"Now that we have the documentation content in chunks, let's put all this information in a vector index for easy retrieval."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"search_index = Vectara.from_texts(source_chunks, embedding=None)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Set Up LLM Chain with Custom Prompt\n",
|
||||
"\n",
|
||||
"Next, let's set up a simple LLM chain but give it a custom prompt for blog post generation. Note that the custom prompt is parameterized and takes two inputs: `context`, which will be the documents fetched from the vector search, and `topic`, which is given by the user."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chains import LLMChain\n",
|
||||
"\n",
|
||||
"prompt_template = \"\"\"Use the context below to write a 400 word blog post about the topic below:\n",
|
||||
" Context: {context}\n",
|
||||
" Topic: {topic}\n",
|
||||
" Blog post:\"\"\"\n",
|
||||
"\n",
|
||||
"PROMPT = PromptTemplate(template=prompt_template, input_variables=[\"context\", \"topic\"])\n",
|
||||
"\n",
|
||||
"llm = OpenAI(openai_api_key=os.environ[\"OPENAI_API_KEY\"], temperature=0)\n",
|
||||
"\n",
|
||||
"chain = LLMChain(llm=llm, prompt=PROMPT)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Generate Text\n",
|
||||
"\n",
|
||||
"Finally, we write a function to apply our inputs to the chain. The function takes an input parameter `topic`. We find the documents in the vector index that correspond to that `topic`, and use them as additional context in our simple LLM chain."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def generate_blog_post(topic):\n",
|
||||
" docs = search_index.similarity_search(topic, k=4)\n",
|
||||
" inputs = [{\"context\": doc.page_content, \"topic\": topic} for doc in docs]\n",
|
||||
" print(chain.apply(inputs))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[{'text': '\\n\\nWhen it comes to running Deno CLI tasks, environment variables can be a powerful tool for customizing the behavior of your tasks. With the Deno Task Definition interface, you can easily configure environment variables to be set when executing your tasks.\\n\\nThe Deno Task Definition interface is configured in a `tasks.json` within your workspace. It includes a `env` field, which allows you to specify any environment variables that should be set when executing the task. For example, if you wanted to set the `NODE_ENV` environment variable to `production` when running a Deno task, you could add the following to your `tasks.json`:\\n\\n```json\\n{\\n \"version\": \"2.0.0\",\\n \"tasks\": [\\n {\\n \"type\": \"deno\",\\n \"command\": \"run\",\\n \"args\": [\\n \"mod.ts\"\\n ],\\n \"env\": {\\n \"NODE_ENV\": \"production\"\\n },\\n \"problemMatcher\": [\\n \"$deno\"\\n ],\\n \"label\": \"deno: run\"\\n }\\n ]\\n}\\n```\\n\\nThe Deno language server and this extension also'}, {'text': '\\n\\nEnvironment variables are a great way to store and access data in your applications. They are especially useful when you need to store sensitive information such as API keys, passwords, and other credentials.\\n\\nDeno.env is a library that provides getter and setter methods for environment variables. This makes it easy to store and retrieve data from environment variables. For example, you can use the setter method to set a variable like this:\\n\\n```ts\\nDeno.env.set(\"FIREBASE_API_KEY\", \"examplekey123\");\\nDeno.env.set(\"FIREBASE_AUTH_DOMAIN\", \"firebasedomain.com\");\\n```\\n\\nAnd then you can use the getter method to retrieve the data like this:\\n\\n```ts\\nconsole.log(Deno.env.get(\"FIREBASE_API_KEY\")); // examplekey123\\nconsole.log(Deno.env.get(\"FIREBASE_AUTH_DOMAIN\")); // firebasedomain.com\\n```\\n\\nYou can also store environment variables in a `.env` file and retrieve them using `dotenv` in the standard'}, {'text': '\\n\\nEnvironment variables are a powerful tool for developers, allowing them to store and access data without hard-coding it into their applications. Deno, the secure JavaScript and TypeScript runtime, offers built-in support for environment variables with the `Deno.env` API.\\n\\nUsing `Deno.env` is simple. It has getter and setter methods that allow you to easily set and retrieve environment variables. For example, you can set the `FIREBASE_API_KEY` and `FIREBASE_AUTH_DOMAIN` environment variables like this:\\n\\n```ts\\nDeno.env.set(\"FIREBASE_API_KEY\", \"examplekey123\");\\nDeno.env.set(\"FIREBASE_AUTH_DOMAIN\", \"firebasedomain.com\");\\n```\\n\\nAnd then you can retrieve them like this:\\n\\n```ts\\nconsole.log(Deno.env.get(\"FIREBASE_API_KEY\")); // examplekey123\\nconsole.log(Deno.env.get(\"FIREBASE_AUTH_DOMAIN\")); // firebasedomain.com\\n```'}, {'text': '\\n\\nEnvironment variables are an important part of any programming language, and Deno is no exception. Environment variables are used to store information about the environment in which a program is running, such as the operating system, user preferences, and other settings. In Deno, environment variables are used to set up proxies, control the output of colors, and more.\\n\\nThe `NO_PROXY` environment variable is a de facto standard in Deno that indicates which hosts should bypass the proxy set in other environment variables. This is useful for developers who want to access certain resources without having to go through a proxy. For more information on this standard, you can check out the website no-color.org.\\n\\nThe `Deno.noColor` environment variable is another important environment variable in Deno. This variable is used to control the output of colors in the Deno terminal. By setting this variable to true, you can disable the output of colors in the terminal. This can be useful for developers who want to focus on the output of their code without being distracted by the colors.\\n\\nFinally, the `Deno.env` environment variable is used to access the environment variables set in the Deno runtime. This variable is useful for developers who want'}]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"generate_blog_post(\"environment variables\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"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.10.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
@ -5,12 +5,19 @@
|
||||
"id": "13afcae7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Vectara\n",
|
||||
"# Vectara self-querying \n",
|
||||
"\n",
|
||||
">[Vectara](https://docs.vectara.com/docs/) is a GenAI platform for developers. It provides a simple API to build Grounded Generation\n",
|
||||
">(aka Retrieval-augmented-generation or RAG) applications.\n",
|
||||
">[Vectara](https://vectara.com/) is the trusted GenAI platform that provides an easy-to-use API for document indexing and querying. \n",
|
||||
"\n",
|
||||
"In the notebook, we'll demo the `SelfQueryRetriever` wrapped around a Vectara vector store. "
|
||||
"Vectara provides an end-to-end managed service for Retrieval Augmented Generation or [RAG](https://vectara.com/grounded-generation/), which includes:\n",
|
||||
"1. A way to extract text from document files and chunk them into sentences.\n",
|
||||
"2. The state-of-the-art [Boomerang](https://vectara.com/how-boomerang-takes-retrieval-augmented-generation-to-the-next-level-via-grounded-generation/) embeddings model. Each text chunk is encoded into a vector embedding using Boomerang, and stored in the Vectara internal knowledge (vector+text) store\n",
|
||||
"3. A query service that automatically encodes the query into embedding, and retrieves the most relevant text segments (including support for [Hybrid Search](https://docs.vectara.com/docs/api-reference/search-apis/lexical-matching) and [MMR](https://vectara.com/get-diverse-results-and-comprehensive-summaries-with-vectaras-mmr-reranker/))\n",
|
||||
"4. An option to create [generative summary](https://docs.vectara.com/docs/learn/grounded-generation/grounded-generation-overview), based on the retrieved documents, including citations.\n",
|
||||
"\n",
|
||||
"See the [Vectara API documentation](https://docs.vectara.com/docs/) for more information on how to use the API.\n",
|
||||
"\n",
|
||||
"This notebook shows how to use `SelfQueryRetriever` with Vectara."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -75,11 +82,14 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chains import ConversationalRetrievalChain\n",
|
||||
"from langchain.chains.query_constructor.base import AttributeInfo\n",
|
||||
"from langchain.document_loaders import TextLoader\n",
|
||||
"from langchain.embeddings import FakeEmbeddings\n",
|
||||
"from langchain.llms import OpenAI\n",
|
||||
"from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
|
||||
"from langchain.schema import Document\n",
|
||||
"from langchain.text_splitter import CharacterTextSplitter\n",
|
||||
"from langchain.vectorstores import Vectara"
|
||||
]
|
||||
},
|
||||
@ -197,29 +207,15 @@
|
||||
"id": "38a126e9",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/Users/ofer/dev/langchain/libs/langchain/langchain/chains/llm.py:278: UserWarning: The predict_and_parse method is deprecated, instead pass an output parser directly to LLMChain.\n",
|
||||
" warnings.warn(\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"query='dinosaur' filter=None limit=None\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[Document(page_content='A bunch of scientists bring back dinosaurs and mayhem breaks loose', metadata={'lang': 'eng', 'offset': '0', 'len': '66', 'year': '1993', 'rating': '7.7', 'genre': 'science fiction', 'source': 'langchain'}),\n",
|
||||
" Document(page_content='Toys come alive and have a blast doing so', metadata={'lang': 'eng', 'offset': '0', 'len': '41', 'year': '1995', 'genre': 'animated', 'source': 'langchain'}),\n",
|
||||
" Document(page_content='Three men walk into the Zone, three men walk out of the Zone', metadata={'lang': 'eng', 'offset': '0', 'len': '60', 'year': '1979', 'rating': '9.9', 'director': 'Andrei Tarkovsky', 'genre': 'science fiction', 'source': 'langchain'}),\n",
|
||||
" Document(page_content='A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception reused the idea', metadata={'lang': 'eng', 'offset': '0', 'len': '116', 'year': '2006', 'director': 'Satoshi Kon', 'rating': '8.6', 'source': 'langchain'}),\n",
|
||||
" Document(page_content='Leo DiCaprio gets lost in a dream within a dream within a dream within a ...', metadata={'lang': 'eng', 'offset': '0', 'len': '76', 'year': '2010', 'director': 'Christopher Nolan', 'rating': '8.2', 'source': 'langchain'}),\n",
|
||||
" Document(page_content='A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception reused the idea', metadata={'lang': 'eng', 'offset': '0', 'len': '116', 'year': '2006', 'director': 'Satoshi Kon', 'rating': '8.6', 'source': 'langchain'})]"
|
||||
" Document(page_content='A bunch of normal-sized women are supremely wholesome and some men pine after them', metadata={'lang': 'eng', 'offset': '0', 'len': '82', 'year': '2019', 'director': 'Greta Gerwig', 'rating': '8.3', 'source': 'langchain'}),\n",
|
||||
" Document(page_content='Three men walk into the Zone, three men walk out of the Zone', metadata={'lang': 'eng', 'offset': '0', 'len': '60', 'year': '1979', 'rating': '9.9', 'director': 'Andrei Tarkovsky', 'genre': 'science fiction', 'source': 'langchain'})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
@ -238,18 +234,11 @@
|
||||
"id": "fc3f1e6e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"query=' ' filter=Comparison(comparator=<Comparator.GT: 'gt'>, attribute='rating', value=8.5) limit=None\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[Document(page_content='Three men walk into the Zone, three men walk out of the Zone', metadata={'lang': 'eng', 'offset': '0', 'len': '60', 'year': '1979', 'rating': '9.9', 'director': 'Andrei Tarkovsky', 'genre': 'science fiction', 'source': 'langchain'}),\n",
|
||||
" Document(page_content='A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception reused the idea', metadata={'lang': 'eng', 'offset': '0', 'len': '116', 'year': '2006', 'director': 'Satoshi Kon', 'rating': '8.6', 'source': 'langchain'})]"
|
||||
"[Document(page_content='A psychologist / detective gets lost in a series of dreams within dreams within dreams and Inception reused the idea', metadata={'lang': 'eng', 'offset': '0', 'len': '116', 'year': '2006', 'director': 'Satoshi Kon', 'rating': '8.6', 'source': 'langchain'}),\n",
|
||||
" Document(page_content='Three men walk into the Zone, three men walk out of the Zone', metadata={'lang': 'eng', 'offset': '0', 'len': '60', 'year': '1979', 'rating': '9.9', 'director': 'Andrei Tarkovsky', 'genre': 'science fiction', 'source': 'langchain'})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
@ -268,13 +257,6 @@
|
||||
"id": "b19d4da0",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"query='women' filter=Comparison(comparator=<Comparator.EQ: 'eq'>, attribute='director', value='Greta Gerwig') limit=None\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
@ -297,13 +279,6 @@
|
||||
"id": "f900e40e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"query=' ' filter=Operation(operator=<Operator.AND: 'and'>, arguments=[Comparison(comparator=<Comparator.GTE: 'gte'>, attribute='rating', value=8.5), Comparison(comparator=<Comparator.EQ: 'eq'>, attribute='genre', value='science fiction')]) limit=None\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
@ -328,13 +303,6 @@
|
||||
"id": "12a51522",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"query='toys' filter=Operation(operator=<Operator.AND: 'and'>, arguments=[Comparison(comparator=<Comparator.GT: 'gt'>, attribute='year', value=1990), Comparison(comparator=<Comparator.LT: 'lt'>, attribute='year', value=2005), Comparison(comparator=<Comparator.EQ: 'eq'>, attribute='genre', value='animated')]) limit=None\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
@ -392,13 +360,6 @@
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"query='dinosaur' filter=None limit=2\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
@ -433,7 +394,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
"version": "3.10.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
@ -7,16 +7,17 @@
|
||||
"source": [
|
||||
"# Vectara\n",
|
||||
"\n",
|
||||
">[Vectara](https://vectara.com/) is a API platform for building GenAI applications. It provides an easy-to-use API for document indexing and querying that is managed by Vectara and is optimized for performance and accuracy. \n",
|
||||
"See the [Vectara API documentation ](https://docs.vectara.com/docs/) for more information on how to use the API.\n",
|
||||
">[Vectara](https://vectara.com/) is the trusted GenAI platform that provides an easy-to-use API for document indexing and querying. \n",
|
||||
"\n",
|
||||
"This notebook shows how to use functionality related to the `Vectara`'s integration with langchain.\n",
|
||||
"Note that unlike many other integrations in this category, Vectara provides an end-to-end managed service for [Grounded Generation](https://vectara.com/grounded-generation/) (aka retrieval augmented generation), which includes:\n",
|
||||
"Vectara provides an end-to-end managed service for Retrieval Augmented Generation or [RAG](https://vectara.com/grounded-generation/), which includes:\n",
|
||||
"1. A way to extract text from document files and chunk them into sentences.\n",
|
||||
"2. Its own embeddings model and vector store - each text segment is encoded into a vector embedding and stored in the Vectara internal vector store\n",
|
||||
"3. A query service that automatically encodes the query into embedding, and retrieves the most relevant text segments (including support for [Hybrid Search](https://docs.vectara.com/docs/api-reference/search-apis/lexical-matching))\n",
|
||||
"2. The state-of-the-art [Boomerang](https://vectara.com/how-boomerang-takes-retrieval-augmented-generation-to-the-next-level-via-grounded-generation/) embeddings model. Each text chunk is encoded into a vector embedding using Boomerang, and stored in the Vectara internal knowledge (vector+text) store\n",
|
||||
"3. A query service that automatically encodes the query into embedding, and retrieves the most relevant text segments (including support for [Hybrid Search](https://docs.vectara.com/docs/api-reference/search-apis/lexical-matching) and [MMR](https://vectara.com/get-diverse-results-and-comprehensive-summaries-with-vectaras-mmr-reranker/))\n",
|
||||
"4. An option to create [generative summary](https://docs.vectara.com/docs/learn/grounded-generation/grounded-generation-overview), based on the retrieved documents, including citations.\n",
|
||||
"\n",
|
||||
"All of these are supported in this LangChain integration."
|
||||
"See the [Vectara API documentation](https://docs.vectara.com/docs/) for more information on how to use the API.\n",
|
||||
"\n",
|
||||
"This notebook shows how to use the basic retrieval functionality, when utilizing Vectara just as a Vector Store (without summarization), incuding: `similarity_search` and `similarity_search_with_score` as well as using the LangChain `as_retriever` functionality."
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -26,8 +27,8 @@
|
||||
"source": [
|
||||
"# Setup\n",
|
||||
"\n",
|
||||
"You will need a Vectara account to use Vectara with LangChain. To get started, use the following steps (see our [quickstart](https://docs.vectara.com/docs/quickstart) guide):\n",
|
||||
"1. [Sign up](https://vectara.com/integrations/langchain) for a Vectara account if you don't already have one. Once you have completed your sign up you will have a Vectara customer ID. You can find your customer ID by clicking on your name, on the top-right of the Vectara console window.\n",
|
||||
"You will need a Vectara account to use Vectara with LangChain. To get started, use the following steps:\n",
|
||||
"1. [Sign up](https://www.vectara.com/integrations/langchain) for a Vectara account if you don't already have one. Once you have completed your sign up you will have a Vectara customer ID. You can find your customer ID by clicking on your name, on the top-right of the Vectara console window.\n",
|
||||
"2. Within your account you can create one or more corpora. Each corpus represents an area that stores text data upon ingest from input documents. To create a corpus, use the **\"Create Corpus\"** button. You then provide a name to your corpus as well as a description. Optionally you can define filtering attributes and apply some advanced options. If you click on your created corpus, you can see its name and corpus ID right on the top.\n",
|
||||
"3. Next you'll need to create API keys to access the corpus. Click on the **\"Authorization\"** tab in the corpus view and then the **\"Create API Key\"** button. Give your key a name, and choose whether you want query only or query+index for your key. Click \"Create\" and you now have an active API key. Keep this key confidential. \n",
|
||||
"\n",
|
||||
@ -47,7 +48,7 @@
|
||||
"os.environ[\"VECTARA_API_KEY\"] = getpass.getpass(\"Vectara API Key:\")\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"1. Provide them as arguments when creating the Vectara vectorstore object:\n",
|
||||
"2. Add them to the Vectara vectorstore constructor:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"vectorstore = Vectara(\n",
|
||||
@ -65,44 +66,31 @@
|
||||
"source": [
|
||||
"## Connecting to Vectara from LangChain\n",
|
||||
"\n",
|
||||
"In this example, we assume that you've created an account and a corpus, and added your VECTARA_CUSTOMER_ID, VECTARA_CORPUS_ID and VECTARA_API_KEY (created with permissions for both indexing and query) as environment variables.\n",
|
||||
"\n",
|
||||
"The corpus has 3 fields defined as metadata for filtering:\n",
|
||||
"\n",
|
||||
"* url: a string field containing the source URL of the document (where relevant)\n",
|
||||
"* speech: a string field containing the name of the speech\n",
|
||||
"* author: the name of the author\n",
|
||||
"\n",
|
||||
"Let's start by ingesting 3 documents into the corpus:\n",
|
||||
"1. The State of the Union speech from 2022, available in the LangChain repository as a text file\n",
|
||||
"2. The \"I have a dream\" speech by Dr. Kind\n",
|
||||
"3. The \"We shall Fight on the Beaches\" speech by Winston Churchil"
|
||||
"To get started, let's ingest the documents using the from_documents() method.\n",
|
||||
"We assume here that you've added your VECTARA_CUSTOMER_ID, VECTARA_CORPUS_ID and query+indexing VECTARA_API_KEY as environment variables."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": 1,
|
||||
"id": "04a1f1a0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chains.query_constructor.base import AttributeInfo\n",
|
||||
"from langchain.document_loaders import TextLoader\n",
|
||||
"from langchain.embeddings import FakeEmbeddings\n",
|
||||
"from langchain.llms import OpenAI\n",
|
||||
"from langchain.retrievers.self_query.base import SelfQueryRetriever\n",
|
||||
"from langchain.embeddings.fake import FakeEmbeddings\n",
|
||||
"from langchain.text_splitter import CharacterTextSplitter\n",
|
||||
"from langchain.vectorstores import Vectara"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 2,
|
||||
"id": "be0a4973",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"loader = TextLoader(\"../../modules/state_of_the_union.txt\")\n",
|
||||
"loader = TextLoader(\"state_of_the_union.txt\")\n",
|
||||
"documents = loader.load()\n",
|
||||
"text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)\n",
|
||||
"docs = text_splitter.split_documents(documents)"
|
||||
@ -110,7 +98,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 3,
|
||||
"id": "8429667e",
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
@ -124,7 +112,7 @@
|
||||
"vectara = Vectara.from_documents(\n",
|
||||
" docs,\n",
|
||||
" embedding=FakeEmbeddings(size=768),\n",
|
||||
" doc_metadata={\"speech\": \"state-of-the-union\", \"author\": \"Biden\"},\n",
|
||||
" doc_metadata={\"speech\": \"state-of-the-union\"},\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
@ -144,7 +132,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 4,
|
||||
"id": "85ef3468",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@ -156,16 +144,14 @@
|
||||
" [\n",
|
||||
" \"https://www.gilderlehrman.org/sites/default/files/inline-pdfs/king.dreamspeech.excerpts.pdf\",\n",
|
||||
" \"I-have-a-dream\",\n",
|
||||
" \"Dr. King\",\n",
|
||||
" ],\n",
|
||||
" [\n",
|
||||
" \"https://www.parkwayschools.net/cms/lib/MO01931486/Centricity/Domain/1578/Churchill_Beaches_Speech.pdf\",\n",
|
||||
" \"we shall fight on the beaches\",\n",
|
||||
" \"Churchil\",\n",
|
||||
" ],\n",
|
||||
"]\n",
|
||||
"files_list = []\n",
|
||||
"for url, _, _ in urls:\n",
|
||||
"for url, _ in urls:\n",
|
||||
" name = tempfile.NamedTemporaryFile().name\n",
|
||||
" urllib.request.urlretrieve(url, name)\n",
|
||||
" files_list.append(name)\n",
|
||||
@ -173,9 +159,7 @@
|
||||
"docsearch: Vectara = Vectara.from_files(\n",
|
||||
" files=files_list,\n",
|
||||
" embedding=FakeEmbeddings(size=768),\n",
|
||||
" metadatas=[\n",
|
||||
" {\"url\": url, \"speech\": title, \"author\": author} for url, title, author in urls\n",
|
||||
" ],\n",
|
||||
" metadatas=[{\"url\": url, \"speech\": title} for url, title in urls],\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
@ -196,7 +180,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 5,
|
||||
"id": "a8c513ab",
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
@ -213,6 +197,36 @@
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "53324492",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[Document(page_content='And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '596', 'len': '97', 'speech': 'state-of-the-union'}),\n",
|
||||
" Document(page_content='In this struggle as President Zelenskyy said in his speech to the European Parliament “Light will win over darkness.”', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '141', 'len': '117', 'speech': 'state-of-the-union'}),\n",
|
||||
" Document(page_content='As Ohio Senator Sherrod Brown says, “It’s time to bury the label “Rust Belt.”', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '0', 'len': '77', 'speech': 'state-of-the-union'}),\n",
|
||||
" Document(page_content='Last month, I announced our plan to supercharge \\nthe Cancer Moonshot that President Obama asked me to lead six years ago.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '0', 'len': '122', 'speech': 'state-of-the-union'}),\n",
|
||||
" Document(page_content='He thought he could roll into Ukraine and the world would roll over.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '664', 'len': '68', 'speech': 'state-of-the-union'}),\n",
|
||||
" Document(page_content='That’s why one of the first things I did as President was fight to pass the American Rescue Plan.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '314', 'len': '97', 'speech': 'state-of-the-union'}),\n",
|
||||
" Document(page_content='And he thought he could divide us at home.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '160', 'len': '42', 'speech': 'state-of-the-union'}),\n",
|
||||
" Document(page_content='He met the Ukrainian people.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '788', 'len': '28', 'speech': 'state-of-the-union'}),\n",
|
||||
" Document(page_content='He thought the West and NATO wouldn’t respond.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '113', 'len': '46', 'speech': 'state-of-the-union'}),\n",
|
||||
" Document(page_content='In this Capitol, generation after generation, Americans have debated great questions amid great strife, and have done great things.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '772', 'len': '131', 'speech': 'state-of-the-union'})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"found_docs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
@ -284,7 +298,7 @@
|
||||
"text": [
|
||||
"Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence. A former top litigator in private practice.\n",
|
||||
"\n",
|
||||
"Score: 0.8299499\n"
|
||||
"Score: 0.74179757\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -330,14 +344,14 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "3e22949f",
|
||||
"id": "29f465e5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"With this threshold of 0.2 we have 5 documents\n"
|
||||
"With this threshold of 0.2 we have 10 documents\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@ -354,17 +368,104 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "691a82d6",
|
||||
"id": "471112c0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Vectara as a Retriever\n",
|
||||
"MMR is an important retrieval capability for many applications, whereby search results feeding your GenAI application are reranked to improve diversity of results. \n",
|
||||
"\n",
|
||||
"Vectara, as all the other LangChain vectorstores, is most often used as a LangChain Retriever:"
|
||||
"Let's see how that works with Vectara:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "5d597e91",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Economic assistance.\n",
|
||||
"\n",
|
||||
"Grow the workforce. Build the economy from the bottom up \n",
|
||||
"and the middle out, not from the top down.\n",
|
||||
"\n",
|
||||
"When we invest in our workers, when we build the economy from the bottom up and the middle out together, we can do something we haven’t done in a long time: build a better America.\n",
|
||||
"\n",
|
||||
"Our economy grew at a rate of 5.7% last year, the strongest growth in nearly 40 years, the first step in bringing fundamental change to an economy that hasn’t worked for the working people of this nation for too long.\n",
|
||||
"\n",
|
||||
"Economists call it “increasing the productive capacity of our economy.”\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"query = \"state of the economy\"\n",
|
||||
"found_docs = vectara.similarity_search(\n",
|
||||
" query,\n",
|
||||
" n_sentence_context=0,\n",
|
||||
" filter=\"doc.speech = 'state-of-the-union'\",\n",
|
||||
" k=5,\n",
|
||||
" mmr_config={\"is_enabled\": True, \"mmr_k\": 50, \"diversity_bias\": 0.0},\n",
|
||||
")\n",
|
||||
"print(\"\\n\\n\".join([x.page_content for x in found_docs]))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "be2b2326",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Economic assistance.\n",
|
||||
"\n",
|
||||
"The Russian stock market has lost 40% of its value and trading remains suspended.\n",
|
||||
"\n",
|
||||
"But that trickle-down theory led to weaker economic growth, lower wages, bigger deficits, and the widest gap between those at the top and everyone else in nearly a century.\n",
|
||||
"\n",
|
||||
"In state after state, new laws have been passed, not only to suppress the vote, but to subvert entire elections.\n",
|
||||
"\n",
|
||||
"The federal government spends about $600 Billion a year to keep the country safe and secure.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"query = \"state of the economy\"\n",
|
||||
"found_docs = vectara.similarity_search(\n",
|
||||
" query,\n",
|
||||
" n_sentence_context=0,\n",
|
||||
" filter=\"doc.speech = 'state-of-the-union'\",\n",
|
||||
" k=5,\n",
|
||||
" mmr_config={\"is_enabled\": True, \"mmr_k\": 50, \"diversity_bias\": 1.0},\n",
|
||||
")\n",
|
||||
"print(\"\\n\\n\".join([x.page_content for x in found_docs]))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "10c1427e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"As you can see, in the first example diversity_bias was set to 0.0 (equivalent to diversity reranking disabled), which resulted in a the top-5 most relevant documents. With diversity_bias=1.0 we maximize diversity and as you can see the resulting top documents are much more diverse in their semantic meanings."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "691a82d6",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Vectara as a Retriever\n",
|
||||
"\n",
|
||||
"Finally let's see how to use Vectara with the `as_retriever()` interface:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "9427195f",
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
@ -376,10 +477,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"VectaraRetriever(tags=['Vectara'], metadata=None, vectorstore=<langchain.vectorstores.vectara.Vectara object at 0x13b15e9b0>, search_type='similarity', search_kwargs={'lambda_val': 0.025, 'k': 5, 'filter': '', 'n_sentence_context': '2'})"
|
||||
"VectorStoreRetriever(tags=['Vectara'], vectorstore=<langchain.vectorstores.vectara.Vectara object at 0x109a3c760>)"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -391,22 +492,23 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"execution_count": 15,
|
||||
"id": "f3c70c31",
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2023-04-04T10:51:26.495652Z",
|
||||
"start_time": "2023-04-04T10:51:26.046407Z"
|
||||
}
|
||||
},
|
||||
"scrolled": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Document(page_content='Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence. A former top litigator in private practice.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '596', 'len': '97', 'speech': 'state-of-the-union', 'author': 'Biden'})"
|
||||
"Document(page_content='Justice Breyer, thank you for your service. One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence. A former top litigator in private practice.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '596', 'len': '97', 'speech': 'state-of-the-union'})"
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@ -416,118 +518,10 @@
|
||||
"retriever.get_relevant_documents(query)[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e944c26a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Using Vectara as a SelfQuery Retriever"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "8be674de",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"metadata_field_info = [\n",
|
||||
" AttributeInfo(\n",
|
||||
" name=\"speech\",\n",
|
||||
" description=\"what name of the speech\",\n",
|
||||
" type=\"string or list[string]\",\n",
|
||||
" ),\n",
|
||||
" AttributeInfo(\n",
|
||||
" name=\"author\",\n",
|
||||
" description=\"author of the speech\",\n",
|
||||
" type=\"string or list[string]\",\n",
|
||||
" ),\n",
|
||||
"]\n",
|
||||
"document_content_description = \"the text of the speech\"\n",
|
||||
"\n",
|
||||
"vectordb = Vectara()\n",
|
||||
"llm = OpenAI(temperature=0)\n",
|
||||
"retriever = SelfQueryRetriever.from_llm(\n",
|
||||
" llm, vectara, document_content_description, metadata_field_info, verbose=True\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "f8938999",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/Users/ofer/dev/langchain/libs/langchain/langchain/chains/llm.py:278: UserWarning: The predict_and_parse method is deprecated, instead pass an output parser directly to LLMChain.\n",
|
||||
" warnings.warn(\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"query='freedom' filter=Comparison(comparator=<Comparator.EQ: 'eq'>, attribute='author', value='Biden') limit=None\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[Document(page_content='Well I know this nation. We will meet the test. To protect freedom and liberty, to expand fairness and opportunity. We will save democracy. As hard as these times have been, I am more optimistic about America today than I have been my whole life.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '346', 'len': '67', 'speech': 'state-of-the-union', 'author': 'Biden'}),\n",
|
||||
" Document(page_content='To our fellow Ukrainian Americans who forge a deep bond that connects our two nations we stand with you. Putin may circle Kyiv with tanks, but he will never gain the hearts and souls of the Ukrainian people. He will never extinguish their love of freedom. He will never weaken the resolve of the free world. We meet tonight in an America that has lived through two of the hardest years this nation has ever faced.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '740', 'len': '47', 'speech': 'state-of-the-union', 'author': 'Biden'}),\n",
|
||||
" Document(page_content='But most importantly as Americans. With a duty to one another to the American people to the Constitution. And with an unwavering resolve that freedom will always triumph over tyranny. Six days ago, Russia’s Vladimir Putin sought to shake the foundations of the free world thinking he could make it bend to his menacing ways. But he badly miscalculated.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '413', 'len': '77', 'speech': 'state-of-the-union', 'author': 'Biden'}),\n",
|
||||
" Document(page_content='We can do this. \\n\\nMy fellow Americans—tonight , we have gathered in a sacred space—the citadel of our democracy. In this Capitol, generation after generation, Americans have debated great questions amid great strife, and have done great things. We have fought for freedom, expanded liberty, defeated totalitarianism and terror. And built the strongest, freest, and most prosperous nation the world has ever known. Now is the hour. \\n\\nOur moment of responsibility.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '906', 'len': '82', 'speech': 'state-of-the-union', 'author': 'Biden'}),\n",
|
||||
" Document(page_content='In state after state, new laws have been passed, not only to suppress the vote, but to subvert entire elections. We cannot let this happen. Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections.', metadata={'source': 'langchain', 'lang': 'eng', 'offset': '0', 'len': '63', 'speech': 'state-of-the-union', 'author': 'Biden'})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"retriever.get_relevant_documents(\"what did Biden say about the freedom?\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "a97037fb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"query='freedom' filter=Comparison(comparator=<Comparator.EQ: 'eq'>, attribute='author', value='Dr. King') limit=None\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[Document(page_content='And if America is to be a great nation, this must become true. So\\nlet freedom ring from the prodigious hilltops of New Hampshire. Let freedom ring from the mighty\\nmountains of New York. Let freedom ring from the heightening Alleghenies of Pennsylvania. Let\\nfreedom ring from the snowcapped Rockies of Colorado.', metadata={'lang': 'eng', 'section': '3', 'offset': '1534', 'len': '55', 'CreationDate': '1424880481', 'Producer': 'Adobe PDF Library 10.0', 'Author': 'Sasha Rolon-Pereira', 'Title': 'Martin Luther King Jr.pdf', 'Creator': 'Acrobat PDFMaker 10.1 for Word', 'ModDate': '1424880524', 'url': 'https://www.gilderlehrman.org/sites/default/files/inline-pdfs/king.dreamspeech.excerpts.pdf', 'speech': 'I-have-a-dream', 'author': 'Dr. King', 'title': 'Martin Luther King Jr.pdf'}),\n",
|
||||
" Document(page_content='And if America is to be a great nation, this must become true. So\\nlet freedom ring from the prodigious hilltops of New Hampshire. Let freedom ring from the mighty\\nmountains of New York. Let freedom ring from the heightening Alleghenies of Pennsylvania. Let\\nfreedom ring from the snowcapped Rockies of Colorado.', metadata={'lang': 'eng', 'section': '3', 'offset': '1534', 'len': '55', 'CreationDate': '1424880481', 'Producer': 'Adobe PDF Library 10.0', 'Author': 'Sasha Rolon-Pereira', 'Title': 'Martin Luther King Jr.pdf', 'Creator': 'Acrobat PDFMaker 10.1 for Word', 'ModDate': '1424880524', 'url': 'https://www.gilderlehrman.org/sites/default/files/inline-pdfs/king.dreamspeech.excerpts.pdf', 'speech': 'I-have-a-dream', 'author': 'Dr. King', 'title': 'Martin Luther King Jr.pdf'}),\n",
|
||||
" Document(page_content='Let freedom ring from the curvaceous slopes of\\nCalifornia. But not only that. Let freedom ring from Stone Mountain of Georgia. Let freedom ring from Lookout\\nMountain of Tennessee. Let freedom ring from every hill and molehill of Mississippi, from every\\nmountain side. Let freedom ring . . .\\nWhen we allow freedom to ring—when we let it ring from every city and every hamlet, from every state\\nand every city, we will be able to speed up that day when all of God’s children, black men and white\\nmen, Jews and Gentiles, Protestants and Catholics, will be able to join hands and sing in the words of the\\nold Negro spiritual, “Free at last, Free at last, Great God a-mighty, We are free at last.”', metadata={'lang': 'eng', 'section': '3', 'offset': '1842', 'len': '52', 'CreationDate': '1424880481', 'Producer': 'Adobe PDF Library 10.0', 'Author': 'Sasha Rolon-Pereira', 'Title': 'Martin Luther King Jr.pdf', 'Creator': 'Acrobat PDFMaker 10.1 for Word', 'ModDate': '1424880524', 'url': 'https://www.gilderlehrman.org/sites/default/files/inline-pdfs/king.dreamspeech.excerpts.pdf', 'speech': 'I-have-a-dream', 'author': 'Dr. King', 'title': 'Martin Luther King Jr.pdf'}),\n",
|
||||
" Document(page_content='Let freedom ring from the curvaceous slopes of\\nCalifornia. But not only that. Let freedom ring from Stone Mountain of Georgia. Let freedom ring from Lookout\\nMountain of Tennessee. Let freedom ring from every hill and molehill of Mississippi, from every\\nmountain side. Let freedom ring . . .\\nWhen we allow freedom to ring—when we let it ring from every city and every hamlet, from every state\\nand every city, we will be able to speed up that day when all of God’s children, black men and white\\nmen, Jews and Gentiles, Protestants and Catholics, will be able to join hands and sing in the words of the\\nold Negro spiritual, “Free at last, Free at last, Great God a-mighty, We are free at last.”', metadata={'lang': 'eng', 'section': '3', 'offset': '1842', 'len': '52', 'CreationDate': '1424880481', 'Producer': 'Adobe PDF Library 10.0', 'Author': 'Sasha Rolon-Pereira', 'Title': 'Martin Luther King Jr.pdf', 'Creator': 'Acrobat PDFMaker 10.1 for Word', 'ModDate': '1424880524', 'url': 'https://www.gilderlehrman.org/sites/default/files/inline-pdfs/king.dreamspeech.excerpts.pdf', 'speech': 'I-have-a-dream', 'author': 'Dr. King', 'title': 'Martin Luther King Jr.pdf'}),\n",
|
||||
" Document(page_content='Let freedom ring from the mighty\\nmountains of New York. Let freedom ring from the heightening Alleghenies of Pennsylvania. Let\\nfreedom ring from the snowcapped Rockies of Colorado. Let freedom ring from the curvaceous slopes of\\nCalifornia. But not only that. Let freedom ring from Stone Mountain of Georgia.', metadata={'lang': 'eng', 'section': '3', 'offset': '1657', 'len': '57', 'CreationDate': '1424880481', 'Producer': 'Adobe PDF Library 10.0', 'Author': 'Sasha Rolon-Pereira', 'Title': 'Martin Luther King Jr.pdf', 'Creator': 'Acrobat PDFMaker 10.1 for Word', 'ModDate': '1424880524', 'url': 'https://www.gilderlehrman.org/sites/default/files/inline-pdfs/king.dreamspeech.excerpts.pdf', 'speech': 'I-have-a-dream', 'author': 'Dr. King', 'title': 'Martin Luther King Jr.pdf'})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"retriever.get_relevant_documents(\"what did Dr. King say about the freedom?\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f6d17e90",
|
||||
"id": "2300e785",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from hashlib import md5
|
||||
from typing import Any, Iterable, List, Optional, Tuple, Type
|
||||
|
||||
@ -15,6 +16,65 @@ from langchain_core.vectorstores import VectorStore, VectorStoreRetriever
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class SummaryConfig:
|
||||
"""
|
||||
is_enabled: True if summary is enabled, False otherwise
|
||||
max_results: maximum number of results to summarize
|
||||
response_lang: requested language for the summary
|
||||
"""
|
||||
|
||||
is_enabled: bool = False
|
||||
max_results: int = 7
|
||||
response_lang: str = "eng"
|
||||
|
||||
|
||||
@dataclass
|
||||
class MMRConfig:
|
||||
"""
|
||||
is_enabled: True if MMR is enabled, False otherwise
|
||||
mmr_k: number of results to fetch for MMR, defaults to 50
|
||||
diversity_bias: number between 0 and 1 that determines the degree
|
||||
of diversity among the results with 0 corresponding
|
||||
to minimum diversity and 1 to maximum diversity.
|
||||
Defaults to 0.3.
|
||||
Note: diversity_bias is equivalent 1-lambda_mult
|
||||
where lambda_mult is the value often used in max_marginal_relevance_search()
|
||||
We chose to use that since we believe it's more intuitive to the user.
|
||||
"""
|
||||
|
||||
is_enabled: bool = False
|
||||
mmr_k: int = 50
|
||||
diversity_bias: float = 0.3
|
||||
|
||||
|
||||
@dataclass
|
||||
class VectaraQueryConfig:
|
||||
"""
|
||||
k: Number of Documents to return. Defaults to 10.
|
||||
lambda_val: lexical match parameter for hybrid search.
|
||||
filter Dictionary of argument(s) to filter on metadata. For example a
|
||||
filter can be "doc.rating > 3.0 and part.lang = 'deu'"} see
|
||||
https://docs.vectara.com/docs/search-apis/sql/filter-overview
|
||||
for more details.
|
||||
score_threshold: minimal score threshold for the result.
|
||||
If defined, results with score less than this value will be
|
||||
filtered out.
|
||||
n_sentence_context: number of sentences before/after the matching segment
|
||||
to add, defaults to 2
|
||||
mmr_config: MMRConfig configuration dataclass
|
||||
summary_config: SummaryConfig configuration dataclass
|
||||
"""
|
||||
|
||||
k: int = 10
|
||||
lambda_val: float = 0.0
|
||||
filter: str = ""
|
||||
score_threshold: Optional[float] = None
|
||||
n_sentence_context: int = 2
|
||||
mmr_config: MMRConfig = field(default_factory=MMRConfig)
|
||||
summary_config: SummaryConfig = field(default_factory=SummaryConfig)
|
||||
|
||||
|
||||
class Vectara(VectorStore):
|
||||
"""`Vectara API` vector store.
|
||||
|
||||
@ -23,7 +83,7 @@ class Vectara(VectorStore):
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_community.vectorstores import Vectara
|
||||
from langchain.vectorstores import Vectara
|
||||
|
||||
vectorstore = Vectara(
|
||||
vectara_customer_id=vectara_customer_id,
|
||||
@ -111,15 +171,20 @@ class Vectara(VectorStore):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _index_doc(self, doc: dict) -> str:
|
||||
def _index_doc(self, doc: dict, use_core_api: bool = False) -> str:
|
||||
request: dict[str, Any] = {}
|
||||
request["customer_id"] = self._vectara_customer_id
|
||||
request["corpus_id"] = self._vectara_corpus_id
|
||||
request["document"] = doc
|
||||
|
||||
api_endpoint = (
|
||||
"https://api.vectara.io/v1/core/index"
|
||||
if use_core_api
|
||||
else "https://api.vectara.io/v1/index"
|
||||
)
|
||||
response = self._session.post(
|
||||
headers=self._get_post_headers(),
|
||||
url="https://api.vectara.io/v1/index",
|
||||
url=api_endpoint,
|
||||
data=json.dumps(request),
|
||||
timeout=self.vectara_api_timeout,
|
||||
verify=True,
|
||||
@ -222,16 +287,20 @@ class Vectara(VectorStore):
|
||||
doc_metadata["source"] = "langchain"
|
||||
else:
|
||||
doc_metadata = {"source": "langchain"}
|
||||
|
||||
use_core_api = kwargs.get("use_core_api", False)
|
||||
section_key = "parts" if use_core_api else "section"
|
||||
doc = {
|
||||
"document_id": doc_id,
|
||||
"metadataJson": json.dumps(doc_metadata),
|
||||
"section": [
|
||||
section_key: [
|
||||
{"text": text, "metadataJson": json.dumps(md)}
|
||||
for text, md in zip(texts, metadatas)
|
||||
],
|
||||
}
|
||||
|
||||
success_str = self._index_doc(doc)
|
||||
success_str = self._index_doc(doc, use_core_api=use_core_api)
|
||||
|
||||
if success_str == "E_ALREADY_EXISTS":
|
||||
self._delete_doc(doc_id)
|
||||
self._index_doc(doc)
|
||||
@ -242,63 +311,66 @@ class Vectara(VectorStore):
|
||||
)
|
||||
return [doc_id]
|
||||
|
||||
def similarity_search_with_score(
|
||||
def vectara_query(
|
||||
self,
|
||||
query: str,
|
||||
k: int = 5,
|
||||
lambda_val: float = 0.025,
|
||||
filter: Optional[str] = None,
|
||||
score_threshold: Optional[float] = None,
|
||||
n_sentence_context: int = 2,
|
||||
config: VectaraQueryConfig,
|
||||
**kwargs: Any,
|
||||
) -> List[Tuple[Document, float]]:
|
||||
"""Return Vectara documents most similar to query, along with scores.
|
||||
"""Run a Vectara query
|
||||
|
||||
Args:
|
||||
query: Text to look up documents similar to.
|
||||
k: Number of Documents to return. Defaults to 5.
|
||||
lambda_val: lexical match parameter for hybrid search.
|
||||
filter: Dictionary of argument(s) to filter on metadata. For example a
|
||||
filter can be "doc.rating > 3.0 and part.lang = 'deu'"} see
|
||||
https://docs.vectara.com/docs/search-apis/sql/filter-overview
|
||||
for more details.
|
||||
score_threshold: minimal score threshold for the result.
|
||||
If defined, results with score less than this value will be
|
||||
filtered out.
|
||||
n_sentence_context: number of sentences before/after the matching segment
|
||||
to add, defaults to 2
|
||||
|
||||
config: VectaraQueryConfig object
|
||||
Returns:
|
||||
List of Documents most similar to the query and score for each.
|
||||
A list of k Documents matching the given query
|
||||
If summary is enabled, last document is the summary text with 'summary'=True
|
||||
"""
|
||||
data = json.dumps(
|
||||
{
|
||||
"query": [
|
||||
{
|
||||
"query": query,
|
||||
"start": 0,
|
||||
"num_results": k,
|
||||
"context_config": {
|
||||
"sentences_before": n_sentence_context,
|
||||
"sentences_after": n_sentence_context,
|
||||
},
|
||||
"corpus_key": [
|
||||
{
|
||||
"customer_id": self._vectara_customer_id,
|
||||
"corpus_id": self._vectara_corpus_id,
|
||||
"metadataFilter": filter,
|
||||
"lexical_interpolation_config": {"lambda": lambda_val},
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
if isinstance(config.mmr_config, dict):
|
||||
config.mmr_config = MMRConfig(**config.mmr_config)
|
||||
if isinstance(config.summary_config, dict):
|
||||
config.summary_config = SummaryConfig(**config.summary_config)
|
||||
|
||||
data = {
|
||||
"query": [
|
||||
{
|
||||
"query": query,
|
||||
"start": 0,
|
||||
"numResults": config.mmr_config.mmr_k
|
||||
if config.mmr_config.is_enabled
|
||||
else config.k,
|
||||
"contextConfig": {
|
||||
"sentencesBefore": config.n_sentence_context,
|
||||
"sentencesAfter": config.n_sentence_context,
|
||||
},
|
||||
"corpusKey": [
|
||||
{
|
||||
"customerId": self._vectara_customer_id,
|
||||
"corpusId": self._vectara_corpus_id,
|
||||
"metadataFilter": config.filter,
|
||||
"lexicalInterpolationConfig": {"lambda": config.lambda_val},
|
||||
}
|
||||
],
|
||||
}
|
||||
]
|
||||
}
|
||||
if config.mmr_config.is_enabled:
|
||||
data["query"][0]["rerankingConfig"] = {
|
||||
"rerankerId": 272725718,
|
||||
"mmrConfig": {"diversityBias": config.mmr_config.diversity_bias},
|
||||
}
|
||||
)
|
||||
if config.summary_config.is_enabled:
|
||||
data["query"][0]["summary"] = [
|
||||
{
|
||||
"maxSummarizedResults": config.summary_config.max_results,
|
||||
"responseLang": config.summary_config.response_lang,
|
||||
}
|
||||
]
|
||||
|
||||
response = self._session.post(
|
||||
headers=self._get_post_headers(),
|
||||
url="https://api.vectara.io/v1/query",
|
||||
data=data,
|
||||
data=json.dumps(data),
|
||||
timeout=self.vectara_api_timeout,
|
||||
)
|
||||
|
||||
@ -308,14 +380,15 @@ class Vectara(VectorStore):
|
||||
f"(code {response.status_code}, reason {response.reason}, details "
|
||||
f"{response.text})",
|
||||
)
|
||||
return []
|
||||
return [], ""
|
||||
|
||||
result = response.json()
|
||||
if score_threshold:
|
||||
|
||||
if config.score_threshold:
|
||||
responses = [
|
||||
r
|
||||
for r in result["responseSet"][0]["response"]
|
||||
if r["score"] > score_threshold
|
||||
if r["score"] > config.score_threshold
|
||||
]
|
||||
else:
|
||||
responses = result["responseSet"][0]["response"]
|
||||
@ -326,10 +399,12 @@ class Vectara(VectorStore):
|
||||
md = {m["name"]: m["value"] for m in x["metadata"]}
|
||||
doc_num = x["documentIndex"]
|
||||
doc_md = {m["name"]: m["value"] for m in documents[doc_num]["metadata"]}
|
||||
if "source" not in doc_md:
|
||||
doc_md["source"] = "vectara"
|
||||
md.update(doc_md)
|
||||
metadatas.append(md)
|
||||
|
||||
docs_with_score = [
|
||||
res = [
|
||||
(
|
||||
Document(
|
||||
page_content=x["text"],
|
||||
@ -340,43 +415,90 @@ class Vectara(VectorStore):
|
||||
for x, md in zip(responses, metadatas)
|
||||
]
|
||||
|
||||
return docs_with_score
|
||||
if config.mmr_config.is_enabled:
|
||||
res = res[: config.k]
|
||||
if config.summary_config.is_enabled:
|
||||
summary = result["responseSet"][0]["summary"][0]["text"]
|
||||
res.append(
|
||||
(Document(page_content=summary, metadata={"summary": True}), 0.0)
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
def similarity_search_with_score(
|
||||
self,
|
||||
query: str,
|
||||
**kwargs: Any,
|
||||
) -> List[Tuple[Document, float]]:
|
||||
"""Return Vectara documents most similar to query, along with scores.
|
||||
|
||||
Args:
|
||||
query: Text to look up documents similar to.
|
||||
k: Number of Documents to return. Defaults to 10.
|
||||
any other querying variable in VectaraQueryConfig like:
|
||||
- lambda_val: lexical match parameter for hybrid search.
|
||||
- filter: filter string
|
||||
- score_threshold: minimal score threshold for the result.
|
||||
- n_sentence_context: number of sentences before/after the matching segment
|
||||
- mmr_config: optional configuration for MMR (see MMRConfig dataclass)
|
||||
- summary_config: optional configuration for summary
|
||||
(see SummaryConfig dataclass)
|
||||
Returns:
|
||||
List of Documents most similar to the query and score for each.
|
||||
"""
|
||||
config = VectaraQueryConfig(**kwargs)
|
||||
docs = self.vectara_query(query, config)
|
||||
return docs
|
||||
|
||||
def similarity_search(
|
||||
self,
|
||||
query: str,
|
||||
k: int = 5,
|
||||
lambda_val: float = 0.025,
|
||||
filter: Optional[str] = None,
|
||||
n_sentence_context: int = 2,
|
||||
**kwargs: Any,
|
||||
) -> List[Document]:
|
||||
"""Return Vectara documents most similar to query, along with scores.
|
||||
|
||||
Args:
|
||||
query: Text to look up documents similar to.
|
||||
k: Number of Documents to return. Defaults to 5.
|
||||
filter: Dictionary of argument(s) to filter on metadata. For example a
|
||||
filter can be "doc.rating > 3.0 and part.lang = 'deu'"} see
|
||||
https://docs.vectara.com/docs/search-apis/sql/filter-overview for more
|
||||
details.
|
||||
n_sentence_context: number of sentences before/after the matching segment
|
||||
to add, defaults to 2
|
||||
any other querying variable in VectaraQueryConfig
|
||||
|
||||
Returns:
|
||||
List of Documents most similar to the query
|
||||
"""
|
||||
docs_and_scores = self.similarity_search_with_score(
|
||||
query,
|
||||
k=k,
|
||||
lambda_val=lambda_val,
|
||||
filter=filter,
|
||||
score_threshold=None,
|
||||
n_sentence_context=n_sentence_context,
|
||||
**kwargs,
|
||||
)
|
||||
return [doc for doc, _ in docs_and_scores]
|
||||
|
||||
def max_marginal_relevance_search(
|
||||
self,
|
||||
query: str,
|
||||
fetch_k: int = 50,
|
||||
lambda_mult: float = 0.5,
|
||||
**kwargs: Any,
|
||||
) -> List[Document]:
|
||||
"""Return docs selected using the maximal marginal relevance.
|
||||
Maximal marginal relevance optimizes for similarity to query AND diversity
|
||||
among selected documents.
|
||||
|
||||
Args:
|
||||
query: Text to look up documents similar to.
|
||||
k: Number of Documents to return. Defaults to 5.
|
||||
fetch_k: Number of Documents to fetch to pass to MMR algorithm.
|
||||
Defaults to 50
|
||||
lambda_mult: Number between 0 and 1 that determines the degree
|
||||
of diversity among the results with 0 corresponding
|
||||
to maximum diversity and 1 to minimum diversity.
|
||||
Defaults to 0.5.
|
||||
kwargs: any other querying variable in VectaraQueryConfig
|
||||
Returns:
|
||||
List of Documents selected by maximal marginal relevance.
|
||||
"""
|
||||
kwargs["mmr_config"] = MMRConfig(
|
||||
is_enabled=True, mmr_k=fetch_k, diversity_bias=1 - lambda_mult
|
||||
)
|
||||
return self.similarity_search(query, **kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_texts(
|
||||
cls: Type[Vectara],
|
||||
@ -390,7 +512,7 @@ class Vectara(VectorStore):
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_community.vectorstores import Vectara
|
||||
from langchain.vectorstores import Vectara
|
||||
vectara = Vectara.from_texts(
|
||||
texts,
|
||||
vectara_customer_id=customer_id,
|
||||
@ -422,7 +544,7 @@ class Vectara(VectorStore):
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_community.vectorstores import Vectara
|
||||
from langchain.vectorstores import Vectara
|
||||
vectara = Vectara.from_files(
|
||||
files_list,
|
||||
vectara_customer_id=customer_id,
|
||||
@ -436,11 +558,6 @@ class Vectara(VectorStore):
|
||||
vectara.add_files(files, metadatas)
|
||||
return vectara
|
||||
|
||||
def as_retriever(self, **kwargs: Any) -> VectaraRetriever:
|
||||
tags = kwargs.pop("tags", None) or []
|
||||
tags.extend(self._get_retriever_tags())
|
||||
return VectaraRetriever(vectorstore=self, search_kwargs=kwargs, tags=tags)
|
||||
|
||||
|
||||
class VectaraRetriever(VectorStoreRetriever):
|
||||
"""Retriever class for `Vectara`."""
|
||||
|
@ -1,9 +1,11 @@
|
||||
import tempfile
|
||||
import urllib.request
|
||||
|
||||
import pytest
|
||||
from langchain_core.documents import Document
|
||||
|
||||
from langchain_community.vectorstores.vectara import Vectara
|
||||
# from langchain_community.vectorstores.vectara import Vectara, SummaryConfig
|
||||
from langchain_community.vectorstores.vectara import SummaryConfig, Vectara
|
||||
from tests.integration_tests.vectorstores.fake_embeddings import FakeEmbeddings
|
||||
|
||||
#
|
||||
@ -22,16 +24,16 @@ def get_abbr(s: str) -> str:
|
||||
return "".join(first_letters) # Join the first letters into a single string
|
||||
|
||||
|
||||
def test_vectara_add_documents() -> None:
|
||||
"""Test end to end construction and search."""
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def vectara1():
|
||||
# Set up code
|
||||
# create a new Vectara instance
|
||||
docsearch: Vectara = Vectara()
|
||||
vectara1: Vectara = Vectara()
|
||||
|
||||
# start with some initial texts, added with add_texts
|
||||
texts1 = ["grounded generation", "retrieval augmented generation", "data privacy"]
|
||||
md = [{"abbr": get_abbr(t)} for t in texts1]
|
||||
doc_id1 = docsearch.add_texts(
|
||||
doc_id1 = vectara1.add_texts(
|
||||
texts1,
|
||||
metadatas=md,
|
||||
doc_metadata={"test_num": "1"},
|
||||
@ -39,14 +41,24 @@ def test_vectara_add_documents() -> None:
|
||||
|
||||
# then add some additional documents, now with add_documents
|
||||
texts2 = ["large language model", "information retrieval", "question answering"]
|
||||
doc_id2 = docsearch.add_documents(
|
||||
doc_id2 = vectara1.add_documents(
|
||||
[Document(page_content=t, metadata={"abbr": get_abbr(t)}) for t in texts2],
|
||||
doc_metadata={"test_num": "2"},
|
||||
)
|
||||
doc_ids = doc_id1 + doc_id2
|
||||
|
||||
yield vectara1
|
||||
|
||||
# Tear down code
|
||||
for doc_id in doc_ids:
|
||||
vectara1._delete_doc(doc_id)
|
||||
|
||||
|
||||
def test_vectara_add_documents(vectara1) -> None:
|
||||
"""Test add_documents."""
|
||||
|
||||
# test without filter
|
||||
output1 = docsearch.similarity_search(
|
||||
output1 = vectara1.similarity_search(
|
||||
"large language model",
|
||||
k=2,
|
||||
n_sentence_context=0,
|
||||
@ -54,37 +66,34 @@ def test_vectara_add_documents() -> None:
|
||||
assert len(output1) == 2
|
||||
assert output1[0].page_content == "large language model"
|
||||
assert output1[0].metadata["abbr"] == "llm"
|
||||
assert output1[1].page_content == "information retrieval"
|
||||
assert output1[1].metadata["abbr"] == "ir"
|
||||
assert output1[1].page_content == "grounded generation"
|
||||
assert output1[1].metadata["abbr"] == "gg"
|
||||
|
||||
# test with metadata filter (doc level)
|
||||
# since the query does not match test_num=1 directly we get "RAG" as the result
|
||||
output2 = docsearch.similarity_search(
|
||||
# since the query does not match test_num=1 directly we get "LLM" as the result
|
||||
output2 = vectara1.similarity_search(
|
||||
"large language model",
|
||||
k=1,
|
||||
n_sentence_context=0,
|
||||
filter="doc.test_num = 1",
|
||||
)
|
||||
assert len(output2) == 1
|
||||
assert output2[0].page_content == "retrieval augmented generation"
|
||||
assert output2[0].metadata["abbr"] == "rag"
|
||||
assert output2[0].page_content == "grounded generation"
|
||||
assert output2[0].metadata["abbr"] == "gg"
|
||||
|
||||
# test without filter but with similarity score
|
||||
# this is similar to the first test, but given the score threshold
|
||||
# we only get one result
|
||||
output3 = docsearch.similarity_search_with_score(
|
||||
output3 = vectara1.similarity_search_with_score(
|
||||
"large language model",
|
||||
k=2,
|
||||
score_threshold=0.1,
|
||||
score_threshold=0.8,
|
||||
n_sentence_context=0,
|
||||
)
|
||||
assert len(output3) == 1
|
||||
assert output3[0][0].page_content == "large language model"
|
||||
assert output3[0][0].metadata["abbr"] == "llm"
|
||||
|
||||
for doc_id in doc_ids:
|
||||
docsearch._delete_doc(doc_id)
|
||||
|
||||
|
||||
def test_vectara_from_files() -> None:
|
||||
"""Test end to end construction and search."""
|
||||
@ -92,7 +101,10 @@ def test_vectara_from_files() -> None:
|
||||
# download documents to local storage and then upload as files
|
||||
# attention paper and deep learning book
|
||||
urls = [
|
||||
("https://arxiv.org/pdf/1706.03762.pdf"),
|
||||
(
|
||||
"https://papers.nips.cc/paper_files/paper/2017/"
|
||||
"file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf"
|
||||
),
|
||||
(
|
||||
"https://www.microsoft.com/en-us/research/wp-content/uploads/"
|
||||
"2016/02/Final-DengYu-NOW-Book-DeepLearn2013-ForLecturesJuly2.docx"
|
||||
@ -149,3 +161,95 @@ models can greatly improve the training of DNNs and other deep discriminative mo
|
||||
|
||||
for doc_id in doc_ids:
|
||||
docsearch._delete_doc(doc_id)
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def vectara3():
|
||||
# Set up code
|
||||
vectara3: Vectara = Vectara()
|
||||
|
||||
# start with some initial texts, added with add_texts
|
||||
texts = [
|
||||
"""
|
||||
The way Grounded Generation with Vectara works is we only use valid responses
|
||||
from your data relative to the search query.
|
||||
This dramatically reduces hallucinations in Vectara's responses.
|
||||
You can try it out on your own on our newly launched AskNews demo to experience
|
||||
Grounded Generation, or register an account to ground generative summaries on
|
||||
your own data.
|
||||
""",
|
||||
"""
|
||||
Generative AI promises to revolutionize how you can benefit from your data,
|
||||
but you need it to provide dependable information without the risk of data
|
||||
leakage. This is why today we're adding a fundamental capability to our
|
||||
platform to make generative AI safer to use. It enables you to ask your
|
||||
data questions and get reliable, accurate answers by retrieving and
|
||||
summarizing only the relevant information. We call it “Grounded Generation”.
|
||||
""",
|
||||
"""
|
||||
We are incredibly excited to share another feature with this launch:
|
||||
Hybrid Search! Neural LLM systems are excellent at understanding the context
|
||||
and meaning of end-user queries, but they can still underperform when matching
|
||||
exact product SKUs, unusual names of people or companies, barcodes, and other
|
||||
text which identifies entities rather than conveying semantics. We're bridging
|
||||
this gap by introducing a lexical configuration that matches exact keywords,
|
||||
supports Boolean operators, and executes phrase searches, and incorporates
|
||||
the results into our neural search results.
|
||||
""",
|
||||
]
|
||||
|
||||
doc_ids = []
|
||||
for text in texts:
|
||||
ids = vectara3.add_documents([Document(page_content=text, metadata={})])
|
||||
doc_ids.extend(ids)
|
||||
|
||||
yield vectara3
|
||||
|
||||
# Tear down code
|
||||
for doc_id in doc_ids:
|
||||
vectara3._delete_doc(doc_id)
|
||||
|
||||
|
||||
def test_vectara_mmr(vectara3) -> None:
|
||||
# test max marginal relevance
|
||||
output1 = vectara3.max_marginal_relevance_search(
|
||||
"generative AI",
|
||||
k=2,
|
||||
fetch_k=6,
|
||||
lambda_mult=1.0, # no diversity bias
|
||||
n_sentence_context=0,
|
||||
)
|
||||
assert len(output1) == 2
|
||||
assert "Generative AI promises to revolutionize how" in output1[0].page_content
|
||||
assert (
|
||||
"This is why today we're adding a fundamental capability"
|
||||
in output1[1].page_content
|
||||
)
|
||||
|
||||
output2 = vectara3.max_marginal_relevance_search(
|
||||
"generative AI",
|
||||
k=2,
|
||||
fetch_k=6,
|
||||
lambda_mult=0.0, # only diversity bias
|
||||
n_sentence_context=0,
|
||||
)
|
||||
assert len(output2) == 2
|
||||
assert "Generative AI promises to revolutionize how" in output2[0].page_content
|
||||
assert (
|
||||
"Neural LLM systems are excellent at understanding the context"
|
||||
in output2[1].page_content
|
||||
)
|
||||
|
||||
|
||||
def test_vectara_with_summary(vectara3) -> None:
|
||||
"""Test vectara summary."""
|
||||
# test summarization
|
||||
num_results = 10
|
||||
output1 = vectara3.similarity_search(
|
||||
query="what is generative AI?",
|
||||
k=num_results,
|
||||
summary_config=SummaryConfig(is_enabled=True, max_results=5),
|
||||
)
|
||||
|
||||
assert len(output1) == num_results + 1
|
||||
assert len(output1[num_results].page_content) > 0
|
||||
|
@ -22,11 +22,12 @@ def _get_tool_classes(skip_tools_without_default_names: bool) -> List[Type[BaseT
|
||||
if isinstance(tool_class, type) and issubclass(tool_class, BaseTool):
|
||||
if tool_class in _EXCLUDE:
|
||||
continue
|
||||
if (
|
||||
skip_tools_without_default_names
|
||||
and tool_class.__fields__["name"].default # type: ignore
|
||||
in [None, ""]
|
||||
):
|
||||
if skip_tools_without_default_names and tool_class.__fields__[
|
||||
"name"
|
||||
].default in [ # type: ignore
|
||||
None,
|
||||
"",
|
||||
]:
|
||||
continue
|
||||
results.append(tool_class)
|
||||
return results
|
||||
|
@ -1,7 +1,6 @@
|
||||
import os
|
||||
|
||||
from langchain.chat_models import ChatOpenAI
|
||||
from langchain.prompts import ChatPromptTemplate
|
||||
from langchain.retrievers.multi_query import MultiQueryRetriever
|
||||
from langchain.vectorstores import Vectara
|
||||
from langchain_core.output_parsers import StrOutputParser
|
||||
@ -15,35 +14,37 @@ if os.environ.get("VECTARA_CORPUS_ID", None) is None:
|
||||
if os.environ.get("VECTARA_API_KEY", None) is None:
|
||||
raise Exception("Missing `VECTARA_API_KEY` environment variable.")
|
||||
|
||||
# If you want to ingest data then use this code.
|
||||
# Note that no document chunking is needed, as this is
|
||||
# done efficiently in the Vectara backend.
|
||||
# Note: you will need to install beautifulsoup4 to ingest
|
||||
|
||||
# from langchain.document_loaders import WebBaseLoader
|
||||
# from langchain.embeddings import OpenAIEmbeddings
|
||||
# loader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")
|
||||
# docs = loader.load()
|
||||
# vec_store = Vectara.from_documents(docs, embedding=OpenAIEmbeddings())
|
||||
# retriever = vec_store.as_retriever()
|
||||
# Setup the Vectara retriever with your Corpus ID and API Key
|
||||
|
||||
# Otherwise, if data is already loaded into Vectara then use this code:
|
||||
# note you can customize the retriever behavior by passing additional arguments:
|
||||
# - k: number of results to return (defaults to 5)
|
||||
# - lambda_val: the
|
||||
# [lexical matching](https://docs.vectara.com/docs/api-reference/search-apis/lexical-matching)
|
||||
# factor for hybrid search (defaults to 0.025)
|
||||
# - filter: a [filter](https://docs.vectara.com/docs/common-use-cases/filtering-by-metadata/filter-overview)
|
||||
# to apply to the results (default None)
|
||||
# - n_sentence_context: number of sentences to include before/after the actual matching
|
||||
# segment when returning results. This defaults to 2.
|
||||
# - mmr_config: can be used to specify MMR mode in the query.
|
||||
# - is_enabled: True or False
|
||||
# - mmr_k: number of results to use for MMR reranking
|
||||
# - diversity_bias: 0 = no diversity, 1 = full diversity. This is the lambda
|
||||
# parameter in the MMR formula and is in the range 0...1
|
||||
vectara_retriever = Vectara().as_retriever()
|
||||
|
||||
# Setup the Multi-query retriever
|
||||
llm = ChatOpenAI(temperature=0)
|
||||
retriever = MultiQueryRetriever.from_llm(retriever=Vectara().as_retriever(), llm=llm)
|
||||
retriever = MultiQueryRetriever.from_llm(retriever=vectara_retriever, llm=llm)
|
||||
|
||||
# RAG prompt
|
||||
template = """Answer the question based only on the following context:
|
||||
{context}
|
||||
Question: {question}
|
||||
"""
|
||||
prompt = ChatPromptTemplate.from_template(template)
|
||||
|
||||
# RAG
|
||||
# Setup RAG pipeline with multi-query.
|
||||
# We extract the summary from the RAG output, which is the last document
|
||||
# (if summary is enabled)
|
||||
# Note that if you want to extract the citation information, you can use res[:-1]]
|
||||
model = ChatOpenAI()
|
||||
chain = (
|
||||
RunnableParallel({"context": retriever, "question": RunnablePassthrough()})
|
||||
| prompt
|
||||
| model
|
||||
| (lambda res: res[-1])
|
||||
| StrOutputParser()
|
||||
)
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
import os
|
||||
|
||||
from langchain.chat_models import ChatOpenAI
|
||||
from langchain.prompts import ChatPromptTemplate
|
||||
from langchain.vectorstores import Vectara
|
||||
from langchain_core.output_parsers import StrOutputParser
|
||||
from langchain_core.pydantic_v1 import BaseModel
|
||||
@ -14,29 +12,30 @@ if os.environ.get("VECTARA_CORPUS_ID", None) is None:
|
||||
if os.environ.get("VECTARA_API_KEY", None) is None:
|
||||
raise Exception("Missing `VECTARA_API_KEY` environment variable.")
|
||||
|
||||
# If you want to ingest data then use this code.
|
||||
# Note that no document chunking is needed, as this is
|
||||
# done efficiently in the Vectara backend.
|
||||
# loader = WebBaseLoader("https://lilianweng.github.io/posts/2023-06-23-agent/")
|
||||
# docs = loader.load()
|
||||
# vec_store = Vectara.from_document(docs)
|
||||
# retriever = vec_store.as_retriever()
|
||||
# Otherwise, if data is already loaded into Vectara then use this code:
|
||||
# Setup the Vectara retriever with your Corpus ID and API Key
|
||||
|
||||
# note you can customize the retriever behavior by passing additional arguments:
|
||||
# - k: number of results to return (defaults to 5)
|
||||
# - lambda_val: the
|
||||
# [lexical matching](https://docs.vectara.com/docs/api-reference/search-apis/lexical-matching)
|
||||
# factor for hybrid search (defaults to 0.025)
|
||||
# - filter: a [filter](https://docs.vectara.com/docs/common-use-cases/filtering-by-metadata/filter-overview)
|
||||
# to apply to the results (default None)
|
||||
# - n_sentence_context: number of sentences to include before/after the actual matching
|
||||
# segment when returning results. This defaults to 2.
|
||||
# - mmr_config: can be used to specify MMR mode in the query.
|
||||
# - is_enabled: True or False
|
||||
# - mmr_k: number of results to use for MMR reranking
|
||||
# - diversity_bias: 0 = no diversity, 1 = full diversity. This is the lambda
|
||||
# parameter in the MMR formula and is in the range 0...1
|
||||
retriever = Vectara().as_retriever()
|
||||
|
||||
# RAG prompt
|
||||
template = """Answer the question based only on the following context:
|
||||
{context}
|
||||
Question: {question}
|
||||
"""
|
||||
prompt = ChatPromptTemplate.from_template(template)
|
||||
|
||||
# RAG
|
||||
model = ChatOpenAI()
|
||||
# RAG pipeline: we extract the summary from the RAG output, which is the last document
|
||||
# (if summary is enabled)
|
||||
# Note that if you want to extract the citation information, you can use res[:-1]]
|
||||
chain = (
|
||||
RunnableParallel({"context": retriever, "question": RunnablePassthrough()})
|
||||
| prompt
|
||||
| model
|
||||
| (lambda res: res[-1])
|
||||
| StrOutputParser()
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user