Benchmarking the Anthropic Messages API
Profile Anthropic Messages API servers using AIPerf with the messages endpoint type.
Overview
The messages endpoint type targets the Anthropic Messages API (/v1/messages). Use it when benchmarking:
- Anthropic API directly (https://api.anthropic.com)
- Self-hosted servers that implement the Anthropic Messages protocol
- Proxy servers that translate to the
/v1/messagesformat
It supports streaming and non-streaming responses, text content, extended thinking, tool use, and raw_messages for verbatim trace replay.
Key Differences from OpenAI Chat
Basic Usage
Non-Streaming
Streaming
Enable streaming to measure time-to-first-token (TTFT) and inter-token latency (ITL):
With Synthetic Input Tokens
Control input and output token distributions:
With a System Prompt
Add a shared system prompt across all requests using --shared-system-prompt-length. The system message is placed in the top-level system field (not in the messages array), matching the Anthropic API specification:
Request Format
The endpoint produces payloads conforming to the Anthropic Messages API. A formatted request looks like:
Key formatting rules:
- Model: Taken from the last turn’s
modelfield, falling back to--model - Max tokens: Taken from the last turn’s
max_tokensfield, defaulting to 1024 if not set - Stream: Set from
--streamingflag (default:false) - System: Placed as a top-level string field when a system message is provided (never in the messages array)
- Tools: Included at the top level when tool definitions are present in the conversation
- System (raw): When a turn carries
raw_system(a list of content blocks), it is placed verbatim in the payload’s top-levelsystemfield, overriding the conversation-levelsystem_messagestring. See Per-block system prompts (raw_system) - Extra inputs: Merged into the payload via
--extra-inputs(e.g.,--extra-inputs temperature:0.7)
Simple Text Content
When a turn has a single text with a single content string and no images, audios, or videos, the content is sent as a plain string:
Complex Content Blocks
When a turn has multiple text items or images, content is sent as a list of typed blocks:
Raw Messages (Verbatim Replay)
When a turn has raw_messages set, those message dicts are expanded directly into the messages list. This is used by trace replay dataset types for faithful reproduction of tool use conversations:
Response Parsing
The endpoint handles both streaming and non-streaming responses.
Non-Streaming Responses
Non-streaming responses have "type": "message". The parser extracts content from the content array and usage from the usage object:
When both thinking and text blocks are present, the response is parsed as a ReasoningResponseData with separate content and reasoning fields:
Streaming Responses
Streaming uses Anthropic’s SSE event format. The endpoint handles the following event types:
A typical streaming sequence:
message_start— carries input token usagepingcontent_block_start— signals a new content blockcontent_block_delta(text_delta) — incremental text tokenscontent_block_stopmessage_delta— carries output token usage and stop reasonmessage_stop
Authentication
The Anthropic Messages endpoint uses x-api-key header authentication (not Authorization: Bearer):
The endpoint also sets the anthropic-version: 2023-06-01 header by default. To override it or add beta headers (e.g., for extended thinking), use --header:
Custom headers are merged with the defaults. If you provide anthropic-version via --header, it takes precedence.
Extra Inputs
Pass additional API parameters with --extra-inputs:
These are merged directly into the request payload, producing:
Custom Dataset Integration
Single-Turn with Custom Prompts
Multi-Turn Conversations
Server Token Counts
To use token counts reported by the server (from usage fields) instead of client-side tokenization:
The Anthropic Messages API returns usage data at two points during streaming:
message_start: reportsinput_tokens(and cache-related fields)message_delta: reportsoutput_tokens
The usage object may include cache_creation_input_tokens and cache_read_input_tokens when prompt caching is active.
Advanced features
Per-block system prompts (raw_system)
The conversation-level system_message string (set, for example, by --shared-system-prompt-length) is rendered as a plain top-level system: "..." string. That works for most cases, but cannot express Anthropic’s per-block extensions — most importantly cache_control: {"type": "ephemeral"} for prompt caching.
To opt in, set raw_system on a Turn to a list of content blocks. The endpoint resolves it the same way as raw_tools: walking the turn list from the end and taking the first non-None value (base_endpoint.py::_latest_turn_attr). When set, it wins over system_message:
Notes:
- Latest-non-
Noneturn wins — a FORK-mode DAG child that does not redeclareraw_systemstill inherits the parent’s value. - The field is Anthropic-specific. Other endpoints (
chat,responses, …) ignore it. - Block contents flow into ISL accounting via the endpoint’s system-prompt walk; see Input token accounting (ISL) below.
raw_systemis currently populated by trace-replay loaders that ingest Anthropic-shaped traces; programmatic callers buildingTurnobjects directly can set it as well.
Audio and video are unsupported
The Anthropic Messages API does not accept audio or video content blocks. _render_audio_part and _render_video_part raise NotImplementedError immediately so a misuse fails at format_payload time with a clear error rather than producing an opaque server 4xx after dispatch:
This is intentional. If your dataset has audio or video, route it to an endpoint that supports it (for example, the OpenAI chat endpoint with a multimodal-capable model) — do not try to coerce it into messages.
Internals
Input token accounting (ISL)
When you set --synthetic-input-tokens-mean, AIPerf needs an accurate count of the input tokens it just placed in the request payload to hit your target. The base endpoint walks messages content parts dispatched via PART_TYPES. Anthropic’s extract_payload_inputs extends that walk in three places (helpers in anthropic_messages.py):
The endpoint also overrides PART_TYPES itself: IMAGE is the bare string image (Anthropic’s shape) rather than OpenAI’s image_url, and AUDIO and VIDEO are explicitly empty sets so the walk does not miscount parts that happen to share OpenAI’s type names.
If your synthetic ISL targeting was undercounting agentic / tool-heavy traces before, this is what changed.
Assistant-turn replay (DAG / FORK mode)
For DAG datasets (dag_jsonl) where a child turn forks from a parent’s history, AIPerf replays the parent’s assistant reply as part of the child request’s messages. The base implementation captures only the streamed text. Anthropic’s build_assistant_turn reassembles the full content array — thinking, then text, then tool_use — so a FORK-mode child sees the complete reply the model originally produced.
Reassembly rules (anthropic_messages.py):
- Text — accumulated from
content_block_deltaevents withdelta.type == "text_delta". - Thinking — keyed by SSE
index;thinking_deltafragments append tothinking,signature_deltafragments append tosignature. Both round-trip — the server requires the matching signature to accept a thinking block on replay. - Tool use — keyed by SSE
index;input_json_delta.partial_jsonfragments concatenate into a raw string, parsed once at finalise. Malformed JSON is preserved as a string underinputrather than dropped, so the server rejects it loudly instead of AIPerf silently losing data. - Non-streaming
type=messageresponses are absorbed by walking the fullcontentarray directly.
When neither thinking nor tool_use blocks are present, build_assistant_turn falls back to the base text-only behaviour — callers that don’t use either feature see no change.
- Tokenizer: Anthropic models use a proprietary tokenizer. When using
--use-server-token-count, you still need a tokenizer for dataset generation —--tokenizer builtinuses a zero-network-access tiktoken tokenizer (also auto-substituted for obvious placeholder model names). For accurate client-side token counts, use a tokenizer that matches the model. - Max tokens default: The endpoint defaults to
max_tokens: 1024when no value is specified in the turn data. Use--oslto control output sequence length. - Audio and video: The Anthropic Messages API does not support audio or video content blocks.
_render_audio_part/_render_video_partraiseNotImplementedErrorso the failure surfaces atformat_payloadtime. See Audio and video are unsupported. - Custom endpoint path: The default path is
/v1/messages. Override with--custom-endpoint /my/pathif your server uses a different path. - Connection strategy: For multi-turn benchmarks where server-side session affinity matters, use
--connection-reuse-strategy sticky-user-sessions.