Generative AIBuilding with foundation modelsTools & frameworks

Advanced LangChain features

7 minutes read

We’ve already seen how LangChain makes it easy to connect your application to LLMs and equip them with external data. However, this is not all. We can also build agents, add safety controls, use external tools, and even divide work among specialized subagents. In this topic, we’ll explore these advanced capabilities LangChain offers.

Tool-calling

LLMs understand and generate natural language well, but they are less reliable at tasks such as performing calculations, querying APIs, searching the web, or retrieving live information. Tools solve this limitation by allowing a model to invoke functions that interact with external systems or perform deterministic processing.

A tool can be anything from a calculator to an API wrapper. LangChain provides prebuilt tools and supports custom tools through the @tool decorator:

# install package
# pip install -qU langchain

from langchain.tools import tool

@tool("search_engine", description="Search DuckDuckGo for information relevant to the given query."
def duckduckgo_search(query: str) -> str:
    """Search DuckDuckGo for information relevant to the given query."""
    if "best coffee shops" in query.lower():
        return "Popular coffee shops in London include Costa and Caffè Nero."
    if "python tutorial" in query.lower():
        return "Python tutorials are available from the official documentation and freeCodeCamp."
    return f"No results found for: {query}"

result = duckduckgo_search.invoke(
    {"query": "best coffee shops in London"}
)
print(result)

A tool has a name, description, and input schema. LangChain can infer these from the function signature and docstring, although they can also be customized. Clear names and descriptions help the model decide when and how to use each tool.

LangChain also provides prebuilt integrations for tasks such as web searches, database queries, API access, and shell operations. Whether custom or prebuilt, tools can be bound to a model using bind_tools():

model_with_tools = llm.bind_tools([duckduckgo_search])

response = model_with_tools.invoke(
    "What are the best coffee shops in London?"
)

print(response.tool_calls)

# [{'name': 'duckduckgo_search', 'args': {'query': 'best coffee shops in London specialty coffee shops 2026 recommendations'}, 'id': 'call_KhVDa7E9rJibSqGEiPgz74Ih', 'type': 'tool_call'}]

The model does not execute the function itself. Instead, it returns a structured tool call containing the selected tool and its arguments. Your application then executes the call and returns the result to the model in a second call. If multiple tools are available, the model can select the appropriate one based on their names, descriptions, and schemas. Ensure you aggregate all tool outputs before invoking the model again for the final response.

Agents

An agent combines an LLM with tools and instructions to intelligently perform tasks autonomously. Agentic workflows need different components, tools, memory, prompts, and other elements to work effectively. LangChain streamlines building such complex workflows. For example, here's how you can create a simple Reason and Act (ReAct) agent with a tool to convert an integer to binary:

# install packages and set your OpenAI API key in the environment: export OPENAI_API_KEY="sk-..." 
# pip install -qU langchain
# pip install -qU "langchain-openai"

from langchain.agents import create_agent
from langchain.tools import tool

@tool
def to_binary(n: int) -> str:
    """Convert a given integer to binary"""
    return bin(n)

agent = create_agent(
    model="openai:gpt-5.4-mini",
    tools=[to_binary],
    prompt="You are a helpful assistant that can help return the binary of integers.",
)
print(agent.invoke({"messages":[{"role":"user","content":"binary of 42"}]}))

The model sees each tool’s name, description, and input schema. If it determines that a tool is needed to perform the task, it generates a relevant tool call. LangChain executes the function and returns its result to the model. With this abstraction, you do not need to execute tool calls yourself. Ensure that descriptions are specific to help the model select relevant tools accurately.

Tools do not always have to wrap simple functions or APIs. You can wrap the agent invocation as a tool and equip it to another agent. The main agent will only see the tool without direct access to every low-level tool used by the other agent. This is the foundation for the subagent pattern. The main agent’s tool list can stay small while specialists operate with their own instructions, tools, and context.

Middleware

As you can see, agents provide a convenient execution loop. However, we sometimes want to modify what happens around model and tool calls. For example, we may want to log model requests, retry failed tools, limit model and tool calls, and even approve sensitive actions. This can be done with middleware.

Middleware provides hooks into different stages of the agent loop. It can observe or modify agent execution without changing the tools or rebuilding the complete agent. LangChain already provides prebuilt middleware and supports custom middleware too. Here’s an example for retrying model calls:

from langchain.agents import create_agent
from langchain.agents.middleware import ModelRetryMiddleware

agent = create_agent(
    model="openai:gpt-5.4-mini",
    tools=[to_binary],
    middleware=[
        ModelRetryMiddleware(
            max_retries=3,
            backoff_factor=2.0,
            initial_delay=1.0,
        ),
    ],
)

LangChain provides middleware for many common requirements like tool- and model-call limits, PII handling, and human-in-the-loop approval workflows. You can view all of them in the documentation. Middleware order is important. If multiple wrappers are configured, they form a nested execution chain. For example, guardrails or PII handling middleware should run before others.

MCP tools

Traditionally, every integration with external systems requires custom tools, as we've seen. With MCP, applications have a standard way to discover and access capabilities exposed by external servers. LangChain integrates with MCP servers through the langchain-mcp-adapters package. A MultiServerMCPClient can connect to one or more servers and convert their tools into LangChain-compatible tools:

from langchain_mcp_adapters.client import MultiServerMCPClient

client = MultiServerMCPClient(
    {
        "support": {
            "transport": "stdio",
            "command": "python",
            "args": ["/absolute/path/to/support_server.py"], 
        }
    }
)

tools = await client.get_tools()

The discovered tools can be passed directly to an agent:

from langchain.agents import create_agent

mcp_agent = create_agent(
    model="openai:gpt-5.4-mini",
    tools=tools,
    system_prompt=(
        "You are a support assistant. Use the available tools to look up "
        "verified information before answering."
    ),
)

result = await mcp_agent.ainvoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "Find the status of support ticket TICKET-42.",
            }
        ]
    }
)

print(result["messages"][-1].content)

The MCP adapter supports local stdio communication, remote HTTP connections, authentication, stateful sessions, and tool-call interceptors. Be sure to verify every MCP server you use, validate tool calls, and handle server failures.

Multi-agent systems

As workflows grow, placing every instruction and tool in one agent can make routing less accurate and context harder to manage. Multi-agent systems divide responsibilities among specialized components. Each component can have its own prompt, tools, memory, and permissions.
LangChain supports several multi-agent patterns:

  • Subagents — in this pattern, a main agent decides when and how to invoke specialist agents.

  • Handoffs — tool calls update state and transfer control to another agent or configuration. This can change the active instructions, tools, or agent according to the current task.

  • Skills — a single agent remains in control while loading specialized prompts and knowledge on demand. This avoids keeping all domain-specific context active at once.

  • Router — here, a routing step transfers control to specialized agents. You can even invoke agents in parallel.

  • Custom workflow — build custom workflows with LangGraph, giving you complete control.

The best pattern depends on the workflow. Subagents are useful when centralized coordination is important. Skills help manage large amounts of optional context without introducing several independent agents. Handoffs suit workflows in which responsibility shifts between specialists, and routers work well for clearly classifiable requests. Custom LangGraph workflows provide the most control for complex routing, parallel execution, retries, and state management.

Conclusion

LangChain supports much more than basic model calls and retrieval. Tools allow models to perform actions and access external information. With agents, you get an execution loop for selecting and invoking those tools. Middleware adds controls such as retries, limits, guardrails, PII handling, and human approval. MCP offers a standardized way to connect agents to external capabilities, and multi-agent patterns divide complex workflows among focused specialists.

2 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo