AnthropicTokenCounter
AnthropicTokenCounter uses Anthropic's POST /v1/messages/count_tokens endpoint to count the input tokens of ChatMessage objects and optional tool schemas for a specific Claude model. The endpoint returns an exact count without generating a response, so it does not incur generation costs.
| Import path | haystack_integrations.token_counters.anthropic.AnthropicTokenCounter |
| Mandatory init variables | model: The Claude model to count for |
| API reference | Anthropic |
| GitHub link | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/anthropic |
| Package name | anthropic-haystack |
Because it calls a remote API, it needs an Anthropic API key and adds network latency to every count. Use it when you need exact, model-specific counts for Claude models. For local estimates, use ApproximateTokenCounter or TiktokenCounter.
Installation
Install the anthropic-haystack package:
Usage
Token counts are model-specific, so pass the model you intend to generate with:
from haystack.dataclasses import ChatMessage
from haystack_integrations.token_counters.anthropic import AnthropicTokenCounter
messages = [
ChatMessage.from_system("You are a helpful assistant."),
ChatMessage.from_user("Explain retrieval-augmented generation."),
]
counter = AnthropicTokenCounter(model="claude-sonnet-4-5")
token_count = counter.count(messages)
print(token_count)
By default, the counter reads the API key from the ANTHROPIC_API_KEY environment variable. You can also pass a Haystack Secret explicitly, and set the HTTP timeout and max_retries of the underlying Anthropic client:
from haystack.utils import Secret
counter = AnthropicTokenCounter(
model="claude-sonnet-4-5",
api_key=Secret.from_env_var("MY_ANTHROPIC_API_KEY"),
timeout=30.0,
max_retries=3,
)
To include the context consumed by tool schemas, pass the tools to count():
The counter creates its API client on the first call to count(). To create it during application startup instead, call warm_up() explicitly. Call close() when you are done with the counter to release the client's HTTP resources:
counter.warm_up()
...
counter.close()
Non-text content
Anthropic counts images and PDF files as part of the request, so the counter measures them exactly instead of applying a flat estimate. It supports the same content types as AnthropicChatGenerator: JPEG, PNG, GIF, and WebP images, and application/pdf files. Other MIME types raise an error rather than being estimated.
Use with compaction
Pass the counter to CompactionHook to size an Agent's conversation with the same tokenizer Claude uses:
from haystack.hooks.compaction import CompactionHook, SlidingWindowCompactor
compaction_hook = CompactionHook(
compactor=SlidingWindowCompactor(),
context_window=200_000,
token_counter=AnthropicTokenCounter(model="claude-sonnet-4-5"),
)
Keep in mind that the hook counts messages on every Agent step, so each compaction check costs an API round trip.