CURRENT TREND INSIGHT
Building an API tool-calling agent using LangChain and Python Illustration

Building an API tool-calling agent using LangChain and Python

Direct Summary:

A LangChain tool-calling agent works by binding a list of Python-defined tools to a chat model with bind_tools(), which passes their schemas to the model so it can request a tool call instead of just generating text. create_tool_calling_agent() plus an AgentExecutor then runs the loop for you: the model decides which tool to call, your code executes it, the result goes back to the model, and this repeats until the model has enough information to answer.

"If you can't explain it simply, you don't understand it well enough."

— Albert Einstein

Key Insights

  • Tools are just typed Python functions: LangChain's @tool decorator turns a regular function with a docstring into something the model can discover and call — the docstring is what the model reads to decide when to use it.
  • The model requests, your code executes: the LLM never actually calls the API itself — it returns a structured tool-call request, and your application code is what actually hits the external API.
  • AgentExecutor handles the loop, not the logic: it manages calling the model, executing the requested tool, and feeding the result back — but you still decide what each tool does and whether its output needs validation before use.

The core trick behind any "AI agent that calls APIs" is simpler than it sounds: the model doesn't call anything itself. It's given a list of available tools with their names, descriptions, and expected arguments, and when it decides a tool would help, it returns a structured request for your code to execute — never raw network access. LangChain's bind_tools() is what wires that tool list into the model call.

Building the agent

1. Define your tools as typed functions. The @tool decorator turns a plain Python function into something the model can discover — its docstring becomes the description the model uses to decide when to call it.

2. Bind the tools to your model. model.bind_tools([...]) makes the model aware of what's available and able to return a tool-call request instead of plain text when appropriate.

3. Wrap it in an AgentExecutor. create_tool_calling_agent() plus AgentExecutor handles the loop — call the model, execute any requested tool, feed the result back — until the model produces a final answer.

langchain_tool_agent.py
# A LangChain agent that can call a real API tool
from langchain.tools import tool
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

@tool
def get_order_status(order_id: str) -> str:
    """Look up the current shipping status for a given order ID."""
    # Your real API call goes here - the model never touches the network directly
    return f"Order {order_id} is out for delivery."

model = ChatOpenAI(model="gpt-4o")
prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful order-status assistant."),
    ("human", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])

agent = create_tool_calling_agent(model, [get_order_status], prompt)
executor = AgentExecutor(agent=agent, tools=[get_order_status])

result = executor.invoke({"input": "Where is order 4471?"})
Component Job
@tool function Defines what the tool does and its docstring, which the model reads to decide when to call it
bind_tools() Makes the model aware of the tool schema so it can request a call
AgentExecutor Runs the call-execute-feedback loop until the model has a final answer

Nothing here gives the model direct API access — every tool call still passes through your own function, which is exactly where you'd add rate limiting, authentication, or validation before anything actually reaches a real backend.

Practical Challenge

Add a second @tool-decorated function (e.g. cancel_order) to the agent above, and test whether the model correctly picks between the two tools based on the user's question.

Concept Check

When a LangChain agent "calls an API," what is actually happening?
Correct! The model never has network access. It returns a tool-call request, and the actual HTTP call happens inside the Python function you wrote and decorated with @tool.
Incorrect. Try again! Hint: think about where the actual `requests.get()` or API SDK call lives in the code — is it inside the model, or inside your function?

Sources & Further Reading

Previous Guide Dashboard Next Guide