LangChain describes itself as “the agent engineering platform,” and the monorepo backs the branding with real architecture: an MIT-licensed Python framework whose core abstraction, the Runnable, lets models, prompts, tools, parsers, and retrievers compose into applications with the pipe operator, plus a v1 agent runtime with a middleware system that reads like a framework for frameworks. The repository is organized as libs/ containing langchain-core, the v1 langchain package, and a partners/ directory of first-party integrations for OpenAI, Anthropic, Ollama, Groq, Mistral, xAI, DeepSeek, OpenRouter, HuggingFace, Chroma, Qdrant, and more. Getting started is one command, uv add langchain, and three lines of Python.

Two things make this codebase worth your reading time. First, it solved the portability problem of the LLM era with abstractions instead of lock-in: BaseChatModel defines what a model is, partner packages implement it per provider, and init_chat_model(“openai:gpt-5.5”) resolves a model by string at runtime, so switching vendors is a one-word edit. Second, the v1 rewrite shows what the team learned in production: agents are built by create_agent with a ToolNode for execution and a middleware sequence where human-in-the-loop approvals, summarization, retries, fallbacks, and model call limits each live in their own module you can read, reorder, or replace.

As always in this series, this is an educational tour of published source code. LangChain connects your code to models that will confidently do the wrong thing if you let them, and the framework knows it: the middleware layer exists to gate risky tools behind approval, the structured output parsers exist to make model responses checkable, and the tracing layer exists so you can see exactly what ran. Build with those guardrails on, and treat agents as software under test rather than magic.

LangChain overview architecture diagram

LangChain at a glance: prompts, chat models, tools, and vector stores all extend one Runnable core; the v1 create_agent runtime drives models and a tool node under middleware; partner packages implement the model base; tracers and callbacks observe everything.

Reading the overview from left to right:

Why You Need This

The first reason is that LangChain is where the industry’s shared vocabulary lives. Messages, tools, structured output, retrievers, embeddings, vector stores: if you have read an LLM tutorial in the last two years, you have used words this codebase defined or popularized. Reading the actual base classes, Runnable in runnables/base.py and BaseChatModel in language_models/chat_models.py, shows how to design interfaces that a hundred third-party packages can implement without stepping on each other, which is a masterclass regardless of whether you ship on LangChain.

The second reason is the composition model. Because every component is a Runnable, you can write chain = prompt model parser and get streaming, batching, async, retries, and fallbacks for free from the base class, not from per-component glue. The composition utilities in runnables/, including retry.py for retries, fallbacks.py for provider outages, and router.py for dynamic dispatch, are each small enough to read in one sitting and generic enough to reuse in your own frameworks. This is the rare codebase where the abstraction and the implementation are both worth studying separately.

The third reason is the v1 agent runtime. create_agent in the v1 factory builds an agent around a model and a ToolNode, and everything else is middleware: human-in-the-loop approval gates, context summarization, model retries and fallbacks, call limits, and more, each an isolated module in agents/middleware. That design answers the hardest question in agent engineering, which is how to keep autonomy configurable without a special-case flag for everything, and it does so in code you can extend with your own middleware class in an afternoon.

How It Works

LangChain detailed architecture diagram

Inside LangChain: the Runnable family with retry, fallbacks, routing, and graph introspection; the message hierarchy; chat models with profiles and rate limiters; the agent factory with middleware, tool node, and MCP; prompts; the retrieval stack; and the tracing flow feeding LangSmith.

Understanding the Architecture

One base class to compose them all. Runnable in runnables/base.py defines invoke, batch, stream, and their async twins, plus the pipe operator that turns components into declarative sequences. The resilience wrappers in runnables/retry.py and runnables/fallbacks.py wrap any Runnable with retries and provider failover, router.py dispatches dynamically between branches, and graph.py can render the composed topology, including ASCII and mermaid views, by introspecting the chain. Every other subsystem in the repo plugs into this contract.

Messages as the universal currency. The message hierarchy in messages/ starts at base.py with content blocks, then specializes into AI messages in ai.py, which carry tool calls and reasoning output, and tool messages in tool.py, which carry results back. Prompts compile into messages through prompts/chat.py on top of prompts/base.py, chat models consume and emit them in language_models/chat_models.py, and chat_history.py persists them, so one data model spans prompting, inference, and memory.

