Day 3 of LangGraph 14‑Day Series: Enabling GPT to Call External APIs with ToolNode

This article walks through LangGraph's three‑step tool‑calling workflow, shows how to define tools with the @tool decorator, demonstrates executing calls via ToolNode, provides a complete agent example, explains bind_tools, shares best‑practice guidelines, streaming execution, and a concise recap.

Tech Ocean
Tech Ocean
Tech Ocean
Day 3 of LangGraph 14‑Day Series: Enabling GPT to Call External APIs with ToolNode

Complete tool‑calling chain

LangGraph splits tool calling into three steps: the LLM generates tool_calls, ToolNode executes the calls, and the results are fed back to the LLM.

LLM 生成 tool_calls → ToolNode 执行 → 结果返回 LLM
# 1. LLM generates tool calls
model_with_tools = model.bind_tools([multiply, get_weather])
response = model_with_tools.invoke("3乘4等于多少")
# response contains tool_calls

# 2. ToolNode executes the calls
tool_node = ToolNode([multiply, get_weather])
result = tool_node.invoke({"messages": [response]})
# 3. Result is appended to messages, LLM continues processing

@tool decorator: defining tools

The @tool decorator turns a Python function into a LangGraph tool and automatically generates an OpenAI‑compatible schema from the function signature and docstring.

from langchain_core.tools import tool

@tool
def multiply(a: int, b: int) -> int:
    """将两个数字相乘"""
    return a * b

@tool
def get_weather(location: str) -> str:
    """获取指定位置的天气"""
    return f"{location} 今天晴天,25°C"

@tool
def search_web(query: str) -> str:
    """搜索网页获取信息"""
    return f"搜索 '{query}' 的结果:找到 10 条相关内容"

Automatically generated schema includes:

Tool name – the function name (e.g., multiply)

Tool description – the first line of the docstring

Parameter schema – inferred from type annotations

ToolNode executes calls

ToolNode

receives the LLM response, extracts tool_calls, runs the corresponding Python functions, and returns a ToolMessage that the LLM can continue processing.

from langgraph.prebuilt import ToolNode
from langchain_core.messages import AIMessage

# Create the tool node
tool_node = ToolNode([multiply, get_weather, search_web])

# Simulated LLM tool call
ai_message = AIMessage(
    content="",
    tool_calls=[
        {
            "name": "multiply",
            "args": {"a": 3, "b": 4},
            "id": "call_001"
        }
    ]
)

# Execute the tool call
result = tool_node.invoke({"messages": [ai_message]})
print(result["messages"])  # Contains ToolMessage with matching tool_call_id

Full agent example

Using create_react_agent to build an agent that can invoke the defined tools.

from langchain_anthropic import ChatAnthropic
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import InMemorySaver

@tool
def multiply(a: int, b: int) -> int:
    """将两个数字相乘"""
    return a * b

@tool
def get_weather(location: str) -> str:
    """获取指定位置的天气"""
    return f"{location} 今天晴天,25°C"

tools = [multiply, get_weather]
model = ChatAnthropic(model="claude-sonnet-4-6")
memory = InMemorySaver()
agent = create_react_agent(model, tools, checkpointer=memory)

config = {"configurable": {"thread_id": "session-1"}}
result = agent.invoke({"messages": [{"role": "user", "content": "北京天气如何?3乘4等于多少?"}]}, config)
print(result["messages"][-1].content)

bind_tools: binding tools to an LLM

If you prefer not to use create_react_agent, you can manually bind tools to a model.

from langchain_openai import ChatOpenAI

model = ChatOpenAI(model="gpt-4o")
model_with_tools = model.bind_tools([multiply, get_weather])
# The LLM decides whether to call a tool based on the query
response = model_with_tools.invoke("3乘4是多少?")
print(response.tool_calls)  # [{'name': 'multiply', 'args': {'a': 3, 'b': 4}}]

Best practices for defining tools

Clear docstring – the LLM uses it to decide when to call the tool.

Semantic parameter names – use descriptive names such as location instead of a single letter.

Specific return values – return concrete strings like "北京今天晴天,25°C" rather than a generic placeholder.

Complete type annotations – help the LLM understand parameter types.

Streaming execution of ToolNode

# Stream execution to observe each step
for chunk in tool_node.stream({"messages": [ai_message]}):
    print(chunk)  # {'messages': [ToolMessage(...)]}

Day 3 recap

@tool – decorator that defines a tool.

bind_tools – binds tools to an LLM.

ToolNode – executes LLM‑generated tool_calls.

create_react_agent – creates an agent with tool‑calling capability.

Related links

Official documentation and reference pages:

LangGraph tool‑calling concepts: https://langchain-ai.github.io/langgraph/concepts/tool-calling/

create_react_agent reference: https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.create_react_agent

ToolNode reference: https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.ToolNode

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PythonAILLMAgentTool CallingLangGraphToolNode
Tech Ocean
Written by

Tech Ocean

Focused on AI programming, sharing ready-to-use development efficiency solutions.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.