Migrating LangChain 0.0.x Imports to 0.1 and Later
10 min read · updated August 11, 2026
LangChain used to be one package with a flat import surface. It is now a small core, a set of per-provider packages, a large community package and a legacy package, and an import written against the old layout fails in one of three different ways depending on how far through that history your installed version is.
The errors you arrive with
Three strings, in rough chronological order of the version that emits them.
LangChainDeprecationWarning: Importing chat models from langchain is deprecated— the 0.1 era. The import still works. The message tells you it will not be supported as oflangchain==0.2.0and names the package to install instead. Nothing is broken yet, which is exactly why these get ignored until they are.ImportError: cannot import name 'ChatOpenAI' from 'langchain.chat_models'— the deadline arrived. The re-export was removed.ModuleNotFoundError: No module named 'langchain_openai'— you followed the deprecation message but did not install the package it named. The partner packages are separate distributions; upgradinglangchaindoes not pull them in.
The last one is the most confusing because the warning that sent you there reads like a rename. It is not a rename. It is a package split, and a split means a new line in your requirements file for every provider you use.
The four layers, and what belongs in each
The reason for the split is dependency weight. A single package containing every integration meant that installing LangChain to call one model dragged in the transitive surface of everything, and that a bug in any integration required a release of the whole framework.
langchain-core— the abstractions and nothing else: message types, prompt templates, output parsers, theRunnableprotocol that LCEL is built on. Deliberately near-dependency-free, because everything else depends on it.- partner packages —
langchain-openai,langchain-anthropic,langchain-chromaand the rest. One provider each, versioned and released independently, maintained closest to the vendor SDK they wrap. This is where the implementation you actually call lives. langchain-community— the long tail of integrations without a partner package. The project has been steadily draining this one; treat an import from here as a signal to check whether a dedicated package now exists.langchain— what used to be everything, now the composition layer.
The mapping for the common imports
# models from langchain.chat_models import ChatOpenAI -> from langchain_openai import ChatOpenAI from langchain.embeddings import OpenAIEmbeddings -> from langchain_openai import OpenAIEmbeddings from langchain.chat_models import ChatAnthropic -> from langchain_anthropic import ChatAnthropic # prompts, parsers, messages, runnables (all core) from langchain.prompts import ChatPromptTemplate -> from langchain_core.prompts import ChatPromptTemplate from langchain.schema import HumanMessage, AIMessage, SystemMessage -> from langchain_core.messages import HumanMessage, AIMessage, SystemMessage from langchain.schema.output_parser import StrOutputParser -> from langchain_core.output_parsers import StrOutputParser from langchain.schema.runnable import RunnablePassthrough -> from langchain_core.runnables import RunnablePassthrough # document loaders, vector stores, tools without a partner package from langchain.document_loaders import PyPDFLoader -> from langchain_community.document_loaders import PyPDFLoader from langchain.vectorstores import FAISS -> from langchain_community.vectorstores import FAISS
The rule that recovers most of this from memory: if the thing is an abstraction it is in langchain_core; if it talks to one named vendor and that vendor is popular enough it has its own package; if it talks to one named vendor and does not, it is in langchain_community.
The project ships a codemod for the bulk of this in the langchain-cli package, which is worth running before doing any of it by hand. Read its diff rather than accepting it: a codemod can rewrite an import path but cannot know which of several candidate classes you meant, which is the subject of the next section.
Two exceptions to that rule are worth memorising because they defeat it. Text splitters live in their own distribution, langchain-text-splitters, so from langchain.text_splitter import RecursiveCharacterTextSplitter becomes an import from langchain_text_splitters — not from core and not from community, which is where most people look first. And a handful of vendors have both a partner package and a lingering community module of the same name, which is the subject of the next section.
Why the same class exists three times
For a period, ChatOpenAI was importable from langchain.chat_models, from langchain_community.chat_models and from langchain_openai. They were not aliases of one object. They were separate implementations at different stages of being moved, and the partner-package one was the maintained one.
The failure this causes is nastier than an import error, because everything imports fine. Two of your modules pick different paths, and then an isinstance check between them is false, a caching layer keyed on class identity misses, or a callback registered against one class never fires for the other. If you are debugging behaviour that differs between two call sites that look identical, print type(obj).__module__ at both.
Migrate the whole repository in one commit for this reason. A half-migrated tree is not a tree with half the work left; it is a tree with a new class of bug in it. The same argument applies to pinning: pin langchain-core explicitly, since every other package depends on it and a resolver is free to satisfy them with a version none of you chose.
What moved again in 1.0
The split did not stop at 0.2. In the 1.0 line the langchain package was reduced again, to agent building blocks — create_agent, init_chat_model, the @tool decorator, message and embedding re-exports from core. Legacy chains, the older retrievers, the indexing API, the hub module and the community re-exports moved to a package called langchain-classic, per LangChain’s own v1 migration guide.
from langchain.chains import LLMChain -> from langchain_classic.chains import LLMChain from langchain.retrievers import MultiQueryRetriever -> from langchain_classic.retrievers import MultiQueryRetriever from langchain import hub -> from langchain_classic import hub
Treat langchain-classic as what its name says: a place to land so the build goes green, not a destination. If you are moving imports into it, the better use of the same afternoon is usually to move the chain itself onto composed runnables, which is a separate piece of work with its own page.
Doing the migration
- Record what you have:
pip freeze | grep langchain. The set of langchain distributions installed tells you which era you are in more reliably than the version of any one of them. - Add the partner packages you need to requirements before touching code —
langchain-openai,langchain-anthropicand so on. Missing distributions produceModuleNotFoundErrorthat looks like a wrong path. - Run the
langchain-clicodemod over the tree, then read the diff for any class that could have come from more than one package. - Escalate warnings to errors in your test run so the remaining deprecations are visible rather than scrolled past.
- Grep for
type(checks andisinstanceagainst LangChain classes. These are the ones that survive the codemod and change meaning. - Commit the whole thing at once. Then pin the versions you landed on, including
langchain-core.