- Published on
From Chatbots to AI Agents: Orchestrating Autonomous Workflows with LangGraph
- Authors

- Name
- Wasif Ali
Introduction
While simple LLM integrations and RAG systems have become table stakes, the frontier of AI development lies in Autonomous Agents. Agents are systems where an LLM is given access to tools (APIs, databases, web search) and acts as a reasoning engine to decide which tools to execute and what to do with their outputs.
LangGraph, an extension to LangChain, provides a powerful framework to build stateful, multi-actor applications with LLMs. Unlike standard chains which are strict Directed Acyclic Graphs (DAGs), LangGraph allows for cycles—essential for agentic behavior like retries and reflection.
- 1. Why LangGraph?
- 2. Defining the Agent State
- 3. Creating Nodes and Tools
- 4. Building the Graph & Conditional Edges
- 5. Streaming and Execution
- Conclusion
- License
1. Why LangGraph?
Standard LangChain AgentExecutor models operate on a hidden loop under the hood. LangGraph brings this loop to the surface, allowing developers to define it explicitly as a state machine.
- Stateful: It maintains a defined "State" object passed between nodes.
- Cyclic: Nodes can route back to themselves or previous nodes based on LLM decisions.
- Controllable: You can inject human-in-the-loop (HIL) breakpoints to require user approval before catastrophic actions (like executing SQL or sending an email).
2. Defining the Agent State
In LangGraph, you define a graph state that gets passed around and updated by your nodes.
import { BaseMessage } from "@langchain/core/messages";
import { StateGraph, START, END } from "@langchain/langgraph";
// Define the state interface
interface AgentState {
messages: BaseMessage[];
// You can add arbitrary data like intermediate steps or user IDs
requiresApproval?: boolean;
}
// Create the graph state definition with update reducers
const graphState = {
messages: {
value: (x: BaseMessage[], y: BaseMessage[]) => x.concat(y),
default: () => [],
},
requiresApproval: {
value: (x: boolean, y: boolean) => y,
default: () => false,
}
};
3. Creating Nodes and Tools
A Node in LangGraph is just a function that takes the current State and returns a partial State update.
Let's define a tool that searches the web, and an agent node that uses an LLM bound with tools.
import { ChatOpenAI } from "@langchain/openai";
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
import { ToolNode } from "@langchain/langgraph/prebuilt";
// 1. Define tools
const tools = [new TavilySearchResults({ maxResults: 3 })];
const toolNode = new ToolNode(tools);
// 2. Define the LLM agent node
const model = new ChatOpenAI({ temperature: 0 }).bindTools(tools);
async function callModel(state: AgentState) {
const { messages } = state;
const response = await model.invoke(messages);
// Return the update to the state (the new message)
return { messages: [response] };
}
4. Building the Graph & Conditional Edges
Now we assemble the StateGraph. We need a conditional edge that decides: Did the LLM choose to call a tool, or did it provide a final answer?
import { END } from "@langchain/langgraph";
// The router function
function shouldContinue(state: AgentState) {
const { messages } = state;
const lastMessage = messages[messages.length - 1];
// If there are tool calls, route to the tools node
if (lastMessage.additional_kwargs.tool_calls) {
return "tools";
}
// Otherwise, route to the END
return END;
}
// Compile the graph
const workflow = new StateGraph({ channels: graphState })
.addNode("agent", callModel)
.addNode("tools", toolNode)
.addEdge(START, "agent")
.addConditionalEdges("agent", shouldContinue)
.addEdge("tools", "agent");
const app = workflow.compile();
5. Streaming and Execution
Because LangGraph operates node-by-node, you can stream the intermediate events to a UI as the agent "thinks".
import { HumanMessage } from "@langchain/core/messages";
const inputs = { messages: [new HumanMessage("What is the current weather in SF?")] };
for await (const event of await app.stream(inputs)) {
for (const [nodeName, stateUpdate] of Object.entries(event)) {
console.log(`Executed node: ${nodeName}`);
// Update the UI...
}
}
Conclusion
LangGraph is revolutionizing how we build complex AI software. By shifting from linear scripts to stateful, cyclic graphs, engineers can build resilient agents capable of coding, researching, and automating backend cloud infrastructure with unprecedented reliability.