本页还没有译文
本页 268 段还没译成日本語,下面显示的是英文原文。ChatAnthropic integration
还没翻译译自英文(docs.langchain.com)本页 268 段都还没译
You can find information about Anthropic's latest models, their costs, context windows, and supported input types in the Claude docs.
Tip
API Reference
For detailed documentation of all features and configuration options, head to the ChatAnthropic API reference.
Info
AWS Bedrock and Gemini Enterprise Agent Platform
Note that certain Anthropic models can also be accessed via AWS Bedrock and Gemini Enterprise Agent Platform. See the ChatBedrock and ChatVertexAI integrations to use Anthropic models via these services.
For Anthropic models on AWS Bedrock with the same API as ChatAnthropic, use ChatAnthropicBedrock from langchain-aws.
Overview
Integration details
| Class | Package | Serializable | JS/TS Support | Downloads | Latest Version |
|---|---|---|---|---|---|
ChatAnthropic | langchain-anthropic | beta | ✅ (npm) |
Model features
| Tool calling | Structured output | Image input | Audio input | Video input | Token-level streaming | Native async | Token usage | Logprobs |
|---|---|---|---|---|---|---|---|---|
| ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ |
Setup
To access Anthropic (Claude) models you'll need to install the langchain-anthropic integration package and acquire a Claude API key.
Installation
pip install -U langchain-anthropicuv add langchain-anthropicCredentials
Head to the Claude console to sign up and generate a Claude API key. Once you've done this set the ANTHROPIC_API_KEY environment variable:
import getpass
import os
if "ANTHROPIC_API_KEY" not in os.environ:
os.environ["ANTHROPIC_API_KEY"] = getpass.getpass("Enter your Anthropic API key: ")To enable automated tracing of your model calls, set your LangSmith API key:
os.environ["LANGSMITH_API_KEY"] = getpass.getpass("Enter your LangSmith API key: ")
os.environ["LANGSMITH_TRACING"] = "true"Instantiation
Now we can instantiate our model object and generate chat completions:
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-haiku-4-5-20251001",
# temperature=,
# max_tokens=,
# timeout=,
# max_retries=,
# ...
)See the ChatAnthropic API reference for details on all available instantiation parameters.
Note
Inference geography
To control where model inference runs for data residency, pass inference_geo when you create ChatAnthropic. See Anthropic documentation for supported values.
Sampling parameters
Newer Claude models reject non-default sampling parameters. Setting temperature, top_p, or top_k to a non-default value on claude-opus-5, claude-fable-5, claude-opus-4-8, claude-opus-4-7, or claude-sonnet-5 returns a 400 error:
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-opus-5", temperature=0)
model.invoke("Hello!")
# anthropic.BadRequestError: Error code: 400 -
# {'type': 'error', 'error': {'type': 'invalid_request_error',
# 'message': '`temperature` is deprecated for this model.'}}Support by model:
| Models | temperature / top_p / top_k |
|---|---|
claude-opus-5, claude-fable-5, claude-opus-4-8, claude-opus-4-7, claude-sonnet-5 | Non-default values rejected (400). Omit the parameters, or pass defaults only (for example, temperature=1). |
claude-opus-4-6, claude-sonnet-4-6, claude-haiku-4-5, and earlier | Accepted |
Warning
Upgrading the model string?
Code written as ChatAnthropic(model=..., temperature=0) breaks when you upgrade the model to one of the newer models above. Remove the sampling parameters rather than adjusting their values. On these models, steer output style through prompting instead. See the Anthropic migration guide for details.
Invocation
Learn more about supported invocation methods in our models guide.
Content blocks
When using tools, extended thinking, and other features, content from a single Anthropic AIMessage can either be a single string or a list of Anthropic content blocks.
For example, when an Anthropic model invokes a tool, the tool invocation is part of the message content (as well as being exposed in the standardized AIMessage.tool_calls):
from langchain_anthropic import ChatAnthropic
from typing_extensions import Annotated
model = ChatAnthropic(model="claude-haiku-4-5-20251001")
def get_weather(
location: Annotated[str, ..., "Location as city and state."]
) -> str:
"""Get the weather at a location."""
return "It's sunny."
model_with_tools = model.bind_tools([get_weather])
response = model_with_tools.invoke("Which city is hotter today: LA or NY?")
response.content[{'text': "I'll help you compare the temperatures of Los Angeles and New York by checking their current weather. I'll retrieve the weather for both cities.",
'type': 'text'},
{'id': 'toolu_01CkMaXrgmsNjTso7so94RJq',
'input': {'location': 'Los Angeles, CA'},
'name': 'get_weather',
'type': 'tool_use'},
{'id': 'toolu_01SKaTBk9wHjsBTw5mrPVSQf',
'input': {'location': 'New York, NY'},
'name': 'get_weather',
'type': 'tool_use'}]Using content_blocks will render the content in LangChain's standard format that is consistent across other model providers. Read more about content blocks.
response.content_blocksYou can also access tool calls specifically in a standard format using the
tool_calls attribute:
response.tool_calls[{'name': 'GetWeather',
'args': {'location': 'Los Angeles, CA'},
'id': 'toolu_01Ddzj5PkuZkrjF4tafzu54A'},
{'name': 'GetWeather',
'args': {'location': 'New York, NY'},
'id': 'toolu_012kz4qHZQqD4qg8sFPeKqpP'}]Tools
Anthropic's tool use features allow you to define external functions that Claude can call during a conversation. This enables dynamic information retrieval, computations, and interactions with external systems.
See ChatAnthropic.bind_tools for details on how to bind tools to your model instance.
Note
For information about Claude's built-in tools (code execution, web browsing, files API, etc), see the Built-in tools.
from pydantic import BaseModel, Field
class GetWeather(BaseModel):
'''Get the current weather in a given location'''
location: str = Field(description="The city and state, e.g. San Francisco, CA")
class GetPopulation(BaseModel):
'''Get the current population in a given location'''
location: str = Field(description="The city and state, e.g. San Francisco, CA")
model_with_tools = model.bind_tools([GetWeather, GetPopulation]) # [!code highlight]
ai_msg = model_with_tools.invoke("Which city is hotter today and which is bigger: LA or NY?")
ai_msg.tool_calls[
{
"name": "GetWeather",
"args": {"location": "Los Angeles, CA"},
"id": "toolu_01KzpPEAgzura7hpBqwHbWdo",
},
{
"name": "GetWeather",
"args": {"location": "New York, NY"},
"id": "toolu_01JtgbVGVJbiSwtZk3Uycezx",
},
{
"name": "GetPopulation",
"args": {"location": "Los Angeles, CA"},
"id": "toolu_01429aygngesudV9nTbCKGuw",
},
{
"name": "GetPopulation",
"args": {"location": "New York, NY"},
"id": "toolu_01JPktyd44tVMeBcPPnFSEJG",
},
]Strict tool use
Info
Strict tool use requires langchain-anthropic>=1.1.0. See the Claude docs for supported models.
Anthropic supports opt-in strict schema adherence to tool calls. This guarantees that tool names and arguments are validated and correctly typed through constrained decoding.
Without strict mode, Claude can occasionally generate invalid tool inputs that break your applications:
- Type mismatches:
passengers: "2"instead ofpassengers: 2 - Missing required fields: Omitting fields your function expects
- Invalid enum values: Values outside the allowed set
- Schema violations: Nested objects not matching expected structure
Strict tool use guarantees schema-compliant tool calls:
- Tool inputs strictly follow your
input_schema - Guaranteed field types and required fields
- Eliminate error handling for malformed inputs
- Tool
nameused is always from provided tools
| Use strict tool use | Use standard tool calling |
|---|---|
| Building agentic workflows where reliability is critical | Simple, single-turn tool calls |
| Tools with many parameters or nested objects | Prototyping and experimentation |
Functions that require specific types (e.g., int vs str) |
To enable strict tool use, specify strict=True when calling bind_tools.
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-sonnet-4-6")
def get_weather(location: str) -> str:
"""Get the weather at a location."""
return "It's sunny."
model_with_tools = model.bind_tools([get_weather], strict=True) # [!code highlight]Strict tool use has some JSON schema limitations to be aware of. See the Claude docs for more details.
If your tool schema uses unsupported features, you'll receive a 400 error. In these cases, simplify the schema or use standard (non-strict) tool calling.
Input examples
For complex tools, you can provide usage examples to help Claude understand how to use them correctly. This is done by setting input_examples in the tool's extras parameter.
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
@tool(
extras={ # [!code highlight]
"input_examples": [ # [!code highlight]
{ # [!code highlight]
"query": "weather report", # [!code highlight]
"location": "San Francisco", # [!code highlight]
"format": "detailed" # [!code highlight]
}, # [!code highlight]
{ # [!code highlight]
"query": "temperature", # [!code highlight]
"location": "New York", # [!code highlight]
"format": "brief" # [!code highlight]
} # [!code highlight]
] # [!code highlight]
} # [!code highlight]
)
def search_weather_data(query: str, location: str, format: str = "brief") -> str:
"""Search weather database with specific query and format preferences.
Args:
query: The type of weather information to retrieve
location: City or region to search
format: Output format, either 'brief' or 'detailed'
"""
return f"{format.title()} {query} for {location}: Data found"
model = ChatAnthropic(model="claude-sonnet-4-6")
model_with_tools = model.bind_tools([search_weather_data])
response = model_with_tools.invoke(
"Get me a detailed weather report for Seattle"
)The extras parameter also supports:
defer_loading(bool): Load tool on-demand for tool search or a mid-conversation tool changecache_control(dict): Enable prompt caching for the tooleager_input_streaming(bool): Enable fine-grained tool streaming for that tool
Fine-grained tool streaming
Anthropic supports fine-grained tool streaming, which reduces latency when streaming tool calls with large parameters.
Rather than buffering entire parameter values before transmission, fine-grained streaming sends parameter data as it becomes available. This can reduce the initial delay from 15 seconds to around 3 seconds for large tool parameters.
Warning
Fine-grained streaming may return invalid or partial JSON inputs, especially if the response reaches max_tokens before completing. Implement appropriate error handling for incomplete JSON data.
To enable fine-grained tool streaming for a tool that should stream tool parameters incrementally, set extras={"eager_input_streaming": True} on the tool. That value is passed through to the Anthropic API on the tool definition.
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
model = ChatAnthropic(model="claude-sonnet-4-6")
@tool(extras={"eager_input_streaming": True})
def write_document(title: str, content: str) -> str:
"""Write a document with the given title and content."""
return f"Document '{title}' written successfully"
model_with_tools = model.bind_tools([write_document])
# Stream tool calls with reduced latency
for chunk in model_with_tools.stream(
"Write a detailed technical document about the benefits of streaming APIs"
):
print(chunk.content)The streaming data arrives as input_json_delta blocks in chunk.content. You can accumulate these to build the complete tool arguments:
import json
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
model = ChatAnthropic(model="claude-sonnet-4-6")
@tool(extras={"eager_input_streaming": True})
def write_document(title: str, content: str) -> str:
"""Write a document with the given title and content."""
return f"Document '{title}' written successfully"
model_with_tools = model.bind_tools([write_document])
accumulated_json = ""
for chunk in model_with_tools.stream("Write a document about AI"):
for block in chunk.content:
if isinstance(block, dict) and block.get("type") == "input_json_delta":
accumulated_json += block.get("partial_json", "")
try:
# Try to parse accumulated JSON
parsed = json.loads(accumulated_json)
print(f"Complete args: {parsed}")
except json.JSONDecodeError:
# JSON is still incomplete, continue accumulating
passComplete args: {'title': 'Artificial Intelligence: An Overview', 'content': '# Artificial Intelligence: An Overview...Programmatic tool calling
Info
Programmatic tool calling requires langchain-anthropic>=1.3.0. See the Claude docs for supported models.
Tools can be configured to be callable from Claude's code execution environment, reducing latency and token consumption in contexts involving large data processing or multi-tool workflows.
Refer to Claude's programmatic tool calling guide for details. To use this feature:
- Include the code execution built-in tool in your set of tools
- Specify
extras={"allowed_callers": ["code_execution_20250825"]}on tools you wish to call programmatically
See below for a full example with create_agent.
Tip
You can specify reuse_last_container on initialization to automatically reuse code execution containers from previous model responses.
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_anthropic import ChatAnthropic
@tool(extras={"allowed_callers": ["code_execution_20250825"]}) # [!code highlight]
def get_weather(location: str) -> str:
"""Get the weather at a location."""
return "It's sunny."
tools = [
{"type": "code_execution_20250825", "name": "code_execution"}, # [!code highlight]
get_weather,
]
model = ChatAnthropic(
model="claude-sonnet-4-6",
reuse_last_container=True, # [!code highlight]
)
agent = create_agent(model, tools=tools)
input_query = {
"role": "user",
"content": "What's the weather in Boston?",
}
result = agent.invoke({"messages": [input_query]})Multimodal
Claude supports image and PDF inputs as content blocks, both in Anthropic's native format (see docs for vision and PDF support) as well as LangChain's standard format.
Supported input methods
| Method | Image | |
|---|---|---|
| Base64 inline data | ✅ | ✅ |
| HTTP/HTTPS URLs | ✅ | ✅ |
| Files API | ✅ | ✅ |
Tip
The Files API can also be used to upload files to a container for use with Claude's built-in code-execution tools. See the code execution section for details.
Image input
Provide image inputs along with text using a HumanMessage with list content format.
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage
model = ChatAnthropic(model="claude-sonnet-4-6")
message = HumanMessage(
content=[
{"type": "text", "text": "Describe the image at the URL."},
{
"type": "image",
"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg",
},
]
)
response = model.invoke([message])import base64
import httpx
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage
model = ChatAnthropic(model="claude-sonnet-4-6")
image_url = "https://picsum.photos/id/237/200/300"
image_data = base64.b64encode(httpx.get(image_url, follow_redirects=True).content).decode("utf-8")
message = HumanMessage(
content=[
{"type": "text", "text": "Describe the image."},
{ # [!code highlight]
"type": "image", # [!code highlight]
"base64": image_data, # [!code highlight]
"mime_type": "image/jpeg", # [!code highlight]
}, # [!code highlight]
]
)
response = model.invoke([message])
import anthropic
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage
client = anthropic.Anthropic()
file = client.beta.files.upload(
file=("image.png", open("/path/to/image.png", "rb"), "image/png"),
)
model = ChatAnthropic(
model="claude-sonnet-4-6",
betas=["files-api-2025-04-14"], # [!code highlight]
)
message = HumanMessage(
content=[
{"type": "text", "text": "Describe this image."},
{
"type": "image",
"file_id": file.id, # [!code highlight]
},
]
)
response = model.invoke([message])
PDF input
Provide PDF file inputs along with text.
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage
model = ChatAnthropic(model="claude-sonnet-4-6")
message = HumanMessage(
content=[
{"type": "text", "text": "Summarize this document."},
{
"type": "file",
"url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
"mime_type": "application/pdf",
},
]
)
response = model.invoke([message])
import base64
import httpx
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage
model = ChatAnthropic(model="claude-sonnet-4-6")
pdf_url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
pdf_data = base64.b64encode(httpx.get(pdf_url).content).decode("utf-8")
message = HumanMessage(
content=[
{"type": "text", "text": "Summarize this document."},
{
"type": "file",
"base64": pdf_data, # [!code highlight]
"mime_type": "application/pdf", # [!code highlight]
},
]
)
response = model.invoke([message])
import anthropic
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage
client = anthropic.Anthropic()
file = client.beta.files.upload(
file=("document.pdf", open("/path/to/document.pdf", "rb"), "application/pdf"),
)
model = ChatAnthropic(
model="claude-sonnet-4-6",
betas=["files-api-2025-04-14"], # [!code highlight]
)
message = HumanMessage(
content=[
{"type": "text", "text": "Summarize this document."},
{
"type": "file",
"file_id": file.id, # [!code highlight]
},
]
)
response = model.invoke([message])
Extended thinking
Some Claude models support an extended thinking feature, which will output the step-by-step reasoning process that led to its final answer.
See compatible models in the Claude documentation.
To use extended thinking, specify the thinking parameter when initializing ChatAnthropic. If needed, it can also be passed in as a parameter during invocation.
For Claude Sonnet and earlier models, you will need to specify a token budget. For Claude Opus 4.6+, you can use adaptive thinking which automatically determines the budget.
import json
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-sonnet-4-6",
max_tokens=5000,
thinking={"type": "enabled", "budget_tokens": 2000}, # [!code highlight]
)
response = model.invoke("What is the cube root of 50.653?")
print(json.dumps(response.content_blocks, indent=2))
import json
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-opus-4-8",
max_tokens=5000,
thinking={"type": "adaptive"}, # [!code highlight]
)
response = model.invoke("What is the cube root of 50.653?")
print(json.dumps(response.content_blocks, indent=2))
import json
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-sonnet-4-6")
response = model.invoke(
"What is the cube root of 50.653?",
max_tokens=5000,
thinking={"type": "enabled", "budget_tokens": 2000} # [!code highlight]
)
print(json.dumps(response.content_blocks, indent=2))
[
{
"type": "reasoning",
"reasoning": "To find the cube root of 50.653, I need to find the value of $x$ such that $x^3 = 50.653$.\n\nI can try to estimate this first. \n$3^3 = 27$\n$4^3 = 64$\n\nSo the cube root of 50.653 will be somewhere between 3 and 4, but closer to 4.\n\nLet me try to compute this more precisely. I can use the cube root function:\n\ncube root of 50.653 = 50.653^(1/3)\n\nLet me calculate this:\n50.653^(1/3) \u2248 3.6998\n\nLet me verify:\n3.6998^3 \u2248 50.6533\n\nThat's very close to 50.653, so I'm confident that the cube root of 50.653 is approximately 3.6998.\n\nActually, let me compute this more precisely:\n50.653^(1/3) \u2248 3.69981\n\nLet me verify once more:\n3.69981^3 \u2248 50.652998\n\nThat's extremely close to 50.653, so I'll say that the cube root of 50.653 is approximately 3.69981.",
"extras": {"signature": "ErUBCkYIBxgCIkB0UjV..."}
},
{
"type": "text",
"text": "The cube root of 50.653 is approximately 3.6998.\n\nTo verify: 3.6998\u00b3 = 50.6530, which is very close to our original number.",
}
]
Warning
The Claude Messages API handles thinking differently across Claude Sonnet 3.7 and Claude 4 models.
Refer to the Claude docs for more info.
Effort
Certain Claude models support an effort feature, which controls how many tokens Claude uses when responding. This is useful for balancing response quality against latency and cost.
Info
Model support
Effort is generally available on Claude Opus 4.6 and Claude Opus 4.5. The max effort level is only supported on Claude Opus 4.6. The xhigh effort level is supported on Claude Opus 4.7. Anthropic may add or adjust model support over time—use the Claude effort documentation as the source of truth.
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-opus-4-5-20251101",
effort="medium", # Options: "max", "xhigh", "high", "medium", "low" [!code highlight]
)
response = model.invoke("Analyze the trade-offs between microservices and monolithic architectures")
Note
Setting effort to "high" produces exactly the same behavior as omitting the parameter altogether.
effort is an alias for the standard reasoning_effort parameter, at both construction and call time. If both are set, effort wins.
Note
reasoning_effort requires langchain-anthropic>=1.5.3.
model = ChatAnthropic(model="claude-opus-4-6")
response = model.invoke(
"Analyze the trade-offs between microservices and monolithic architectures",
reasoning_effort="high",
)
See the Claude documentation for detail on when to use different effort levels and to see supported models.
Task budgets
Claude Opus 4.7 and later support task budgets, an advisory token target for an agentic loop (thinking, tool calls, tool results, and final output). The model sees a running countdown and uses it to prioritize work and finish gracefully. Unlike max_tokens, task budgets are not a hard cap.
Info
Task budgets require langchain-anthropic>=1.4.1 and are currently in beta.
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-opus-4-8",
output_config={ # [!code highlight]
"effort": "high", # [!code highlight]
"task_budget": {"type": "tokens", "total": 128_000}, # [!code highlight]
}, # [!code highlight]
)
Citations
Anthropic supports a citations feature that lets Claude attach context to its answers based on source documents supplied by the user.
When document or search_result content blocks with "citations": {"enabled": True} are included in a query, Claude may generate citations in its response.
Simple example
In this example we pass a plain text document. In the background, Claude automatically chunks the input text into sentences, which are used when generating citations.
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-haiku-4-5-20251001")
messages = [
{
"role": "user",
"content": [
{
"type": "document",
"source": {
"type": "text",
"media_type": "text/plain",
"data": "The grass is green. The sky is blue.",
},
"title": "My Document",
"context": "This is a trustworthy document.",
"citations": {"enabled": True},
},
{"type": "text", "text": "What color is the grass and sky?"},
],
}
]
response = model.invoke(messages)
response.content
[{'text': 'Based on the document, ', 'type': 'text'},
{'text': 'the grass is green',
'type': 'text',
'citations': [{'type': 'char_location',
'cited_text': 'The grass is green. ',
'document_index': 0,
'document_title': 'My Document',
'start_char_index': 0,
'end_char_index': 20}]},
{'text': ', and ', 'type': 'text'},
{'text': 'the sky is blue',
'type': 'text',
'citations': [{'type': 'char_location',
'cited_text': 'The sky is blue.',
'document_index': 0,
'document_title': 'My Document',
'start_char_index': 20,
'end_char_index': 36}]},
{'text': '.', 'type': 'text'}]
In tool results (agentic RAG)
Claude supports a search_result content block representing citable results from queries against a knowledge base or other custom source. These content blocks can be passed to claude both top-line (as in the above example) and within a tool result. This allows Claude to cite elements of its response using the result of a tool call.
To pass search results in response to tool calls, define a tool that returns a list of search_result content blocks in Anthropic's native format. For example:
def retrieval_tool(query: str) -> list[dict]:
"""Access my knowledge base."""
# Run a search (e.g., with a LangChain vector store)
results = vector_store.similarity_search(query=query, k=2)
# Package results into search_result blocks
return [
{
"type": "search_result",
# Customize fields as desired, using document metadata or otherwise
"title": "My Document Title",
"source": "Source description or provenance",
"citations": {"enabled": True},
"content": [{"type": "text", "text": doc.page_content}],
}
for doc in results
]
Using with text splitters
Anthropic also lets you specify your own splits using custom document types. LangChain text splitters can be used to generate meaningful splits for this purpose. See the below example, where we split the LangChain README.md (a markdown document) and pass it to Claude as context:
This example requires langchain-text-splitters to be installed:
pip install langchain-text-splittersimport requests
from langchain_anthropic import ChatAnthropic
from langchain_text_splitters import MarkdownTextSplitter
def format_to_anthropic_documents(documents: list[str]):
return {
"type": "document",
"source": {
"type": "content",
"content": [{"type": "text", "text": document} for document in documents],
},
"citations": {"enabled": True},
}
# Pull readme
get_response = requests.get(
"https://raw.githubusercontent.com/langchain-ai/langchain/master/README.md"
)
readme = get_response.text
# Split into chunks
splitter = MarkdownTextSplitter(
chunk_overlap=0,
chunk_size=50,
)
documents = splitter.split_text(readme)
# Construct message
message = {
"role": "user",
"content": [
format_to_anthropic_documents(documents),
{"type": "text", "text": "Give me a link to LangChain's tutorials."},
],
}
# Query model
model = ChatAnthropic(model="claude-haiku-4-5-20251001")
response = model.invoke([message])
Prompt caching
Anthropic supports caching of elements of your prompts, including messages, tool definitions, tool results, images and documents. This allows you to reuse large documents, instructions, few-shot documents, and other data to reduce latency and costs.
There are two ways to enable prompt caching on direct model calls:
- Automatic caching: Pass
cache_controlat invocation time (model.invoke(..., cache_control=...)). This is provider/API-level caching: the Anthropic API applies the cache breakpoint to the last cacheable block and moves it forward as conversations grow. - Explicit cache breakpoints: Place
cache_controldirectly on individual content blocks for fine-grained, direct breakpoint control over exactly what gets cached.
Warning
Only certain Claude models support prompt caching. See the Claude documentation for details.
Note
For LangChain agents, prefer AnthropicPromptCachingMiddleware when you want LangChain to optimize stable system prompt and tool content. The middleware is a LangChain agent/harness optimization and is not the same as the invocation-level cache_control shown below, which mirrors the Anthropic API behavior.
Automatic caching
Info
Automatic caching requires langchain-anthropic>=1.4.0.
Pass cache_control as an invocation parameter to automatically cache all content up to and including the last cacheable block. On subsequent requests with the same prefix, cached content is reused automatically. The cache breakpoint moves forward as conversations grow, so you don't need to manage individual cache_control markers.
from langchain_anthropic import ChatAnthropic
import requests
model = ChatAnthropic(model="claude-sonnet-4-5")
# Pull LangChain readme
get_response = requests.get(
"https://raw.githubusercontent.com/langchain-ai/langchain/b476fdb54aa6e6f5f0b24a68c2f4a94e43b369f9/README.md"
)
readme = get_response.text
messages = [
{
"role": "system",
"content": [
{
"type": "text",
"text": "You are a technology expert.",
},
{
"type": "text",
"text": f"{readme}"
},
],
},
{
"role": "user",
"content": "What's LangChain, according to its README?",
},
]
response = model.invoke(
messages,
cache_control={"type": "ephemeral"}, # [!code highlight]
)
usage = response.usage_metadata["input_token_details"]
print(f"Usage:\n{usage}")
For 1-hour caching, specify the ttl field:
response = model.invoke(
messages,
cache_control={"type": "ephemeral", "ttl": "1h"}, # [!code highlight]
)
Explicit cache breakpoints
For fine-grained control, mark individual content blocks with cache_control. This is useful when you need to cache different sections that change at different frequencies.
Messages
import requests
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-sonnet-4-5")
# Pull LangChain readme
get_response = requests.get(
"https://raw.githubusercontent.com/langchain-ai/langchain/b476fdb54aa6e6f5f0b24a68c2f4a94e43b369f9/README.md"
)
readme = get_response.text
messages = [
{
"role": "system",
"content": [
{
"type": "text",
"text": "You are a technology expert.",
},
{
"type": "text",
"text": f"{readme}",
"cache_control": {"type": "ephemeral"}, # [!code highlight]
},
],
},
{
"role": "user",
"content": "What's LangChain, according to its README?",
},
]
response_1 = model.invoke(messages)
response_2 = model.invoke(messages)
usage_1 = response_1.usage_metadata["input_token_details"]
usage_2 = response_2.usage_metadata["input_token_details"]
print(f"First invocation:\n{usage_1}")
print(f"\nSecond:\n{usage_2}")
First invocation:
{'cache_read': 0, 'cache_creation': 0, 'ephemeral_5m_input_tokens': 1569, 'ephemeral_1h_input_tokens': 0}
Second:
{'cache_read': 1569, 'cache_creation': 0, 'ephemeral_5m_input_tokens': 0, 'ephemeral_1h_input_tokens': 0}
Tip
1-hour caching
The cache lifetime is 5 minutes by default. For longer caching, specify "ttl": "1h" in the cache_control field. 1-hour cache writes cost 2x the base input token price (vs 1.25x for 5-minute).
Caching tools
import requests
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
# For demonstration purposes, we artificially expand the
# tool description using the LangChain README text.
get_response = requests.get(
"https://raw.githubusercontent.com/langchain-ai/langchain/master/README.md"
)
readme = get_response.text
description = (
"Get the weather at a location. "
f"By the way, check out this readme: {readme}"
)
@tool(description=description, extras={"cache_control": {"type": "ephemeral"}}) # [!code highlight]
def get_weather(location: str) -> str:
return "It's sunny."
model = ChatAnthropic(model="claude-sonnet-4-6")
model_with_tools = model.bind_tools([get_weather])
query = "What's the weather in San Francisco?"
response_1 = model_with_tools.invoke(query)
response_2 = model_with_tools.invoke(query)
usage_1 = response_1.usage_metadata["input_token_details"]
usage_2 = response_2.usage_metadata["input_token_details"]
print(f"First invocation:\n{usage_1}")
print(f"\nSecond:\n{usage_2}")
First invocation:
{'cache_read': 0, 'cache_creation': 1809}
Second:
{'cache_read': 1809, 'cache_creation': 0}
Incremental caching in conversational applications
Prompt caching can be used in multi-turn conversations to maintain context from earlier messages without redundant processing.
We can enable incremental caching by marking the final message with cache_control. Claude will automatically use the longest previously-cached prefix for follow-up messages.
Below, we implement a simple chatbot that incorporates this feature. We follow the LangChain chatbot tutorial, but add a custom reducer that automatically marks the last content block in each user message with cache_control:
Token counting
You can count tokens in messages before sending them to the model using get_num_tokens_from_messages(). This uses Anthropic's official token counting API.
Mid-conversation system messages
Note
Mid-conversation system messages require langchain-anthropic>=1.7.3.
Supported Claude models accept a system message partway through a conversation. Its instructions apply from that point onward. Adding one leaves the earlier turns unchanged, so it does not invalidate the prompt cache for them.
A leading SystemMessage always goes in the top-level system field. ChatAnthropic sends a later SystemMessage at its own position in the conversation when both of these conditions hold:
- The model supports mid-conversation system messages. The Claude documentation lists which models do.
- The message follows a human or tool message, and is either the last message or followed by an AI message.
Otherwise, ChatAnthropic moves the message into the top-level system field with a warning, where it applies to the whole conversation. If a leading system message already fills that field, ChatAnthropic raises a ValueError.
from langchain.messages import AIMessage, HumanMessage, SystemMessage
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-opus-5-5")
response = model.invoke(
[
SystemMessage("You are a travel assistant."),
HumanMessage("Suggest a day trip from Lisbon."),
AIMessage("Sintra is a good choice: palaces, gardens, and a short train ride."),
HumanMessage("How do I get there?"),
SystemMessage("The user has switched to the mobile app. Keep answers under 50 words."), # [!code highlight]
]
)
For wording guidance and the full placement rules, see the Claude documentation.
Change tools mid-conversation
Note
Mid-conversation tool changes require langchain-anthropic>=1.7.4.
A mid-conversation SystemMessage can also add or remove tools with Anthropic's tool_addition and tool_removal content blocks. Editing tools on the request invalidates the prompt cache for the whole conversation. These blocks leave tools unchanged, so the cached prefix still matches.
The placement and model rules above apply. When ChatAnthropic cannot send the message in place, it drops the tool-change blocks with a warning.
ChatAnthropic adds the required beta header, so you do not need to set betas.
To add a tool partway through, bind it with extras={"defer_loading": True} so Claude does not see it at first. Then reference it by name in a tool_addition block:
from langchain.messages import HumanMessage, SystemMessage
from langchain.tools import tool
from langchain_anthropic import ChatAnthropic
@tool
def get_time() -> str:
"""Get the current time."""
return "12:00"
@tool(extras={"defer_loading": True}) # [!code highlight]
def get_weather(location: str) -> str:
"""Get the current weather for a location."""
return f"It's sunny in {location}."
model = ChatAnthropic(model="claude-opus-5-5")
model_with_tools = model.bind_tools([get_time, get_weather])
response = model_with_tools.invoke(
[
HumanMessage("What's the weather in San Francisco?"),
SystemMessage(
[
{ # [!code highlight]
"type": "tool_addition", # [!code highlight]
"tool": {"type": "tool_reference", "name": "get_weather"}, # [!code highlight]
}, # [!code highlight]
]
),
]
)
The API rejects a request in which every tool is deferred, so bind at least one tool without defer_loading.
To withdraw a tool, reference it in a tool_removal block. A later tool_addition can offer it again.
SystemMessage(
[
{
"type": "tool_removal",
"tool": {"type": "tool_reference", "name": "get_weather"},
},
]
)
To add a tool that you did not bind up front, define it inline with a tool_definition. Inline definitions are in beta and available only on the Claude API.
from langchain.messages import HumanMessage, SystemMessage
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-opus-5-5")
response = model.invoke(
[
HumanMessage("How many orders did we get yesterday?"),
SystemMessage(
[
{
"type": "tool_addition",
"tool": {
"type": "tool_definition", # [!code highlight]
"definition": { # [!code highlight]
"name": "db_query",
"description": "Run a read-only SQL query against the analytics database.",
"input_schema": {
"type": "object",
"properties": {"sql": {"type": "string"}},
"required": ["sql"],
},
},
},
},
]
),
]
)
You can also write these blocks wrapped in a non_standard block, which is how content_blocks returns them. ChatAnthropic sends the same request for either form.
Context management
Anthropic supports context management features that automatically manage the model's context window to optimize performance and cost.
See the Claude documentation for more details and configuration options.
Clearing tool uses
Clear tool results from the context to reduce token usage while preserving the conversation flow.
Info
Context management is supported since langchain-anthropic>=0.3.21
You must specify the context-management-2025-06-27 beta header to apply context management to your model calls.
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-sonnet-4-6",
betas=["context-management-2025-06-27"], # [!code highlight]
context_management={"edits": [{"type": "clear_tool_uses_20250919"}]}, # [!code highlight]
)
model_with_tools = model.bind_tools([{"type": "web_search_20260209", "name": "web_search"}])
response = model_with_tools.invoke("Search for recent developments in AI")
Automatic compaction
Claude Opus 4.6 and later support automatic server-side compaction, which intelligently condenses conversation history when the context window approaches its limit. This allows for longer conversations without manual context management.
Info
Automatic compaction requirements:
- Claude Opus 4.6 or later
langchain-anthropic>=1.3.0compact-2026-01-12beta header
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-opus-4-8",
betas=["compact-2026-01-12"], # [!code highlight]
max_tokens=4096,
context_management={ # [!code highlight]
"edits": [ # [!code highlight]
{ # [!code highlight]
"type": "compact_20260112", # [!code highlight]
"trigger": {"type": "input_tokens", "value": 50000}, # [!code highlight]
} # [!code highlight]
] # [!code highlight]
}, # [!code highlight]
)
See Anthropic's docs for details on trigger configuration.
When a compaction event is triggered, ChatAnthropic will return compaction blocks representing the state of the prompt. These should be retained in the message history that is passed back to the model in multi-turn applications.
Structured output
Info
Structured output requires langchain-anthropic>=1.1.0. See the Claude docs for supported models.
Anthropic supports a native structured output feature, which guarantees that its responses adhere to a given schema.
You can access this feature in individual model calls, or by specifying the response format of a LangChain agent. See below for examples.
Built-in tools
Anthropic supports a variety of built-in client and server-side tools.
Server-side tools (e.g., web search) are passed to the model and executed by Anthropic. Client-side tools (e.g., bash tool) require you to implement the callback execution logic in your application and return results to the model.
In either case, you make tools accessible to your chat model by using bind_tools on the model instance.
Importantly, client-side tools require you to implement the execution logic. See the relevant sections below for examples.
Info
Middleware vs tools
For client-side tools (e.g. bash, text editor, memory), you may opt to use middleware, which provide production-ready implementations that contain built-in execution, state management, and security policies.
Use middleware when you want a turnkey solution; use tools (documented below) when you need custom execution logic or want to use bind_tools directly.
Note
Beta tools
If binding a beta tool to your chat model, LangChain will automatically add the required beta header for you.
Bash tool
Claude supports a client-side bash tool that allows it to execute shell commands in a persistent bash session. This enables system operations, script execution, and command-line automation.
Note
Important: You must provide the execution environment
LangChain handles the API integration (sending/receiving tool calls), but you are responsible for:
- Setting up a sandboxed computing environment (Docker, VM, etc.)
- Implementing command execution and output capture
- Passing results back to Claude in an agent loop
See the Claude bash tool docs for implementation guidance.
Info
Requirements:
- Claude 4 models or Claude Sonnet 3.7
import subprocess
from anthropic.types.beta import BetaToolBash20250124Param # [!code highlight]
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage, ToolMessage
from langchain.tools import tool
tool_spec = BetaToolBash20250124Param( # [!code highlight]
name="bash", # [!code highlight]
type="bash_20250124", # [!code highlight]
) # [!code highlight]
@tool(extras={"provider_tool_definition": tool_spec}) # [!code highlight]
def bash(*, command: str, restart: bool = False, **kw):
"""Execute a bash command."""
if restart:
return "Bash session restarted"
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=30,
)
return result.stdout + result.stderr
except Exception as e:
return f"Error: {e}"
model = ChatAnthropic(model="claude-sonnet-4-6")
model_with_bash = model.bind_tools([bash]) # [!code highlight]
# Initial request
messages = [HumanMessage("List all files in the current directory")]
response = model_with_bash.invoke(messages)
print(response.content_blocks)
# Tool execution loop
while response.tool_calls:
# Execute each tool call
tool_messages = []
for tool_call in response.tool_calls:
result = bash.invoke(tool_call)
tool_messages.append(result)
# Continue conversation with tool results
messages = [*messages, response, *tool_messages]
response = model_with_bash.invoke(messages)
print(response.content_blocks)
import subprocess
from anthropic.types.beta import BetaToolBash20250124Param # [!code highlight]
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
tool_spec = BetaToolBash20250124Param( # [!code highlight]
name="bash", # [!code highlight]
type="bash_20250124", # [!code highlight]
) # [!code highlight]
@tool(extras={"provider_tool_definition": tool_spec}) # [!code highlight]
def bash(*, command: str, restart: bool = False, **kw):
"""Execute a bash command."""
if restart:
return "Bash session restarted"
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
)
return result.stdout + result.stderr
agent = create_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[bash], # [!code highlight]
)
result = agent.invoke({"messages": [{"role": "user", "content": "List files"}]})
for message in result["messages"]:
message.pretty_print()
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-sonnet-4-6")
bash_tool = { # [!code highlight]
"type": "bash_20250124", # [!code highlight]
"name": "bash", # [!code highlight]
} # [!code highlight]
model_with_bash = model.bind_tools([bash_tool]) # [!code highlight]
response = model_with_bash.invoke(
"List all Python files in the current directory"
)
# You must handle execution of the bash command in response.tool_calls via a tool execution loop
Using create_agent handles the tool execution loop automatically.
response.tool_calls will contain the bash command Claude wants to execute. You must run this command in your environment and pass the result back.
[{'type': 'text',
'text': "I'll list the Python files in the current directory for you."},
{'type': 'tool_call',
'name': 'bash',
'args': {'command': 'ls -la *.py'},
'id': 'toolu_01ABC123...'}]
The bash tool supports two parameters:
command(required): The bash command to executerestart(optional): Set totrueto restart the bash session
Tip
For a "batteries-included" implementation, consider using ClaudeBashToolMiddleware which provides persistent sessions, Docker isolation, output redaction, and startup/shutdown commands out of the box.
Code execution
Claude can use a server-side code execution tool to execute code in a sandboxed environment.
Info
Anthropic's 2025-08-25 code execution tools are supported since langchain-anthropic>=1.0.3.
The legacy 2025-05-22 tool is supported since langchain-anthropic>=0.3.14.
Note
The code sandbox does not have internet access, thus you may only use packages that are pre-installed in the environment. See the Claude docs for more info.
from anthropic.types.beta import BetaCodeExecutionTool20250825Param # [!code highlight]
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-sonnet-4-6",
# (Optional) Enable the param below to automatically
# pass back in container IDs from previous response
reuse_last_container=True,
)
code_tool = BetaCodeExecutionTool20250825Param( # [!code highlight]
name="code_execution", # [!code highlight]
type="code_execution_20250825", # [!code highlight]
) # [!code highlight]
model_with_tools = model.bind_tools([code_tool]) # [!code highlight]
response = model_with_tools.invoke(
"Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
)
from anthropic.types.beta import BetaCodeExecutionTool20250825Param # [!code highlight]
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
code_tool = BetaCodeExecutionTool20250825Param( # [!code highlight]
name="code_execution", # [!code highlight]
type="code_execution_20250825", # [!code highlight]
) # [!code highlight]
agent = create_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[code_tool], # [!code highlight]
)
result = agent.invoke({
"messages": [{"role": "user", "content": "Calculate mean and std of [1,2,3,4,5]"}]
})
for message in result["messages"]:
message.pretty_print()
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-sonnet-4-6",
)
code_tool = {"type": "code_execution_20250825", "name": "code_execution"} # [!code highlight]
model_with_tools = model.bind_tools([code_tool])
response = model_with_tools.invoke(
"Calculate the mean and standard deviation of [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
)
Computer use
Claude supports client-side computer use capabilities, allowing it to interact with desktop environments through screenshots, mouse control, and keyboard input.
Note
Important: You must provide the execution environment
LangChain handles the API integration (sending/receiving tool calls), but you are responsible for:
- Setting up a sandboxed computing environment (Linux VM, Docker container, etc.)
- Implementing a virtual display (e.g., Xvfb)
- Executing Claude's tool calls (screenshot, mouse clicks, keyboard input)
- Passing results back to Claude in an agent loop
Anthropic provides a reference implementation to help you get started.
Info
Requirements:
- Claude Opus 4.5, Claude 4, or Claude Sonnet 3.7
import base64
from typing import Literal
from anthropic.types.beta import BetaToolComputerUse20250124Param # [!code highlight]
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage, ToolMessage
from langchain.tools import tool
DISPLAY_WIDTH = 1024
DISPLAY_HEIGHT = 768
tool_spec = BetaToolComputerUse20250124Param( # [!code highlight]
name="computer", # [!code highlight]
type="computer_20250124", # [!code highlight]
display_width_px=DISPLAY_WIDTH, # [!code highlight]
display_height_px=DISPLAY_HEIGHT, # [!code highlight]
display_number=1, # [!code highlight]
) # [!code highlight]
@tool(extras={"provider_tool_definition": tool_spec}) # [!code highlight]
def computer(
*,
action: Literal[
"key", "type", "mouse_move", "left_click", "left_click_drag",
"right_click", "middle_click", "double_click", "screenshot",
"cursor_position", "scroll"
],
coordinate: list[int] | None = None,
text: str | None = None,
**kw
):
"""Control the computer display."""
if action == "screenshot":
# Take screenshot and return base64-encoded image
# Implementation depends on your display setup (e.g., Xvfb, pyautogui)
return {"type": "image", "data": "base64_screenshot_data..."}
elif action == "left_click" and coordinate:
# Execute click at coordinate
return f"Clicked at {coordinate}"
elif action == "type" and text:
# Type text
return f"Typed: {text}"
# ... implement other actions
return f"Executed {action}"
model = ChatAnthropic(model="claude-sonnet-4-6")
model_with_computer = model.bind_tools([computer]) # [!code highlight]
# Initial request
messages = [HumanMessage("Take a screenshot to see what's on the screen")]
response = model_with_computer.invoke(messages)
print(response.content_blocks)
# Tool execution loop
while response.tool_calls:
tool_messages = []
for tool_call in response.tool_calls:
result = computer.invoke(tool_call)
tool_messages.append(
ToolMessage(content=str(result), tool_call_id=tool_call["id"])
)
messages = [*messages, response, *tool_messages]
response = model_with_computer.invoke(messages)
print(response.content_blocks)
from typing import Literal
from anthropic.types.beta import BetaToolComputerUse20250124Param # [!code highlight]
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
tool_spec = BetaToolComputerUse20250124Param( # [!code highlight]
name="computer", # [!code highlight]
type="computer_20250124", # [!code highlight]
display_width_px=1024, # [!code highlight]
display_height_px=768, # [!code highlight]
) # [!code highlight]
@tool(extras={"provider_tool_definition": tool_spec}) # [!code highlight]
def computer(
*,
action: Literal[
"key", "type", "mouse_move", "left_click", "left_click_drag",
"right_click", "middle_click", "double_click", "screenshot",
"cursor_position", "scroll"
],
coordinate: list[int] | None = None,
text: str | None = None,
**kw
):
"""Control the computer display."""
if action == "screenshot":
return {"type": "image", "data": "base64_screenshot_data..."}
elif action == "left_click" and coordinate:
return f"Clicked at {coordinate}"
elif action == "type" and text:
return f"Typed: {text}"
return f"Executed {action}"
agent = create_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[computer], # [!code highlight]
)
result = agent.invoke({
"messages": [{"role": "user", "content": "Take a screenshot"}]
})
for message in result["messages"]:
message.pretty_print()
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-sonnet-4-6")
computer_tool = {
"type": "computer_20250124",
"name": "computer",
"display_width_px": 1024,
"display_height_px": 768,
"display_number": 1,
}
model_with_computer = model.bind_tools([computer_tool]) # [!code highlight]
response = model_with_computer.invoke(
"Take a screenshot to see what's on the screen"
)
# You must handle execution of the computer actions in response.tool_calls via a tool execution loop
Using create_agent handles the tool execution loop automatically.
response.tool_calls will contain the computer action Claude wants to perform. You must execute this action in your environment and pass the result back.
[{'type': 'text',
'text': "I'll take a screenshot to see what's currently on the screen."},
{'type': 'tool_call',
'name': 'computer',
'args': {'action': 'screenshot'},
'id': 'toolu_01RNsqAE7dDZujELtacNeYv9'}]
Note
Available tool versions:
computer_20250124(for Claude 4 and Claude Sonnet 3.7)computer_20251124(for Claude Opus 4.5)
Remote MCP
Claude can use a server-side MCP connector tool for model-generated calls to remote MCP servers.
Info
Remote MCP is supported since langchain-anthropic>=0.3.14
from anthropic.types.beta import BetaMCPToolsetParam # [!code highlight]
from langchain_anthropic import ChatAnthropic
mcp_servers = [
{
"type": "url",
"url": "https://docs.langchain.com/mcp",
"name": "LangChain Docs",
}
]
model = ChatAnthropic(
model="claude-sonnet-4-6",
mcp_servers=mcp_servers, # [!code highlight]
)
mcp_tool = BetaMCPToolsetParam( # [!code highlight]
type="mcp_toolset", # [!code highlight]
mcp_server_name="LangChain Docs", # [!code highlight]
) # [!code highlight]
response = model.invoke(
"What are LangChain content blocks?",
tools=[mcp_tool], # [!code highlight]
)
from anthropic.types.beta import BetaMCPToolsetParam # [!code highlight]
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
mcp_servers = [
{
"type": "url",
"url": "https://docs.langchain.com/mcp",
"name": "LangChain Docs",
}
]
mcp_tool = BetaMCPToolsetParam( # [!code highlight]
type="mcp_toolset", # [!code highlight]
mcp_server_name="LangChain Docs", # [!code highlight]
) # [!code highlight]
agent = create_agent(
model=ChatAnthropic(
model="claude-sonnet-4-6",
mcp_servers=mcp_servers, # [!code highlight]
),
tools=[mcp_tool], # [!code highlight]
)
result = agent.invoke({
"messages": [{"role": "user", "content": "What are LangChain content blocks?"}]
})
for message in result["messages"]:
message.pretty_print()
from langchain_anthropic import ChatAnthropic
mcp_servers = [
{
"type": "url",
"url": "https://docs.langchain.com/mcp",
"name": "LangChain Docs",
# "tool_configuration": { # optional configuration
# "enabled": True,
# "allowed_tools": ["ask_question"],
# },
# "authorization_token": "PLACEHOLDER", # optional authorization if needed
}
]
model = ChatAnthropic(
model="claude-sonnet-4-6",
mcp_servers=mcp_servers, # [!code highlight]
)
response = model.invoke(
"What are LangChain content blocks?",
tools=[{"type": "mcp_toolset", "mcp_server_name": "LangChain Docs"}], # [!code highlight]
)
response.content_blocks
Text editor
Claude supports a client-side text editor tool can be used to view and modify text local files. See the text editor tool documentation for details.
from typing import Literal
from anthropic.types.beta import BetaToolTextEditor20250728Param # [!code highlight]
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage, ToolMessage
from langchain.tools import tool
tool_spec = BetaToolTextEditor20250728Param( # [!code highlight]
name="str_replace_based_edit_tool", # [!code highlight]
type="text_editor_20250728", # [!code highlight]
) # [!code highlight]
# Simple in-memory file storage for demonstration
files: dict[str, str] = {
"/workspace/primes.py": "def is_prime(n):\n if n < 2\n return False\n return True"
}
@tool(extras={"provider_tool_definition": tool_spec}) # [!code highlight]
def str_replace_based_edit_tool(
*,
command: Literal["view", "create", "str_replace", "insert", "undo_edit"],
path: str,
file_text: str | None = None,
old_str: str | None = None,
new_str: str | None = None,
insert_line: int | None = None,
view_range: list[int] | None = None,
**kw
):
"""View and edit text files."""
if command == "view":
if path not in files:
return f"Error: File {path} not found"
content = files[path]
if view_range:
lines = content.splitlines()
start, end = view_range[0] - 1, view_range[1]
return "\n".join(lines[start:end])
return content
elif command == "create":
files[path] = file_text or ""
return f"Created {path}"
elif command == "str_replace" and old_str is not None:
if path not in files:
return f"Error: File {path} not found"
files[path] = files[path].replace(old_str, new_str or "", 1)
return f"Replaced in {path}"
# ... implement other commands
return f"Executed {command} on {path}"
model = ChatAnthropic(model="claude-sonnet-4-6")
model_with_tools = model.bind_tools([str_replace_based_edit_tool]) # [!code highlight]
# Initial request
messages = [HumanMessage("There's a syntax error in my primes.py file. Can you fix it?")]
response = model_with_tools.invoke(messages)
print(response.content_blocks)
# Tool execution loop
while response.tool_calls:
tool_messages = []
for tool_call in response.tool_calls:
result = str_replace_based_edit_tool.invoke(tool_call)
tool_messages.append(
ToolMessage(content=result, tool_call_id=tool_call["id"])
)
messages = [*messages, response, *tool_messages]
response = model_with_tools.invoke(messages)
print(response.content_blocks)
from typing import Literal
from anthropic.types.beta import BetaToolTextEditor20250728Param # [!code highlight]
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
# Simple in-memory file storage
files: dict[str, str] = {
"/workspace/primes.py": "def is_prime(n):\n if n < 2\n return False\n return True"
}
tool_spec = BetaToolTextEditor20250728Param( # [!code highlight]
name="str_replace_based_edit_tool", # [!code highlight]
type="text_editor_20250728", # [!code highlight]
) # [!code highlight]
@tool(extras={"provider_tool_definition": tool_spec}) # [!code highlight]
def str_replace_based_edit_tool(
*,
command: Literal["view", "create", "str_replace", "insert", "undo_edit"],
path: str,
file_text: str | None = None,
old_str: str | None = None,
new_str: str | None = None,
**kw
):
"""View and edit text files."""
if command == "view":
return files.get(path, f"Error: File {path} not found")
elif command == "create":
files[path] = file_text or ""
return f"Created {path}"
elif command == "str_replace" and old_str is not None:
if path not in files:
return f"Error: File {path} not found"
files[path] = files[path].replace(old_str, new_str or "", 1)
return f"Replaced in {path}"
return f"Executed {command} on {path}"
agent = create_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[str_replace_based_edit_tool], # [!code highlight]
)
result = agent.invoke({
"messages": [{"role": "user", "content": "Fix the syntax error in /workspace/primes.py"}]
})
for message in result["messages"]:
message.pretty_print()
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-sonnet-4-6")
editor_tool = {"type": "text_editor_20250728", "name": "str_replace_based_edit_tool"} # [!code highlight]
model_with_tools = model.bind_tools([editor_tool]) # [!code highlight]
response = model_with_tools.invoke(
"There's a syntax error in my primes.py file. Can you help me fix it?"
)
# You must handle execution of the text editor commands in response.tool_calls via a tool execution loop
Using create_agent handles the tool execution loop automatically.
[{'name': 'str_replace_based_edit_tool',
'args': {'command': 'view', 'path': '/root'},
'id': 'toolu_011BG5RbqnfBYkD8qQonS9k9',
'type': 'tool_call'}]
Note
Available tool versions:
text_editor_20250124(legacy)text_editor_20250728(recommended)
Tip
For a "batteries-included" implementation, consider using StateClaudeTextEditorMiddleware or FilesystemClaudeTextEditorMiddleware which provide LangGraph state integration or filesystem persistence, path validation, and other features.
Web fetching
Claude can use a server-side web fetching tool to retrieve full content from specified web pages and PDF documents and ground its responses with citations.
from anthropic.types.beta import BetaWebFetchTool20250910Param # [!code highlight]
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-haiku-4-5-20251001")
fetch_tool = BetaWebFetchTool20250910Param( # [!code highlight]
name="web_fetch", # [!code highlight]
type="web_fetch_20250910", # [!code highlight]
max_uses=3, # [!code highlight]
) # [!code highlight]
model_with_tools = model.bind_tools([fetch_tool]) # [!code highlight]
response = model_with_tools.invoke(
"Please analyze the content at https://docs.langchain.com/"
)
from anthropic.types.beta import BetaWebFetchTool20250910Param # [!code highlight]
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
fetch_tool = BetaWebFetchTool20250910Param( # [!code highlight]
name="web_fetch", # [!code highlight]
type="web_fetch_20250910", # [!code highlight]
max_uses=3, # [!code highlight]
) # [!code highlight]
agent = create_agent(
model=ChatAnthropic(model="claude-haiku-4-5-20251001"),
tools=[fetch_tool], # [!code highlight]
)
result = agent.invoke({
"messages": [{"role": "user", "content": "Analyze https://docs.langchain.com/"}]
})
for message in result["messages"]:
message.pretty_print()
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-haiku-4-5-20251001")
fetch_tool = {"type": "web_fetch_20250910", "name": "web_fetch", "max_uses": 3} # [!code highlight]
model_with_tools = model.bind_tools([fetch_tool]) # [!code highlight]
response = model_with_tools.invoke(
"Please analyze the content at https://docs.langchain.com/"
)
Web search
Claude can use a server-side web search tool to run searches and ground its responses with citations.
Info
Web search tool is supported since langchain-anthropic>=0.3.13
from anthropic.types import WebSearchTool20260209Param # [!code highlight]
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-sonnet-4-6")
search_tool = WebSearchTool20260209Param( # [!code highlight]
name="web_search", # [!code highlight]
type="web_search_20260209", # [!code highlight]
max_uses=3, # [!code highlight]
) # [!code highlight]
model_with_tools = model.bind_tools([search_tool]) # [!code highlight]
response = model_with_tools.invoke("How do I update a web app to TypeScript 5.5?")
from anthropic.types import WebSearchTool20260209Param # [!code highlight]
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
search_tool = WebSearchTool20260209Param( # [!code highlight]
name="web_search", # [!code highlight]
type="web_search_20260209", # [!code highlight]
max_uses=3, # [!code highlight]
) # [!code highlight]
agent = create_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[search_tool], # [!code highlight]
)
result = agent.invoke({
"messages": [{"role": "user", "content": "How do I update a web app to TypeScript 5.5?"}]
})
for message in result["messages"]:
message.pretty_print()
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(model="claude-sonnet-4-6")
search_tool = {"type": "web_search_20260209", "name": "web_search", "max_uses": 3} # [!code highlight]
model_with_tools = model.bind_tools([search_tool]) # [!code highlight]
response = model_with_tools.invoke("How do I update a web app to TypeScript 5.5?")
Memory tool
Claude supports a memory tool for client-side storage and retrieval of context across conversational threads. See the memory tool documentation for details.
Info
Anthropic's built-in memory tool is supported since langchain-anthropic>=0.3.21
from typing import Literal
from anthropic.types.beta import BetaMemoryTool20250818Param # [!code highlight]
from langchain_anthropic import ChatAnthropic
from langchain.messages import HumanMessage, ToolMessage
from langchain.tools import tool
tool_spec = BetaMemoryTool20250818Param( # [!code highlight]
name="memory", # [!code highlight]
type="memory_20250818", # [!code highlight]
) # [!code highlight]
# Simple in-memory storage for demonstration purposes
memory_store: dict[str, str] = {
"/memories/interests": "User enjoys Python programming and hiking"
}
@tool(extras={"provider_tool_definition": tool_spec}) # [!code highlight]
def memory(
*,
command: Literal["view", "create", "str_replace", "insert", "delete", "rename"],
path: str,
content: str | None = None,
old_str: str | None = None,
new_str: str | None = None,
insert_line: int | None = None,
new_path: str | None = None,
**kw,
):
"""Manage persistent memory across conversations."""
if command == "view":
if path == "/memories":
# List all memories
return "\n".join(memory_store.keys()) or "No memories stored"
return memory_store.get(path, f"No memory at {path}")
elif command == "create":
memory_store[path] = content or ""
return f"Created memory at {path}"
elif command == "str_replace" and old_str is not None:
if path in memory_store:
memory_store[path] = memory_store[path].replace(old_str, new_str or "", 1)
return f"Updated {path}"
elif command == "delete":
memory_store.pop(path, None)
return f"Deleted {path}"
# ... implement other commands
return f"Executed {command} on {path}"
model = ChatAnthropic(model="claude-sonnet-4-6")
model_with_tools = model.bind_tools([memory]) # [!code highlight]
# Initial request
messages = [HumanMessage("What are my interests?")]
response = model_with_tools.invoke(messages)
print(response.content_blocks)
# Tool execution loop
while response.tool_calls:
tool_messages = []
for tool_call in response.tool_calls:
result = memory.invoke(tool_call)
tool_messages.append(ToolMessage(content=result, tool_call_id=tool_call["id"]))
messages = [*messages, response, *tool_messages]
response = model_with_tools.invoke(messages)
print(response.content_blocks)
[{'type': 'text',
'text': "I'll check my memory to see what information I have about your interests."},
{'type': 'tool_call',
'name': 'memory',
'args': {'command': 'view', 'path': '/memories'},
'id': 'toolu_01XeP9sxx44rcZHFNqXSaKqh'}]
from typing import Literal
from anthropic.types.beta import BetaMemoryTool20250818Param # [!code highlight]
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
# Simple in-memory storage
memory_store: dict[str, str] = {
"/memories/interests": "User enjoys Python programming and hiking"
}
tool_spec = BetaMemoryTool20250818Param( # [!code highlight]
name="memory", # [!code highlight]
type="memory_20250818", # [!code highlight]
) # [!code highlight]
@tool(extras={"provider_tool_definition": tool_spec}) # [!code highlight]
def memory(
*,
command: Literal["view", "create", "str_replace", "insert", "delete", "rename"],
path: str,
content: str | None = None,
old_str: str | None = None,
new_str: str | None = None,
**kw
):
"""Manage persistent memory across conversations."""
if command == "view":
if path == "/memories":
return "\n".join(memory_store.keys()) or "No memories stored"
return memory_store.get(path, f"No memory at {path}")
elif command == "create":
memory_store[path] = content or ""
return f"Created memory at {path}"
elif command == "str_replace" and old_str is not None:
if path in memory_store:
memory_store[path] = memory_store[path].replace(old_str, new_str or "", 1)
return f"Updated {path}"
elif command == "delete":
memory_store.pop(path, None)
return f"Deleted {path}"
return f"Executed {command} on {path}"
agent = create_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[memory], # [!code highlight]
)
result = agent.invoke({
"messages": [{"role": "user", "content": "What are my interests?"}]
})
for message in result["messages"]:
message.pretty_print()
Using create_agent handles the tool execution loop automatically.
from langchain_anthropic import ChatAnthropic
model = ChatAnthropic(
model="claude-sonnet-4-6",
)
model_with_tools = model.bind_tools([{"type": "memory_20250818", "name": "memory"}]) # [!code highlight]
response = model_with_tools.invoke("What are my interests?")
response.content_blocks
# You must handle execution of the memory commands in response.tool_calls via a tool execution loop
[{'type': 'text',
'text': "I'll check my memory to see what information I have about your interests."},
{'type': 'tool_call',
'name': 'memory',
'args': {'command': 'view', 'path': '/memories'},
'id': 'toolu_01XeP9sxx44rcZHFNqXSaKqh'}]
Tip
For a "batteries-included" implementation, consider using StateClaudeMemoryMiddleware or FilesystemClaudeMemoryMiddleware which provide LangGraph state integration or filesystem persistence, automatic system prompt injection, and other features.
Tool search
Claude supports a server-side tool search feature that enables dynamic tool discovery and loading. Instead of loading all tool definitions into the context window upfront, Claude can search your tool catalog and load only the tools it needs.
This is useful when:
- You have 10+ tools available in your system
- Tool definitions are consuming significant tokens
- You're experiencing tool selection accuracy issues with large tool sets
There are two tool search variants:
- Regex (
tool_search_tool_regex_20251119): Claude constructs regex patterns to search for tools - BM25 (
tool_search_tool_bm25_20251119): Claude uses natural language queries to search for tools
Use the extras parameter to specify defer_loading on LangChain tools:
from anthropic.types.beta import BetaToolSearchToolRegex20251119Param # [!code highlight]
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
@tool(extras={"defer_loading": True}) # [!code highlight]
def get_weather(location: str, unit: str = "fahrenheit") -> str:
"""Get the current weather for a location.
Args:
location: City name
unit: Temperature unit (celsius or fahrenheit)
"""
return f"Weather in {location}: Sunny"
@tool(extras={"defer_loading": True}) # [!code highlight]
def search_files(query: str) -> str:
"""Search through files in the workspace.
Args:
query: Search query
"""
return f"Found files matching '{query}'"
model = ChatAnthropic(model="claude-sonnet-4-6")
tool_search = BetaToolSearchToolRegex20251119Param( # [!code highlight]
name="tool_search_tool_regex", # [!code highlight]
type="tool_search_tool_regex_20251119", # [!code highlight]
) # [!code highlight]
model_with_tools = model.bind_tools([
tool_search, # [!code highlight]
get_weather,
search_files,
])
response = model_with_tools.invoke("What's the weather in San Francisco?")
from anthropic.types.beta import BetaToolSearchToolRegex20251119Param # [!code highlight]
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
tool_search = BetaToolSearchToolRegex20251119Param( # [!code highlight]
name="tool_search_tool_regex", # [!code highlight]
type="tool_search_tool_regex_20251119", # [!code highlight]
) # [!code highlight]
@tool(extras={"defer_loading": True}) # [!code highlight]
def get_weather(location: str, unit: str = "fahrenheit") -> str:
"""Get the current weather for a location.
Args:
location: City name
unit: Temperature unit (celsius or fahrenheit)
"""
return f"Weather in {location}: Sunny"
@tool(extras={"defer_loading": True}) # [!code highlight]
def search_files(query: str) -> str:
"""Search through files in the workspace.
Args:
query: Search query
"""
return f"Found files matching '{query}'"
agent = create_agent(
model=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[
tool_search, # [!code highlight]
get_weather,
search_files,
],
)
result = agent.invoke({
"messages": [{"role": "user", "content": "What's the weather in San Francisco?"}]
})
for message in result["messages"]:
message.pretty_print()
from langchain_anthropic import ChatAnthropic
from langchain.tools import tool
@tool(extras={"defer_loading": True}) # [!code highlight]
def get_weather(location: str, unit: str = "fahrenheit") -> str:
"""Get the current weather for a location.
Args:
location: City name
unit: Temperature unit (celsius or fahrenheit)
"""
return f"Weather in {location}: Sunny"
@tool(extras={"defer_loading": True}) # [!code highlight]
def search_files(query: str) -> str:
"""Search through files in the workspace.
Args:
query: Search query
"""
return f"Found files matching '{query}'"
model = ChatAnthropic(model="claude-sonnet-4-6")
model_with_tools = model.bind_tools([
{"type": "tool_search_tool_regex_20251119", "name": "tool_search_tool_regex"}, # [!code highlight]
get_weather,
search_files,
])
response = model_with_tools.invoke("What's the weather in San Francisco?")
sequenceDiagram
participant User
participant Model
participant ToolSearch as Tool Search
participant Tool as get_weather
User->>Model: "What's the weather in San Francisco?"
Model->>ToolSearch: tool_search_tool_regex(pattern="weather")
ToolSearch-->>Model: tool_references: [get_weather]
Model->>Tool: get_weather(location="San Francisco")
Tool-->>Model: Weather result
Model->>User: Response with weather info
Key points:
- Tools with
defer_loading: Trueare only loaded when Claude discovers them via search - Keep your 3-5 most frequently used tools as non-deferred for optimal performance
- Both variants search tool names, descriptions, argument names, and argument descriptions
See the Claude documentation for more details on tool search, including usage with MCP servers and client-side implementations.
To offer a deferred tool yourself instead of through search, change tools mid-conversation.
Response metadata
ai_msg = model.invoke(messages)
ai_msg.response_metadata
{
"id": "msg_013xU6FHEGEq76aP4RgFerVT",
"model": "claude-sonnet-4-6",
"stop_reason": "end_turn",
"stop_sequence": None,
"usage": {"input_tokens": 25, "output_tokens": 11},
}
Token usage metadata
ai_msg = model.invoke(messages)
ai_msg.usage_metadata
{"input_tokens": 25, "output_tokens": 11, "total_tokens": 36}
Message chunks containing token usage will be included during streaming by default:
stream = model.stream_events(messages, version="v3")
full_message = stream.output
full_message.usage_metadata
{"input_tokens": 25, "output_tokens": 11, "total_tokens": 36}
These can be disabled by setting stream_usage=False in the stream method or when initializing ChatAnthropic.
API reference
For detailed documentation of all features and configuration options, head to the ChatAnthropic API reference.