Create your first AI agent using a local model running inside Ollama and understanding Basics
If you have Ollama installed in your system and running any LLM, you can create your own AI Agnet after reading this tutorial. This is a Hands-On Tutorial for LangGraph agents.
Understanding Basics
To build sophisticated AI systems that require multi-step planning, LangGraph offers a graph framework that handles the heavy lifting automatically. By supporting flexible node structures - whether they trigger LLMs, external tools, or custom code - it makes it effortless to design interconnected workflows with built-in support for state retention and complex branching logic.
State
At the heart of every LangGraph workflow is the State a shared memory object that travels through the graph as execution progresses. Think of it as a central workspace where every node can read from and write to the same source of truth.
The State holds everything your application needs to keep track of, including conversation messages, variables, intermediate computation results, and even the history of decisions made throughout the workflow. Instead of manually passing data between nodes, LangGraph automatically manages the State for you, making your graphs simpler to build, easier to maintain, and less error-prone.
Beyond the basic State object, LangGraph also provides several advanced memory capabilities. Features like checkpointing let you save and resume execution, thread-local memory keeps context isolated for individual conversations or tasks, and cross-session persistence allows important information to survive beyond a single run. Together, these features make it possible to build intelligent, long-running, and stateful AI applications with minimal effort.
Node
A Node is a single step in a LangGraph workflow. Think of it as a task that performs one specific job before passing the result to the next step.
A node can perform different types of actions, including:
- Calling a Large Language Model (LLM)
- Using an external tool or API
- Running a custom Python function
- Making routing or branching decisions
Each node receives the current State, performs its task, and returns an updated State. The updated State is then passed to the next node in the workflow.
Edges and Conditional Edges
Edges connect nodes and define how the workflow moves from one step to another.
LangGraph supports three main types of edges:
- Static Edges – Connect nodes in a fixed order, creating a simple, linear workflow.
- Cyclical Edges – Allow the workflow to loop back and repeat steps until a condition is met.
- Conditional Edges – Enable dynamic branching. Based on the current State, the workflow can choose different execution paths, making your application more flexible and intelligent.
Graph and StateGraph
A Graph is the foundation of every LangGraph application. It defines how your workflow is organized by connecting nodes with edges. Together, these nodes and edges determine the path your application follows while executing tasks.
A StateGraph is a special type of graph that maintains a shared State throughout the entire workflow. As each node runs, it can read from and update this shared State. This allows the graph to remember previous actions, make context-aware decisions, and keep information available across multiple steps.
You can think of a StateGraph as the combination of a Graph and a State working together.
Tools and ToolNode
A Tool is a function that an AI agent can use to perform tasks beyond generating text. For example, a tool can search the web, perform calculations, query a database, or execute your own custom business logic.
There are two types of tools in LangGraph:
- Built-in Tools – Ready-to-use tools provided by LangChain. You can use these directly by following the official documentation.
- Custom Tools – Tools that you create yourself. These are usually regular Python functions decorated with
@tooland include a docstring describing what they do.
A ToolNode is a special node designed specifically for running tools inside a graph. Instead of writing extra code to execute a tool, you can simply add a ToolNode to your workflow and let LangGraph handle the execution.
You can think of a ToolNode as the combination of a Tool and a Node.
Message Types
Messages are structured pieces of information that move through the graph and are stored in the State. They represent conversations, instructions, tool outputs, and other important information that helps the agent understand context and make better decisions.
LangGraph supports several message types:
HumanMessage
Represents input from a user. This is usually the first message in a conversation and is used whenever a user sends a new request to the agent.
AIMessage
Represents the response generated by the language model. These messages are stored in the State so the agent can remember previous conversations and respond with context.
SystemMessage
Provides instructions or context for the language model. For example, you can define the assistant's role by using a message like:
"You are a helpful travel assistant."
System messages guide the model's behavior throughout the conversation.
ToolMessage
Represents the output returned by a tool. Whenever an agent calls a tool such as a calculator, search engine, or API - the result is stored as a ToolMessage so it can be used in future reasoning.
RemoveMessage
Used to remove previously stored messages from the State. This is useful for deleting unnecessary context, correcting mistakes, or managing conversation history.
BaseMessage
BaseMessage is the parent class for all message types in LangChain and LangGraph. Every other message type, including HumanMessage, AIMessage, SystemMessage, and ToolMessage, inherits from it.
Here is the simple AI agent for you
This is git repo: https://github.com/dmsbilas/ai_agent_for_all.git AI Agent for All
I have used UV as python package manager. Ollama and qwen3.5:4b is running in my local machine.
What this agent does?
This agent reads what you write in text_eng.txt file. When you save the file, the agent automatically translates the text to Bengali language and saves in final.txt file.
"""LangGraph agent that reads a file and translates its content into Bengali."""
from __future__ import annotations
import sys
from pathlib import Path
from typing import TypedDict
from langchain_ollama import ChatOllama
from langgraph.graph import END, START, StateGraph
class AgentState(TypedDict):
file_path: str
content: str
bengali: str
def read_file(state: AgentState) -> dict:
path = Path(state["file_path"])
if not path.is_file():
raise FileNotFoundError(f"File not found: {path}")
return {"content": path.read_text(encoding="utf-8")}
def translate_to_bengali(state: AgentState) -> dict:
llm = ChatOllama(
model="qwen3.5:4b",
base_url="http://localhost:11434",
temperature=0.7,
)
prompt = (
"Translate the following text into Bengali (বাংলা). "
"Preserve meaning, tone, and paragraph structure. "
"Return only the Bengali translation, with no preamble.\n\n"
f"{state['content']}"
)
response = llm.invoke(prompt)
text = response.content if isinstance(response.content, str) else str(response.content)
Path("final.txt").write_text(text, encoding="utf-8")
return {"bengali": text}
def build_agent():
graph = StateGraph(AgentState)
graph.add_node("read_file", read_file)
graph.add_node("translate_to_bengali", translate_to_bengali)
graph.add_edge(START, "read_file")
graph.add_edge("read_file", "translate_to_bengali")
graph.add_edge("translate_to_bengali", END)
return graph.compile()
def main() -> None:
if len(sys.argv) < 2:
print("Usage: python agent2.py <path-to-file>")
sys.exit(1)
file_path = sys.argv[1]
agent = build_agent()
result = agent.invoke(
{
"file_path": file_path,
"content": "",
"bengali": "",
}
)
print(result["bengali"])
if __name__ == "__main__":
main()