Build Your First AI Agent with LangGraph

Build a calculator AI agent that autonomously chains tool calls to solve math problems.

Introduction

30 Second Summary

When you solve a tricky math problem, you break it into smaller steps. You might multiply two numbers first, then divide the result. An AI agent works the same way, picking the right tool for each step and looping until the job is done.

In this project, you will build an AI agent that autonomously solves multi-step math questions by calling custom tools you create. You will use LangGraph to wire the agent's decision-making logic into a graph that routes between thinking and acting.

What You'll Build

A calculator agent powered by Claude that receives a math question, figures out which tools to call (multiply, divide, add), and loops until it has the final answer.

By the end of this project, you'll have:

  • A Python script containing a fully functional LangGraph agent that decides when and how to use tools.
  • Three custom tools (add, multiply, divide) the agent can call on its own to solve problems.
  • A state graph with conditional routing that controls the agent's loop between thinking and acting.
  • Secret Mission: Add a memory tool that lets your agent store and recall facts across conversations.

Are there any prerequisites?

None. This project includes full setup instructions for Python, pip, and your Anthropic API key. You will need roughly $0.05 in API credits to run the agent.

Set Up Your Environment

Your AI agent needs three things to run: Python to execute the code, a few libraries that provide the agent framework, and an API key that connects to Claude.

This step installs everything and gets your environment ready to build.

In this step, get ready to:
  • Install Python 3.11 or higher.
  • Install the LangGraph, LangChain, and LangChain-Anthropic packages.
  • Create an Anthropic account and get your API key.
Install Python 3.11+

LangGraph requires Python 3.11 or higher. macOS ships with an older system Python, so you may need to install a newer version.

