Last Updated: 3/7/2026
Deep AgentsLangChainLangGraphIntegrationsLearnReferenceContribute
Get started
Capabilities
Production
- Application structure
- Test
- LangSmith Studio
- Agent Chat UI
- LangSmith Deployment
- LangSmith Observability
LangGraph APIs
Use time-travel
When working with non-deterministic systems that make model-based decisions (e.g., agents powered by LLMs), it can be useful to examine their decision-making process in detail:
- Understand reasoning: Analyze the steps that led to a successful result.
- Debug mistakes: Identify where and why errors occurred.
- Explore alternatives: Test different paths to uncover better solutions.
LangGraph provides time-travel functionality to support these use cases. Specifically, you can resume execution from a prior checkpoint — either replaying the same state or modifying it to explore alternatives. In all cases, resuming past execution produces a new fork in the history. To use time-travel in LangGraph:
- Run the graph with initial inputs using
invokeorstreammethods. - Identify a checkpoint in an existing thread: Use the
get_state_historymethod to retrieve the execution history for a specificthread_idand locate the desiredcheckpoint_id. Alternatively, set an interrupt before the node(s) where you want execution to pause. You can then find the most recent checkpoint recorded up to that interrupt. - Update the graph state (optional): Use the
update_statemethod to modify the graph’s state at the checkpoint and resume execution from alternative state. - Resume execution from the checkpoint: Use the
invokeorstreammethods with an input ofNoneand a configuration containing the appropriatethread_idandcheckpoint_id.
In a workflow
This example builds a simple LangGraph workflow that generates a joke topic and writes a joke using an LLM. It demonstrates how to run the graph, retrieve past execution checkpoints, optionally modify the state, and resume execution from a chosen checkpoint to explore alternate outcomes.
Setup
To build this workflow in this example you need to set up the Anthropic LLM and install the required dependencies:
- Install dependencies:
Copy
pip install langchain_core langchain-anthropic langgraph pip install langchain_core langchain-anthropic langgraph- Initialize the LLM:
Copy
import os import os import getpass import getpass from langchain_anthropic import ChatAnthropic from langchain_anthropic import ChatAnthropic def _set_env(var: str): def _set_env(var: str): if not os.environ.get(var): if not os.environ.get(var): os.environ[var] = getpass.getpass(f"{var}: ") os.environ[var] = getpass.getpass(f "{var}: ") _set_env("ANTHROPIC_API_KEY")_set_env("ANTHROPIC_API_KEY") llm = ChatAnthropic(model="claude-sonnet-4-5-20250929") llm = ChatAnthropic(model ="claude-sonnet-4-5-20250929")Sign up for LangSmith to quickly spot issues and improve the performance of your LangGraph projects. LangSmith lets you use trace data to debug, test, and monitor your LLM apps built with LangGraph. You can also fetch traces from LangSmith to replay and debug production issues locally.
- Implement the workflow The implementation of the workflow is a simple graph with two nodes, one for generating a joke topic, another for writing the joke itself and a state to storing the intermediate values.
Copy
import uuid import uuid from typing_extensions import TypedDict, NotRequired from typing_extensions import TypedDict, NotRequiredfrom langgraph.graph import StateGraph, START, END from langgraph.graph import StateGraph, START, ENDfrom langchain.chat_models import init_chat_model from langchain.chat_models import init_chat_modelfrom langgraph.checkpoint.memory import InMemorySaver from langgraph.checkpoint.memory import InMemorySaver class State(TypedDict): class State(TypedDict): topic: NotRequired[str] topic: NotRequired[str] joke: NotRequired[str] joke: NotRequired[str] model = init_chat_model(model = init_chat_model( "claude-sonnet-4-5-20250929", "claude-sonnet-4-5-20250929", temperature=0, temperature = 0,)) def generate_topic(state: State): def generate_topic(state: State): """LLM call to generate a topic for the joke""" """LLM call to generate a topic for the joke""" msg = model.invoke("Give me a funny topic for a joke") msg = model.invoke("Give me a funny topic for a joke") return {"topic": msg.content} return {"topic": msg.content} def write_joke(state: State): def write_joke(state: State): """LLM call to write a joke based on the topic""" """LLM call to write a joke based on the topic""" msg = model.invoke(f"Write a short joke about {state['topic']}") msg = model.invoke(f "Write a short joke about {state['topic']} ") return {"joke": msg.content} return {"joke": msg.content} # Build workflow # Build workflowworkflow = StateGraph(State) workflow = StateGraph(State) # Add nodes # Add nodesworkflow.add_node("generate_topic", generate_topic)workflow.add_node("generate_topic", generate_topic)workflow.add_node("write_joke", write_joke)workflow.add_node("write_joke", write_joke) # Add edges to connect nodes # Add edges to connect nodesworkflow.add_edge(START, "generate_topic")workflow.add_edge(START, "generate_topic")workflow.add_edge("generate_topic", "write_joke")workflow.add_edge("generate_topic", "write_joke")workflow.add_edge("write_joke", END)workflow.add_edge("write_joke", END) # Compile # Compilecheckpointer = InMemorySaver() checkpointer = InMemorySaver()graph = workflow.compile(checkpointer=checkpointer) graph = workflow.compile(checkpointer =checkpointer) graph graph 1. Run the graph
To start the workflow, invoke is called without any inputs. Note the thread_id to track this execution and retrieve its checkpoints later.
Copy
config = {config = { "configurable": { "configurable": { "thread_id": uuid.uuid4(), "thread_id": uuid.uuid4(), } }}}state = graph.invoke({}, config) state = graph.invoke({}, config) print(state["topic"]) print(state["topic"])print() print()print(state["joke"]) print(state["joke"])Output:
Copy
How about "The Secret Life of Socks in the Dryer"? You know, exploring the mysterious phenomenon of how socks go into the laundry as pairs but come out as singles. Where do they go? Are they starting new lives elsewhere? Is there a sock paradise we don't know about? There's a lot of comedic potential in the everyday mystery that unites us all!How about "The Secret Life of Socks in the Dryer"? You know, exploring the mysterious phenomenon of how socks go into the laundry as pairs but come out as singles. Where do they go? Are they starting new lives elsewhere? Is there a sock paradise we don't know about? There's a lot of comedic potential in the everyday mystery that unites us all! # The Secret Life of Socks in the Dryer # The Secret Life of Socks in the Dryer I finally discovered where all my missing socks go after the dryer. Turns out they're not missing at all—they've just eloped with someone else's socks from the laundromat to start new lives together.I finally discovered where all my missing socks go after the dryer. Turns out they're not missing at all—they've just eloped with someone else's socks from the laundromat to start new lives together. My blue argyle is now living in Bermuda with a red polka dot, posting vacation photos on Sockstagram and sending me lint as alimony.My blue argyle is now living in Bermuda with a red polka dot, posting vacation photos on Sockstagram and sending me lint as alimony. 2. Identify a checkpoint
To continue from a previous point in the graphs run, use get_state_history to retrieve all the states and select the one where you want to resume execution.
Copy
# The states are returned in reverse chronological order.# The states are returned in reverse chronological order.states = list(graph.get_state_history(config)) states = list(graph.get_state_history(config)) for state in states: for state in states: print(state.next) print(state.next) print(state.config["configurable"]["checkpoint_id"]) print(state.config["configurable"]["checkpoint_id"]) print() print()Output:
Copy
()()1f02ac4a-ec9f-6524-8002-8f7b0bbeed0e1f02ac4a-ec9f-6524-8002-8f7b0bbeed0e ('write_joke',)('write_joke',)1f02ac4a-ce2a-6494-8001-cb2e2d6512271f02ac4a-ce2a-6494-8001-cb2e2d651227 ('generate_topic',)('generate_topic',)1f02ac4a-a4e0-630d-8000-b73c254ba7481f02ac4a-a4e0-630d-8000-b73c254ba748 ('__start__',)('__start__',)1f02ac4a-a4dd-665e-bfff-e6c8c44315d91f02ac4a-a4dd-665e-bfff-e6c8c44315d9 Copy
# This is the state before last (states are listed in chronological order)# This is the state before last (states are listed in chronological order)selected_state = states[1] selected_state = states[1]print(selected_state.next) print(selected_state.next)print(selected_state.values) print(selected_state.values)Output:
Copy
('write_joke',)('write_joke',){'topic': 'How about "The Secret Life of Socks in the Dryer"? You know, exploring the mysterious phenomenon of how socks go into the laundry as pairs but come out as singles. Where do they go? Are they starting new lives elsewhere? Is there a sock paradise we don\\'t know about? There\\'s a lot of comedic potential in the everyday mystery that unites us all!'}{'topic': 'How about "The Secret Life of Socks in the Dryer"? You know, exploring the mysterious phenomenon of how socks go into the laundry as pairs but come out as singles. Where do they go? Are they starting new lives elsewhere? Is there a sock paradise we don\\'t know about? There\\'s a lot of comedic potential in the everyday mystery that unites us all!'} 3. Update the state (optional)
update_state will create a new checkpoint. The new checkpoint will be associated with the same thread, but a new checkpoint ID.
Copy
new_config = graph.update_state(selected_state.config, values={"topic": "chickens"}) new_config = graph.update_state(selected_state.config, values ={"topic": "chickens"})print(new_config) print(new_config)Output:
Copy
{'configurable': {'thread_id': 'c62e2e03-c27b-4cb6-8cea-ea9bfedae006', 'checkpoint_ns': '', 'checkpoint_id': '1f02ac4a-ecee-600b-8002-a1d21df32e4c'}}{'configurable': {'thread_id': 'c62e2e03-c27b-4cb6-8cea-ea9bfedae006', 'checkpoint_ns': '', 'checkpoint_id': '1f02ac4a-ecee-600b-8002-a1d21df32e4c'}} 4. Resume execution from the checkpoint
For resumings execution from the selected checkpoint, call invoke with the config that points to the new checkpoint.
Copy
graph.invoke(None, new_config)graph.invoke(None, new_config)Output:
Copy
{'topic': 'chickens',{'topic': 'chickens', 'joke': 'Why did the chicken join a band?\n\nBecause it had excellent drumsticks!'} 'joke': 'Why did the chicken join a band? \n\nBecause it had excellent drumsticks!'}Edit this page on GitHub or file an issue .
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.
Was this page helpful?