langchain-upgrade-migration
Migrate a LangChain 0.3.x Python codebase to LangChain 1.0 / LangGraph 1.0 without breaking production — named breaking changes, codemod patterns, and a phased rollout. Use when upgrading LangChain or LangGraph from 0.2 or 0.3 to 1.0, when hitting ImportError after an upgrade, or when preparing a migration PR. Trigger with "langchain 1.0 migration", "langchain upgrade", "LLMChain removed", "initialize_agent removed", "ConversationBufferMemory removed", "astream_log deprecated", "langchain-anthropic 1.0".
Allowed Tools
Provided by Plugin
langchain-py-pack
Claude Code skill pack for LangChain 1.0 + LangGraph 1.0 (Python) - 34 skills covering chains, agents, RAG, middleware, checkpointing, HITL, streaming, and production patterns
Installation
This skill is included in the langchain-py-pack plugin:
/plugin install langchain-py-pack@claude-code-plugins-plus
Click to copy
Instructions
LangChain 1.0 Upgrade Migration (Python)
Overview
The first deploy after pip install -U langchain crashes on import with:
ImportError: cannot import name 'ChatOpenAI' from 'langchain.chat_models'
Fix the import, restart, and the next error lands:
ImportError: cannot import name 'LLMChain' from 'langchain.chains'
AttributeError: module 'langchain.agents' has no attribute 'initialize_agent'
AttributeError: 'ConversationBufferMemory' object has no attribute 'save_context'
LangChain 1.0 removed four entire public-API surfaces in one release:
- Provider imports under
langchain.chat_models/langchain.llms(pain code P38). - The
LLMChainfamily underlangchain.chains(P39). ConversationBufferMemoryand siblings underlangchain.memory(P40).initialize_agentunderlangchain.agents(P41).
Anything that inspected intermediate_steps also breaks because the tuple shape changed from (AgentAction, observation) to (ToolCall, observation) (P42).
This skill walks a reversible, phased migration:
- A pre-flight grep audit.
- A pinned package upgrade (including the
langchain-anthropic1.0 peer-pin againstanthropic >= 0.40, P66). - Codemod patterns for the seven removed APIs.
- A rollout playbook with shadow traffic and a sub-five-minute rollback.
It covers 7 named breaking changes and typically touches 10–100 files in a mid-sized service.
The fix for the error above:
# BEFORE (0.3)
from langchain.chat_models import ChatOpenAI
# AFTER (1.0)
from langchain_openai import ChatOpenAI
See codemod-patterns.md for the other six patterns.
Prerequisites
- Python 3.10+ (LangChain 1.0 dropped 3.8/3.9).
- A working test suite for the service being migrated (the playbook runs
pytest -W error::DeprecationWarningat every phase). - Git on a clean working tree — the migration uses per-module commits so rollback is per-commit.
- Access to staging traffic or a request-mirror. Phase 4 of the playbook needs real-shape traffic.
- If conversations are persisted (Redis / Postgres / DynamoDB), a snapshot of the chat-history store before Phase 2. The LangGraph checkpointer uses a new schema and a naive rollback is data-lossy.
Instructions
Step 1 — Pre-flight grep audit
Inventory every 0.3 usage before touching a requirements.txt. Each grep below maps to one pain code and one codemod pattern.
grep -rn "from langchain\.chat_models\|from langchain\.llms" --include="*.py" . # P38
grep -rn "from langchain\.chains\b\|\bLLMChain\b\|\bRetrievalQA\b" --include="*.py" . # P39
grep -rn "from langchain\.memory\|ConversationBufferMemory" --include="*.py" . # P40
grep -rn "initialize_agent\|AgentType\." --include="*.py" . # P41
grep -rn "\.tool_input\b\|intermediate_steps" --include="*.py" . # P42
grep -rn "astream_log\b" --include="*.py" . # P67
Pipe the full set into langchain-0.3-hits.txt — that file is the migration work list. The migration-detection.md reference has the one-shot bundled block and a line-count triage table.
Step 2 — Pin and upgrade packages together
LangChain 1.0 spans six coordinated packages. A partial upgrade (e.g. pip install -U langchain-anthropic without bumping anthropic) triggers AttributeError at import time (P66). Update all six in the same commit:
langchain>=1.0,<2
langchain-core>=0.3,<0.4
langchain-openai>=1.0
langchain-anthropic>=1.0
langgraph>=1.0,<2
anthropic>=0.40,<1
Apply:
pip install -U \
"langchain>=1.0,<2" \
"langchain-core>=0.3,<0.4" \
"langchain-openai>=1.0" \
"langchain-anthropic>=1.0" \
"langgraph>=1.0,<2" \
"anthropic>=0.40,<1"
Then snapshot the prior state for the rollback: pip freeze > requirements.lock.pre-1.0.txt.
Step 3 — Codemod the four removed APIs
Work through the hits from Step 1 in this order (lowest blast radius first):
- Provider imports (P38) — mechanical find/replace.
from langchain.chatmodels import ChatOpenAI→from langchainopenai import ChatOpenAI. Same pattern forChatAnthropic,OpenAIEmbeddings,Chroma, etc. LLMChain→ LCEL (P39) — replacechain = LLMChain(llm=llm, prompt=prompt)withchain = prompt | llm | StrOutputParser(). Caller changes fromchain.run(x=1)tochain.invoke({"x": 1}). If the caller treated the result as a dict, unwrap —invokereturns the string directly.initializeagent→createreactagent(P41) — swap the import tofrom langgraph.prebuilt import createreactagent. Tools written withTool(name=..., func=...)still work; prefer the@tooldecorator fromlangchaincore.tools. Agent input becomes{"messages": [("user", "...")]}; the final reply isresult["messages"][-1].content.ConversationBufferMemory→ LangGraph checkpointer (P40) — swap the memory object forMemorySaver()(dev) orSqliteSaver.fromconnstring(...)(prod). Compile the graph/agent withcheckpointer=saver, then passconfig={"configurable": {"threadid": "..."}}on everyinvoke. Thethreadidis the conversation primary key.
Full before/after snippets for all four are in codemod-patterns.md.
Step 4 — Update streaming callers (P67)
astreamlog still works in 1.0 but is soft-deprecated. The replacement is astreamevents(version="v2"):
# BEFORE
async for patch in chain.astream_log({"input": "hi"}):
for op in patch.ops:
if op["op"] == "add" and op["path"].endswith("/streamed_output/-"):
print(op["value"], end="")
# AFTER
async for event in chain.astream_events({"input": "hi"}, version="v2"):
if event["event"] == "on_chat_model_stream":
print(event["data"]["chunk"].content, end="")
Event names in v2: onchainstart, onchainend, onchatmodelstart, onchatmodelstream, onchatmodelend, ontoolstart, ontool_end. The payload under data is typed — chunk is an AIMessageChunk, not a raw string.
Step 5 — Fix intermediate_steps consumers (P42)
If any code iterates result["intermediatesteps"] and reads .tool / .toolinput, it breaks silently in 1.0 — the tuples now hold ToolCall dicts, not AgentAction objects. The 1.0 equivalent reads from graph state:
# BEFORE
for action, observation in result["intermediate_steps"]:
log(action.tool, action.tool_input, observation)
# AFTER
for msg in result["messages"]:
for tc in getattr(msg, "tool_calls", []) or []:
log(tc["name"], tc["args"]) # .tool -> "name", .tool_input -> "args"
ToolCall dict keys are name, args, id. There is no tool or tool_input accessor anywhere in 1.0.
Step 6 — Gate on deprecation-as-error tests
Turn DeprecationWarning into a test failure so any surviving 0.3 pattern surfaces before the rollout:
pytest -W error::DeprecationWarning
Do not promote to staging while this is red. Re-run the Step 1 greps — they should now return zero hits outside intentionally-pinned 0.3 test fixtures.
Step 7 — Phased rollout on production traffic
Deploy behind a feature flag (LANGCHAIN10_ENABLED), canary at 1%, and ramp to 100% over 2–4 hours with a 15-minute soak at each step. The rollback is always "flip the flag off" — not a redeploy. Full playbook (shadow traffic in staging, dual-write for persistent chat histories, per-phase exit criteria) is in phased-rollout-playbook.md.
Output
requirements.txtpinning all six 1.0 packages with theanthropic >= 0.40peer-pin (P66).requirements.lock.pre-1.0.txtin the repo root for five-minute rollback.- Per-module git commits referencing pain codes (e.g.
refactor: migrate P39 LLMChain in billing-summariser to LCEL). langchain-0.3-hits.txtwork-list returning zero non-test hits on re-run.pytest -W error::DeprecationWarninggreen on the migration branch.- Feature-flagged production cutover at 100%, flag removed after a full day of soak.
Error Handling
| Error | Cause | Fix | ||
|---|---|---|---|---|
ImportError: cannot import name 'ChatOpenAI' from 'langchain.chat_models' |
P38 — provider imports moved to partner packages | from langchain_openai import ChatOpenAI |
||
ImportError: cannot import name 'LLMChain' from 'langchain.chains' |
P39 — LLMChain removed |
Replace with LCEL: `prompt \ | llm \ | StrOutputParser()` |
AttributeError: 'ConversationBufferMemory' object has no attribute 'save_context' |
P40 — memory classes removed from the public API | Swap for LangGraph MemorySaver / SqliteSaver with a thread_id |
||
AttributeError: module 'langchain.agents' has no attribute 'initialize_agent' |
P41 — legacy agent constructor removed | from langgraph.prebuilt import createreactagent |
||
AttributeError: 'ToolCall' object has no attribute 'tool' |
P42 — tuple shape changed, fields renamed | Read tc["name"] and tc["args"] instead of .tool / .tool_input |
||
AttributeError: module 'anthropic' has no attribute 'AsyncAnthropic' |
P66 — langchain-anthropic 1.0 needs anthropic >= 0.40 |
Pin anthropic>=0.40,<1 in the same commit as the langchain-anthropic bump |
||
DeprecationWarning: astreamlog is deprecated; use astreamevents(version="v2") |
P67 — soft deprecation | Switch to astream_events(version="v2") and update event-name handling |
Examples
Example 1 — Minimal LLMChain to LCEL
# BEFORE (0.3)
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([("system", "Summarise in one line."), ("user", "{text}")])
chain = LLMChain(llm=llm, prompt=prompt)
print(chain.run(text="LangChain 1.0 removed LLMChain."))
# AFTER (1.0)
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([("system", "Summarise in one line."), ("user", "{text}")])
chain = prompt | llm | StrOutputParser()
print(chain.invoke({"text": "LangChain 1.0 removed LLMChain."}))
Example 2 — Stateful agent with LangGraph checkpointer
# AFTER (1.0)
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver # use SqliteSaver / PostgresSaver in prod
@tool
def add(a: int, b: int) -> int:
"""Add two integers."""
return a + b
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
agent = create_react_agent(llm, [add], checkpointer=MemorySaver())
config = {"configurable": {"thread_id": "user-42"}}
r1 = agent.invoke({"messages": [("user", "What's 2 + 3?")]}, config=config)
r2 = agent.invoke({"messages": [("user", "And plus 10?")]}, config=config) # remembers "5"
print(r2["messages"][-1].content)
Example 3 — Rollback pin
If Phase 5 of the rollout regresses and the feature flag is already off:
git checkout main
pip install -r requirements.lock.pre-1.0.txt
pytest # confirm green on the rollback pin
# deploy
Resources
- LangChain migration guide
- LangChain release policy
- LangGraph prebuilt
createreactagent astream_eventsv2 reference- Breaking changes matrix — all 7 named changes mapped to pain codes
- Codemod patterns — before/after for the 7 most common migrations
- Phased rollout playbook — shadow traffic, dual-write, rollback
- Migration detection — pre-flight grep audit
- One-pager — executive summary