LangChainLangChain 1.4 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
46 small wins to finish your pathNext lesson →

Tools: a function the model can call

A tool is a Python function wrapped by @tool so a model can ask for it by name: it takes its name from the function, its description from the docstring, and its argument schema from the type hints.

Last updated: 27 Sep, 2026 · LangChain 1.4

The model never runs the tool. It asks for it by name and your code runs it. The shop keeps order statuses in a dictionary, and looking one up is ordinary Python.

The @tool decorator

python
from langchain.tools import tool

@tool
def my_tool(arg: str) -> str:
    """What it does and when to use it."""  # the model reads this
    return "result"

Writing the lookup_order tool

Decorate a plain function with @tool. The docstring and the type hints do the work.

python
from langchain.tools import tool

ORDERS = {"A17": "shipped on 3 March", "C40": "waiting for stock"}


@tool
def lookup_order(order_id: str) -> str:
    """Look up an order's shipping status by its id, such as A17."""
    status = ORDERS.get(order_id)
    return f"{order_id} {status}." if status else f"{order_id} is not an order we have."

@tool turns the function into a tool object. It takes the name from the function, the description from the docstring, and the argument types from the type hints.

What the model is told

Print the three things @tool built. This is all the model ever learns about the tool.

Example
print(lookup_order.name)
print(lookup_order.description)
print(lookup_order.args)

This is everything a model learns about the tool. The docstring is how it decides when to use it, so it says what the tool does and what an order id looks like. The schema tells it to send one string called order_id.

Running a tool yourself

Call a tool with a dictionary of arguments, the form a model produces.

Example
print(lookup_order.invoke({"order_id": "A17"}))
print(lookup_order.invoke({"order_id": "B22"}))

A tool is called with a dictionary of arguments, the form a model produces. B22 is not in the dictionary, so the tool says so in words the model can pass on.

What @tool built

  • The model is handed only the name, the description and the argument schema; the docstring is how it decides when to call the tool.
  • You call a tool with a dictionary of arguments, the same shape a model produces.
  • An id the tool does not know, B22, comes back as a plain message the model can pass on, not an exception.

A tool without type hints

Leave the type hint off and the schema changes. Watch what the model is told about the argument.

Example
from langchain.tools import tool


@tool
def lookup_order(order_id):
    """Look up an order's shipping status by its id, such as A17."""
    return "unknown"


print(lookup_order.args)

Type hints are meant to be required, but 1.4.2 accepts the function anyway and drops the type from the schema, so a model is no longer told that order_id is a string. Keep the hints.

With type hints vs without

With <code>order_id: str</code>Without a hint
Schema{'title': 'Order Id', 'type': 'string'}{'title': 'Order Id'}
Model told the typeYes, a stringNo type at all
Accepted by 1.4.2YesYes, but keep the hint

When to write a tool

  • Looking data up in your own database or API.
  • Taking an action, such as creating a ticket or sending an email.
  • Any step you want the model to request but your code to run and control.
Watch out. The docstring is not decoration: it is how the model decides when to call the tool. Delete it and @tool raises an error, and a vague one leaves the model guessing when to use it.
Try it yourself
  • Add a second argument, customer: str, and print args again.
  • Pass name="order_status" to @tool and print the tool's name.
  • Delete the docstring and read the error.

Little by little, you're building something great.