Skip to content

LangChain v1: What Changed, What Moved, and Why Old Tutorials Break

Site Console Site Console
7 min read Updated Oct 9, 2026 AI & Tools 0 comments

The Import That Does Not Resolve

You find a tutorial that does exactly what you need. You install LangChain, paste the first cell, and get this:

ImportError: cannot import name 'LLMChain' from 'langchain.chains'

So you search the error, find a Stack Overflow answer from a year ago, try that, and hit a different import failure. Somewhere around the fourth attempt you start wondering whether you picked the wrong framework.

You did not. You picked a framework that shipped a major version and deliberately threw most of its surface area overboard — and the internet has not caught up, because two years of tutorials, blog posts and model-generated code snippets all describe the old shape.

This post is the map. Read it once and you will be able to date any LangChain snippet in about five seconds.


What Actually Happened

LangChain 1.0 landed on 22 October 2025, alongside LangGraph 1.0. The headline was create_agent, but the structural change was the package split.

The old langchain package had accumulated years of abstractions — chains, memory classes, agent executors, dozens of retrievers, community integrations — most of which represented a bet on how people would build with language models in 2023. That bet turned out to be wrong in an interesting way: the field converged on agents calling tools in a loop, and most of the chain machinery became a longer path to the same place.

So v1 kept the parts that survived and moved the rest into a separate package called langchain-classic. Nothing was deleted. The old code still exists, still works, and still receives compatibility maintenance — it just lives behind a different import, and you have to install it on purpose.

That last detail is why your paste failed. The symbol exists; it is simply not in the package you installed.


What Is in langchain Now

The namespace is small enough to list on one hand, and most of it re-exports from langchain-core:

Module

What you get

langchain.agents

create_agent, AgentState

langchain.chat_models

init_chat_model, BaseChatModel

langchain.messages

Message types, content blocks, trim_messages

langchain.tools

@tool, BaseTool, injection helpers

langchain.embeddings

Embeddings, init_embeddings

Model providers live in their own packages — langchain-openai, langchain-anthropic, langchain-google-genai, and so on — installed through extras:

pip install -U "langchain[openai]"

That is the entire modern surface. If a tutorial imports something that is not in the table above and not from a provider package, it is pre-v1 code.


Where the Old Things Went

Everything below now imports from langchain_classic instead of langchain:

pip install langchain-classic

What you are reading

Where it lives now

from langchain import ...

from langchain_classic import ...

from langchain.chains import LLMChain

from langchain_classic.chains import LLMChain

from langchain.retrievers import MultiQueryRetriever

from langchain_classic.retrievers import ...

from langchain.indexes import ...

from langchain_classic.indexes import ...

from langchain import hub

from langchain_classic import hub

CacheBackedEmbeddings, community embeddings

langchain_classic

langchain-community re-exports

langchain_classic

The mechanical fix for most pre-v1 code is therefore a find-and-replace of langchain. to langchain_classic. plus one install. That gets old code running again, which is genuinely useful when you are trying to understand a tutorial rather than ship it.

It is not, however, what you want for new code. LLMChain works in langchain-classic, and it is still the long way round to something init_chat_model and a prompt template do in two lines. Use the classic package to read the past, not to build the present.


Agents: Renamed, Not Just Moved

Agent code is where v1 broke most decisively, because the agent API was redesigned rather than relocated.

create_react_agent from langgraph.prebuilt became create_agent from langchain.agents. Along with the name, several argument conventions changed. The prompt= parameter became system_prompt=, and prompts that need to vary at runtime now go through @dynamic_prompt middleware. The pre_model_hook and post_model_hook parameters became before_model and after_model middleware. Tool error handling moved from ToolNode(handle_tool_errors=...) to a @wrap_tool_call middleware.

Middleware is the thread running through all of that, and it is the real idea in v1. Instead of a growing list of constructor arguments for every customization anyone might want, the agent loop exposes hooks — before_agent, before_model, wrap_model_call, wrap_tool_call, after_model, after_agent — and anything you want to change is a function that wraps a step. LangChain ships a few prebuilt ones, including PII redaction, message summarization and human-in-the-loop approval.

A few things are not accepted at all any more. create_agent will not take a ToolNode in its tools= argument, will not take a pre-bound model such as ChatOpenAI().bind_tools(...), and will not take a Pydantic model or dataclass as a state schema — state is TypedDict only. Prompted output in response_format, the (prompt, Schema) tuple pattern, is gone in favour of ToolStrategy and ProviderStrategy.

If you are reading streaming code, note that the node formerly streamed as "agent" is now "model". That one silently changes what your event handler matches on.


The Breaks That Do Not Raise ImportError

An import error is a good failure. It stops immediately and tells you where. The changes worth real attention are the ones that let your code run and quietly behave differently.

.text is a property now, not a method. Calling response.text() still works and emits a deprecation warning, and the method form disappears in v2. Pre-v1 snippets use the parentheses; new code should not.

langchain-openai changed what lands in content. It now stores Responses API items there by default. If you have code that assumes the older content shape, set output_version="v0" on the model or the LC_OUTPUT_VERSION=v0 environment variable to restore the previous behaviour. This one is easy to miss because nothing errors — your string handling simply sees something it did not expect.

langchain-anthropic no longer defaults max_tokens to 1024. The default is now model-dependent. Code that relied on the old implicit ceiling will behave differently, and the symptom is a cost or truncation surprise rather than an exception.

Standard content blocks are opt-in for serialization. Messages gained a content_blocks property giving a typed, provider-agnostic view of reasoning traces, citations and tool calls. It is supported in the OpenAI, Anthropic, AWS, Google GenAI and Ollama integrations. The blocks are not serialized into content unless you opt in with output_version="v1" or LC_OUTPUT_VERSION=v1.

Python 3.9 is no longer supported. v1 requires 3.10 or newer. A tutorial whose setup pins 3.9 predates the split entirely.


Dating a Snippet in Five Seconds

Once you know the shape of both eras, the tell is usually in the imports. Anything importing from langchain.chains, or naming LLMChain, ConversationChain, initialize_agent or RetrievalQA, is pre-v1. Anything importing create_react_agent from langgraph.prebuilt is from the 0.x agent era. An agent constructor taking prompt= rather than system_prompt= is pre-v1. A .text() call with parentheses is old style, even though it still runs. And a setup block installing plain langchain while importing things that now live in langchain-classic will fail on the first cell, which at least fails honestly.

None of this means an old tutorial is worthless. The explanation of why retrieval needs chunking does not expire. It means you read old material for the concepts and the current documentation for the API — which is the right habit with any fast-moving library, and an essential one here.


The Part That Should Reassure You

LangChain's maintainers committed to no breaking changes until 2.0. LangGraph 1.0 kept full backward compatibility, its only notable change being the deprecation of langgraph.prebuilt in favour of langchain.agents.

So the churn that made the internet's LangChain content unreliable was a one-time correction, not the normal state of affairs. Code written against v1 should keep working for a long time — which is precisely why it is worth learning the v1 shape properly rather than pattern-matching against whatever a search engine surfaces.

Every post in this series pins its versions and states its verification date for the same reason. This one was written against langchain 1.4.3, langchain-core 1.6.7 and langchain-openai 1.6.7 on 8 October 2026.


🧭 What's Next

  • Post 3: Tokens, Models and Prices — before writing any more code, it is worth understanding what you are being billed for. Tokens are not words, output costs several times more than input, and cached input changes the maths entirely. The next post works through what a realistic feature actually costs per month.

Related

Leave a comment

Sign in to leave a comment.

Comments