Skip to main content

Carrot AI Python SDK — automatic tracing for LLM calls

Project description

Carrot AI Python SDK

Automatic tracing for LLM calls. Wrap your OpenAI or Anthropic client — or patch litellm — and every call is captured as a structured trace in the Carrot platform with zero changes to your application code.

Installation

pip install carrot-ai

Or install from source (in the sdk/python/ directory):

pip install -e .

Quick Start

1. Wrap your client (one line)

import carrot_ai
from openai import OpenAI

carrot_ai.init(api_key="sk-...")  # your Carrot API key

client = carrot_ai.wrap(OpenAI())

# Use the client exactly as normal — traces are captured automatically
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)
print(response.choices[0].message.content)

That's it. Every create() call through the wrapped client is captured as a trace with the full request, response, token counts, and latency.

2. Works with Anthropic too

import carrot_ai
from anthropic import Anthropic

carrot_ai.init(api_key="sk-...")

client = carrot_ai.wrap(Anthropic())

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello!"}],
)

3. Streaming works transparently

client = carrot_ai.wrap(OpenAI())

stream = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Tell me a story"}],
    stream=True,
)

for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

# Trace is submitted automatically when the stream finishes

4. LiteLLM support

If you use litellm to call 100+ LLM providers through a single interface, one call patches everything:

import carrot_ai
import litellm

carrot_ai.init(api_key="sk-...")
carrot_ai.patch_litellm()

# Every litellm.completion() / litellm.acompletion() is now traced
response = litellm.completion(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "Hello!"}],
)

Streaming, token counts, and @trace nesting all work the same way as with wrap().

@trace Decorator

For multi-step pipelines (RAG, agents, chains), use the @trace decorator to capture the full workflow as a single trace. Any wrapped LLM calls inside the function are automatically linked as children.

import carrot_ai
from openai import OpenAI

carrot_ai.init(api_key="sk-...")
client = carrot_ai.wrap(OpenAI())


@carrot_ai.trace
def answer_question(question: str) -> str:
    # Step 1: retrieve context
    docs = search_knowledge_base(question)

    # Step 2: LLM call (auto-traced as a child)
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": f"Context:\n{docs}"},
            {"role": "user", "content": question},
        ],
    )

    return response.choices[0].message.content


# The decorator creates a parent trace for the full function,
# and the LLM call inside creates a child trace linked via parent_trace_id
result = answer_question("How do I reset my password?")

Decorator variants

# Bare decorator
@carrot_ai.trace
def my_function():
    ...

# With a custom name
@carrot_ai.trace("my-pipeline")
def my_function():
    ...

# With tags and metadata
@carrot_ai.trace(name="my-pipeline", tags=["production"], metadata={"version": "2"})
def my_function():
    ...

Async support

Both wrap() and @trace work with async clients and async functions:

from openai import AsyncOpenAI

client = carrot_ai.wrap(AsyncOpenAI())


@carrot_ai.trace
async def answer_question(question: str) -> str:
    response = await client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": question}],
    )
    return response.choices[0].message.content

Configuration

carrot_ai.init()

Parameter Type Default Description
api_key str CARROT_API_KEY env var Your Carrot API key
base_url str https://api.carrotlabs.ai API endpoint (override for self-hosted)
flush_interval float 5.0 Seconds between background batch flushes
batch_size int 50 Max traces per batch POST

Environment variables

Variable Description
CARROT_API_KEY API key (used if not passed to init())
CARROT_BASE_URL API base URL override

If CARROT_API_KEY is set, init() is called automatically on first use — you can skip the explicit init() call.

carrot_ai.wrap()

Parameter Type Default Description
client OpenAI | Anthropic required The LLM client to wrap
tags list[str] None Default tags added to every trace from this client

carrot_ai.patch_litellm()

Parameter Type Default Description
tags list[str] None Default tags added to every trace from litellm calls

Patches litellm.completion and litellm.acompletion in-place. Safe to call multiple times (only patches once).

carrot_ai.flush()

Force-flush any pending traces to the server. Useful before process exit in short-lived scripts:

carrot_ai.flush()

An atexit handler also flushes automatically on normal interpreter shutdown.

Proxy Header (Alternative)

If you already route inference through the Carrot proxy, you can capture traces without the SDK by adding a header:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.carrotlabs.ai/v1",
    api_key="sk-...",  # your Carrot API key
    default_headers={"X-Carrot-Trace": "true"},
)

# Traces are captured automatically by the proxy
response = client.chat.completions.create(
    model="my-model",
    messages=[{"role": "user", "content": "Hello!"}],
)

This only works for requests routed through the Carrot proxy. Use the SDK wrap() approach for calls sent directly to OpenAI, Anthropic, or any other provider.

What Gets Captured

Each trace includes:

Field Description
input Messages, model, temperature, and other request params
output.message Assistant response (content + tool calls)
metadata.provider "openai", "anthropic", or "litellm"
metadata.model Model name used
metadata.input_tokens Prompt token count
metadata.output_tokens Completion token count
metadata.latency_ms End-to-end call duration
metadata.source "sdk", "decorator", or "proxy"
metadata.parent_trace_id Links child LLM calls to @trace parent
status "success" or "error"
started_at / ended_at ISO 8601 timestamps

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

carrot_ai-0.1.0.tar.gz (49.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

carrot_ai-0.1.0-py3-none-any.whl (16.4 kB view details)

Uploaded Python 3

File details

Details for the file carrot_ai-0.1.0.tar.gz.

File metadata

  • Download URL: carrot_ai-0.1.0.tar.gz
  • Upload date:
  • Size: 49.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.8

File hashes

Hashes for carrot_ai-0.1.0.tar.gz
Algorithm Hash digest
SHA256 241d736c190ac81e36bd80ed7da96dc7cdbe9aa89ad9e5d9900a4689b97b2bc8
MD5 7f4def0edce144bc5227ea1f38aee0f9
BLAKE2b-256 f5dd42ef476bc5abc581f828989e62d50b75461571f754693b27dd7e3377dfe9

See more details on using hashes here.

File details

Details for the file carrot_ai-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: carrot_ai-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.8

File hashes

Hashes for carrot_ai-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ad32c7bbeaf30a0f07b15a1ea93098d95047036c2e511cbe1743610b6d68077a
MD5 314b7bf65158dcb79d94143fe67d8740
BLAKE2b-256 e1cf686afe0575a53fe00c68ba6d2f715bc3c1b562357074d229bdd05d4c13b8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page