You will use VS Code as your text editor for this project. Any text editor works, but VS Code has a built-in terminal that makes running commands easy.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Visual Studio Code and press Enter to open it.
  • Press Ctrl+` (backtick) to open the integrated terminal inside VS Code.

Don't have VS Code installed?

Download it for free from code.visualstudio.com. Run the installer, then open it using the search bar steps above.

  • Check your Python version by running this command in the terminal:
python3 --version

✔️ I see a version number

If you see Python 3.11 or higher (like 3.12 or 3.13), you are good to go. Move on to the next substep.

ⓧ Command not found or version is below 3.11

You need to install Python 3.11 or higher.

  • Go to python.org/downloads in your browser.
  • Click the large Download Python button to get the latest version.
  • Run the downloaded installer and follow the prompts.
  • On Windows, check the box that says Add Python to PATH before clicking Install Now.
  • Close and reopen your VS Code terminal, then run python3 --version again to confirm the install.

You should now see a version number of 3.11 or higher.

Install the required packages

Your agent relies on three Python packages. LangGraph provides the graph-based agent framework. LangChain provides the tool and message utilities. LangChain-Anthropic connects everything to Claude.

  • Install all three packages by running this command in your VS Code terminal:
pip3 install langgraph==1.1.10 langchain==1.2.16 langchain-anthropic==1.4.3

What does this command do?

pip3 install downloads packages from the Python Package Index and installs them on your machine. The == pins each package to a specific version so your code behaves the same way this guide describes.

The installation may take a minute. You should see progress bars followed by a Successfully installed message listing all the packages.

Seeing a permissions error?

If you see Permission denied, try adding --user to the end of the install command. This installs the packages for your user account only.

If you see pip3: command not found, try using pip instead of pip3.

Help me fix my pip installation error

Create your Anthropic API account

Your agent sends requests to Claude through the Anthropic API. To authenticate those requests, you need an API key.

  • Open console.anthropic.com in your browser.
  • Sign up for a new account (or log in if you already have one).
  • Navigate to the Billing section in the left sidebar.
  • Purchase at least $5 in credits. This is the minimum amount required to reach Tier 1 API access.

How much will this project cost?

This project uses Claude Haiku 4.5, which costs $1 per million input tokens and $5 per million output tokens. A simple calculator agent uses very few tokens per run.

You will spend roughly $0.05 or less completing this project, even with experimentation. The $5 credit purchase gives you access and will last well beyond this project.

Now create your API key.

  • Click API Keys in the left sidebar.
  • Click Create Key.
  • Give your key a name like langgraph-agent.
  • Copy the key and paste it somewhere safe (like a notes app). You will not be able to see it again after closing this dialog.

Keep your API key private

Never share your API key publicly or commit it to a Git repository. Anyone with your key can make API calls charged to your account.

Your environment is ready. Next up, you will define the tools your agent can use to solve math problems.

Define Your Tools

Your environment is set up and ready to go. Now it's time to give your AI agent something to work with: tools.

Tools are Python functions that an LLM can decide to call on its own. In this step, you'll define three arithmetic tools and connect them to Claude so it knows they're available.

In this step, get ready to:
  • Create your agent file and import the required modules.
  • Define three tool functions that the LLM can call.
  • Bind the tools to Claude so it knows how to use them.
Create your agent file and add imports

Your agent will live in a single Python file. You'll import everything upfront so the rest of the step can focus on building logic.

  • In VS Code, click File in the top menu bar.
  • Click New File.
  • Name the file agent.py and save it to your Desktop.
  • Add the following imports and model initialization to agent.py:
import operator
from typing import Literal
from typing_extensions import TypedDict, Annotated

from langchain.tools import tool
from langchain.chat_models import init_chat_model
from langchain.messages import AnyMessage, SystemMessage, HumanMessage, ToolMessage
from langgraph.graph import StateGraph, START, END


# Step 1: Define tools and model

model = init_chat_model(
    "claude-haiku-4-5",
    temperature=0
)

What does this code do?

  • The first group of imports (operator, TypedDict, Annotated) are Python utilities you'll use in the next step to define your agent's state.
  • The LangGraph and LangChain imports bring in the @tool decorator, the model factory, message types, and the graph builder.
  • init_chat_model("claude-haiku-4-5", temperature=0) creates a connection to Claude Haiku 4.5. Setting temperature=0 makes the model's responses deterministic, which is ideal for tool-calling tasks.
  • Save agent.py.

The tools you define next put these imports to work.

Seeing a red underline on an import?

If VS Code shows a warning on any import line, your Python environment may not have the packages installed. Make sure you installed the packages in Step 1 using the same Python that VS Code is using.

Check the Python interpreter in the bottom-right corner of VS Code. It should show Python 3.11 or higher.

Help me fix my Python imports in VS Code

Define your tool functions

A tool is just a Python function with a special decorator. The @tool decorator reads the function's docstring and uses it to tell the LLM what the tool does and what arguments it expects.

  • In agent.py, add the following three tool functions below the model initialization:
@tool
def multiply(a: int, b: int) -> int:
    """Multiply a and b.

    Args:
        a: First int
        b: Second int
    """
    return a * b


@tool
def add(a: int, b: int) -> int:
    """Add a and b.

    Args:
        a: First int
        b: Second int
    """
    return a + b


@tool
def divide(a: int, b: int) -> float:
    """Divide a by b.

    Args:
        a: First int
        b: Second int
    """
    return a / b

What does this code do?

Each function performs a single arithmetic operation. The @tool decorator turns them into tools that Claude can call.

The docstring is critical. LangChain reads the description and the Args section to generate a schema that tells Claude exactly what each tool does and what inputs it needs. Without a docstring, the tool won't work.

  • Save agent.py.
  • Confirm your tools are syntactically correct by running this command:
python3 agent.py

Python exits silently with no output. That means your imports and tool definitions are error-free.

Seeing a syntax error?

Make sure each function has a docstring wrapped in triple quotes ("""). The docstring must include an Args: section with each parameter listed.

Also check that @tool sits directly above each def line with no blank line between them.

Help me fix my @tool function definitions

Bind the tools to Claude

Defining tools isn't enough on its own. You need to tell Claude that these tools exist so it can choose to call them during a conversation.

  • Add the following code below your divide function in agent.py:
# Augment the model with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)

What does this code do?

  • tools is a list of all your tool functions. This makes it easy to pass them around.
  • tools_by_name creates a dictionary that maps each tool's name (like "multiply") to its function. You'll use this later to look up and run the right tool when Claude asks for it.
  • model.bind_tools(tools) returns a new model instance that knows about your tools. When this model generates a response, it can choose to call one of them instead of just returning text.
  • Save agent.py.
  • Confirm your file has no red underlines or error indicators in VS Code.

Seeing a NameError on the tools list?

Make sure the tools = [add, multiply, divide] line comes after all three function definitions. Python reads top to bottom, so the functions must be defined before you reference them.

Help me fix a NameError in my agent.py

💡 Why do tools need docstrings?

When you call model.bind_tools(tools), LangChain reads each tool's docstring and converts it into a JSON schema. This schema gets sent to Claude with every request.

Claude reads the schema to decide which tool to call and what arguments to pass. The better your docstrings, the better Claude's tool-calling decisions.

✔️ Awesome, I've got everything!

Great. Double check you've saved agent.py before moving on.

ⓧ I'd like to double check the full code

Here's everything your agent.py should contain so far:

import operator
from typing import Literal
from typing_extensions import TypedDict, Annotated

from langchain.tools import tool
from langchain.chat_models import init_chat_model
from langchain.messages import AnyMessage, SystemMessage, HumanMessage, ToolMessage
from langgraph.graph import StateGraph, START, END


# Step 1: Define tools and model

model = init_chat_model(
    "claude-haiku-4-5",
    temperature=0
)


@tool
def multiply(a: int, b: int) -> int:
    """Multiply a and b.

    Args:
        a: First int
        b: Second int
    """
    return a * b


@tool
def add(a: int, b: int) -> int:
    """Add a and b.

    Args:
        a: First int
        b: Second int
    """
    return a + b


@tool
def divide(a: int, b: int) -> float:
    """Divide a by b.

    Args:
        a: First int
        b: Second int
    """
    return a / b


# Augment the model with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)

Your tools are defined and Claude knows about them. Next up, you'll build the graph that controls how your agent thinks and acts.

Build the Graph

Your tools are ready and bound to Claude. Now you need to define the actual decision-making logic that tells the agent what to do at each step.

In LangGraph, this logic lives in a graph made of nodes (functions that do work) and edges (connections that control flow). You'll define the state that travels through this graph, the nodes that process it, and the conditional logic that decides what happens next.

In this step, get ready to:
  • Define your agent's state using a typed dictionary with a message reducer.
  • Create two node functions that call Claude and execute tools.
  • Write a conditional edge function that routes between tool calls and stopping.
Define your agent's state

Every LangGraph agent carries a state object that travels from node to node. For a chat agent, that state is a list of messages. Each node reads the current messages, does its work, and appends new messages to the list.

  • In agent.py, find the line that says model_with_tools = model.bind_tools(tools), then add the following code below it:

# Step 2: Define state

class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], operator.add]

What does this code do?

AgentState is a Python class that defines the shape of your agent's memory as it processes a request.

  • messages: Annotated[list[AnyMessage], operator.add] creates a list that holds every message in the conversation.
  • The operator.add part is a reducer. It tells LangGraph to append new messages to the list instead of replacing it. Without this, each node would overwrite the entire conversation history.
Create the node functions

Nodes are the workers in your graph. Each node is a Python function that receives the current state, does something, and returns an update to the state. Your agent needs two nodes: one that asks Claude what to do, and one that executes the tool Claude chose.

  • Add the first node function below the AgentState class by copying this code:

# Step 3: Define nodes

def llm_call(state: AgentState):
    """LLM decides whether to call a tool or not"""
    return {
        "messages": [
            model_with_tools.invoke(
                [
                    SystemMessage(
                        content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
                    )
                ]
                + state["messages"]
            )
        ]
    }

What does this code do?

The llm_call function is where Claude does its thinking. Each time this node runs, Claude looks at the full conversation and decides what to do next.

  • A SystemMessage tells Claude its role (arithmetic assistant).
  • state["messages"] passes along the full conversation so far.
  • Claude's response is wrapped in a list and returned as a state update. The reducer appends it to the message history.
  • Add the second node function directly below llm_call by copying this code:

def tool_node(state: AgentState):
    """Executes the tool call from the last message"""
    result = []
    for tool_call in state["messages"][-1].tool_calls:
        tool_to_call = tools_by_name[tool_call["name"]]
        observation = tool_to_call.invoke(tool_call["args"])
        result.append(
            ToolMessage(content=str(observation), tool_call_id=tool_call["id"])
        )
    return {"messages": result}

What does this code do?

The tool_node function is the hands of your agent. When Claude says "call the multiply tool with 15 and 7", this function actually runs that calculation.

  • state["messages"][-1].tool_calls grabs the tool calls from Claude's last response.
  • tools_by_name[tool_call["name"]] looks up the actual Python function to run.
  • Each result becomes a ToolMessage so Claude can see what the tool returned on its next turn.
  • Save agent.py.
Write the conditional edge function

Right now your graph has two nodes but no logic connecting them. A conditional edge is a routing function that inspects the state and decides which node to visit next. This is what gives your agent its autonomy.

  • Add the conditional edge function below tool_node by copying this code:

# Step 4: Define conditional edge

def should_continue(state: AgentState) -> Literal["tool_node", "__end__"]:
    """Route to tool_node if the LLM made a tool call, otherwise end"""
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tool_node"
    return END

What does this code do?

This function runs every time Claude responds. It checks one thing: did Claude ask to use a tool?

  • If last_message.tool_calls has items, Claude wants to use a tool. The function routes to tool_node to execute it.
  • If there are no tool calls, Claude is done thinking. The function returns END to stop the loop.

This is the "agent loop" pattern. Claude calls tools until it has enough information, then responds with a final answer.

  • Save agent.py.

Seeing a syntax error?

  • Check that the Literal type hint uses straight double quotes, not curly quotes.
  • Make sure should_continue is defined outside the tool_node function (no extra indentation).
  • Verify you have a blank line between the end of tool_node and the comment # Step 4: Define conditional edge.

Help me debug a syntax error in my LangGraph agent

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Here is the full agent.py file as it should look at this point.

import operator
from typing import Literal
from typing_extensions import TypedDict, Annotated

from langchain.tools import tool
from langchain.chat_models import init_chat_model
from langchain.messages import AnyMessage, SystemMessage, HumanMessage, ToolMessage
from langgraph.graph import StateGraph, START, END


# Step 1: Define tools and model

model = init_chat_model(
    "claude-haiku-4-5",
    temperature=0
)


@tool
def multiply(a: int, b: int) -> int:
    """Multiply a and b.

    Args:
        a: First int
        b: Second int
    """
    return a * b


@tool
def add(a: int, b: int) -> int:
    """Add a and b.

    Args:
        a: First int
        b: Second int
    """
    return a + b


@tool
def divide(a: int, b: int) -> float:
    """Divide a by b.

    Args:
        a: First int
        b: Second int
    """
    return a / b


# Augment the model with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)


# Step 2: Define state

class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], operator.add]


# Step 3: Define nodes

def llm_call(state: AgentState):
    """LLM decides whether to call a tool or not"""
    return {
        "messages": [
            model_with_tools.invoke(
                [
                    SystemMessage(
                        content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
                    )
                ]
                + state["messages"]
            )
        ]
    }


def tool_node(state: AgentState):
    """Executes the tool call from the last message"""
    result = []
    for tool_call in state["messages"][-1].tool_calls:
        tool_to_call = tools_by_name[tool_call["name"]]
        observation = tool_to_call.invoke(tool_call["args"])
        result.append(
            ToolMessage(content=str(observation), tool_call_id=tool_call["id"])
        )
    return {"messages": result}


# Step 4: Define conditional edge

def should_continue(state: AgentState) -> Literal["tool_node", "__end__"]:
    """Route to tool_node if the LLM made a tool call, otherwise end"""
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tool_node"
    return END

Your agent's brain is built. You have a state to carry messages, a node that thinks, a node that acts, and a router that decides what happens next. In the next step, you'll wire these pieces into a compiled graph and watch the agent solve a real problem.

Wire It All Together and Run

You have all the pieces of your agent ready: tools that perform calculations, a state container that tracks the conversation, node functions that process messages, and a routing function that decides what happens next. Now it is time to connect everything into a working graph.

In LangGraph, the graph is the structure that ties nodes together with edges. You will build the graph, compile it into a runnable agent, and then watch it solve a multi-step math problem by chaining tool calls on its own.

In this step, get ready to:
  • Build and compile the agent graph with nodes, edges, and conditional routing.
  • Run the agent with a multi-step math question and see it reason through the problem.
  • Experiment with different prompts to see how the agent chains tool calls.
Build and compile the graph

A StateGraph is the container that holds your nodes and the edges between them. Once compiled, it becomes an executable agent you can invoke with input.

  • In agent.py, add the following code at the bottom of the file (below the should_continue function):
# Step 5: Build and compile the graph

agent_builder = StateGraph(AgentState)

agent_builder.add_node("llm_call", llm_call)
agent_builder.add_node("tool_node", tool_node)

agent_builder.add_edge(START, "llm_call")
agent_builder.add_conditional_edges(
    "llm_call",
    should_continue,
    ["tool_node", END]
)
agent_builder.add_edge("tool_node", "llm_call")

agent = agent_builder.compile()

What does this code do?

This is where the graph structure comes to life. Here is what each line accomplishes:

  • StateGraph(AgentState) creates a new graph that uses your AgentState to track conversation messages.
  • add_node registers your two functions as named nodes the graph can visit.
  • add_edge(START, "llm_call") tells the graph to always begin at the LLM node.
  • add_conditional_edges uses your should_continue function to route the graph to either tool_node or END.
  • add_edge("tool_node", "llm_call") creates the loop. After a tool runs, the agent returns to the LLM to decide what to do next.
  • compile() finalizes the graph into a runnable agent.

💡 Why does tool_node loop back to llm_call?

This loop is what makes an agent different from a simple chatbot. After executing a tool, the LLM gets the result and decides whether it needs another tool call or has enough information to respond.

For a question like "15 multiplied by 7, then divided by 3", the agent loops twice: once to multiply, once to divide. Then it returns the final answer.

  • Save agent.py.

Time for the payoff. The next chunk adds the code that runs your agent and prints the full conversation.

Add the main block and run the agent

Your graph is compiled and ready. Now you need a main block that sets your API key, sends a question to the agent, and prints the conversation so you can see how it reasons through the problem.

  • In agent.py, add the following code at the very bottom of the file (below agent = agent_builder.compile()):
# Step 6: Run the agent

if __name__ == "__main__":
    import os
    os.environ["ANTHROPIC_API_KEY"] = "your-api-key-here"

    messages = [HumanMessage(content="What is 15 multiplied by 7, then divided by 3?")]
    result = agent.invoke({"messages": messages})

    print("\n--- Agent Conversation ---\n")
    for m in result["messages"]:
        m.pretty_print()

What does this code do?

  • if __name__ == "__main__": ensures this block only runs when you execute the script directly (not when importing it).
  • os.environ["ANTHROPIC_API_KEY"] sets your API key so the Anthropic client can authenticate your requests.
  • agent.invoke({"messages": messages}) sends your question into the graph and runs the full agent loop until it reaches END.
  • m.pretty_print() formats each message (human, AI, tool) so you can see the agent's reasoning step by step.
  • Replace your-api-key-here with your actual Anthropic API key from console.anthropic.com.
  • Save agent.py.
  • Run the agent by executing this command in your terminal:
python3 agent.py

You should see output showing the full conversation: your human message, the AI requesting a multiply tool call, the tool result (105), the AI requesting a divide tool call, the tool result (35.0), and finally the AI's response with the answer.

Seeing an authentication error?

  • Double-check that you replaced your-api-key-here with your actual API key string. The key should start with sk-ant-.
  • Make sure your Anthropic account has credits available. You need at least $5 in prepaid credits for API access.
  • Confirm there are no extra spaces or quotes around your key in the code.

Help me debug my Anthropic API authentication error.

🙋‍♀️ Seeing a ModuleNotFoundError?

  • Make sure you installed all three packages: langgraph, langchain, and langchain-anthropic.
  • Confirm you are using python3 (not python) to run the script. The packages must be installed for the same Python version.

Help me fix my ModuleNotFoundError.

Experiment with different prompts

The real power of your agent shows when you change the question. Different prompts trigger different tool call sequences, and you can watch the agent reason through each one.

  • Try changing the HumanMessage content in your code to different math problems. Here are some ideas:
  • "Add 5 and 12, then multiply the result by 3." triggers an add followed by a multiply.
  • "What is 100 divided by 4, plus 75?" triggers a divide followed by an add.
  • "Multiply 6 by 7." triggers a single tool call with no loop.
  • After each change, save agent.py and re-run python3 agent.py to see the results.

Notice how the number of tool calls changes depending on the complexity of the question. A single-operation question loops once. A three-operation question loops three times. The agent decides on its own.

What if I ask something that does not need tools?

Try asking something like "What is the capital of France?" and watch what happens. The agent's should_continue function checks for tool calls in the response. If Claude responds without calling any tools, the graph routes straight to END and you see the answer immediately.

  • When you are done experimenting, change the HumanMessage back to "What is 15 multiplied by 7, then divided by 3?" so your code matches the final version.
  • Save agent.py.

✔️ Awesome, I've got everything!

Great. Double check you have saved your file with the original question restored.

ⓧ I'd like to double check the full code

Here is the complete agent.py file. Make sure yours matches:

import operator
from typing import Literal
from typing_extensions import TypedDict, Annotated

from langchain.tools import tool
from langchain.chat_models import init_chat_model
from langchain.messages import AnyMessage, SystemMessage, HumanMessage, ToolMessage
from langgraph.graph import StateGraph, START, END


# Step 1: Define tools and model

model = init_chat_model(
    "claude-haiku-4-5",
    temperature=0
)


@tool
def multiply(a: int, b: int) -> int:
    """Multiply a and b.

    Args:
        a: First int
        b: Second int
    """
    return a * b


@tool
def add(a: int, b: int) -> int:
    """Add a and b.

    Args:
        a: First int
        b: Second int
    """
    return a + b


@tool
def divide(a: int, b: int) -> float:
    """Divide a by b.

    Args:
        a: First int
        b: Second int
    """
    return a / b


# Augment the model with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)


# Step 2: Define state

class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], operator.add]


# Step 3: Define nodes

def llm_call(state: AgentState):
    """LLM decides whether to call a tool or not"""
    return {
        "messages": [
            model_with_tools.invoke(
                [
                    SystemMessage(
                        content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
                    )
                ]
                + state["messages"]
            )
        ]
    }


def tool_node(state: AgentState):
    """Executes the tool call from the last message"""
    result = []
    for tool_call in state["messages"][-1].tool_calls:
        tool_to_call = tools_by_name[tool_call["name"]]
        observation = tool_to_call.invoke(tool_call["args"])
        result.append(
            ToolMessage(content=str(observation), tool_call_id=tool_call["id"])
        )
    return {"messages": result}


# Step 4: Define conditional edge

def should_continue(state: AgentState) -> Literal["tool_node", "__end__"]:
    """Route to tool_node if the LLM made a tool call, otherwise end"""
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tool_node"
    return END


# Step 5: Build and compile the graph

agent_builder = StateGraph(AgentState)

agent_builder.add_node("llm_call", llm_call)
agent_builder.add_node("tool_node", tool_node)

agent_builder.add_edge(START, "llm_call")
agent_builder.add_conditional_edges(
    "llm_call",
    should_continue,
    ["tool_node", END]
)
agent_builder.add_edge("tool_node", "llm_call")

agent = agent_builder.compile()


# Step 6: Run the agent

if __name__ == "__main__":
    import os
    os.environ["ANTHROPIC_API_KEY"] = "your-api-key-here"

    messages = [HumanMessage(content="What is 15 multiplied by 7, then divided by 3?")]
    result = agent.invoke({"messages": messages})

    print("\n--- Agent Conversation ---\n")
    for m in result["messages"]:
        m.pretty_print()

Your agent is fully functional. It can receive a question, decide which tools to call, execute them, loop back to think again, and stop when it has the final answer. Next up, you can extend it with an entirely new capability: memory.

Secret mission

Add a Memory Tool

Your agent can do math, but it forgets everything between conversations. What if it could remember facts you tell it and recall them later? Give your agent a persistent memory store that makes it truly useful across multiple interactions.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

This project runs entirely locally, so there are no ongoing costs. Anthropic API credits are only consumed when you actively run the script.

Resources you used:

  • Python packages: langgraph, langchain, langchain-anthropic.
  • Project file: agent.py on your Desktop.
  • Anthropic API account with prepaid credits.
  • Environment variable: ANTHROPIC_API_KEY stored in your script.

Keep everything running

No action needed. Choose this if you plan to keep experimenting with your agent or extending it with new tools.

  • Your agent.py file stays on your Desktop, ready to run anytime.
  • Your installed Python packages remain available for future projects.
  • Your Anthropic API credits remain in your account until used or until they expire (1 year from purchase).

Pause - I'll come back to this later

Since nothing is actively running, there is nothing to pause. Your script only uses API credits when you execute it.

  • Keep your agent.py file where it is for when you return.
  • Your Anthropic API key remains valid. No need to regenerate it later.
  • Your Python packages stay installed. You can pick up exactly where you left off.

Delete - I don't want to use this again

Remove all project resources and start fresh.

  • Delete the agent.py file from your Desktop.
  • Uninstall the Python packages by running:
pip3 uninstall langgraph langchain langchain-anthropic -y
  • If you no longer need your Anthropic API key, go to console.anthropic.com, navigate to API Keys, and delete the key you created.
  • Your remaining Anthropic credits stay in your account. You do not need to close the account unless you want to.

Nice Work!

Nice Work!

You just built your first AI agent with LangGraph. You now have a working Python script where Claude autonomously decides which tools to call and when to stop.

You've learned how to:

  • Built a working AI agent that autonomously decides which tools to use and chains multiple calls to solve multi-step problems.
  • Learned LangGraph's core primitives: State, Nodes, Edges, and Conditional Routing.
  • Saw the agent loop pattern in action where the LLM decides, a tool executes, and the cycle repeats until the task is complete.
  • Extended your agent with memory tools for cross-conversation recall.

Ready to quiz yourself?