Files
langgraph/examples/map-reduce.ipynb
T

232 lines
23 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"id": "95a87145-34d0-4f97-b45f-5c9fd8532c8a",
"metadata": {},
"source": [
"# How to create map-reduce branches for parallel execution\n",
"\n",
"A common pattern in agents is to generate a list of objects, do some work on each of those objects, and then combine the results. This is very similar to the common [map-reduce](https://en.wikipedia.org/wiki/MapReduce) operation. This can be tricky for a few reasons. First, it can be tough to define a structured graph ahead of time because the length of the list of objects may be unknown. Second, in order to do this map-reduce you need multiple versions of the state to exist... but the graph shares a common shared state, so how can this be?\n",
"\n",
"LangGraph supports this via the `Send` api. This can be used to allow a conditional edge to `Send` multiple different states to multiple nodes. The state it sends can be different from the state of the core graph.\n",
"\n",
"Let's see what this looks like in action! We'll put together a toy example of generating a list of words, and then writing a joke about each word, and then judging what the best joke is."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3eb04cd1",
"metadata": {},
"outputs": [],
"source": [
"%pip install -U langchain-anthropic langgraph"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "dc292321",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import getpass\n",
"\n",
"\n",
"def _set_env(name: str):\n",
" if not os.getenv(name):\n",
" os.environ[name] = getpass.getpass(f\"{name}: \")\n",
"\n",
"\n",
"_set_env(\"ANTHROPIC_API_KEY\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "0f0f78e4-423d-4e2d-aa1a-01efaec4715f",
"metadata": {},
"outputs": [],
"source": [
"import operator\n",
"from typing import Annotated, TypedDict\n",
"\n",
"from langchain_core.pydantic_v1 import BaseModel\n",
"from langchain_anthropic import ChatAnthropic\n",
"\n",
"from langgraph.constants import Send\n",
"from langgraph.graph import END, StateGraph, START\n",
"\n",
"# Model and prompts\n",
"# Define model and prompts we will use\n",
"subjects_prompt = \"\"\"Generate a comma separated list of between 2 and 5 {topic}.\"\"\"\n",
"joke_prompt = \"\"\"Generate a joke about {subject}\"\"\"\n",
"best_joke_prompt = \"\"\"Below are a bunch of jokes about {topic}. Select the best one! Return the ID of the best one.\n",
"\n",
"{jokes}\"\"\"\n",
"\n",
"\n",
"class Subjects(BaseModel):\n",
" subjects: list[str]\n",
"\n",
"\n",
"class Joke(BaseModel):\n",
" joke: str\n",
"\n",
"\n",
"class BestJoke(BaseModel):\n",
" id: int\n",
"\n",
"\n",
"model = ChatAnthropic(model=\"claude-3-5-sonnet-20240620\")\n",
"\n",
"# Graph components: define the components that will make up the graph\n",
"\n",
"\n",
"# This will be the overall state of the main graph.\n",
"# It will contain a topic (which we expect the user to provide)\n",
"# and then will generate a list of subjects, and then a joke for\n",
"# each subject\n",
"class OverallState(TypedDict):\n",
" topic: str\n",
" subjects: list\n",
" # Notice here we use the operator.add\n",
" # This is because we want combine all the jokes we generate\n",
" # from individual nodes back into one list - this is essentially\n",
" # the \"reduce\" part\n",
" jokes: Annotated[list, operator.add]\n",
" best_selected_joke: str\n",
"\n",
"\n",
"# This will be the state of the node that we will \"map\" all\n",
"# subjects to in order to generate a joke\n",
"class JokeState(TypedDict):\n",
" subject: str\n",
"\n",
"\n",
"# This is the function we will use to generate the subjects of the jokes\n",
"def generate_topics(state: OverallState):\n",
" prompt = subjects_prompt.format(topic=state[\"topic\"])\n",
" response = model.with_structured_output(Subjects).invoke(prompt)\n",
" return {\"subjects\": response.subjects}\n",
"\n",
"\n",
"# Here we generate a joke, given a subject\n",
"def generate_joke(state: JokeState):\n",
" prompt = joke_prompt.format(subject=state[\"subject\"])\n",
" response = model.with_structured_output(Joke).invoke(prompt)\n",
" return {\"jokes\": [response.joke]}\n",
"\n",
"\n",
"# Here we define the logic to map out over the generated subjects\n",
"# We will use this an edge in the graph\n",
"def continue_to_jokes(state: OverallState):\n",
" # We will return a list of `Send` objects\n",
" # Each `Send` object consists of the name of a node in the graph\n",
" # as well as the state to send to that node\n",
" return [Send(\"generate_joke\", {\"subject\": s}) for s in state[\"subjects\"]]\n",
"\n",
"\n",
"# Here we will judge the best joke\n",
"def best_joke(state: OverallState):\n",
" jokes = \"\\n\\n\".format()\n",
" prompt = best_joke_prompt.format(topic=state[\"topic\"], jokes=jokes)\n",
" response = model.with_structured_output(BestJoke).invoke(prompt)\n",
" return {\"best_selected_joke\": state[\"jokes\"][response.id]}\n",
"\n",
"\n",
"# Construct the graph: here we put everything together to construct our graph\n",
"graph = StateGraph(OverallState)\n",
"graph.add_node(\"generate_topics\", generate_topics)\n",
"graph.add_node(\"generate_joke\", generate_joke)\n",
"graph.add_node(\"best_joke\", best_joke)\n",
"graph.add_edge(START, \"generate_topics\")\n",
"graph.add_conditional_edges(\"generate_topics\", continue_to_jokes, [\"generate_joke\"])\n",
"graph.add_edge(\"generate_joke\", \"best_joke\")\n",
"graph.add_edge(\"best_joke\", END)\n",
"app = graph.compile()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "37ed1f71-63db-416f-b715-4617b33d4b7f",
"metadata": {},
"outputs": [
{
"data": {
"image/jpeg": "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",
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.display import Image\n",
"\n",
"Image(app.get_graph().draw_mermaid_png())"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "fd90cace",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'generate_topics': {'subjects': ['lion', 'elephant', 'penguin', 'giraffe']}}\n",
"{'generate_joke': {'jokes': [\"Why don't you see penguins in Britain? Because they're afraid of Wales!\"]}}\n",
"{'generate_joke': {'jokes': [\"Why don't elephants use computers? They're afraid of the mouse!\"]}}\n",
"{'generate_joke': {'jokes': [\"Why don't lions like fast food? Because they can't catch it!\"]}}\n",
"{'generate_joke': {'jokes': [\"Why don't giraffes ever get caught in traffic jams? Because they can always stick their necks out and see what's ahead!\"]}}\n",
"{'best_joke': {'best_selected_joke': \"Why don't elephants use computers? They're afraid of the mouse!\"}}\n"
]
}
],
"source": [
"# Call the graph: here we call it to generate a list of jokes\n",
"for s in app.stream({\"topic\": \"animals\"}):\n",
" print(s)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f28eaf56",
"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.12.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}