Models behind a stable interface. BaseChatModel defines the contract; partner packages like langchain-openai and langchain-anthropic implement it, and legacy completion-style models live behind llms.py. Model capabilities travel as metadata through language_models/model_profile.py, so an agent can check whether its model supports tools before offering them, and rate_limiters.py provides token-bucket throttling shared by implementations. Structured output gets its own stack in output_parsers/, with base.py, json.py, and pydantic.py turning free text into validated objects.

Agents as a runtime plus middleware. create_agent in the v1 agents/factory.py assembles a model, a tool list, an optional system prompt, and a middleware sequence into an executable agent, with structured_output.py wiring a response schema onto the run. Tools execute in tool_node.py, which handles errors, state injection, and returning tool messages. The middleware directory is where the interesting engineering lives: human_in_the_loop.py interrupts before risky tools, summarization.py compacts long histories, and the system covers model retries, fallbacks, call limits, shell tool policies, and more. mcp/adapter.py bridges Model Context Protocol servers into ordinary LangChain tools.

Retrieval as first-class data engineering. The retrieval stack pairs vectorstores/base.py, the interface every vector database implements, with embeddings/embeddings.py for the embedding contract and indexing/api.py, which syncs documents into a store with content hashing so unchanged sources are not re-embedded. Documents themselves are defined in documents/base.py. This trio is the conceptual core of every RAG system built with the framework.

Observability built in, not bolted on. Every Runnable emits lifecycle events through callbacks/manager.py to registered handlers, and tracers/base.py defines the run-tree tracer that powers debugging, with tracers/langchain.py exporting to LangSmith and tracers/event_stream.py feeding astream_events. Because the hooks live in the base class, adding a new tracer requires no changes to models or agents, which is exactly what an observability boundary should look like.

Advantages

  • Vendor portability. One chat-model interface across OpenAI, Anthropic, Ollama, Groq, Mistral, xAI, DeepSeek, OpenRouter, and more, with model resolution by string.
  • Composable by construction. The Runnable contract gives every component streaming, batching, retries, fallbacks, and async without glue code.
  • A modern agent runtime. create_agent plus middleware provides approvals, summarization, retries, and limits as composable, readable modules.
  • MCP support. Protocol servers become ordinary tools through one adapter, connecting the agent ecosystem to the broader tool ecosystem.
  • RAG primitives done right. Vector stores, embeddings, and a content-hash indexing API cover the standard retrieval patterns with production discipline.
  • Observability by default. Callbacks and tracers are wired into the base class, with LangSmith export and event streams ready out of the box.

Benefits

  • Learn interface design. The base classes are textbook examples of how to keep a fast-moving ecosystem stable through contracts rather than versions.
  • Standard-tests as a quality model. The separate standard-tests package runs the same suite against every integration, a pattern worth copying for any plugin system.
  • Python-native. Fully typed with pydantic models, async-first APIs, and pip or uv installation, it fits modern Python toolchains.
  • Ecosystem leverage. Deep Agents, LangGraph, and LangSmith build on the same core, so time spent learning it transfers upward.
  • Readable resilience. Retry, fallback, and rate limiting are visible source files, not invisible middleware, so failure behavior is something you can tune with knowledge.
  • License and continuity. MIT-licensed and actively maintained, with the v1 rewrite showing the project re-architects rather than accumulates.

Usage

Install the framework, then talk to a model in three lines:

uv add langchain
from langchain.chat_models import init_chat_model

model = init_chat_model("openai:gpt-5.5")
result = model.invoke("Hello, world!")

Define a tool, then build an agent around the same model string:

from langchain.tools import tool

@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return "sunny"

from langchain.agents import create_agent

agent = create_agent(
    "openai:gpt-5.5",
    tools=[get_weather],
    system_prompt="You are a concise assistant.",
)

Run the agent and compose small chains from a prompt, a model, and a parser:

agent.invoke({"messages": [{"role": "user", "content": "What is the weather in Osaka?"}]})

chain = prompt | model
chain.invoke({"topic": "caching"})

Add integrations per provider as you need them, following the partner packages in the same repository:

uv add langchain-openai
uv add langchain-anthropic

Conclusion

LangChain matters in this series because it is the layer beneath the layers: the coding agents and model servers we have toured all eventually meet an application that needs composition, portability, and observability, and this codebase is the most complete open answer to that problem. Study the Runnable for interface design, the partner split for plugin ecosystems, and the v1 middleware for how to make agent autonomy a configurable property instead of a hardcoded gamble. Then build something small with it, because a framework this composable is best understood by composing.

Links:

Watch PyShine on YouTube

Contents