Skip to main content

Tracify Python SDK

Observability and tracing for AI agents. Gain full visibility into your agent's decision-making process, tool usage, and LLM costs.

Installation

pip install tracify-sdk

Quickstart

  1. Get your API Key from the Tracify Dashboard.
  2. Set it as an environment variable:
export TRACIFY_API_KEY=your_sk_live_...
  1. Instrument your agent:
from tracify import trace_agent, llm_call, tool_call

@trace_agent(environment="development", release="quickstart")
async def my_agent(query: str):
    # LLM Call
    llm_call(
        input_data=query,
        output_data="Thinking...",
        model_id="gpt-4o",
        cost_usd=0.002,
        latency_ms=800
    )
    
    # Tool Use
    tool_call(
        tool_name="web_search",
        input_data={"q": query},
        output_data="Found results...",
        latency_ms=1200
    )
    
    return "Final Answer"

Steps

Inside a @trace_agent function, every step you record is linked to the step it ran in, so the trace graph shows which step called which and how loops repeat. Use span for a block and observe for a function:

import tracify

@tracify.observe(type="tool")
def search_docs(query):
    return search(query)

@tracify.trace_agent()
def answer(question):
    for turn in range(5):
        with tracify.span("think", type="agent"):
            with tracify.span("chat", type="llm", input=question) as step:
                reply = call_model(question)
                step.set_output(reply.text)
                step.set(model="claude-sonnet-5-5", input_tokens=reply.usage.input, output_tokens=reply.usage.output)
            if reply.done:
                return reply.text
            search_docs(reply.query)

type is one of agent, llm, tool, retrieval or span. Errors are recorded with their type and message. Concurrent runs (threads or asyncio tasks) stay in separate traces. Inputs and outputs have obvious secrets (bearer tokens, API keys, JWTs, password= values) removed and are capped at 10,000 characters; avoid sending anything else you would not want stored.

Features

  • @trace_agent Decorator: Automatically captures run lifecycle and errors.
  • Granular Spans: Manually record LLMs, tools, and custom decisions.
  • Cost Tracking: Monitor your infrastructure spend in real-time.
  • Asynchronous & Synchronous Support: Works with async/await or standard functions.
  • Session context: Attach session_id, end_user_id, environment, release, and tags to connect related traces.

Feedback and evaluation scores

Pass project_id when constructing the client to attach end-user feedback and typed scores to traces:

client = TracifyClient(project_id="your-project-id")
client.feedback(run_id, True, kind="thumb", comment="Helpful answer")
client.score(run_id, "answer_quality", 0.92, data_type="numeric")

Feedback and scores use the same API key as ingestion and do not interrupt the agent when delivery fails.

Prompt deployment

Resolve a deployed prompt without shipping a new application build:

deployed = client.get_prompt("support-agent", "production")
client.ingest(spanType="llm", input=question, output=answer, promptVersionId=deployed["version"]["id"])

Prompt responses are cached for 60 seconds by default. Use cache_ttl_seconds=0 or provide a fallback for development and guaranteed-availability behavior.

License

MIT

Provider integrations (0.4.0)

Install the optional provider/framework extras you use: pip install 'tracify-sdk[openai,anthropic,langgraph]'. Set TRACIFY_API_KEY and the existing regional configuration.

import tracify
from openai import OpenAI, AsyncOpenAI
from anthropic import Anthropic

openai = tracify.wrap_openai(OpenAI())
anthropic = tracify.wrap_anthropic(Anthropic())
async_openai = tracify.wrap_openai(AsyncOpenAI())
# Existing create calls keep their provider response types and exceptions.
reply = openai.responses.create(model=MODEL, input="Hello")
with anthropic.messages.stream(model=MODEL, max_tokens=100,
        messages=[{"role": "user", "content": "Hello"}]) as stream:
    for text in stream.text_stream:
        print(text, end="")

# Add a callback to a compiled LangGraph invocation.
graph.invoke(inputs, config={"callbacks": [tracify.langgraph_callback()]})

Wrap sync or async clients once. Supported: OpenAI chat completions and Responses create APIs, including streams; Anthropic messages create/stream and beta equivalents, including sync/async context managers, text streams and final messages. Close streams when stopping early. Raw response resources and unsupported convenience methods are passed through without instrumentation.

Calls inside trace_agent/span inherit their run/parent and custom client. Standalone calls receive an independent completed root. LangGraph callbacks preserve graph/node/tool/model parent IDs and concurrent runs. Avoid using both framework model callbacks and a provider wrapper for the same call. Provider packages remain optional; newer framework extras may require a newer Python than the core SDK.

Options: client=custom_client, name="my-agent", capture_input=False, capture_output=False. Existing redaction/size caps apply. Records include model, tokens, latency, TTFT, failures and raw usage metadata. Costs default to zero with costKnown=False; supply calculate_cost=lambda usage: ... with your own current provider rate card. The callback receives provider, model, input_tokens, output_tokens, and raw usage (including cache details). Missing usage is not estimated. Telemetry failures do not change provider results or exceptions.

Anthropic total input tokens include uncached input plus cache reads and cache writes; the original usage breakdown remains in metadata for rate-card calculations. See the provider’s token breakdown.

Framework one-liners

import tracify

tools = tracify.trace_tools({"search_docs": search_docs, "send_email": send_email})  # plain or async functions
client = tracify.wrap_openai(OpenAI())   # also wrap_anthropic, langgraph_callback

Copy-paste starters live in templates/.

Sampling, redaction and clearer errors

client = tracify.TracifyClient(
    sample_rate=0.1,                                   # record about 1 in 10 runs; each run is kept or dropped whole
    redact={"pii": True, "patterns": [re.compile(r"ACME-\d{6}")]},  # emails, phones, card numbers + your own
    on_error=lambda error: log(str(error)),            # problems come with a plain-language fix (error.hint)
)

Spans that report an error are kept even when their run was not sampled (keep_errors=False turns that off). Secrets such as bearer tokens and API keys are always removed.

Metadata

Release files for tracify-sdk 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tracify-sdk 0.5.0
File Size Uploaded Provenance
tracify_sdk-0.5.0.tar.gz 29.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for tracify-sdk 0.5.0
File Interpreter ABI Platform
tracify_sdk-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 49.1 kB

Release files / tracify_sdk-0.5.0.tar.gz

Download URL tracify_sdk-0.5.0.tar.gz
Size 29.0 kB
Tags Source
SHA-256 checksum
How to use checksums
7aa75bb6ed4641d1c47fd4a9e4c856042d7a5461bb09c2d2e50a0589dd26a54d
BLAKE2b-256 checksum
How to use checksums
cf372b400a723ea081f4b832a45876d93e60e71058b1203ba66d2198a7749162
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / tracify_sdk-0.5.0-py3-none-any.whl

Download URL tracify_sdk-0.5.0-py3-none-any.whl
Size 20.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bbf7e2b8596de7d7716199861ace4e033904024ac0e3ea9c6f3742d514921f0f
BLAKE2b-256 checksum
How to use checksums
55d271e8b33c55ba964ee1cb91c3f5e03d94401b7b012b93418991c17189472a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Security for tracify-sdk 0.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page