{"slug": "the-building-blocks-of-langgraph-part-0", "title": "The Building Blocks of LangGraph (Part 0)", "summary": "LangGraph, an orchestration framework from the LangChain team, enables developers to build stateful, controllable AI workflows by modeling them as graphs with nodes, edges, and shared state. The framework addresses the challenge of coordinating complex AI systems that reason, use tools, and collaborate across tasks.", "body_md": "*For other parts of the series : **Part 0** , **Part 1** , **Part 2** , **Part 3*\n\nAs Large Language Models (LLMs) have become more capable, developers have moved beyond simple chatbots and begun building systems that can reason, make decisions, use tools, retrieve information, interact with APIs, and collaborate with other AI agents.\n\nBuilding these systems introduces a new challenge:\n\n**How do we coordinate and manage the flow of intelligence?**\n\nThis is the problem that **LangGraph** was created to solve.\n\nAt its core, LangGraph is a framework for building **stateful, controllable, and production-ready AI workflows**. It allows developers to define how AI agents think, make decisions, communicate with tools, and move through complex tasks.\n\nIf LangChain helps you connect AI components together, LangGraph helps you orchestrate how those components behave over time.\n\nLangGraph is an orchestration framework built by the team behind LangChain.\n\nIt allows developers to model AI applications as a **graph**\n\nLet’s build a simple graph with 3 nodes and one conditional edge.\n\nThe easiest way to understand **nodes, edges, and state** is to imagine a food delivery process.\n\nA **node** is simply a task or action that does something.\n\nFor example:\n\n```\nReceive Order\n```\n\nis a node.\n\n```\nPrepare Food\n```\n\nis another node.\n\n```\nDeliver Food\n```\n\nis another node.\n\nEvery time some work is performed, you are at a node.\n\nAn **edge** is the path that tells the system where to go next.\n\nFor example:\n\n```\nReceive Order      ↓Prepare Food      ↓Deliver Food\n```\n\nThose arrows are the edges.\n\nThe edge is not doing any work itself. It simply says:\n\n“After this step finishes, go to that step.”\n\nThink of an edge as a road connecting two cities. The cities are the nodes, and the road is the edge.\n\nA **state** is the information that travels through the entire process.\n\nImagine a customer orders:\n\n```\nPizzaAddress: 123 Main StreetCustomer: John\n```\n\nWhen the order is received, that information enters the system.\n\nAs the order moves from:\n\n```\nReceive Order      ↓Prepare Food      ↓Deliver Food\n```\n\nthe information moves along with it.\n\nThat information is the state.\n\nThink of **state** as the graph’s shared memory.\n\nIt is the information that travels through the workflow as it moves from one node to another. Every node can read the state, update it, and pass the updated version to the next node.\n\nIn this example, the state contains a single piece of information called graph_state. First, define the [State](https://docs.langchain.com/oss/python/langgraph/graph-api#state) of the graph.\n\nThe State schema serves as the input schema for all Nodes and Edges in the graph.\n\nLet’s use the TypedDict class from python's typing module as our schema, which provides type hints for the keys.\n\n``` python\nfrom typing_extensions import TypedDictclass State(TypedDict):    graph_state: strNodes\n```\n\nA **node** is simply a function that performs some work.\n\nWhen a node runs, it receives the current state, does something with it, and returns an updated state.\n\nYou can think of a node as a worker in a factory. The worker receives a package (the state), modifies it, and then passes it along.\n\nThe first positional argument is the state, as defined above.\n\nBecause the state is a TypedDict with schema as defined above, each node can access the key, graph_state, with state['graph_state'].\n\nEach node returns a new value of the state key graph_state.\n\nBy default, the new value returned by each node [will override](https://docs.langchain.com/oss/python/langgraph/graph-api/#reducers) the prior state value.\n\n``` python\ndef node_1(state):  print(\"---Node 1---\")  return {\"graph_state\": state['graph_state'] + \"I am\"}def node_2(state):  print(\"---Node 2---\")  return {\"graph_state\": state['graph_state'] + \"happy!\"}def node_3(state):  print(\"---Node 3---\")  return {\"graph_state\": state['graph_state'] + \"sad!\"}\n```\n\nAn **edge** is simply a connection between nodes. It tells the graph where to go after a node finishes its work.\n\nA **normal edge** is a fixed path. After one node completes, the graph always moves to the same next node.\n\nFor example, if a workflow has “Collect Data” followed by “Analyze Data,” the graph will always move from the first node to the second.\n\nA **conditional edge** is a decision point. Instead of always following the same path, the graph looks at the current state and decides where to go next.\n\nFor example, after analyzing data, the graph might ask:\n\n“Do I have enough information?”\n\nIf the answer is yes, it moves to “Generate Report.”\n\nIf the answer is no, it moves back to “Collect More Data.”\n\nConditional edges are implemented as functions that return the next node to visit based on some logic.\n\n``` php\nimport randomfrom typing import Literaldef decide_mood(state) -> Literal[\"node_2\", \"node_3\"]:    # Often, we will use state to decide on the next node to visit  user_input = state['graph_state']      # Here, let's just do a 50 / 50 split between nodes 2, 3  if random.random() < 0.5      # 50% of the time, we return Node 2      return \"node_2\"     # 50% of the time, we return Node 3  return \"node_3\"\n```\n\nNow, we build the graph from our components defined above.\n\nThe [StateGraph class](https://docs.langchain.com/oss/python/langgraph/graph-api/#stategraph) is the graph class that we can use.\n\nFirst, we initialize a StateGraph with the State class we defined above.\n\nThen, we add our nodes and edges.\n\nWe use the [START Node, a special node](https://docs.langchain.com/oss/python/langgraph/graph-api/#start-node) that sends user input to the graph, to indicate where to start our graph.\n\nThe [END Node](https://docs.langchain.com/oss/python/langgraph/graph-api/#end-node) is a special node that represents a terminal node.\n\nFinally, we [compile our graph](https://docs.langchain.com/oss/python/langgraph/graph-api/#compiling-your-graph) to perform a few basic checks on the graph structure.\n\nWe can visualize the graph as a [Mermaid diagram](https://github.com/mermaid-js/mermaid).\n\n``` python\nfrom IPython.display import Image, displayfrom langgraph.graph import StateGraph, START, END#Build Graphbuilder = StateGraph(state)builder.add_node(\"node_1\", node_1)builder.add_node(\"node_2\", node_2)builder.add_node(\"node_3\", node_3)#Logicbuilder.add_edge(START, \"node_1\")builder.add_conditional_edges(\"node_1\", decide_mood)builder.add_edge(\"node_2\", END)builder.add_edge(\"node_3\", END)#Addgraph = builder.compile()#Viewdisplay(Image(graph.get_graph().draw_mermaid_png()))\n```\n\n#OUTPUT\n\nThe compiled graph implements the [runnable](https://reference.langchain.com/python/langchain_core/runnables/?h=runnables) protocol.\n\nThis provides a standard way to execute LangChain components.\n\ninvoke is one of the standard methods in this interface.\n\nThe input is a dictionary {\"graph_state\": \"Hi, this is lance.\"}, which sets the initial value for our graph state dict.\n\nWhen invoke is called, the graph starts execution from the START node.\n\nIt progresses through the defined nodes (node_1, node_2, node_3) in order.\n\nThe conditional edge will traverse from node 1 to node 2 or 3 using a 50/50 decision rule.\n\nEach node function receives the current state and returns a new value, which overrides the graph state.\n\nThe execution continues until it reaches the END node.\n\n```\ngraph.invoke({\"graph_state\" : \"Hi, this is Lance.\"})\n###OUTPUT---Node 1------Node 3---{'graph_state': 'Hi, this is Lance. I am sad!'}\n```\n\ninvoke runs the entire graph synchronously.\n\nThis waits for each step to complete before moving to the next.\n\nIt returns the final state of the graph after all nodes have executed.\n\nIn this case, it returns the state after node_3 has completed:\n\n```\n{'graph_state': 'Hi, this is Lance. I am sad!'}\n```\n\nWe built a simple graph with nodes, normal edges, and conditional edges.\n\nNow, let’s build up to a simple chain that combines 4 concepts.\n\n```\n%%capture --no-stderr%pip install --quiet -U langchain_openai langchain_core langgraph\n```\n\nChat models can use [messages](https://docs.langchain.com/oss/python/langchain/messages), which capture different roles within a conversation.\n\nLangChain supports various message types, including HumanMessage, AIMessage, SystemMessage, and ToolMessage.\n\nThese represent a message from the user, from chat model, for the chat model to instruct behavior, and from a tool call.\n\nLet’s create a list of messages.\n\nEach message can be supplied with a few things:\n\n``` python\nfrom pprint import pprintfrom langchain_core.messages import AIMessage, HumanMessagemessages = [AIMessage(content=f\"So you said you were researching ocean mammals?\", name=\"Model\")]messages.append(HumanMessage(content=f\"Yes, that's right.\",name=\"Lance\"))messages.append(AIMessage(content=f\"Great, what would you like to learn about.\", name=\"Model\"))messages.append(HumanMessage(content=f\"I want to learn about the best place to see Orcas in the US.\", name=\"Lance\"))for m in messages:    m.pretty_print()\n#OUTPUT================================== Ai Message ==================================Name: ModelSo you said you were researching ocean mammals?================================ Human Message =================================Name: LanceYes, that's right.================================== Ai Message ==================================Name: ModelGreat, what would you like to learn about.================================ Human Message =================================Name: LanceI want to learn about the best place to see Orcas in the US.\n```\n\nChat models use a sequence of messages as input and support message types, as discussed above.\n\nThere are [many](https://docs.langchain.com/oss/python/integrations/chat) to choose from! Let’s work with OpenAI.\n\nWe can load a chat model and invoke it with out list of messages.\n\nWe can see that the result is an AIMessage with specific response_metadata.\n\n``` python\nfrom langchain_openai import ChatOpenAIllm = ChatOpenAI(model=\"gpt-4o\")result = llm.invoke(messages)type(result)result\n#OUTPUTlangchain_core.messages.ai.AIMessageresultAIMessage(content='One of the best places to see orcas in the United States is the Pacific Northwest, particularly around the San Juan Islands in Washington State. Here are some details:\\n\\n1. **San Juan Islands, Washington**: These islands are a renowned spot for whale watching, with orcas frequently spotted between late spring and early fall. The waters around the San Juan Islands are home to both resident and transient orca pods, making it an excellent location for sightings.\\n\\n2. **Puget Sound, Washington**: This area, including places like Seattle and the surrounding waters, offers additional opportunities to see orcas, particularly the Southern Resident killer whale population.\\n\\n3. **Olympic National Park, Washington**: The coastal areas of the park provide a stunning backdrop for spotting orcas, especially during their migration periods.\\n\\nWhen planning a trip for whale watching, consider peak seasons for orca activity and book tours with reputable operators who adhere to responsible wildlife viewing practices. Additionally, land-based spots like Lime Kiln Point State Park, also known as “Whale Watch Park,” on San Juan Island, offer great opportunities for orca watching from shore.', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 228, 'prompt_tokens': 67, 'total_tokens': 295, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_50cad350e4', 'finish_reason': 'stop', 'logprobs': None}, id='run-57ed2891-c426-4452-b44b-15d0a5c3f225-0', usage_metadata={'input_tokens': 67, 'output_tokens': 228, 'total_tokens': 295, 'input_token_details': {'audio': 0, 'cache_read': 0}, 'output_token_details': {'audio': 0, 'reasoning': 0}})\n```\n\nTools are useful whenever you want a model to interact with external systems.\n\nExternal systems (e.g., APIs) often require a particular input schema or payload, rather than natural language.\n\nWhen we bind an API, for example, as a tool we given the model awareness of the required input schema.\n\nThe model will choose to call a tool based upon the natural language input from the user.\n\nAnd, it will return an output that adheres to the tool’s schema.\n\n[Many LLM providers support tool calling](https://docs.langchain.com/oss/python/integrations/chat) and [tool calling interface](https://blog.langchain.com/improving-core-tool-interfaces-and-docs-in-langchain/) in LangChain is simple.\n\nYou can simply pass any Python function into ChatModel.bind_tools(function).\n\nLet’s showcase a simple example of tool calling!\n\nThe multiply function is our tool.\n\n``` php\ndef multiply(a:int, b:int)-> int:  return a*bllm_with_tools = llm.bind_tools([multiply])\n```\n\nIf we pass an input — e.g., \"What is 2 multiplied by 3\" - we see a tool call returned.\n\nThe tool call has specific arguments that match the input schema of our function along with the name of the function to call. {‘arguments’: ‘{“a”:2,”b”:3}’, ‘name’: ‘multiply’}\n\n```\ntool_call = llm_with_tools.invoke([HumanMessage(content=f\"What is 2 multiplied by 3\", name=\"Lance\")])\ntool_call.tool_calls\n#OUTPUT[{'name': 'multiply',  'args': {'a': 2, 'b': 3},  'id': 'call_lBBBNo5oYpHGRqwxNaNRbsiT',  'type': 'tool_call'}]\n```\n\nWith these foundations in place, we can now use [messages](https://docs.langchain.com/oss/python/langchain/overview#messages) in our graph state.\n\nLet’s define our state, MessagesState, as a TypedDict with a single key: messages.\n\nmessages is simply a list of messages, as we defined above (e.g., HumanMessage, etc).\n\n``` python\nfrom typing_extentions import TypedDictfrom langchain_core.messges import AnyMessageclass MessagesState(TypedDict):  messages : list[AnyMessage]\n```\n\nNow, we have a minor problem!\n\nAs we discussed, each node will return a new value for our state key messages.\n\nBut, this new value will overwrite the prior messages value!\n\nAs our graph runs, we want to **append** messages to our messages state key.\n\nWe can use [reducer functions](https://docs.langchain.com/oss/python/langgraph/graph-api#reducers) to address this.\n\nReducers specify how state updates are performed.\n\nIf no reducer function is specified, then it is assumed that updates to the key should *override it* as we saw before.\n\nBut, to append messages, we can use the pre-built add_messages reducer.\n\nThis ensures that any messages are appended to the existing list of messages.\n\nWe simply need to annotate our messages key with the add_messages reducer function as metadata.\n\n``` python\nfrom typing import Annotatedfrom langgraph.graph.message import add_messagesclass MessagesState(TypedDict):    messages: Annotated[list[AnyMessage], add_messages]\n```\n\nSince having a list of messages in graph state is so common, LangGraph has a pre-built [MessagesState](https://docs.langchain.com/oss/python/langgraph/graph-api#messagesstate)!\n\nMessagesState is defined:\n\nWe’ll usually use MessagesState because it is less verbose than defining a custom TypedDict, as shown above.\n\n``` python\nfrom langgraph.graph import MessagesStateclass MessagesState(MessagesState):    # Add any keys needed beyond messages, which is pre-built     pass\n```\n\nTo go a bit deeper, we can see how the `add_messages` reducer works in isolation.\n\n```\n# Initial stateinitial_messages = [AIMessage(content=\"Hello! How can I assist you?\", name=\"Model\"),                    HumanMessage(content=\"I'm looking for information on marine biology.\", name=\"Lance\")                   ]# New message to addnew_message = AIMessage(content=\"Sure, I can help with that. What specifically are you interested in?\", name=\"Model\")# Testadd_messages(initial_messages , new_message)\n```\n\nNow, lets use MessagesState with a graph.\n\n``` python\nfrom IPython.display import Image, displayfrom langgraph.graph import StateGraph, START, END    # Nodedef tool_calling_llm(state: MessagesState):    return {\"messages\": [llm_with_tools.invoke(state[\"messages\"])]}# Build graphbuilder = StateGraph(MessagesState)builder.add_node(\"tool_calling_llm\", tool_calling_llm)builder.add_edge(START, \"tool_calling_llm\")builder.add_edge(\"tool_calling_llm\", END)graph = builder.compile()# Viewdisplay(Image(graph.get_graph().draw_mermaid_png()))\n```\n\n#OUTPUT\n\nIf we pass in `Hello!`, the LLM responds without any tool calls.\n\n```\nmessages = graph.invoke({\"messages\": HumanMessage(content=\"Hello!\")})for m in messages['messages']:    m.pretty_print()\n#OUTPUT================================ Human Message =================================Hello!================================== Ai Message ==================================Hi there! How can I assist you today?\n```\n\nThe LLM chooses to use a tool when it determines that the input or task requires the functionality provided by that tool.\n\n```\nmessages = graph.invoke({\"messages\": HumanMessage(content=\"Multiply 2 and 3\")})for m in messages['messages']:    m.pretty_print()\nOUTPUT================================ Human Message =================================Multiply 2 and 3!================================== Ai Message ==================================Tool Calls:  multiply (call_Er4gChFoSGzU7lsuaGzfSGTQ) Call ID: call_Er4gChFoSGzU7lsuaGzfSGTQ  Args:    a: 2    b: 3\n```\n\nGREAT JOB GUYS ! 🚀\n\n[The Building Blocks of LangGraph (Part 0)](https://pub.towardsai.net/the-building-blocks-of-langgraph-1975904edac8) was originally published in [Towards AI](https://pub.towardsai.net) on Medium, where people are continuing the conversation by highlighting and responding to this story.", "url": "https://wpnews.pro/news/the-building-blocks-of-langgraph-part-0", "canonical_source": "https://pub.towardsai.net/the-building-blocks-of-langgraph-1975904edac8?source=rss----98111c9905da---4", "published_at": "2026-06-25 07:42:40+00:00", "updated_at": "2026-06-25 07:47:59.484618+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "large-language-models"], "entities": ["LangGraph", "LangChain"], "alternates": {"html": "https://wpnews.pro/news/the-building-blocks-of-langgraph-part-0", "markdown": "https://wpnews.pro/news/the-building-blocks-of-langgraph-part-0.md", "text": "https://wpnews.pro/news/the-building-blocks-of-langgraph-part-0.txt", "jsonld": "https://wpnews.pro/news/the-building-blocks-of-langgraph-part-0.jsonld"}}