iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

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 »

Test yourself

Q1. An agent is roughly…
Q2. A graph-based agent runtime is…
Q3. Observability + eval tooling is…

Discussion

Loading…