Claude API Integration with LangChain in Python
Claude API Integration with LangChain Python
If you're building a Python application and want to use Claude as the underlying LLM inside LangChain, the integration is straightforward: install langchain-anthropic, set an API key, instantiate ChatAnthropic, and drop it into any chain, agent, or retriever you're already using. LangChain treats Claude like any other chat model, so existing LangChain code (prompt templates, output parsers, memory, tools) works with minimal changes.
The rest of this guide walks through a working setup, common gotchas (streaming, tool calling, rate limits), and how to decide whether you need the raw Anthropic SDK, LangChain's wrapper, or a managed API layer like SubToAPI sitting in front of either.
Installing the Right Packages
LangChain split provider integrations into separate packages a while back, so you need the Anthropic-specific one, not just the core langchain package.
pip install langchain-anthropic langchain-core
If you're going to use agents, tools, or document loaders elsewhere in your app, you'll likely also want langchain-community, but it's not required just to call Claude.
Basic Setup
import os
from langchain_anthropic import ChatAnthropic
os.environ["ANTHROPIC_API_KEY"] = "your-api-key"
llm = ChatAnthropic(
model="claude-3-5-sonnet-20241022",
temperature=0.2,
max_tokens=1024,
)
response = llm.invoke("Summarize the plot of Dune in two sentences.")
print(response.content)
ChatAnthropic implements LangChain's standard chat model interface, so .invoke(), .stream(), .batch(), and async equivalents all work the way they do with any other provider.
Using Claude Inside a Chain
Most real integrations don't call the model directly — they build a chain with a prompt template and an output parser.
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
prompt = ChatPromptTemplate.from_messages([
("system", "You are a concise technical writer."),
("human", "Explain {topic} in under 100 words."),
])
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"topic": "database indexing"})
print(result)
This pattern — prompt, model, parser, piped together with | — is the core of LangChain's expression language (LCEL) and works identically regardless of which model you plug in.
Streaming Responses
Claude supports streaming, and LangChain exposes it through .stream():
for chunk in llm.stream("Write a haiku about distributed systems."):
print(chunk.content, end="", flush=True)
For async apps (FastAPI, for example), use astream() instead. This matters for anything user-facing where you want tokens appearing incrementally rather than waiting for the full response.
Tool Calling with Claude
Claude's tool use maps onto LangChain's tool-calling interface. Define a tool with @tool, bind it to the model, and LangChain handles the schema translation.
from langchain_core.tools import tool
@tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"It's 18°C and cloudy in {city}."
llm_with_tools = llm.bind_tools([get_weather])
response = llm_with_tools.invoke("What's the weather in Lisbon?")
print(response.tool_calls)
LangChain generates the JSON schema from the function signature and docstring automatically, so you don't need to hand-write Claude's tool definition format. If you want to understand what's happening under the hood at the API level, it's worth reading the raw tool schema docs at /docs/tools separately from the LangChain abstraction — it helps when debugging why a tool call didn't trigger the way you expected.
Adding Memory for Multi-Turn Conversations
LangChain's newer approach favors explicit message history over the older memory classes:
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
store = {}
def get_history(session_id: str):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
chain_with_history = RunnableWithMessageHistory(
chain,
get_history,
input_messages_key="topic",
history_messages_key="history",
)
For production use, swap InMemoryChatMessageHistory for a Redis- or Postgres-backed store so conversation state survives restarts.
Where SubToAPI Fits In
LangChain talks to Claude using an Anthropic-compatible key and the standard Messages format. If your team is already managing access through SubToAPI — for example because you want per-application keys (sub_live_...), usage metadata per key, or seat-based billing across a team instead of one shared Anthropic account — you can point ChatAnthropic at that endpoint by overriding the base URL and using your SubToAPI key:
llm = ChatAnthropic(
model="claude-3-5-sonnet-20241022",
anthropic_api_url="https://api.subtoapi.app/v1",
anthropic_api_key=os.environ["SUBTOAPI_KEY"],
)
This is useful when multiple services or developers on a team each need their own key with separate usage tracking, rather than everyone sharing one Anthropic credential. Check /docs/quickstart for how keys and base URLs are structured, and /docs/messages if you want to see the raw request/response shape LangChain is building on top of.
Common Pitfalls
- Model name typos. Claude model identifiers are versioned strings (e.g.,
claude-3-5-sonnet-20241022). A stale or misspelled model name fails silently in some LangChain versions with a generic error rather than a clear "model not found." - Mixing sync and async incorrectly. Calling
.invoke()inside anasync deffunction blocks the event loop. Use.ainvoke()in async code. - Token limits ignored in long chains. LangChain doesn't automatically truncate conversation history to fit Claude's context window — you need to manage that yourself, especially with
RunnableWithMessageHistory. - Rate limit errors in agent loops. Agents that call Claude repeatedly in a loop (e.g., ReAct-style reasoning) can hit rate limits fast. Add backoff logic or reduce intermediate steps.
questions
Do I need the Anthropic SDK if I'm using LangChain? No. langchain-anthropic wraps the API calls for you. You only need the raw Anthropic SDK if you want functionality LangChain hasn't exposed yet or you're debugging at the request level.
Can I use Claude's extended thinking or vision features through LangChain? Vision (image inputs) works through LangChain's multimodal message format. Extended thinking support depends on your installed langchain-anthropic version — check the changelog if a feature seems missing, since provider packages lag the main API slightly.
Is LangChain required to integrate Claude in Python? No. LangChain adds chain composition, memory, and agent abstractions on top of the Claude API. If you just need direct request/response calls, the Anthropic SDK or a plain HTTPS client against a Messages-compatible endpoint is simpler and has less overhead.