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
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.
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.
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.
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.
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 type | Yes, a string | No type at all |
| Accepted by 1.4.2 | Yes | Yes, 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.
@tool raises an error, and a vague one leaves the model guessing when to use it.Related
- Previous: invoke, batch and stream
- Next: bind_tools: asking for a tool
- Reference: Tools
- Add a second argument,
customer: str, and printargsagain. - Pass
name="order_status"to@tooland print the tool's name. - Delete the docstring and read the error.
Little by little, you're building something great.