Skip to main content
Install the integration extra:

Usage

Call patch_anthropic_client() once after creating your Anthropic client. All subsequent client.messages.create() and client.messages.stream() calls are traced automatically. No changes to individual API calls are needed. Works with both anthropic.Anthropic and anthropic.AsyncAnthropic - pass whichever client you use, sync or async, streaming or not.

What gets traced

By default, each messages.create() or messages.stream() call produces its own trace. The raw Anthropic SDK has no built-in concept of “tool call” or “retrieval”; those only exist as plain Python code around your messages.create() calls, so the patch can’t see them on its own. Use tracer.trace_tool_call() and tracer.trace_retrieval() (below) to record them manually so they show up in the trace’s performance summary.

Tool use

Anthropic tool use is a manual loop: you call messages.create(), execute whatever tool the model requested yourself, then call messages.create() again with the result. The tool execution happens in plain Python between the two API calls, so wrap it in tracer.trace_tool_call() to record it:

tracer.trace_tool_call()

Times the block automatically. Assign t.output before the block exits. For cases where you already have the timing and result computed, use tracer.record_tool_call() directly instead of the context manager:

Retrieval-augmented generation (RAG)

Like tool calls, a hand-rolled retrieval step (vector search, keyword lookup, etc.) run before messages.create() is invisible to the patch. Record it with tracer.trace_retrieval():

tracer.trace_retrieval()

Times the block automatically. Assign r.doc_count and r.output inside the block. The context manager attaches the retrieval to whichever trace is sent next: either the current active span (see below) or the next standalone messages.create() call.
A retrieval or tool call recorded with no active span is queued and merged into the very next trace this tracer sends, so call trace_retrieval() / trace_tool_call() immediately before the messages.create() call it belongs to.

Multi-call agentic loops

Tool-use loops and multi-turn agents call messages.create() more than once. By default each call is its own independent trace. Wrap the whole loop in with tracer.trace(...) to collapse it into one trace instead: every messages.create() call made while that span is active is folded in as an "LLM Call N" step (in call order, interleaved with any trace_tool_call() steps):
This works because patch_anthropic_client() checks tracer.current_span on every call: if a span is active on the current thread, the call is attached to it; otherwise it sends its own trace as usual. No other code changes are needed. The same patched client works standalone or inside a span.
Without the with tracer.trace(...) wrapper, a tool-use loop like the one above still produces a working trace per call, but the tool call recorded via trace_tool_call() attaches to whichever trace is sent next, which is the following turn, not the turn that requested the tool. Wrapping the loop in a span keeps everything on one trace, in the right order.

patch_anthropic_client() reference

Calling patch_anthropic_client() on an already-patched client is a no-op; it is safe to call multiple times.

Full example