LangGraphLangGraph 1.2 · Python 3.10+
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
37 small wins to finish your pathNext lesson

Binding tools to a model

A model cannot use a tool it has never heard of. Binding is how you tell it what it has.

This is the line that most tutorials skip past, and it is the one that turns a chat model into something that can act.

Example
from pretend_model import PretendModel
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool

@tool
def lookup_order(order_id: str) -> str:
    """Look up the status of an order by its id."""
    return f"Order {order_id} shipped on 3 March."

model = PretendModel().bind_tools([lookup_order])

reply = model.invoke([HumanMessage("Where is order A17?")])
print("content:   ", repr(reply.content))
print("tool_calls:", reply.tool_calls)

Read those two lines carefully

The content is empty. The model had nothing to say, because it did not want to say anything. It wanted to do something.

tool_calls is not empty. It holds a request: the name of the tool, the arguments to call it with, and an id. The model worked out that A17 was the order id from the question.

That is the whole mechanism. A model with tools bound can answer in two ways, with words or with a request, and your program looks at tool_calls to see which one happened.

Nothing has been called yet

This is the part people get wrong. The model did not run lookup_order. It cannot. It is a model, sitting behind an API, with no access to your machine.

It said please call this. Something has to read that request and actually call the function, and that something is your program. In the next lesson LangGraph does it for you.

Example
from pretend_model import PretendModel
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool

@tool
def lookup_order(order_id: str) -> str:
    """Look up the status of an order by its id."""
    return f"Order {order_id} shipped on 3 March."

model = PretendModel().bind_tools([lookup_order])
request = model.invoke([HumanMessage("Where is order A17?")]).tool_calls[0]

print("the model asked for:", request["name"], "with", request["args"])
print("so we call it:      ", lookup_order.invoke(request["args"]))

Four lines, and you have done by hand exactly what an agent framework does for you. Read the request, call the function, and you have the answer.

Bind returns a copy
bind_tools gives you back a new model with the tools attached. It does not change the one you had. Assigning the result, as above, is not optional.
Try it yourself
  • Ask something with no order id in it and print tool_calls again.
  • Bind a second tool and ask a question that matches it.
  • Print request in full and find the id field.

You understood something today that you didn't yesterday.