AI learning lang state with LangChain

 One important clarification first: LangGraph does not have a separate class literally called LangState. The state we define for LangGraph is normally just called State. We can call it LangState ourselves if that makes the concept clearer.

Here in this code with LangState explicitly named, while keeping your original tool code and showing exactly where the state is used:

My workflow will maintain some state, and that state contains messages.

The important part is only this:

# =============================================================
# 4. LANGSTATE
# =============================================================

class LangState(TypedDict):

    messages: list
       

and then:

# Create the initial LangState
state: LangState = {
    "messages": [
        HumanMessage(content=user_query)
    ]
}


So we have:

LangState

    │

    └── messages

           │

           └── HumanMessage


Why it is called LangState? 

You don't have to.

class LangState(TypedDict):

and this:

class State(TypedDict):

are technically equivalent as far as Python/LangGraph is concerned.

I used LangState here only to make it visually obvious while you're learning that this is the state we're defining for LangGraph.

The important relationship is:

LangState

   ↓

contains

   ↓

messages

   ↓

HumanMessage / AIMessage / ToolMessage


We can now take this LangState concept into LangGraph, where we will introduce nodes and edges without changing the basic idea of the state.

Complete Code

import json
from langgraph.graph import StateGraph, START, END
# from typing import Annotated, TypedDict
from typing import  TypedDict

from dotenv import load_dotenv
from langchain_core.messages import HumanMessage, ToolMessage
from langchain_core.tools import tool
from langchain_google_genai import ChatGoogleGenerativeAI

# from langgraph.graph.message import add_messages


# Load environment variables
load_dotenv()


# -------------------------------------------------------------
# 1. Define Custom Python Tools
# -------------------------------------------------------------
@tool
def calculate_compound_interest(
    principal: float,
    annual_rate: float,
    years: int
) -> str:
    """Calculates compound interest."""

    amount = principal * ((1 + (annual_rate / 100)) ** years)
    interest = amount - principal

    return json.dumps({
        "principal": principal,
        "interest_earned": round(interest, 2),
        "total_amount": round(amount, 2),
        "years": years,
    })


@tool
def get_stock_price(ticker: str) -> str:
    """Fetches the mock current stock price."""

    mock_prices = {
        "AAPL": 220.50,
        "GOOGL": 175.30,
        "MSFT": 415.00
    }

    price = mock_prices.get(ticker.upper(), 100.00)

    return json.dumps({
        "ticker": ticker.upper(),
        "price_usd": price
    })


# -------------------------------------------------------------
# 2. Tools
# -------------------------------------------------------------
tools_list = [
    calculate_compound_interest,
    get_stock_price
]

tools_by_name = {
    t.name: t for t in tools_list
}


# -------------------------------------------------------------
# 3. Initialize Gemini
# -------------------------------------------------------------
llm = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash",
    temperature=0.0,
)

llm_with_tools = llm.bind_tools(tools_list)


# =============================================================
# 4. LANGSTATE
# =============================================================

class LangState(TypedDict):
    messages: list

# =============================================================
# 5. USE LANGSTATE
# =============================================================

user_query = (
    "If I invest $5,000 at a 7% interest rate "
    "for 10 years, how much will I earn?"
)


# Create the initial LangState
state: LangState = {
    "messages": [
        HumanMessage(content=user_query)
    ]
}


print("Initial State:")
print(state)

ai_response = llm_with_tools.invoke(state["messages"])
state["messages"].append(ai_response)

for tool_call in ai_response.tool_calls:

    tool_name = tool_call["name"]
    tool_args = tool_call["args"]
    tool_id = tool_call["id"]

    print("\nLLM requested:")
    print("Tool:", tool_name)
    print("Arguments:", tool_args)

    # Find the actual Python tool
    selected_tool = tools_by_name[tool_name]

    # Execute the tool
    tool_result = selected_tool.invoke(tool_args)

    print("\nTool Result:")
    print(tool_result)

    # Put the tool result into the state
    state["messages"].append(
        ToolMessage(
            content=str(tool_result),
            tool_call_id=tool_id
        )
    )


print("\nUpdated State:")
print(state)

Comments

Popular posts from this blog

Aggregate function with spring data

Java Persistence API with Spring Data

NodeJS vs Java