LangChain standardises the parts around a model call. Instead of inventing a new format for every provider and tool, the application uses a common set of building blocks.
| Building block | What it does | Paris example |
|---|---|---|
| Model I/O | Gives a common way to call providers such as Anthropic, OpenAI, or open-weight models without rewriting the application. | The travel assistant's model call |
| Tools | Declares callable functions with names, descriptions, and typed arguments. | search_flights, search_hotels, check_policy |
| Messages and typed output | Represents the conversation and validates the returned data. | A PolicyVerdict, not prose that code must guess how to read |
The common interface makes provider changes smaller. It does not guarantee that two models behave exactly the same.
A tool is an ordinary function with enough information for the model and application to use it safely.
from langchain.tools import tool
@tool
def search_flights(
origin: str,
destination: str,
max_price: int,
) -> list:
"""Find flights below max_price. Search only; do not book."""
...
From that declaration, the framework gets:
search_flightsorigin, destination, and max_price, with typesThe tool still needs application-side validation and permissions. A decorator does not make a function safe.
Free text is easy for a person to read:
The itinerary looks mostly fine, although the departure may be a little close to the travel date under section 5.
Code still does not know whether that means pass or fail.
A typed result makes the decision clear:
from pydantic import BaseModel
class PolicyVerdict(BaseModel):
compliant: bool
violated_clause: str | None
reason: str
{
"compliant": false,
"violated_clause": "§5.1",
"reason": "Departs in 5 days; policy needs 7"
}
Now the graph can route to replan without decoding a paragraph.
Typed output helps because:
LangChain components share common operations:
| Operation | Meaning |
|---|---|
invoke |
Send one input and receive one output. |
batch |
Process many inputs. |
stream |
Receive output as it arrives. |
The pipe operator can form a chain:
policy_chain = prompt | model | parser
verdict = policy_chain.invoke(
{"policy": policy_text, "itinerary": trip}
)
A chain moves data one way, from left to right.
It does not naturally express:
That missing control-flow layer is where LangGraph enters.
LangChain supplies reusable model and tool components; typed output makes decisions machine-readable, while runnable chains handle straight-line flows.