HOW-TO · RAG
How to Implement Tool Calling in LangGraph Agents
Target environment
Ubuntu 24.04 · Ollama 0.4.x
PREREQUISITES
LangGraph agent set up, tool functions defined, Python 3.10+
What this does
Tool calling in LangGraph agents allows the LLM to request external function execution (API calls, database queries, calculations). The graph routes the LLM's tool requests to a tools node, then feeds results back to the LLM.
Steps
- Define tool functions. Each tool is a plain Python function with a docstring.
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"The weather in {city} is 22°C and sunny."
def calculate(expression: str) -> str:
"""Evaluate a mathematical expression."""
return str(eval(expression))
- Bind tools to the LLM. Convert functions to tool schemas and attach them.
from langchain_ollama import ChatOllama
from langchain.tools import tool
tools = [tool(get_weather), tool(calculate)]
llm = ChatOllama(model="llama3.2", temperature=0)
llm_with_tools = llm.bind_tools(tools)
- Create the tool execution node. Parse tool calls from the LLM response and execute them.
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from typing import TypedDict, Annotated, Sequence
from langchain_core.messages import BaseMessage, ToolMessage
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
def call_model(state: AgentState) -> dict:
response = llm_with_tools.invoke(state["messages"])
return {"messages": [response]}
def call_tool(state: AgentState) -> dict:
last_msg = state["messages"][-1]
tool_map = {t.name: t for t in tools}
messages = []
for tc in last_msg.tool_calls:
result = tool_map[tc["name"]].invoke(tc["args"])
messages.append(ToolMessage(content=result, tool_call_id=tc["id"]))
return {"messages": messages}
- Add conditional routing. After the LLM, check if tool calls exist.
def should_continue(state: AgentState) -> str:
last = state["messages"][-1]
return "continue" if hasattr(last, "tool_calls") and last.tool_calls else "end"
- Build the graph with tool routing.
workflow = StateGraph(AgentState)
workflow.add_node("agent", call_model)
workflow.add_node("tools", call_tool)
workflow.set_entry_point("agent")
workflow.add_conditional_edges("agent", should_continue, {
"continue": "tools",
"end": END
})
workflow.add_edge("tools", "agent")
app = workflow.compile()
- Invoke with a tool-requiring query.
from langchain_core.messages import HumanMessage
result = app.invoke({"messages": [HumanMessage(content="What's 15 * 7 and the weather in Paris?")]})
print(result["messages"][-1].content)
Verification
python -c "
from langchain.tools import tool
@tool
def add(a: int, b: int) -> int:
'''Add two numbers.'''
return a + b
print(add.name, add.invoke({'a': 2, 'b': 3}))
# Expected: add 5
"
Common failures
- Tool schema mismatch. Function signature parameters must have type hints; otherwise, the binding may fail. Always annotate arguments.
- Model doesn't support tool calling. Older or smaller models may never produce
tool_calls. Usellama3.2:3bor larger. - Tool call ID mismatch. The
ToolMessagemust include the correcttool_call_idfrom the original call, or the agent ignores it. - Version mismatch - The installed package or runtime differs from the command shown; check the version first and rerun the smallest verification command.
- Local environment drift - Another service, virtual environment, model, or path is being used; print the active binary path and configuration before changing the guide steps.
Related guides
- How to Set Up Basic LangGraph Agent from Scratch
- How to Create Conditional Edges in LangGraph