Agent loop
The agent loop is the pattern that makes an agent: call the model, and if it asked for a tool, run the tool and loop back to the model, otherwise stop.
Last updated: 29 Sep, 2026 · LangGraph 1.2
Everything so far comes together here. The one new idea is the edge from the tools node back to the model, so the model can read the tool's result and decide again.
From one tool call to a loop
In the graph from ToolNode and tools_condition, a question with two parts got only one part done, because the tool's result went to END. The video's fix is one edge: "tools" goes back to tool_calling_llm instead of to END. The model reads each tool result and decides again, to call another tool or to answer. The video calls this the ReAct architecture, after its three steps: act (call a tool), observe (read what came back) and reason (decide what to do next).

The video's two-part question, "Give me the recent ai news and then multiply 5 by 10", runs below on the looping graph with both of its tools: tool, the TavilySearch from ToolNode and tools_condition, which needs langchain-tavily and TAVILY_API_KEY, and multiply. It is a complete script: save it as its own file, such as agent_loop.py, and set GROQ_API_KEY and TAVILY_API_KEY first (add the load_dotenv() lines at the top if they are in .env). The code is the video's looping graph; only the model string changes:
from typing import Annotated
from typing_extensions import TypedDict
from langgraph.graph import StateGraph,START,END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition
from langchain.chat_models import init_chat_model
from langchain_tavily import TavilySearch
class State(TypedDict):
messages:Annotated[list,add_messages]
llm=init_chat_model("groq:openai/gpt-oss-120b")
tool=TavilySearch(max_results=2)
## Custom function
def multiply(a:int,b:int)->int:
"""Multiply a and b
Args:
a (int): first int
b (int): second int
Returns:
int: output int
"""
return a*b
tools=[tool,multiply]
llm_with_tool=llm.bind_tools(tools)
## Node definition
def tool_calling_llm(state:State):
return {"messages":[llm_with_tool.invoke(state["messages"])]}
## Grpah
builder=StateGraph(State)
builder.add_node("tool_calling_llm",tool_calling_llm)
builder.add_node("tools",ToolNode(tools))
## Add Edges
builder.add_edge(START, "tool_calling_llm")
builder.add_conditional_edges("tool_calling_llm",tools_condition)
builder.add_edge("tools","tool_calling_llm") # the one change: back to the model
## compile the graph
graph=builder.compile()
response=graph.invoke({"messages":"Give me the recent ai news and then multiply 5 by 10"})
for m in response['messages']:
m.pretty_print()================================ Human Message =================================
Give me the recent ai news and then multiply 5 by 10
================================== Ai Message ==================================
Tool Calls:
tavily_search (fc_754efac9-eafd-4dff-805f-4326dbc30239)
Call ID: fc_754efac9-eafd-4dff-805f-4326dbc30239
Args:
query: latest AI news September 2026
search_depth: advanced
time_range: month
================================= Tool Message =================================
Name: tavily_search
{"query": "latest AI news September 2026", "follow_up_questions": null, "answer": null, "images": [], "results": [{"url": "https://www.youtube.com/watch?v=hrfTovN3kMw", "title": "AI News - Mid-September 2026", "content": "Aaron and Brandon announce that the Enterprise AI Show is shifting from monthly to bi-weekly AI news episodes and discuss major stories from the past two weeks. They cover Oracle’s sharply higher cloud revenue, a large GPU backlog for AI customers, questions about what “backlog” and revenue mean, and the impact and tone of Oracle layoffs, including reports of termination notices sent by early-morning email. They examine the sudden industry push to “slow down” AI development, debating whether leaders at Anthropic, Google, and OpenAI are coordinating messaging, how credible doomsday claims are, and the competitive angle with China. They also review Salesforce’s Agentforce direction, new model efforts based on NVIDIA Nemotron, evolving agent licensing, headless AI interfaces, MCP as [...] 00:00 Biweekly News Shift\n00:49 Sponsor Messages\n02:19 News Remix Kickoff\n03:18 Sports Rivalry Detour\n04:26 Oracle Cloud Surge\n05:34 Backlog Reality Check\n09:45 Layoffs And Culture\n13:02 AI Slowdown Debate\n15:27 Coordination Or Coincidence\n17:33 China Distillation Theory\n18:36 Sci-Fi Time Travel Aside\n21:45 Salesforce Outage Example\n22:21 Outages Happen\n23:14 Salesforce Bets on Agents\n25:35 Headless CRM Future\n28:16 Agent Pricing Tiers\n29:27 MCP vs APIs Debate\n32:30 GPT-6 Astra Reality Check\n34:54 Agent Swarms MMO Analogy\n37:28 Research Limits and Benchmarks\n41:31 Wrap Up and Next Steps", "score": 0.95197505, "raw_content": null, "id": "a6ee7c-00"}, {"url": "https://www.enterprisetimes.co.uk/2026/09/28/security-and-ai-news-from-the-week-beginning-21-september-2026", "title": "Security and AI news from the week beginning 21 September 2026 -", "content": "Ripjar introduced new AI capabilities within ULTRA, its intelligence engine for screening operations at financial institutions and enterprises. It says that the technology is used by 25% of Global Systemically Important Banks and 35+ Global Fortune 500 companies. Designed for compliance teams, the updates aim to improve the confidence, speed and clarity of risk identification and management.\n\nComplir has announced a new $11 million seed round to help retailers and brands better manage regulatory complexities and bring their products to market faster. The investment was led by General Catalyst alongside angel investors and specialist industry funds. It is expected to help retailers and brands navigate regulatory complexity and bring products to market faster. [...] Latest News\n News in Brief\n Security\n\n# Security and AI news from the week beginning 21 September 2026\n\nBy\n\nIan Murphy\n\n-\n\nFacebookXWhatsAppLinkedinEmail\n\nNIBS (credit image/Pixabay/ Ryan McGuire)\")AI continues to generate large revenue streams for those vendors building core software and hardware solutions. Last week, after the significant revenue surge announced by Nvidia, AMD saw its shares breach the $600 barrier. That values the company at over a trillion dollars. The key driver for this was Anthropic committing to 2 gigawatts of AMD’s MI450 GPUs. AMD is also growing its share of the AI accelerator market. While Nvidia still has over 80% of that market, the rise of AMD and maybe others will create a competitive market. [...] ShinyHunters claimed to have breached the U.S. Federal Bureau of Investigation. It says it stole data on current and former employees, which has created a lot of concern among those affected. The group used an Oracle PeopleSoft zero-day vulnerability. This gave it access to FBI job portals, human resources systems, and internal services.\n\nMicrosoft has seized 50 websites used by EvilTokens. The AI-powered phishing service has compromised over 12,000 email inboxes across 10,000 organisations since February 2026. The entire attack chain used AI, from phishing users to gain access to email, to then analysing inboxes to select new targets. It also mapped financial relationships to identify other targets for fraud attacks.", "score": 0.93952066, "raw_content": null, "id": "a7765e-01"}], "response_time": 0.0, "request_id": "2476d6e0-ba26-49d0-9dbc-0b0842a39e82"}
================================== Ai Message ==================================
Tool Calls:
multiply (fc_91cd6993-22a8-4397-ba39-1e7022e8b5f3)
Call ID: fc_91cd6993-22a8-4397-ba39-1e7022e8b5f3
Args:
a: 5
b: 10
================================= Tool Message =================================
Name: multiply
50
================================== Ai Message ==================================
**Recent AI News (Late September 2026)**
| Topic | Key Points | Source |
|-------|------------|--------|
| **Enterprise AI Show shifts to bi‑weekly** | The show now airs every two weeks, covering major AI developments such as Oracle’s cloud revenue surge, a huge GPU backlog for AI customers, and the industry‑wide “slow‑down” debate on AI development. | 【a6ee7c-00】 |
| **Oracle Cloud & AI workforce** | Oracle reported sharply higher cloud revenue, but also announced layoffs with termination notices sent early in the morning, sparking discussion about AI‑driven cost cuts. | 【a6ee7c-00】 |
| **AI “slow‑down” debate** | Leaders at Anthropic, Google, and OpenAI are being scrutinized for possibly coordinating messaging to temper hype and address “doomsday” concerns. | 【a6ee7c-00】 |
| **AMD’s AI accelerator push** | After Nvidia’s revenue surge, AMD’s shares broke the $600 mark, driven by Anthropic’s commitment to 2 GW of AMD MI450 GPUs, signaling growing competition in the AI‑chip market. | 【a7765e-01】 |
| **Security‑focused AI tools** | • Ripjar added AI capabilities to its ULTRA intelligence engine, now used by ~25 % of Global Systemically Important Banks and 35+ Fortune‑500 firms. <br>• Complir raised $11 M to help retailers manage regulatory compliance with AI‑driven risk identification. | 【a7765e-01】 |
| **AI‑enabled cyber‑threats** | • ShinyHunters claimed a breach of the FBI using an Oracle PeopleSoft zero‑day. <br>• Microsoft took down 50 sites used by the AI‑powered phishing service EvilTokens, which had compromised >12 k inboxes across 10 k organizations. | 【a7765e-01】 |
| **AI model developments** | Discussions about GPT‑6 (codenamed “Astra”) and NVIDIA’s Nemotron‑based agents, including new licensing models and headless AI interfaces for CRM (e.g., Salesforce Agentforce). | 【a6ee7c-00】 |
**Quick Math Result**
5 × 10 = **50**.The model asked for tavily_search first, with its own query and an advanced search over the past month. Because "tools" now leads back to the model, it read the two results and then asked for multiply with 5 and 10, which returned 50. Its last message has no tool call: a table of the news, each row naming the result it came from, and 5 × 10 = 50. The video's run on the tools-to-END graph stopped after the search; here both parts are done. Search results change from day to day, so your run will find other pages and word its answer differently. Below, the support agent builds the same loop around an order lookup.
The agent-loop wiring
from langgraph.graph import MessagesState, StateGraph, START, END
from langgraph.prebuilt import ToolNode, tools_condition
def call_model(state: MessagesState):
return {"messages": [model_with_tools.invoke(state["messages"])]}
builder = StateGraph(MessagesState)
builder.add_node("call_model", call_model)
builder.add_node("tools", ToolNode(tools))
builder.add_edge(START, "call_model")
builder.add_conditional_edges("call_model", tools_condition) # -> "tools" or END
builder.add_edge("tools", "call_model") # tools back to the model
agent = builder.compile()The model here is the real one from the chat-models lesson, given the tool with bind_tools so it can ask for it. Build the graph one piece at a time.
The imports
Start with the imports: the graph pieces, the tools node and its router, the model builder, the tool decorator, and the message types.
from langgraph.graph import StateGraph, START, MessagesState
from langgraph.prebuilt import ToolNode, tools_condition # tools node + ready-made router
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langchain.messages import HumanMessage, SystemMessageThe tool
Define the tool the agent can call. It takes an order id and returns a short line about the order.
@tool
def lookup_order(order_id: str) -> str:
"""Look up an order by id."""
return f"Order {order_id}: shipped on 3 March."The model node
Give the model the tool with bind_tools, and a system message that keeps its answers short and grounded. The node sends the whole conversation and appends the model's reply.
model = init_chat_model("groq:openai/gpt-oss-120b", temperature=0) # uses your GROQ_API_KEY
model_with_tools = model.bind_tools([lookup_order])
SYSTEM = SystemMessage("You are the support assistant for a small online shop. "
"Answer in one short sentence, using only what the tools returned.")
def call_model(state: MessagesState):
return {"messages": [model_with_tools.invoke([SYSTEM] + state["messages"])]}bind_toolstells the model which tools it may ask for.- Each call gets the system message plus the conversation so far, and the reply is either a tool call or a final answer.
Wiring the loop
Wire the two nodes into a graph. The edges are what make it loop.
builder = StateGraph(MessagesState)
builder.add_node("call_model", call_model)
builder.add_node("tools", ToolNode([lookup_order]))
builder.add_edge(START, "call_model")
builder.add_conditional_edges("call_model", tools_condition) # tool call? -> tools, else END
builder.add_edge("tools", "call_model") # the loop: back to the model
agent = builder.compile()tools_conditionsends a tool call to thetoolsnode, and anything else to END.- The edge from
toolsback tocall_modelis the loop: run the tool, then let the model read the result.
Running the agent
Run one question through the agent and print every message with its type, so you can watch the loop.
out = agent.invoke({"messages": [HumanMessage("Where is order A17?")]})
for m in out["messages"]:
calls = [(c["name"], c["args"]) for c in getattr(m, "tool_calls", [])]
print(f"{m.type:<5}", calls or m.content)The agent loop end to end
The same pieces in one file.
from langgraph.graph import StateGraph, START, MessagesState
from langgraph.prebuilt import ToolNode, tools_condition
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langchain.messages import HumanMessage, SystemMessage
@tool
def lookup_order(order_id: str) -> str:
"""Look up an order by id."""
return f"Order {order_id}: shipped on 3 March."
model = init_chat_model("groq:openai/gpt-oss-120b", temperature=0) # uses your GROQ_API_KEY
model_with_tools = model.bind_tools([lookup_order])
SYSTEM = SystemMessage("You are the support assistant for a small online shop. "
"Answer in one short sentence, using only what the tools returned.")
def call_model(state: MessagesState):
return {"messages": [model_with_tools.invoke([SYSTEM] + state["messages"])]}
builder = StateGraph(MessagesState)
builder.add_node("call_model", call_model)
builder.add_node("tools", ToolNode([lookup_order]))
builder.add_edge(START, "call_model")
builder.add_conditional_edges("call_model", tools_condition)
builder.add_edge("tools", "call_model")
agent = builder.compile()
out = agent.invoke({"messages": [HumanMessage("Where is order A17?")]})
for m in out["messages"]:
calls = [(c["name"], c["args"]) for c in getattr(m, "tool_calls", [])]
print(f"{m.type:<5}", calls or m.content)human Where is order A17?
ai [('lookup_order', {'order_id': 'A17'})]
tool Order A17: shipped on 3 March.
ai Order A17 was shipped on March 3.How the run reached its answer
Read it top to bottom. The model's first reply was a tool call, so tools_condition sent the run to the tools node. ToolNode ran lookup_order and appended its result, the edge sent it back to the model, and this time the model answered in plain text from that result, so the run reached END.
How a run flows
- START → call_model: the model reads the conversation.
- call_model → tools (via
tools_condition) if it asked for a tool; the tool runs and returns a result. - tools → call_model: the model reads the result and answers, or asks for another tool.
- call_model → END when the model replies with no tool call.
The load-bearing edge
The edge tools → call_model is what makes this an agent rather than a one-shot call. Without it the model could ask for a tool but never see the answer. With it, the model can look something up, read the result, and use it in its reply.
Where the agent loop fits
- Any assistant that looks things up before answering.
- The base shape every tool-using agent is built on, by hand here and with
create_agentin the next lesson.
recursion_limit, as in Loops and recursion limit, so a runaway run stops with GraphRecursionError.Related
- Previous: Structured output
- Next: create_agent
- Reference: Workflows and agents
- Draw the four transitions above on paper before running anything.
- Remove the
tools → call_modeledge and describe what breaks.
Every expert started right here.