diff --git a/docs/extras/guides/expression_language/interface.ipynb b/docs/extras/guides/expression_language/interface.ipynb index d263805bd9..98a1a38600 100644 --- a/docs/extras/guides/expression_language/interface.ipynb +++ b/docs/extras/guides/expression_language/interface.ipynb @@ -41,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 1, "id": "466b65b3", "metadata": {}, "outputs": [], @@ -256,6 +256,131 @@ "source": [ "await chain.abatch([{\"topic\": \"bears\"}])" ] + }, + { + "cell_type": "markdown", + "id": "0a1c409d", + "metadata": {}, + "source": [ + "## Parallelism\n", + "\n", + "Let's take a look at how LangChain Expression Language support parralel requests as much as possible. For example, when using a RunnableMapping (often written as a dictionary) it executes each element in parralel." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "e3014c7a", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.schema.runnable import RunnableMap\n", + "chain1 = ChatPromptTemplate.from_template(\"tell me a joke about {topic}\") | model\n", + "chain2 = ChatPromptTemplate.from_template(\"write a short (2 line) poem about {topic}\") | model\n", + "combined = RunnableMap({\n", + " \"joke\": chain1,\n", + " \"poem\": chain2,\n", + "})" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "08044c0a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 31.7 ms, sys: 8.59 ms, total: 40.3 ms\n", + "Wall time: 1.05 s\n" + ] + }, + { + "data": { + "text/plain": [ + "AIMessage(content=\"Why don't bears like fast food?\\n\\nBecause they can't catch it!\", additional_kwargs={}, example=False)" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "chain1.invoke({\"topic\": \"bears\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "22c56804", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 42.9 ms, sys: 10.2 ms, total: 53 ms\n", + "Wall time: 1.93 s\n" + ] + }, + { + "data": { + "text/plain": [ + "AIMessage(content=\"In forest's embrace, bears roam free,\\nSilent strength, nature's majesty.\", additional_kwargs={}, example=False)" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "chain2.invoke({\"topic\": \"bears\"})" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "4fff4cbb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 96.3 ms, sys: 20.4 ms, total: 117 ms\n", + "Wall time: 1.1 s\n" + ] + }, + { + "data": { + "text/plain": [ + "{'joke': AIMessage(content=\"Why don't bears wear socks?\\n\\nBecause they have bear feet!\", additional_kwargs={}, example=False),\n", + " 'poem': AIMessage(content=\"In forest's embrace,\\nMajestic bears leave their trace.\", additional_kwargs={}, example=False)}" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "combined.invoke({\"topic\": \"bears\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fab75d1d", + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -274,7 +399,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.1" + "version": "3.10.1" } }, "nbformat": 4, diff --git a/docs/extras/use_cases/question_answering/how_to/multiple_retrieval.ipynb b/docs/extras/use_cases/question_answering/how_to/multiple_retrieval.ipynb new file mode 100644 index 0000000000..96b6ef6986 --- /dev/null +++ b/docs/extras/use_cases/question_answering/how_to/multiple_retrieval.ipynb @@ -0,0 +1,166 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "66398b75", + "metadata": {}, + "source": [ + "# Multiple Retrieval Sources\n", + "\n", + "Often times you may want to do retrieval over multiple sources. These can be different vectorstores (where one contains information about topic X and the other contains info about topic Y). They could also be completely different databases altogether!\n", + "\n", + "A key part is is doing as much of the retrieval in parrelel as possible. This will keep the latency as low as possible. Luckily, [LangChain Expression Language](../../) supports parrellism out of the box.\n", + "\n", + "Let's take a look where we do retrieval over a SQL database and a vectorstore." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1c5bab6a", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.chat_models import ChatOpenAI" + ] + }, + { + "cell_type": "markdown", + "id": "43a6210f", + "metadata": {}, + "source": [ + "## Set up SQL query" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "ab3bf8ba", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.utilities import SQLDatabase\n", + "from langchain.chains import create_sql_query_chain\n", + "\n", + "db = SQLDatabase.from_uri(\"sqlite:///../../../../../notebooks/Chinook.db\")\n", + "query_chain = create_sql_query_chain(ChatOpenAI(temperature=0), db)" + ] + }, + { + "cell_type": "markdown", + "id": "a8585120", + "metadata": {}, + "source": [ + "## Set up vectorstore" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "b916b0b0", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.indexes import VectorstoreIndexCreator\n", + "from langchain.schema.document import Document\n", + "index_creator = VectorstoreIndexCreator()\n", + "index = index_creator.from_documents([Document(page_content=\"Foo\")])\n", + "retriever = index.vectorstore.as_retriever()" + ] + }, + { + "cell_type": "markdown", + "id": "a3b91816", + "metadata": {}, + "source": [ + "## Combine" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "4423211c", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.prompts import ChatPromptTemplate\n", + "\n", + "system_message = \"\"\"Use the information from the below two sources to answer any questions.\n", + "\n", + "Source 1: a SQL database about employee data\n", + "\n", + "{source1}\n", + "\n", + "\n", + "Source 2: a text database of random information\n", + "\n", + "{source2}\n", + "\n", + "\"\"\"\n", + "\n", + "prompt = ChatPromptTemplate.from_messages([(\"system\", system_message), (\"human\", \"{question}\")])" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "7ff87e0c", + "metadata": {}, + "outputs": [], + "source": [ + "full_chain = {\n", + " \"source1\": {\"question\": lambda x: x[\"question\"]} | query_chain | db.run,\n", + " \"source2\": (lambda x: x['question']) | retriever,\n", + " \"question\": lambda x: x['question'],\n", + "} | prompt | ChatOpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "d6706410", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Number of requested results 4 is greater than number of elements in index 1, updating n_results = 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "content='There are 8 employees.' additional_kwargs={} example=False\n" + ] + } + ], + "source": [ + "response = full_chain.invoke({\"question\":\"How many Employees are there\"})\n", + "print(response)" + ] + } + ], + "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.1" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}