LangChain Development Guide: From LCEL to Production Agents
LangChain is one of the most popular open-source frameworks for building LLM applications. Its official positioning is "Agent + configurable orchestration": the model (Model) does the reasoning, and everything around it—prompts, tools, middleware—is composed by the framework. Its core value is unifying interfaces across model vendors, so you write once and run on OpenAI, Anthropic, Google, Ollama, and more, while also providing the primitives for building chains (Chain) and agents.
1. Unified Model Interface: Write Once, Run Everywhere
LangChain abstracts chat models, embedding models, image models, and more behind a unified interface. For example, create_agent accepts a model identifier string and routes to the right vendor automatically:
from langchain.agents import create_agent
def get_weather(city: str) -> str:
"""Get weather for a given city."""
return f"It's always sunny in {city}!"
agent = create_agent(
model="openai:gpt-5.5",
tools=[get_weather],
system_prompt="You are a helpful assistant",
)
Switching vendors only means changing the model identifier, for example to anthropic:claude-sonnet-4-6 or ollama:llama3. This matters for business: when one vendor raises prices or throttles requests, your application can switch quickly instead of rewriting call logic.
2. LCEL: Compose Chains with the Pipe Operator
LCEL (LangChain Expression Language) is the framework's declarative composition syntax, chaining components with | into pipelines. For example, "prompt template → model → output parser":
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_template("Summarize in one sentence: {topic}")
chain = prompt | model | StrOutputParser()
print(chain.invoke({"topic": "RAG"}))
The advantage of LCEL is that chains are ordinary objects: they can be nested, run in parallel, called asynchronously, and they natively support streaming and automatic retries. The more complex the business logic, the more "composition over hard-coding" pays off.
3. Tool Calling: Let the Model Take Action
The biggest difference between an agent and a plain chatbot is tool calling. Tools can be any Python function, declared with the @tool decorator and parameter descriptions. The framework passes the tool schema to the model, which returns a call request when needed; the framework executes it and feeds the result back to the model.
from langchain.tools import tool
@tool
def search_docs(query: str) -> str:
"""Search the knowledge base and return matching chunks."""
return run_search(query)
Tools define the agent's capability boundary: connect databases, email, payments, search APIs, and the model can do real work. The key principles for tools are clear descriptions, simple inputs, and graceful failures. For a more systematic agent development approach, see AI Agent Development Basics.
4. Memory: Give Conversations Context
Multi-turn conversations need memory. LangChain provides conversation history management that can inject past messages into the prompt, or combine with vector retrieval for long-term memory. Two practical notes:
- Control the short-term window: Too many history messages crowd the context and raise cost; typically truncate or summarize.
- Retrieve long-term memory: Store history as vectors and retrieve relevant snippets instead of stuffing everything in—this is exactly the RAG approach. See RAG Implementation Guide.
5. Agent Development: Model + Harness
The official definition is "Agent = Model + Harness." create_agent is the minimal harness; you add capabilities incrementally through middleware—retries, guardrails, routing, tool policies—composing only what your use case needs.
The framework family includes two important companions:
- LangGraph: the low-level graph orchestration framework for complex applications that combine deterministic flows with agent branches, supporting durable execution, persistence, and human-in-the-loop.
- LangSmith: the observability and evaluation platform. It records full traces of every call (prompts, tool calls, state transitions, latency) for failure diagnosis and quality evaluation.
The division of labor: Deep Agents for "batteries included", LangChain for "highly customizable", and LangGraph for "low-level orchestration".
6. Practical Advice
- Prototype locally first: Use Local LLM Deployment with Ollama to run a small model on your machine for development and debugging, saving cost and avoiding network dependencies.
- Add observability early: Turn on LangSmith tracing from the first version; diagnosing agent behavior later becomes far easier.
- Keep tools minimal: Limit each agent to the necessary tools. Too many tools cause decision fatigue and enlarge the failure surface.
- Validate outputs: Add format and security validation for both tool results and model outputs, especially for user-facing scenarios.
7. A Minimal Example: Turning an LCEL Chain into an Agent
Concepts float until you wire them together, so let's walk through the same "customer support bot" to connect every abstraction above. Version one is a plain chain: prompt template → model → output. It answers common questions but cannot check orders. The agent version adds a query_order tool; when the user asks "where is my order," the model calls the tool automatically and composes the answer from the result.
from langchain.agents import create_agent, tool
@tool
def query_order(order_id: str) -> str:
"""Look up the shipping status of an order by its ID."""
return fetch_status(order_id)
agent = create_agent(
model="openai:gpt-5.5",
tools=[query_order],
system_prompt="You are an e-commerce support agent; answer only from tool-returned facts.",
)
reply = agent.invoke({"input": "Where is order 20260808-001?"})
print(reply)
There is almost nothing new here — it just adds "tool calling" and "orchestration" to the original chain. In real projects, layer capabilities the same way: first add RAG for the knowledge base, then business tools such as orders and refunds, and finally use LangGraph to turn human-approved flows like refunds into explicit state machines. As long as each layer stays independently testable and each tool stays reusable, complexity will not get out of hand.
Frequently Asked Questions
LCEL or LangGraph? The test is whether the flow is fixed. For request-response conversations and tool calls, LCEL is enough. Move to LangGraph when you need multi-step approvals, branch-and-retry, or cross-session persistence.
How many tools should an agent have? A practical range is 3-6. Fewer underuses the agent; more causes frequent mis-selection and enlarges the attack surface. Tool descriptions should state when to use them — and what they are not for.
Memory in the prompt or in a vector store? Keep the last 5-10 turns in the prompt, and retrieve long-term facts (preferences, order history) into the prompt as well; a combination usually beats either approach alone.
Is multi-vendor switching really painless? Switching the model identifier is painless, but tool-calling formats and system-prompt styles differ across vendors. Write a separate prompt template per vendor rather than relying on one prompt everywhere.
16IDC Perspective
For website teams, LangChain is a shortcut to embedding AI capabilities into products: whether it's an AI-related support bot, content generation, or data analysis, unify model access with LangChain first, then layer RAG, tools, and agents as needed. This significantly reduces the complexity of multi-vendor switching and service orchestration. The framework itself is free open-source infrastructure; what you really invest in is data quality, prompt engineering, and an evaluation system.
Source: https://docs.langchain.com/oss/python/langchain/overview