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
+}