From f1a57c761d61a9eec60772d15103dafa59a5b05a Mon Sep 17 00:00:00 2001 From: jacoblee93 Date: Sat, 24 Aug 2024 17:37:22 -0700 Subject: [PATCH] Add streaming from final node notebook --- deno.json | 4 +- .../how-tos/streaming-from-final-node.ipynb | 328 ++++++++++++++++++ .../how-tos/use-in-web-environments.ipynb | 72 ++-- 3 files changed, 362 insertions(+), 42 deletions(-) create mode 100644 examples/how-tos/streaming-from-final-node.ipynb diff --git a/deno.json b/deno.json index 207fead9..350033b7 100644 --- a/deno.json +++ b/deno.json @@ -6,8 +6,8 @@ "@langchain/cloudflare": "npm:/@langchain/cloudflare", "@langchain/groq": "npm:/@langchain/groq", "@langchain/core/": "npm:/@langchain/core@latest/", - "@langchain/langgraph": "npm:/@langchain/langgraph@0.0.26", - "@langchain/langgraph/": "npm:/@langchain/langgraph@0.0.26/", + "@langchain/langgraph": "npm:/@langchain/langgraph@0.1.1", + "@langchain/langgraph/": "npm:/@langchain/langgraph@0.1.1/", "@langchain/mistralai": "npm:/@langchain/mistralai", "@langchain/anthropic": "npm:/@langchain/anthropic@latest", "@xenova/transformers": "npm:/@xenova/transformers", diff --git a/examples/how-tos/streaming-from-final-node.ipynb b/examples/how-tos/streaming-from-final-node.ipynb new file mode 100644 index 00000000..2f6857e3 --- /dev/null +++ b/examples/how-tos/streaming-from-final-node.ipynb @@ -0,0 +1,328 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "15c4bd28", + "metadata": {}, + "source": [ + "# How to stream from the final node" + ] + }, + { + "cell_type": "markdown", + "id": "964686a6-8fed-4360-84d2-958c48186008", + "metadata": {}, + "source": [ + "One common pattern for graphs is to stream LLM tokens from inside the final node only. This guide demonstrates how you can do this." + ] + }, + { + "cell_type": "markdown", + "id": "17f994ca-28e7-4379-a1c9-8c1682773b5f", + "metadata": {}, + "source": [ + "## Define model and tools\n", + "\n", + "First, set up a chat model and a tool to call within your graph:\n", + "\n", + "```bash\n", + "npm install @langchain/langgraph @langchain/anthropic\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1d51c35c-dbf2-4c01-932d-c5d308ea37d2", + "metadata": {}, + "outputs": [], + "source": [ + "import { z } from \"zod\";\n", + "import { tool } from \"@langchain/core/tools\";\n", + "import { ChatAnthropic } from \"@langchain/anthropic\";\n", + "\n", + "const getWeather = tool(async ({ city }) => {\n", + " if (city === \"nyc\") {\n", + " return \"It might be cloudy in nyc\";\n", + " } else if (city === \"sf\") {\n", + " return \"It's always sunny in sf\";\n", + " } else {\n", + " throw new Error(\"Unknown city.\");\n", + " }\n", + "}, {\n", + " name: \"get_weather\",\n", + " schema: z.object({\n", + " city: z.enum([\"nyc\", \"sf\"]),\n", + " }),\n", + " description: \"Use this to get weather information\",\n", + "});\n", + "\n", + "const tools = [getWeather];\n", + "\n", + "const model = new ChatAnthropic({\n", + " model: \"claude-3-5-sonnet-20240620\",\n", + "}).bindTools(tools);\n", + "\n", + "\n", + "// We add a tag that we'll be using later to filter outputs\n", + "const finalModel = new ChatAnthropic({\n", + " model: \"claude-3-5-sonnet-20240620\",\n", + "}).withConfig({\n", + " tags: [\"final_node\"],\n", + "});" + ] + }, + { + "cell_type": "markdown", + "id": "9acef997-5dd6-4108-baf1-c4d6be3e4999", + "metadata": {}, + "source": [ + "## Define graph\n", + "\n", + "Now, lay out your graph:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2efe9fb4-c6c2-4171-becd-d45bbf899209", + "metadata": {}, + "outputs": [], + "source": [ + "import { StateGraph, MessagesAnnotation } from \"@langchain/langgraph\";\n", + "import { ToolNode } from \"@langchain/langgraph/prebuilt\";\n", + "import { AIMessage, HumanMessage, SystemMessage } from \"@langchain/core/messages\";\n", + "\n", + "const shouldContinue = async (state: typeof MessagesAnnotation.State) => {\n", + " const messages = state.messages;\n", + " const lastMessage: AIMessage = messages[messages.length - 1];\n", + " // If the LLM makes a tool call, then we route to the \"tools\" node\n", + " if (lastMessage.tool_calls?.length) {\n", + " return \"tools\";\n", + " }\n", + " // Otherwise, we stop (reply to the user)\n", + " return \"final\";\n", + "};\n", + "\n", + "const callModel = async (state: typeof MessagesAnnotation.State) => {\n", + " const messages = state.messages;\n", + " const response = await model.invoke(messages);\n", + " // We return a list, because this will get added to the existing list\n", + " return { messages: [response] };\n", + "};\n", + "\n", + "const callFinalModel = async (state: typeof MessagesAnnotation.State) => {\n", + " const messages = state.messages;\n", + " const lastAIMessage = messages[messages.length - 1];\n", + " const response = await finalModel.invoke([\n", + " new SystemMessage(\"Rewrite this in the voice of Al Roker\"),\n", + " new HumanMessage({ content: lastAIMessage.content })\n", + " ]);\n", + " // MessagesAnnotation allows you to overwrite messages from the agent\n", + " // by returning a message with the same id\n", + " response.id = lastAIMessage.id;\n", + " return { messages: [response] };\n", + "}\n", + "\n", + "const toolNode = new ToolNode(tools);\n", + "\n", + "const graph = new StateGraph(MessagesAnnotation)\n", + " .addNode(\"agent\", callModel)\n", + " .addNode(\"tools\", toolNode)\n", + " // add a separate final node\n", + " .addNode(\"final\", callFinalModel)\n", + " .addEdge(\"__start__\", \"agent\")\n", + " // Third parameter is optional and only here to draw a diagram of the graph\n", + " .addConditionalEdges(\"agent\", shouldContinue, {\n", + " tools: \"tools\",\n", + " final: \"final\",\n", + " })\n", + " .addEdge(\"tools\", \"agent\")\n", + " .addEdge(\"final\", \"__end__\")\n", + " .compile();" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "f8b77e74-17e9-4fee-a164-4637013b55ff", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import * as tslab from \"tslab\";\n", + "\n", + "const diagram = graph.getGraph();\n", + "const image = await diagram.drawMermaidPng();\n", + "const arrayBuffer = await image.arrayBuffer();\n", + "\n", + "tslab.display.png(new Uint8Array(arrayBuffer));" + ] + }, + { + "cell_type": "markdown", + "id": "521adaef-dd2f-46d6-8f6a-5cc1d6e0aefc", + "metadata": {}, + "source": [ + "## Stream outputs from the final node" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a37c3a5f-5a43-46db-940e-c583df776520", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hey |\n", + " there, folks |\n", + "! Al |\n", + " Roker here with |\n", + " your weather update. |\n", + "\n", + "\n", + "Well |\n", + ", well |\n", + ", well, it seems |\n", + " like |\n", + " the |\n", + " Big |\n", + " Apple might |\n", + " be getting |\n", + " a little over |\n", + "cast today. That |\n", + "'s right |\n", + ", we |\n", + "'re |\n", + " looking |\n", + " at some |\n", + " cloud cover moving in over |\n", + " New |\n", + " York City. But hey |\n", + ", don't let that |\n", + " dampen your spirits! |\n", + " A |\n", + " little clou |\n", + "d never |\n", + " hurt anybody |\n", + ", |\n", + " right?\n", + "\n", + "Now |\n", + ", I |\n", + "' |\n", + "d love |\n", + " to give |\n", + " you more |\n", + " details, |\n", + " but Mother |\n", + " Nature can |\n", + " be as |\n", + " unpredictable as |\n", + " a game |\n", + " of chance sometimes |\n", + ". So |\n", + ", if |\n", + " you want |\n", + " the full |\n", + " scoop on NYC |\n", + "'s weather |\n", + " or |\n", + " if |\n", + " you're |\n", + " curious |\n", + " about conditions |\n", + " in any other city across |\n", + " this |\n", + " great nation of ours |\n", + ", just give |\n", + " me a ho |\n", + "ller! I'm here |\n", + " to keep |\n", + " you in the know, |\n", + " whether |\n", + " it's sunshine |\n", + ", |\n", + " rain, or anything |\n", + " in between.\n", + "\n", + "Remember |\n", + ", a clou |\n", + "dy day is |\n", + " just |\n", + " the |\n", + " sun |\n", + "'s |\n", + " way of letting |\n", + " you know it's still |\n", + " there, even if you |\n", + " can't see it. |\n", + " Stay |\n", + " weather |\n", + "-aware |\n", + ", |\n", + " an |\n", + "d don |\n", + "'t forget your |\n", + " umbrella... |\n", + " just in case! |\n" + ] + } + ], + "source": [ + "const inputs = { messages: [new HumanMessage(\"What's the weather in nyc?\")] };\n", + "\n", + "const eventStream = await graph.streamEvents(inputs, { version: \"v2\"});\n", + "\n", + "for await (const { event, tags, data } of eventStream) {\n", + " if (event === \"on_chat_model_stream\" && tags.includes(\"final_node\")) {\n", + " if (data.chunk.content) {\n", + " // Empty content in the context of OpenAI or Anthropic usually means\n", + " // that the model is asking for a tool to be invoked.\n", + " // So we only print non-empty content\n", + " console.log(data.chunk.content, \"|\");\n", + " }\n", + " }\n", + "}\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6adb47f", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "TypeScript", + "language": "typescript", + "name": "tslab" + }, + "language_info": { + "codemirror_mode": { + "mode": "typescript", + "name": "javascript", + "typescript": true + }, + "file_extension": ".ts", + "mimetype": "text/typescript", + "name": "typescript", + "version": "3.7.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/how-tos/use-in-web-environments.ipynb b/examples/how-tos/use-in-web-environments.ipynb index 7df80dca..4541af5b 100644 --- a/examples/how-tos/use-in-web-environments.ipynb +++ b/examples/how-tos/use-in-web-environments.ipynb @@ -111,23 +111,10 @@ "metadata": {}, "outputs": [ { - "name": "stderr", + "name": "stdout", "output_type": "stream", "text": [ - "evalmachine.:41\n", - "for await (const event of eventStream2) {\n", - " ^^^^^\n", - "\n", - "SyntaxError: Unexpected reserved word\n", - " at new Script (node:vm:116:7)\n", - " at createScript (node:vm:268:10)\n", - " at Object.runInThisContext (node:vm:316:10)\n", - " at Object.execute (/Users/bracesproul/code/lang-chain-ai/langgraphjs/examples/node_modules/tslab/dist/executor.js:160:38)\n", - " at JupyterHandlerImpl.handleExecuteImpl (/Users/bracesproul/code/lang-chain-ai/langgraphjs/examples/node_modules/tslab/dist/jupyter.js:250:38)\n", - " at /Users/bracesproul/code/lang-chain-ai/langgraphjs/examples/node_modules/tslab/dist/jupyter.js:208:57\n", - " at async JupyterHandlerImpl.handleExecute (/Users/bracesproul/code/lang-chain-ai/langgraphjs/examples/node_modules/tslab/dist/jupyter.js:208:21)\n", - " at async ZmqServer.handleExecute (/Users/bracesproul/code/lang-chain-ai/langgraphjs/examples/node_modules/tslab/dist/jupyter.js:406:25)\n", - " at async ZmqServer.handleShellMessage (/Users/bracesproul/code/lang-chain-ai/langgraphjs/examples/node_modules/tslab/dist/jupyter.js:351:21)\n" + "Received 0 events from the nested function\n" ] } ], @@ -194,7 +181,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -206,30 +193,38 @@ " data: { input: { messages: [] } },\n", " name: \"nested\",\n", " tags: [],\n", - " run_id: \"9a7c5a55-f9f1-4058-8c58-7be43078468c\",\n", - " metadata: {}\n", + " run_id: \"22747451-a2fa-447b-b62f-9da19a539b2f\",\n", + " metadata: {\n", + " langgraph_step: 1,\n", + " langgraph_node: \"node\",\n", + " langgraph_triggers: [ \"start:node\" ],\n", + " langgraph_task_idx: 0,\n", + " __pregel_resuming: false,\n", + " checkpoint_id: \"1ef62793-f065-6840-fffe-cdfb4cbb1248\",\n", + " checkpoint_ns: \"node\"\n", + " }\n", "}\n", "{\n", " event: \"on_chain_end\",\n", " data: {\n", " output: HumanMessage {\n", - " lc_serializable: true,\n", - " lc_kwargs: {\n", - " content: \"Hello from a nested function!\",\n", - " additional_kwargs: {},\n", - " response_metadata: {}\n", - " },\n", - " lc_namespace: [ \"langchain_core\", \"messages\" ],\n", - " content: \"Hello from a nested function!\",\n", - " name: undefined,\n", - " additional_kwargs: {},\n", - " response_metadata: {}\n", + " \"content\": \"Hello from a nested function!\",\n", + " \"additional_kwargs\": {},\n", + " \"response_metadata\": {}\n", " }\n", " },\n", - " run_id: \"9a7c5a55-f9f1-4058-8c58-7be43078468c\",\n", + " run_id: \"22747451-a2fa-447b-b62f-9da19a539b2f\",\n", " name: \"nested\",\n", " tags: [],\n", - " metadata: {}\n", + " metadata: {\n", + " langgraph_step: 1,\n", + " langgraph_node: \"node\",\n", + " langgraph_triggers: [ \"start:node\" ],\n", + " langgraph_task_idx: 0,\n", + " __pregel_resuming: false,\n", + " checkpoint_id: \"1ef62793-f065-6840-fffe-cdfb4cbb1248\",\n", + " checkpoint_ns: \"node\"\n", + " }\n", "}\n", "Received 2 events from the nested function\n" ] @@ -307,20 +302,17 @@ ], "metadata": { "kernelspec": { - "display_name": "TypeScript", + "display_name": "Deno", "language": "typescript", - "name": "tslab" + "name": "deno" }, "language_info": { - "codemirror_mode": { - "mode": "typescript", - "name": "javascript", - "typescript": true - }, "file_extension": ".ts", - "mimetype": "text/typescript", + "mimetype": "text/x.typescript", "name": "typescript", - "version": "3.7.2" + "nb_converter": "script", + "pygments_lexer": "typescript", + "version": "5.3.3" } }, "nbformat": 4,