AmazonBedrockTokenCounter
AmazonBedrockTokenCounter uses Amazon Bedrock's CountTokens API to count the input tokens of ChatMessage objects and optional tool schemas for a specific Bedrock model. The API returns an exact count without generating a response, so it does not incur generation costs.
| Import path | haystack_integrations.token_counters.amazon_bedrock.AmazonBedrockTokenCounter |
| Mandatory init variables | model: The Bedrock model ID or ARN to count for |
| API reference | Amazon Bedrock |
| GitHub link | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/amazon_bedrock |
| Package name | amazon-bedrock-haystack |
Because it calls a remote API, it needs AWS credentials and adds network latency to every count. Use it when you need exact, model-specific counts for models hosted on Bedrock. For local estimates, use ApproximateTokenCounter or TiktokenCounter.
The counter converts messages and tools to the Bedrock Converse format in the same way AmazonBedrockChatGenerator does, so the count matches what an equivalent Converse request consumes.
Installation
Install the amazon-bedrock-haystack package:
Usage
Token counts are model-specific, so pass the model you intend to generate with. The model must support the CountTokens API:
from haystack.dataclasses import ChatMessage
from haystack_integrations.token_counters.amazon_bedrock import (
AmazonBedrockTokenCounter,
)
messages = [
ChatMessage.from_system("You are a helpful assistant."),
ChatMessage.from_user("Explain retrieval-augmented generation."),
]
counter = AmazonBedrockTokenCounter(model="anthropic.claude-sonnet-4-20250514-v1:0")
token_count = counter.count(messages)
print(token_count)
The counter authenticates like the other Amazon Bedrock components. By default, it reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_DEFAULT_REGION, and AWS_PROFILE from the environment. You can also pass them as Haystack Secret arguments and configure the underlying Boto3 client with boto3_config:
from haystack.utils import Secret
counter = AmazonBedrockTokenCounter(
model="anthropic.claude-sonnet-4-20250514-v1:0",
aws_region_name=Secret.from_token("us-west-2"),
boto3_config={"read_timeout": 30},
)
To include the context consumed by tool schemas, pass the tools to count():
The counter creates its Bedrock 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 resources:
counter.warm_up()
...
counter.close()
Whole conversations only
Bedrock validates the input of CountTokens the same way it validates a Converse request: the conversation must begin with a user message, and each tool result must follow the tool call that produced it. The counter therefore measures complete conversations, and raises AmazonBedrockInferenceError for fragments such as a single tool result message.
Because of this, do not pass the counter to CompactionHook or a compactor. They count groups of messages and lone tool results, which Bedrock rejects. Use a local counter such as ApproximateTokenCounter for compaction, and use AmazonBedrockTokenCounter to size a full request before you send it.
Non-text content
The counter sends images and files to Bedrock in the same format as AmazonBedrockChatGenerator, so Bedrock counts them as part of the request instead of applying a flat estimate. It supports the same content types as the generator: JPEG, PNG, GIF, and WebP images, PDF and other document formats, and video files. Unsupported MIME types raise an error rather than being estimated.