Agents
An agent is an LLM in a loop: receive input, decide whether to call a tool, observe the result, repeat until done. langgraph is the modern way to build them — explicit state, explicit graph, full observability.
A real ReAct agent with langgraph
EXAMPLE
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
from langchain_core.messages import HumanMessage
llm = ChatOpenAI(model='gpt-4o-mini')
# 1) Define tools — type hints + docstring = schema
@tool
def search(query: str) -> str:
"""Search the company knowledge base for a query and return the top result."""
return kb.search(query, k=3)
@tool
def run_sql(query: str) -> list:
"""Run a READ-ONLY SQL query against the analytics warehouse."""
if not query.strip().lower().startswith('select'):
return [{'error': 'read-only'}]
return warehouse.fetchall(query)
@tool
def send_email(to: str, subject: str, body: str) -> str:
"""Send an email. Use only after explicit user confirmation."""
return mail.send(to=to, subject=subject, body=body)
# 2) Pre-built ReAct agent (Reason + Act loop)
agent = create_react_agent(llm, tools=[search, run_sql, send_email])
result = agent.invoke({
'messages': [HumanMessage('How many active users do we have right now? Email the answer to ops@example.com.')],
})
print(result['messages'][-1].content)
# 3) Stream the agent's intermediate steps (great for UX)
for step in agent.stream(
{ 'messages': [HumanMessage('Find SQL injection mentions and summarise')] },
stream_mode='values',
):
last = step['messages'][-1]
print(f'{last.type:>5}: {last.content[:200]}')
# 4) Custom graph — for non-trivial agents (memory, branches, conditional edges)
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
from typing import Annotated, TypedDict
import operator
class AgentState(TypedDict):
messages: Annotated[list, operator.add]
def call_model(state):
return { 'messages': [llm.invoke(state['messages'])] }
def should_continue(state):
return 'end' if not state['messages'][-1].tool_calls else 'tools'
g = StateGraph(AgentState)
g.add_node('agent', call_model)
g.add_node('tools', tool_node)
g.add_conditional_edges('agent', should_continue, { 'tools': 'tools', 'end': END })
g.add_edge('tools', 'agent')
g.set_entry_point('agent')
app = g.compile(checkpointer=MemorySaver())
Why it matters
Tool descriptions ARE the agent. Models pick tools by reading docstrings + parameter names — not by magic. Write them like API docs: what it does, when to use it, what it returns.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
agent = create_react_agent(ChatOpenAI(model='gpt-4o-mini'), tools=[multiply])
for s in agent.stream({'messages': [('user', '6 * 7 then double it')]}):
print(s)
Try it Yourself »
Discussion
Loading…