diff --git a/docs/docs/expression_language/interface.ipynb b/docs/docs/expression_language/interface.ipynb index 3adaa916a3..d1d6f863f2 100644 --- a/docs/docs/expression_language/interface.ipynb +++ b/docs/docs/expression_language/interface.ipynb @@ -16,7 +16,9 @@ "id": "9a9acd2e", "metadata": {}, "source": [ - "In an effort to make it as easy as possible to create custom chains, we've implemented a [\"Runnable\"](https://api.python.langchain.com/en/latest/schema/langchain.schema.runnable.base.Runnable.html#langchain.schema.runnable.base.Runnable) protocol that most components implement. This is a standard interface with a few different methods, which makes it easy to define custom chains as well as making it possible to invoke them in a standard way. The standard interface exposed includes:\n", + "To make it as easy as possible to create custom chains, we've implemented a [\"Runnable\"](https://api.python.langchain.com/en/latest/schema/langchain.schema.runnable.base.Runnable.html#langchain.schema.runnable.base.Runnable) protocol. The `Runnable` protocol is implemented for most components. \n", + "This is a standard interface, which makes it easy to define custom chains as well as invoke them in a standard way. \n", + "The standard interface includes:\n", "\n", "- [`stream`](#stream): stream back chunks of the response\n", "- [`invoke`](#invoke): call the chain on an input\n", @@ -29,7 +31,7 @@ "- [`abatch`](#async-batch): call the chain on a list of inputs async\n", "- [`astream_log`](#async-stream-intermediate-steps): stream back intermediate steps as they happen, in addition to the final response\n", "\n", - "The type of the input varies by component:\n", + "The **input type** varies by component:\n", "\n", "| Component | Input Type |\n", "| --- | --- |\n", @@ -39,7 +41,7 @@ "|Tool|Single string, or dictionary, depending on the tool|\n", "|OutputParser|The output of an LLM or ChatModel|\n", "\n", - "The output type also varies by component:\n", + "The **output type** also varies by component:\n", "\n", "| Component | Output Type |\n", "| --- | --- |\n", @@ -50,11 +52,11 @@ "| Tool | Depends on the tool |\n", "| OutputParser | Depends on the parser |\n", "\n", - "All runnables expose properties to inspect the input and output types:\n", + "All runnables expose input and output **schemas** to inspect the inputs and outputs:\n", "- [`input_schema`](#input-schema): an input Pydantic model auto-generated from the structure of the Runnable\n", "- [`output_schema`](#output-schema): an output Pydantic model auto-generated from the structure of the Runnable\n", "\n", - "Let's take a look at these methods! To do so, we'll create a super simple PromptTemplate + ChatModel chain." + "Let's take a look at these methods. To do so, we'll create a super simple PromptTemplate + ChatModel chain." ] }, { @@ -65,37 +67,11 @@ "outputs": [], "source": [ "from langchain.prompts import ChatPromptTemplate\n", - "from langchain.chat_models import ChatOpenAI\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "3c634ef0", - "metadata": {}, - "outputs": [], - "source": [ - "model = ChatOpenAI()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "d1850a1f", - "metadata": {}, - "outputs": [], - "source": [ - "prompt = ChatPromptTemplate.from_template(\"tell me a joke about {topic}\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "56d0669f", - "metadata": {}, - "outputs": [], - "source": [ - "chain = prompt | model\n" + "from langchain.chat_models import ChatOpenAI\n", + "\n", + "model = ChatOpenAI()\n", + "prompt = ChatPromptTemplate.from_template(\"tell me a joke about {topic}\")\n", + "chain = prompt | model" ] }, { @@ -112,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 13, "id": "25e146d4-60da-40a2-9026-b5dfee106a3f", "metadata": {}, "outputs": [ @@ -124,14 +100,145 @@ " 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}}" ] }, - "execution_count": 5, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The input schema of the chain is the input schema of its first part, the prompt.\n", - "chain.input_schema.schema()\n" + "chain.input_schema.schema()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "ad130546-4c14-4f6c-95af-c56ea19b12ac", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'title': 'PromptInput',\n", + " 'type': 'object',\n", + " 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}}" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "prompt.input_schema.schema()" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "49d34744-d6db-4fdf-a0d6-261522b7f251", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'title': 'ChatOpenAIInput',\n", + " 'anyOf': [{'type': 'string'},\n", + " {'$ref': '#/definitions/StringPromptValue'},\n", + " {'$ref': '#/definitions/ChatPromptValueConcrete'},\n", + " {'type': 'array',\n", + " 'items': {'anyOf': [{'$ref': '#/definitions/AIMessage'},\n", + " {'$ref': '#/definitions/HumanMessage'},\n", + " {'$ref': '#/definitions/ChatMessage'},\n", + " {'$ref': '#/definitions/SystemMessage'},\n", + " {'$ref': '#/definitions/FunctionMessage'}]}}],\n", + " 'definitions': {'StringPromptValue': {'title': 'StringPromptValue',\n", + " 'description': 'String prompt value.',\n", + " 'type': 'object',\n", + " 'properties': {'text': {'title': 'Text', 'type': 'string'},\n", + " 'type': {'title': 'Type',\n", + " 'default': 'StringPromptValue',\n", + " 'enum': ['StringPromptValue'],\n", + " 'type': 'string'}},\n", + " 'required': ['text']},\n", + " 'AIMessage': {'title': 'AIMessage',\n", + " 'description': 'A Message from an AI.',\n", + " 'type': 'object',\n", + " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", + " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", + " 'type': {'title': 'Type',\n", + " 'default': 'ai',\n", + " 'enum': ['ai'],\n", + " 'type': 'string'},\n", + " 'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},\n", + " 'required': ['content']},\n", + " 'HumanMessage': {'title': 'HumanMessage',\n", + " 'description': 'A Message from a human.',\n", + " 'type': 'object',\n", + " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", + " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", + " 'type': {'title': 'Type',\n", + " 'default': 'human',\n", + " 'enum': ['human'],\n", + " 'type': 'string'},\n", + " 'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},\n", + " 'required': ['content']},\n", + " 'ChatMessage': {'title': 'ChatMessage',\n", + " 'description': 'A Message that can be assigned an arbitrary speaker (i.e. role).',\n", + " 'type': 'object',\n", + " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", + " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", + " 'type': {'title': 'Type',\n", + " 'default': 'chat',\n", + " 'enum': ['chat'],\n", + " 'type': 'string'},\n", + " 'role': {'title': 'Role', 'type': 'string'}},\n", + " 'required': ['content', 'role']},\n", + " 'SystemMessage': {'title': 'SystemMessage',\n", + " 'description': 'A Message for priming AI behavior, usually passed in as the first of a sequence\\nof input messages.',\n", + " 'type': 'object',\n", + " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", + " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", + " 'type': {'title': 'Type',\n", + " 'default': 'system',\n", + " 'enum': ['system'],\n", + " 'type': 'string'}},\n", + " 'required': ['content']},\n", + " 'FunctionMessage': {'title': 'FunctionMessage',\n", + " 'description': 'A Message for passing the result of executing a function back to a model.',\n", + " 'type': 'object',\n", + " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", + " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", + " 'type': {'title': 'Type',\n", + " 'default': 'function',\n", + " 'enum': ['function'],\n", + " 'type': 'string'},\n", + " 'name': {'title': 'Name', 'type': 'string'}},\n", + " 'required': ['content', 'name']},\n", + " 'ChatPromptValueConcrete': {'title': 'ChatPromptValueConcrete',\n", + " 'description': 'Chat prompt value which explicitly lists out the message types it accepts.\\nFor use in external schemas.',\n", + " 'type': 'object',\n", + " 'properties': {'messages': {'title': 'Messages',\n", + " 'type': 'array',\n", + " 'items': {'anyOf': [{'$ref': '#/definitions/AIMessage'},\n", + " {'$ref': '#/definitions/HumanMessage'},\n", + " {'$ref': '#/definitions/ChatMessage'},\n", + " {'$ref': '#/definitions/SystemMessage'},\n", + " {'$ref': '#/definitions/FunctionMessage'}]}},\n", + " 'type': {'title': 'Type',\n", + " 'default': 'ChatPromptValueConcrete',\n", + " 'enum': ['ChatPromptValueConcrete'],\n", + " 'type': 'string'}},\n", + " 'required': ['messages']}}}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.input_schema.schema()" ] }, { @@ -148,7 +255,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 17, "id": "a0e41fd3-77d8-4911-af6a-d4d3aad5f77b", "metadata": {}, "outputs": [ @@ -156,13 +263,13 @@ "data": { "text/plain": [ "{'title': 'ChatOpenAIOutput',\n", - " 'anyOf': [{'$ref': '#/definitions/HumanMessageChunk'},\n", - " {'$ref': '#/definitions/AIMessageChunk'},\n", - " {'$ref': '#/definitions/ChatMessageChunk'},\n", - " {'$ref': '#/definitions/FunctionMessageChunk'},\n", - " {'$ref': '#/definitions/SystemMessageChunk'}],\n", - " 'definitions': {'HumanMessageChunk': {'title': 'HumanMessageChunk',\n", - " 'description': 'A Human Message chunk.',\n", + " 'anyOf': [{'$ref': '#/definitions/HumanMessage'},\n", + " {'$ref': '#/definitions/AIMessage'},\n", + " {'$ref': '#/definitions/ChatMessage'},\n", + " {'$ref': '#/definitions/FunctionMessage'},\n", + " {'$ref': '#/definitions/SystemMessage'}],\n", + " 'definitions': {'HumanMessage': {'title': 'HumanMessage',\n", + " 'description': 'A Message from a human.',\n", " 'type': 'object',\n", " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", @@ -170,14 +277,10 @@ " 'default': 'human',\n", " 'enum': ['human'],\n", " 'type': 'string'},\n", - " 'example': {'title': 'Example', 'default': False, 'type': 'boolean'},\n", - " 'is_chunk': {'title': 'Is Chunk',\n", - " 'default': True,\n", - " 'enum': [True],\n", - " 'type': 'boolean'}},\n", + " 'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},\n", " 'required': ['content']},\n", - " 'AIMessageChunk': {'title': 'AIMessageChunk',\n", - " 'description': 'A Message chunk from an AI.',\n", + " 'AIMessage': {'title': 'AIMessage',\n", + " 'description': 'A Message from an AI.',\n", " 'type': 'object',\n", " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", @@ -185,14 +288,10 @@ " 'default': 'ai',\n", " 'enum': ['ai'],\n", " 'type': 'string'},\n", - " 'example': {'title': 'Example', 'default': False, 'type': 'boolean'},\n", - " 'is_chunk': {'title': 'Is Chunk',\n", - " 'default': True,\n", - " 'enum': [True],\n", - " 'type': 'boolean'}},\n", + " 'example': {'title': 'Example', 'default': False, 'type': 'boolean'}},\n", " 'required': ['content']},\n", - " 'ChatMessageChunk': {'title': 'ChatMessageChunk',\n", - " 'description': 'A Chat Message chunk.',\n", + " 'ChatMessage': {'title': 'ChatMessage',\n", + " 'description': 'A Message that can be assigned an arbitrary speaker (i.e. role).',\n", " 'type': 'object',\n", " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", @@ -200,14 +299,10 @@ " 'default': 'chat',\n", " 'enum': ['chat'],\n", " 'type': 'string'},\n", - " 'role': {'title': 'Role', 'type': 'string'},\n", - " 'is_chunk': {'title': 'Is Chunk',\n", - " 'default': True,\n", - " 'enum': [True],\n", - " 'type': 'boolean'}},\n", + " 'role': {'title': 'Role', 'type': 'string'}},\n", " 'required': ['content', 'role']},\n", - " 'FunctionMessageChunk': {'title': 'FunctionMessageChunk',\n", - " 'description': 'A Function Message chunk.',\n", + " 'FunctionMessage': {'title': 'FunctionMessage',\n", + " 'description': 'A Message for passing the result of executing a function back to a model.',\n", " 'type': 'object',\n", " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", @@ -215,36 +310,28 @@ " 'default': 'function',\n", " 'enum': ['function'],\n", " 'type': 'string'},\n", - " 'name': {'title': 'Name', 'type': 'string'},\n", - " 'is_chunk': {'title': 'Is Chunk',\n", - " 'default': True,\n", - " 'enum': [True],\n", - " 'type': 'boolean'}},\n", + " 'name': {'title': 'Name', 'type': 'string'}},\n", " 'required': ['content', 'name']},\n", - " 'SystemMessageChunk': {'title': 'SystemMessageChunk',\n", - " 'description': 'A System Message chunk.',\n", + " 'SystemMessage': {'title': 'SystemMessage',\n", + " 'description': 'A Message for priming AI behavior, usually passed in as the first of a sequence\\nof input messages.',\n", " 'type': 'object',\n", " 'properties': {'content': {'title': 'Content', 'type': 'string'},\n", " 'additional_kwargs': {'title': 'Additional Kwargs', 'type': 'object'},\n", " 'type': {'title': 'Type',\n", " 'default': 'system',\n", " 'enum': ['system'],\n", - " 'type': 'string'},\n", - " 'is_chunk': {'title': 'Is Chunk',\n", - " 'default': True,\n", - " 'enum': [True],\n", - " 'type': 'boolean'}},\n", + " 'type': 'string'}},\n", " 'required': ['content']}}}" ] }, - "execution_count": 6, + "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The output schema of the chain is the output schema of its last part, in this case a ChatModel, which outputs a ChatMessage\n", - "chain.output_schema.schema()\n" + "chain.output_schema.schema()" ] }, { @@ -257,7 +344,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 20, "id": "bea9639d", "metadata": {}, "outputs": [ @@ -265,15 +352,15 @@ "name": "stdout", "output_type": "stream", "text": [ - "Why don't bears wear shoes? \n", + "Why don't bears wear shoes?\n", "\n", - "Because they have bear feet!" + "Because they already have bear feet!" ] } ], "source": [ "for s in chain.stream({\"topic\": \"bears\"}):\n", - " print(s.content, end=\"\", flush=True)\n" + " print(s.content, end=\"\", flush=True)" ] }, { @@ -286,23 +373,23 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 21, "id": "470e483f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "AIMessage(content=\"Why don't bears wear shoes?\\n\\nBecause they have bear feet!\")" + "AIMessage(content=\"Why don't bears wear shoes?\\n\\nBecause they already have bear feet!\")" ] }, - "execution_count": 8, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "chain.invoke({\"topic\": \"bears\"})\n" + "chain.invoke({\"topic\": \"bears\"})" ] }, { @@ -315,7 +402,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 22, "id": "9685de67", "metadata": {}, "outputs": [ @@ -326,13 +413,13 @@ " AIMessage(content=\"Why don't cats play poker in the wild?\\n\\nToo many cheetahs!\")]" ] }, - "execution_count": 9, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "chain.batch([{\"topic\": \"bears\"}, {\"topic\": \"cats\"}])\n" + "chain.batch([{\"topic\": \"bears\"}, {\"topic\": \"cats\"}])" ] }, { @@ -345,24 +432,24 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 23, "id": "a08522f6", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "[AIMessage(content=\"Why don't bears wear shoes?\\n\\nBecause they have bear feet!\"),\n", - " AIMessage(content=\"Sure, here's a cat joke for you:\\n\\nWhy don't cats play poker in the wild?\\n\\nToo many cheetahs!\")]" + "[AIMessage(content=\"Why don't bears wear shoes? \\n\\nBecause they have bear feet!\"),\n", + " AIMessage(content=\"Why don't cats play poker in the wild?\\n\\nToo many cheetahs!\")]" ] }, - "execution_count": 10, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "chain.batch([{\"topic\": \"bears\"}, {\"topic\": \"cats\"}], config={\"max_concurrency\": 5})\n" + "chain.batch([{\"topic\": \"bears\"}, {\"topic\": \"cats\"}], config={\"max_concurrency\": 5})" ] }, { @@ -375,7 +462,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 24, "id": "ea35eee4", "metadata": {}, "outputs": [ @@ -383,17 +470,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "Sure, here's a bear joke for you:\n", + "Sure, here's a bear-themed joke for you:\n", "\n", "Why don't bears wear shoes?\n", "\n", - "Because they have bear feet!" + "Because they already have bear feet!" ] } ], "source": [ "async for s in chain.astream({\"topic\": \"bears\"}):\n", - " print(s.content, end=\"\", flush=True)\n" + " print(s.content, end=\"\", flush=True)" ] }, { @@ -406,7 +493,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 25, "id": "ef8c9b20", "metadata": {}, "outputs": [ @@ -416,13 +503,13 @@ "AIMessage(content=\"Why don't bears wear shoes? \\n\\nBecause they have bear feet!\")" ] }, - "execution_count": 12, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "await chain.ainvoke({\"topic\": \"bears\"})\n" + "await chain.ainvoke({\"topic\": \"bears\"})" ] }, { @@ -435,7 +522,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 26, "id": "eba2a103", "metadata": {}, "outputs": [ @@ -445,13 +532,13 @@ "[AIMessage(content=\"Why don't bears wear shoes?\\n\\nBecause they have bear feet!\")]" ] }, - "execution_count": 13, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "await chain.abatch([{\"topic\": \"bears\"}])\n" + "await chain.abatch([{\"topic\": \"bears\"}])" ] }, { @@ -461,11 +548,11 @@ "source": [ "## Async Stream Intermediate Steps\n", "\n", - "All runnables also have a method `.astream_log()` which can be used to stream (as they happen) all or part of the intermediate steps of your chain/sequence. \n", + "All runnables also have a method `.astream_log()` which is used to stream (as they happen) all or part of the intermediate steps of your chain/sequence. \n", "\n", - "This is useful eg. to show progress to the user, to use intermediate results, or even just to debug your chain.\n", + "This is useful to show progress to the user, to use intermediate results, or to debug your chain.\n", "\n", - "You can choose to stream all steps (default), or include/exclude steps by name, tags or metadata.\n", + "You can stream all steps (default) or include/exclude steps by name, tags or metadata.\n", "\n", "This method yields [JSONPatch](https://jsonpatch.com) ops that when applied in the same order as received build up the RunState.\n", "\n", @@ -516,12 +603,12 @@ "source": [ "### Streaming JSONPatch chunks\n", "\n", - "This is useful eg. to stream the JSONPatch in an HTTP server, and then apply the ops on the client to rebuild the run state there. See [LangServe](https://github.com/langchain-ai/langserve) for tooling to make it easier to build a webserver from any Runnable." + "This is useful eg. to stream the `JSONPatch` in an HTTP server, and then apply the ops on the client to rebuild the run state there. See [LangServe](https://github.com/langchain-ai/langserve) for tooling to make it easier to build a webserver from any Runnable." ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 29, "id": "21c9019e", "metadata": {}, "outputs": [ @@ -529,38 +616,51 @@ "name": "stdout", "output_type": "stream", "text": [ + "----------------------------------------\n", "RunLogPatch({'op': 'replace',\n", " 'path': '',\n", " 'value': {'final_output': None,\n", - " 'id': 'fd6fcf62-c92c-4edf-8713-0fc5df000f62',\n", + " 'id': 'e2f2cc72-eb63-4d20-8326-237367482efb',\n", " 'logs': {},\n", " 'streamed_output': []}})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add',\n", " 'path': '/logs/Docs',\n", " 'value': {'end_time': None,\n", " 'final_output': None,\n", - " 'id': '8c998257-1ec8-4546-b744-c3fdb9728c41',\n", + " 'id': '8da492cc-4492-4e74-b8b0-9e60e8693390',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:35.668',\n", + " 'start_time': '2023-10-19T17:50:13.526',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add',\n", " 'path': '/logs/Docs/final_output',\n", " 'value': {'documents': [Document(page_content='harrison worked at kensho')]}},\n", " {'op': 'add',\n", " 'path': '/logs/Docs/end_time',\n", - " 'value': '2023-10-05T12:52:36.033'})\n", + " 'value': '2023-10-19T17:50:13.713'})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ''})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': 'H'})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': 'arrison'})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' worked'})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' at'})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ' Kens'})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': 'ho'})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '.'})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': ''})\n", + "----------------------------------------\n", "RunLogPatch({'op': 'replace',\n", " 'path': '/final_output',\n", " 'value': {'output': 'Harrison worked at Kensho.'}})\n" @@ -591,6 +691,7 @@ ")\n", "\n", "async for chunk in retrieval_chain.astream_log(\"where did harrison work?\", include_names=['Docs']):\n", + " print(\"-\"*40)\n", " print(chunk)\n" ] }, @@ -601,12 +702,13 @@ "source": [ "### Streaming the incremental RunState\n", "\n", - "You can simply pass diff=False to get incremental values of RunState." + "You can simply pass `diff=False` to get incremental values of `RunState`. \n", + "You get more verbose output with more repetitive parts." ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 31, "id": "5c26b731-b4eb-4967-a42a-dec813249ecb", "metadata": {}, "outputs": [ @@ -614,138 +716,150 @@ "name": "stdout", "output_type": "stream", "text": [ + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", " 'logs': {},\n", " 'streamed_output': []})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", " 'logs': {'Docs': {'end_time': None,\n", " 'final_output': None,\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': []})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': []})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': ['']})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': ['', 'H']})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': ['', 'H', 'arrison']})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': ['', 'H', 'arrison', ' worked']})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': ['', 'H', 'arrison', ' worked', ' at']})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': ['', 'H', 'arrison', ' worked', ' at', ' Kens']})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': ['', 'H', 'arrison', ' worked', ' at', ' Kens', 'ho']})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", " 'streamed_output': ['', 'H', 'arrison', ' worked', ' at', ' Kens', 'ho', '.']})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': None,\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", @@ -758,14 +872,15 @@ " 'ho',\n", " '.',\n", " '']})\n", + "----------------------------------------------------------------------\n", "RunLog({'final_output': {'output': 'Harrison worked at Kensho.'},\n", - " 'id': 'f95ccb87-31f1-48ea-a51c-d2dadde44185',\n", - " 'logs': {'Docs': {'end_time': '2023-10-05T12:52:37.217',\n", + " 'id': 'afe66178-d75f-4c2d-b348-b1d144239cd6',\n", + " 'logs': {'Docs': {'end_time': '2023-10-19T17:52:15.738',\n", " 'final_output': {'documents': [Document(page_content='harrison worked at kensho')]},\n", - " 'id': '621597dd-d716-4532-938d-debc21a453d1',\n", + " 'id': '88d51118-5756-4891-89c5-2f6a5e90cc26',\n", " 'metadata': {},\n", " 'name': 'Docs',\n", - " 'start_time': '2023-10-05T12:52:36.935',\n", + " 'start_time': '2023-10-19T17:52:15.438',\n", " 'streamed_output_str': [],\n", " 'tags': ['map:key:context', 'FAISS'],\n", " 'type': 'retriever'}},\n", @@ -783,7 +898,8 @@ ], "source": [ "async for chunk in retrieval_chain.astream_log(\"where did harrison work?\", include_names=['Docs'], diff=False):\n", - " print(chunk)\n" + " print(\"-\"*70)\n", + " print(chunk)" ] }, { @@ -793,12 +909,13 @@ "source": [ "## Parallelism\n", "\n", - "Let's take a look at how LangChain Expression Language support parallel requests as much as possible. For example, when using a RunnableParallel (often written as a dictionary) it executes each element in parallel." + "Let's take a look at how LangChain Expression Language supports parallel requests. \n", + "For example, when using a `RunnableParallel` (often written as a dictionary) it executes each element in parallel." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 32, "id": "0a1c409d", "metadata": {}, "outputs": [], @@ -806,12 +923,12 @@ "from langchain.schema.runnable import RunnableParallel\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 = RunnableParallel(joke=chain1, poem=chain2)\n" + "combined = RunnableParallel(joke=chain1, poem=chain2)" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 43, "id": "08044c0a", "metadata": {}, "outputs": [ @@ -819,29 +936,29 @@ "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" + "CPU times: user 54.3 ms, sys: 0 ns, total: 54.3 ms\n", + "Wall time: 2.29 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)" + "AIMessage(content=\"Why don't bears wear shoes?\\n\\nBecause they already have bear feet!\")" ] }, - "execution_count": 11, + "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", - "chain1.invoke({\"topic\": \"bears\"})\n" + "chain1.invoke({\"topic\": \"bears\"})" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 44, "id": "22c56804", "metadata": {}, "outputs": [ @@ -849,29 +966,29 @@ "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" + "CPU times: user 7.8 ms, sys: 0 ns, total: 7.8 ms\n", + "Wall time: 1.43 s\n" ] }, { "data": { "text/plain": [ - "AIMessage(content=\"In forest's embrace, bears roam free,\\nSilent strength, nature's majesty.\", additional_kwargs={}, example=False)" + "AIMessage(content=\"In wild embrace,\\nNature's strength roams with grace.\")" ] }, - "execution_count": 12, + "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", - "chain2.invoke({\"topic\": \"bears\"})\n" + "chain2.invoke({\"topic\": \"bears\"})" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 45, "id": "4fff4cbb", "metadata": {}, "outputs": [ @@ -879,31 +996,137 @@ "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" + "CPU times: user 167 ms, sys: 921 µs, total: 168 ms\n", + "Wall time: 1.56 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)}" + "{'joke': AIMessage(content=\"Why don't bears wear shoes?\\n\\nBecause they already have bear feet!\"),\n", + " 'poem': AIMessage(content=\"Fierce and wild, nature's might,\\nBears roam the woods, shadows of the night.\")}" ] }, - "execution_count": 13, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "combined.invoke({\"topic\": \"bears\"})" + ] + }, + { + "cell_type": "markdown", + "id": "80164216-0abd-439b-8407-409539e104b6", + "metadata": {}, + "source": [ + "### Parallelism on batches\n", + "\n", + "Parallelism can be combined with other runnables.\n", + "Let's try to use parallelism with batches." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "f67d2268-c766-441b-8d64-57b8219ccb34", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 159 ms, sys: 3.66 ms, total: 163 ms\n", + "Wall time: 1.34 s\n" + ] + }, + { + "data": { + "text/plain": [ + "[AIMessage(content=\"Why don't bears wear shoes?\\n\\nBecause they already have bear feet!\"),\n", + " AIMessage(content=\"Sure, here's a cat joke for you:\\n\\nWhy don't cats play poker in the wild?\\n\\nBecause there are too many cheetahs!\")]" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "chain1.batch([{\"topic\": \"bears\"}, {\"topic\": \"cats\"}])" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "83c8d511-9563-403e-9c06-cae986cf5dee", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 165 ms, sys: 0 ns, total: 165 ms\n", + "Wall time: 1.73 s\n" + ] + }, + { + "data": { + "text/plain": [ + "[AIMessage(content=\"Silent giants roam,\\nNature's strength, love's emblem shown.\"),\n", + " AIMessage(content='Whiskers aglow, paws tiptoe,\\nGraceful hunters, hearts aglow.')]" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "%%time\n", + "chain2.batch([{\"topic\": \"bears\"}, {\"topic\": \"cats\"}])" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "id": "07a81230-8db8-4b96-bdcb-99ae1d171f2f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CPU times: user 507 ms, sys: 125 ms, total: 632 ms\n", + "Wall time: 1.49 s\n" + ] + }, + { + "data": { + "text/plain": [ + "[{'joke': AIMessage(content=\"Why don't bears wear shoes?\\n\\nBecause they already have bear feet!\"),\n", + " 'poem': AIMessage(content=\"Majestic bears roam,\\nNature's wild guardians of home.\")},\n", + " {'joke': AIMessage(content=\"Sure, here's a cat joke for you:\\n\\nWhy did the cat sit on the computer?\\n\\nBecause it wanted to keep an eye on the mouse!\"),\n", + " 'poem': AIMessage(content='Whiskers twitch, eyes gleam,\\nGraceful creatures, feline dream.')}]" + ] + }, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", - "combined.invoke({\"topic\": \"bears\"})\n" + "combined.batch([{\"topic\": \"bears\"}, {\"topic\": \"cats\"}])" ] }, { "cell_type": "code", "execution_count": null, - "id": "fab75d1d", + "id": "5218cafd-370a-4e3a-85a0-452e570092fe", "metadata": {}, "outputs": [], "source": [] @@ -925,7 +1148,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.1" + "version": "3.10.12" } }, "nbformat": 4,