langchain · diff
git:20260813.422f18d to git:20261017.2236aa0
254 added, 121 removed. Audit A to A.
---
name: langchain
- description: Build AI agents with LangChain framework. Use when building agents, tools, memory, MCP integrations, RAG pipelines, multi-agent systems, or any LLM-powered applications using LangChain or LangGraph in Python or TypeScript.
+ description: >
+ Build AI agents with LangChain v1 and LangGraph in Python. Use this skill whenever the user
+ mentions LangChain, LangGraph, create_agent, init_chat_model, @tool, ToolRuntime, agent
+ middleware, human-in-the-loop, structured output, MCP tools (langchain.mcp, MCPAdapter),
+ RAG, multi-agent handoffs or subagents, checkpointers, or Deep Agents. Also trigger for
+ migrating from create_react_agent, LLMChain, AgentExecutor or langchain-mcp-adapters,
+ stream_events, SummarizationMiddleware, and langchain-classic.
---
# LangChain Skill
- Build production AI agents using LangChain's pre-built architecture and integrations.
+ Build production AI agents with LangChain v1 (`create_agent` on top of LangGraph), its middleware
+ system, built-in MCP support and the LangGraph runtime. Verified against `langchain` 1.4.6,
+ `langchain-core` 1.6, `langgraph` 1.2 and `deepagents` 0.7 (Python 3.10+; `deepagents` needs 3.11+).
+ ## Quick Reference
+
+ | Topic | File |
+ |-------|------|
+ | Built-in and custom middleware | [references/middleware.md](references/middleware.md) |
+ | LangGraph graphs, persistence, durability, streaming | [references/langgraph.md](references/langgraph.md) |
+ | Subagents, handoffs, skills, routers, Deep Agents | [references/multi-agent.md](references/multi-agent.md) |
+ | RAG, embeddings, vector stores, retrievers | [references/retrieval.md](references/retrieval.md) |
+
## Installation
```bash
- pip install langchain langchain-anthropic langgraph
- # For MCP support
- pip install langchain-mcp-adapters
+ pip install -U langchain langgraph langchain-anthropic # or langchain-openai, langchain-google-genai, ...
+ pip install -U "langchain[mcp]" # built-in MCP client (langchain.mcp, beta)
+ pip install -U deepagents # optional: planning + filesystem + subagents harness
+ pip install -U langchain-classic # only for legacy chains/retrievers
```
## Quick Agent
```python
from langchain.agents import create_agent
- from langchain.tools import tool
- @tool
def get_weather(city: str) -> str:
- """Get weather for a city."""
+ """Get the current weather for a city."""
return f"Sunny in {city}!"
agent = create_agent(
- model="claude-sonnet-4-5-20250929",
+ model="anthropic:claude-sonnet-5",
tools=[get_weather],
- system_prompt="You are a helpful assistant"
+ system_prompt="You are a helpful assistant.",
)
result = agent.invoke({"messages": [{"role": "user", "content": "Weather in SF?"}]})
+ print(result["messages"][-1].content)
```
+ `create_agent` returns a compiled LangGraph graph, so `invoke`, `stream`, `stream_events`,
+ checkpointers, stores and interrupts all work on it. Plain functions with type hints and a
+ docstring are accepted as tools; use `@tool` when you need a custom name, schema or `ToolRuntime`.
+
+ ## Model Configuration
+
+ ```python
+ from langchain.chat_models import init_chat_model
+
+ model = init_chat_model(
+ "anthropic:claude-sonnet-5", # "provider:model"; e.g. "openai:gpt-5.5", "google_genai:gemini-3.6-flash"
+ temperature=0,
+ timeout=30,
+ max_tokens=2000,
+ max_retries=2,
+ )
+
+ model.profile["max_input_tokens"] # model capabilities (from models.dev): context size, tool calling, modalities
+ ```
+
+ Pass either the string or the model instance as `model=` to `create_agent`. `system_prompt` accepts
+ a `str` or a `SystemMessage` (useful for content blocks such as provider cache-control markers).
+
## Tools
- Define tools with `@tool` decorator. Type hints required, docstring becomes description:
+ The docstring becomes the description the model sees, and type hints become the argument schema:
```python
- from langchain.tools import tool, ToolRuntime
from dataclasses import dataclass
+ from langchain.tools import tool, ToolRuntime
@tool
def search(query: str, limit: int = 10) -> str:
- """Search database for records."""
+ """Search the order database. Returns up to `limit` matching records."""
return f"Found {limit} results for '{query}'"
- # With runtime context access
@dataclass
class Context:
user_id: str
@tool
def get_user_data(runtime: ToolRuntime[Context]) -> str:
- """Get current user data."""
- user_id = runtime.context.user_id
- return f"Data for {user_id}"
+ """Get the current user's profile."""
+ return f"Data for {runtime.context.user_id}"
```
- ### ToolRuntime Access
-
- - `runtime.state` - Agent state (messages, custom fields)
- - `runtime.context` - Immutable config (user_id, session)
- - `runtime.store` - Persistent memory across conversations
- - `runtime.stream_writer` - Stream updates during execution
-
- ### Reserved Parameters
- Cannot use as tool args: `config`, `runtime`
+ `ToolRuntime` is injected and hidden from the model. It exposes `state` (messages and custom fields),
+ `context` (immutable per-run data passed as `agent.invoke(..., context=Context(...))`), `store`
+ (long-term memory), `stream_writer` (custom stream updates), `tool_call_id` and `config`.
+ `config` and `runtime` are reserved argument names. Finer-grained injectables also live in
+ `langchain.tools`: `InjectedState`, `InjectedStore`, `InjectedToolCallId`, `InjectedToolArg`.
## Memory
```python
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.store.memory import InMemoryStore
- # Short-term (conversation) memory
- checkpointer = InMemorySaver()
-
- # Long-term (cross-conversation) memory
- store = InMemoryStore()
-
agent = create_agent(
- model="claude-sonnet-4-5-20250929",
- tools=[...],
- checkpointer=checkpointer,
- store=store
+ model="anthropic:claude-sonnet-5",
+ tools=[search],
+ checkpointer=InMemorySaver(), # short-term: per-thread conversation state
+ store=InMemoryStore(), # long-term: cross-thread memory via runtime.store
)
- # Use thread_id for conversation continuity
config = {"configurable": {"thread_id": "conversation-1"}}
- agent.invoke({"messages": [...]}, config=config)
+ agent.invoke({"messages": [{"role": "user", "content": "Hi, I'm Ana"}]}, config=config)
```
+ In production use `PostgresSaver`/`AsyncPostgresSaver` or `SqliteSaver` ([references/langgraph.md](references/langgraph.md)),
+ and keep long threads in budget with `SummarizationMiddleware`.
+
## Structured Output
```python
- from dataclasses import dataclass
- from langchain.agents.structured_output import ToolStrategy
+ from pydantic import BaseModel
+ from langchain.agents.structured_output import ToolStrategy, ProviderStrategy
- @dataclass
- class Response:
+ class Response(BaseModel):
answer: str
confidence: float | None = None
- agent = create_agent(
- model="claude-sonnet-4-5-20250929",
- tools=[...],
- response_format=ToolStrategy(Response)
- )
- # Access: result['structured_response']
+ agent = create_agent(model="anthropic:claude-sonnet-5", tools=[search],
+ response_format=ToolStrategy(Response))
+ result = agent.invoke({"messages": [{"role": "user", "content": "..."}]}) # result["structured_response"]: Response
```
- ## MCP Integration
+ | `response_format` | Behavior |
+ |-------------------|----------|
+ | `Response` (bare type) | Auto: provider-native JSON schema when the model profile supports it, else tool calling |
+ | `ToolStrategy(Response, handle_errors=True)` | Structured output via an artificial tool call; retries on validation errors; works with any tool-calling model |
+ | `ProviderStrategy(Response, strict=True)` | Provider-native structured output (OpenAI, Anthropic, Gemini, ...) |
- Connect to MCP servers for external tools:
+ Schemas can be Pydantic models, dataclasses, `TypedDict`s or JSON schema dicts. Outside agents, use `model.with_structured_output(Response)`.
+ ## Middleware
+
+ Middleware is the v1 extension point that replaces pre/post hooks. Built-ins come from
+ `langchain.agents.middleware`:
+
```python
- from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
+ from langchain.agents.middleware import (
+ SummarizationMiddleware, HumanInTheLoopMiddleware, ModelFallbackMiddleware,
+ ToolCallLimitMiddleware, PIIMiddleware,
+ )
+ from langgraph.checkpoint.memory import InMemorySaver
- client = MultiServerMCPClient({
- "math": {
- "transport": "stdio",
- "command": "python",
- "args": ["/path/to/server.py"]
- },
- "api": {
- "transport": "http",
- "url": "http://localhost:8000/mcp",
- "headers": {"Authorization": "Bearer TOKEN"}
- }
- })
+ agent = create_agent(
+ model="anthropic:claude-sonnet-5",
+ tools=[search, send_email],
+ checkpointer=InMemorySaver(), # required for interrupts
+ middleware=[
+ SummarizationMiddleware(model="openai:gpt-5.4-mini", trigger=("fraction", 0.8), keep=("messages", 20)),
+ ModelFallbackMiddleware("openai:gpt-5.5"),
+ ToolCallLimitMiddleware(tool_name="search", run_limit=5),
+ PIIMiddleware("email", strategy="redact", apply_to_input=True),
+ HumanInTheLoopMiddleware(interrupt_on={"send_email": {"allowed_decisions": ["approve", "edit", "reject"]}}),
+ ],
+ )
+ ```
- tools = await client.get_tools()
- agent = create_agent("claude-sonnet-4-5-20250929", tools)
+ Custom middleware uses decorators (`before_agent`, `before_model`, `after_model`, `after_agent`,
+ `wrap_model_call`, `wrap_tool_call`, `dynamic_prompt`) or an `AgentMiddleware` subclass:
+
+ ```python
+ from langchain.agents.middleware import dynamic_prompt, wrap_tool_call, ModelRequest
+
+ @dynamic_prompt
+ def tiered_prompt(request: ModelRequest) -> str:
+ return f"You are a support agent. Customer tier: {request.runtime.context.tier}."
+
+ @wrap_tool_call
+ def audit_tool_calls(request, handler):
+ print("calling", request.tool_call["name"], request.tool_call["args"])
+ return handler(request)
```
- ### MCP Interceptors
+ Full catalogue (retries, tool selection, context editing, to-do lists, shell, emulators) and
+ patterns (dynamic models, dynamic tools, jumps) are in [references/middleware.md](references/middleware.md).
- Modify tool calls, inject context, handle errors:
+ ## Human-in-the-Loop
+ With `HumanInTheLoopMiddleware` and a checkpointer, the run pauses before the listed tools.
+ Resume with one decision per pending action:
+
```python
- from langchain_mcp_adapters.interceptors import MCPToolCallRequest
+ from langgraph.types import Command
- async def auth_interceptor(request: MCPToolCallRequest, handler):
- runtime = request.runtime
- user_id = runtime.context.user_id
- modified = request.override(args={**request.args, "user_id": user_id})
- return await handler(modified)
+ config = {"configurable": {"thread_id": "t1"}}
+ result = agent.invoke({"messages": [{"role": "user", "content": "Email Bob the report"}]},
+ config=config, version="v2")
+ while result.interrupts:
+ actions = result.interrupts[0].value["action_requests"]
+ for action in actions:
+ print("Pending:", action["name"], action["args"])
+ decisions = [{"type": "approve"} for _ in actions] # one decision per action, in order
+ result = agent.invoke(Command(resume={"decisions": decisions}), config=config, version="v2")
+ ```
- client = MultiServerMCPClient({...}, tool_interceptors=[auth_interceptor])
+ Decision types: `{"type": "approve"}`, `{"type": "edit", "edited_action": {"name": ..., "args": {...}}}`,
+ `{"type": "reject", "message": "why"}`, and `{"type": "respond", "message": "..."}`. With
+ `version="v2"`, `invoke` returns a `GraphOutput` (`.value`, `.interrupts`) instead of a plain dict.
+
+ ## Streaming
+
+ Use event streaming (`version="v3"`) for apps and UIs. It returns a run object with typed projections:
+
+ ```python
+ stream = agent.stream_events({"messages": [{"role": "user", "content": "Weather in SF?"}]}, version="v3")
+ for kind, item in stream.interleave("messages", "tool_calls"):
+ if kind == "messages":
+ for token in item.text:
+ print(token, end="", flush=True)
+ else:
+ print(f"\n[tool] {item.tool_name}({item.input})")
+ for delta in item.output_deltas: # drain first: item.output is None until the tool finishes
+ print(delta, end="", flush=True)
+ print(f"\n[result] {item.output}")
+ final_state = stream.output
```
- ## Model Configuration
+ Event streaming is experimental in LangGraph 1.2 (it emits a `LangChainBetaWarning`). Classic
+ `agent.stream(input, stream_mode=["updates", "messages", "custom"])` still works; the model node is `"model"`.
+ ## MCP Integration
+
+ LangChain 1.4 ships a built-in MCP client, `langchain.mcp` (beta, built on FastMCP). It replaces
+ `langchain-mcp-adapters`' `MultiServerMCPClient`:
+
```python
- from langchain.chat_models import init_chat_model
+ from langchain.agents import create_agent
+ from langchain.mcp import MCPAdapter
- model = init_chat_model(
- "claude-sonnet-4-5-20250929", # or "gpt-4o", "gemini-1.5-pro"
- temperature=0.5,
- timeout=10,
- max_tokens=1000
- )
+ config = {"mcpServers": {
+ "math": {"command": "python", "args": ["/path/to/math_server.py"]}, # stdio
+ "api": {"url": "https://api.example.com/mcp", "headers": {"Authorization": "Bearer TOKEN"}},
+ }}
+
+ async def build_agent():
+ async with MCPAdapter(config) as adapter: # or MCPAdapter("https://..."), MCPAdapter(Path("server.py"))
+ tools = await adapter.list_tools() # multi-server tools are prefixed: math_..., api_...
+ return create_agent("anthropic:claude-sonnet-5", tools)
```
+ - A plain string target must be an `http(s)` URL; reach local servers with `pathlib.Path(...)` or a config.
+ - Tools stay usable after the `async with` block exits. They are async, so run the agent with `ainvoke`/`astream`.
+ - Server elicitation requests become LangGraph `interrupt()`s, so add a checkpointer.
+ - Interceptors are gone: use `@wrap_tool_call` middleware (MCP provenance is in `request.tool.metadata["mcp"]`).
+
## State Updates from Tools
- Return `Command` to update state or control flow:
+ Return a `Command` to update state or control flow:
```python
+ from langchain.messages import RemoveMessage, ToolMessage
+ from langchain.tools import tool, ToolRuntime
+ from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langgraph.types import Command
- from langchain.messages import RemoveMessage
@tool
def clear_history() -> Command:
- """Clear conversation."""
- return Command(update={"messages": [RemoveMessage(id="__all__")]})
+ """Clear the conversation history."""
+ return Command(update={"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES)]})
- @tool
- def complete_task() -> Command:
- """End agent run."""
- return Command(update={"status": "done"}, goto="__end__")
+ @tool
+ def set_language(language: str, runtime: ToolRuntime) -> Command:
+ """Remember the user's preferred language."""
+ return Command(update={
+ "language": language, # custom field: needs state_schema= (a TypedDict extending AgentState)
+ "messages": [ToolMessage(f"Language set to {language}", tool_call_id=runtime.tool_call_id)],
+ })
```
- ## Common Patterns
+ ## Deep Agents
- ### Full Production Agent
+ `deepagents` wraps `create_agent` with a virtual filesystem, a `task` tool for subagents,
+ summarization, and optional skills and memory files, for long multi-step tasks. Backends, planning
+ (`TodoListMiddleware`) and interrupts are covered in [references/multi-agent.md](references/multi-agent.md).
```python
+ from deepagents import create_deep_agent
+
+ agent = create_deep_agent(
+ model="anthropic:claude-sonnet-5",
+ tools=[internet_search],
+ system_prompt="You are an expert researcher. Write the final report to /report.md.",
+ subagents=[{"name": "critic", "description": "Reviews drafts", "system_prompt": "You are a strict reviewer."}],
+ )
+ ```
+
+ ## Full Production Agent
+
+ ```python
from dataclasses import dataclass
from langchain.agents import create_agent
+ from langchain.agents.middleware import SummarizationMiddleware, ToolRetryMiddleware
+ from langchain.agents.structured_output import ToolStrategy
from langchain.chat_models import init_chat_model
from langchain.tools import tool, ToolRuntime
- from langchain.agents.structured_output import ToolStrategy
from langgraph.checkpoint.memory import InMemorySaver
@dataclass
class Context:
user_id: str
@tool
def search_orders(query: str, runtime: ToolRuntime[Context]) -> str:
- """Search user orders."""
+ """Search the current user's orders by keyword, date or status."""
return f"Orders for {runtime.context.user_id}: {query}"
@dataclass
class Response:
answer: str
order_ids: list[str] | None = None
agent = create_agent(
- model=init_chat_model("claude-sonnet-4-5-20250929", temperature=0),
+ model=init_chat_model("anthropic:claude-sonnet-5", temperature=0),
system_prompt="You are a customer service agent.",
tools=[search_orders],
context_schema=Context,
response_format=ToolStrategy(Response),
- checkpointer=InMemorySaver()
+ middleware=[ToolRetryMiddleware(max_retries=2), SummarizationMiddleware("openai:gpt-5.4-mini", trigger=("tokens", 4000))],
+ checkpointer=InMemorySaver(),
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "Find my recent orders"}]},
config={"configurable": {"thread_id": "session-1"}},
- context=Context(user_id="user123")
+ context=Context(user_id="user123"),
)
+ print(result["structured_response"])
```
+ ## Migrating to v1
+
+ | Old (0.x / pre-1.4) | Current |
+ |---------------------|---------|
+ | `langgraph.prebuilt.create_react_agent` | `langchain.agents.create_agent` |
+ | `prompt=` | `system_prompt=` (static) or `@dynamic_prompt` middleware |
+ | `pre_model_hook` / `post_model_hook` | `@before_model` / `@after_model` middleware |
+ | `config["configurable"]` for user data | `context_schema=` + `invoke(..., context=...)` |
+ | `AgentExecutor`, `LLMChain`, `RetrievalQA`, `langchain.retrievers` | `create_agent`, or `langchain_classic.*` for legacy code |
+ | `langchain.text_splitter` | `langchain_text_splitters` |
+ | `langchain_mcp_adapters.client.MultiServerMCPClient` | `langchain.mcp.MCPAdapter` |
+ | MCP `tool_interceptors` | `@wrap_tool_call` middleware |
+ | Prompted structured output | `ToolStrategy` / `ProviderStrategy` |
+ | `message.content` parsing for reasoning/citations | `message.content_blocks` (standard blocks) |
+
## Anti-Patterns to Avoid
- - **Tools without type hints or docstrings** — the docstring *is* the tool description the model sees; a missing or vague one means the agent misuses the tool
- - **Global state in tools** — tools that read globals instead of `ToolRuntime[Context]` are untestable and unsafe in concurrent runs
- - **No checkpointer, then wondering why the agent forgets** — multi-turn agents need `checkpointer=InMemorySaver()` (or a persistent saver) plus a stable `thread_id`
- - **Rebuilding everything as one giant system prompt** — tools, structured output (`ToolStrategy`/`with_structured_output`), and retrieval exist to keep prompts small
- - **Letting raw tool exceptions reach the model** — wrap tools, catch, and return structured error strings so the agent can recover
- - **Using deprecated `LLMChain`/`SequentialChain` APIs** — current LangChain builds on `create_agent` and LangGraph; the old chains are removed from recent versions
- - **Stuffing whole documents into context** — use the retrieval patterns in [retrieval.md](references/retrieval.md) instead of naive full-document injection
+ - **Tools without type hints or docstrings**: the docstring *is* the tool description the model sees; a missing or vague one means the agent misuses the tool
+ - **Global state in tools**: read per-user data from `ToolRuntime[Context]`, not globals, so tools stay testable and safe in concurrent runs
+ - **No checkpointer, then wondering why the agent forgets**: multi-turn agents, human-in-the-loop and MCP elicitation all need a checkpointer plus a stable `thread_id`
+ - **Hand-rolled hook loops**: use middleware (`SummarizationMiddleware`, `ModelFallbackMiddleware`, `ToolRetryMiddleware`, limits) instead of wrapping `agent.invoke` in custom retry/trim code
+ - **Letting raw tool exceptions reach the model or user**: use `ToolErrorMiddleware(on_error=...)` or `ToolRetryMiddleware`, and return the exception type rather than internal details
+ - **Importing removed modules**: `langchain.vectorstores`, `langchain.document_loaders`, `langchain.text_splitter`, `langchain.retrievers` and `LLMChain` no longer exist in `langchain` v1; use provider packages, `langchain_core`, `langchain_text_splitters` or `langchain_classic`
+ - **Starting new code on `langchain-mcp-adapters` or `create_react_agent`**: both are superseded by `langchain.mcp` and `create_agent`
+ - **Passing a local script path as a string to `MCPAdapter`**: strings must be URLs; use `Path(...)` or an `mcpServers` config for stdio servers
+ - **Stuffing whole documents into context**: use the retrieval patterns in [references/retrieval.md](references/retrieval.md)
## When to Use / Not Use
**Use this skill when:**
- - Building agents with LangChain or LangGraph (Python or TypeScript)
- - Wiring tools, memory, MCP servers, or structured output into an LLM app
- - Implementing RAG, multi-agent handoffs, routers, or stateful workflows
+ - Building agents with LangChain v1 or LangGraph in Python
+ - Adding tools, memory, middleware, human approval, MCP servers or structured output to an LLM app
+ - Implementing RAG, subagents, handoffs, routers, Deep Agents or stateful workflows
+ - Migrating 0.x code (`create_react_agent`, `AgentExecutor`, chains, `langchain-mcp-adapters`)
**Do NOT use this skill when:**
- - A single stateless LLM call is all you need — the plain provider SDK is lighter
- - The project standardizes on another agent framework (e.g., smolagents) — follow the project's stack
- - The agent is code-first and benefits from the smaller SmolAgents execution model — see the smolagents skill
-
- ## References
-
- For detailed patterns, see:
- - `references/langgraph.md` - LangGraph workflows, graphs, persistence
- - `references/multi-agent.md` - Handoffs, routers, subagents
- - `references/retrieval.md` - RAG, vector stores, embeddings
+ - A single stateless LLM call is all you need; the plain provider SDK is lighter
+ - The project standardizes on another agent framework; follow the project's stack
+ - The agent is code-first and benefits from the smaller SmolAgents execution model; see the smolagents skill
## Key Links
- - Docs: https://docs.langchain.com
- - Python SDK: https://reference.langchain.com/python
- - LangGraph: https://docs.langchain.com/oss/python/langgraph
- - MCP Adapters: https://github.com/langchain-ai/langchain-mcp-adapters
+ - Docs: https://docs.langchain.com/oss/python/langchain/overview
+ - Middleware: https://docs.langchain.com/oss/python/langchain/middleware/built-in
+ - MCP: https://docs.langchain.com/oss/python/langchain/mcp/connections
+ - From langchain-mcp-adapters: https://docs.langchain.com/oss/python/migrate/langchain-mcp-adapters
+ - Event streaming: https://docs.langchain.com/oss/python/langchain/event-streaming
+ - Deep Agents: https://docs.langchain.com/oss/python/deepagents/customization
+ - API reference: https://reference.langchain.com/python
+