Trace, monitor, and evaluate AI agents and LLM applications with simple decorators
Project description
Auditi Python SDK
Official Python SDK for Auditi - AI/LLM Evaluation and Monitoring Platform.
Trace, monitor, and evaluate your AI agents with minimal code changes.
Features
- ๐ฏ Simple Decorators - Add tracing with just
@trace_agent,@trace_tool, and@trace_llm - ๐ Async & Sync Support - Works with both synchronous and asynchronous functions
- ๐ค Multi-Provider - Auto-detects OpenAI, Anthropic, and Google Gemini models
- ๐ฐ Cost Tracking - Automatic token usage and cost calculation
- ๐ Standalone Traces - Simple LLM calls don't need agent wrappers
- ๐ ๏ธ Custom Evaluators - Implement your own evaluation logic
- ๐ Production Ready - FastAPI, LangChain, and framework integrations
Installation
pip install auditi
Or install from source:
git clone https://github.com/deduu/auditi
cd auditi
pip install -e .
Quick Start
1. Initialize the SDK
import auditi
# For production
auditi.init(api_key="your-api-key", base_url="https://api.auditi.dev")
# For local development (prints to console)
auditi.init() # Uses localhost:8000 by default
2. Trace Your Agent
from auditi import trace_agent, trace_tool, trace_llm
import openai
@trace_agent(name="customer_support")
def customer_support_agent(user_message: str, user_id: str = None):
"""Your existing agent - just add the decorator!"""
# Fetch user context
context = get_user_context(user_id)
# Search knowledge base
docs = search_knowledge_base(user_message)
# Generate response
response = call_openai(user_message, context, docs)
return response
@trace_tool(name="search_kb")
def search_knowledge_base(query: str):
"""Tool calls are automatically captured as spans."""
results = vector_db.similarity_search(query, k=5)
return results
@trace_llm(model="gpt-4o")
def call_openai(message: str, context: dict, docs: list):
"""LLM calls capture usage metrics and costs."""
response = openai.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": f"Context: {context}"},
{"role": "user", "content": message}
]
)
return response.choices[0].message.content
3. View Traces in Auditi Dashboard
That's it! Every call to customer_support_agent() will:
- โ Capture user input and assistant output
- โ Track all tool calls and LLM calls as spans
- โ Calculate token usage and costs
- โ Send to Auditi for evaluation and monitoring
Usage Patterns
Pattern 1: Simple LLM Calls (Standalone)
For simple chatbots or single LLM calls, you don't need @trace_agent:
@trace_llm(standalone=True)
def simple_chat(prompt: str):
"""Creates its own trace automatically - no agent wrapper needed!"""
response = openai.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
# This creates a complete trace automatically
result = simple_chat("What is the capital of France?")
Pattern 2: Complex Agents with Tools
For multi-step agentic workflows:
@trace_agent(name="research_assistant")
def research_assistant(query: str, user_id: str):
"""Main agent creates ONE trace that captures all spans."""
# Step 1: Web search (creates a tool span)
search_results = web_search(query)
# Step 2: Generate initial response (creates an LLM span)
initial_response = generate_response(query, search_results)
# Step 3: Reflect on quality (creates another LLM span)
quality_score = evaluate_response(initial_response)
# Step 4: Refine if needed (creates another LLM span)
if quality_score < 0.7:
final_response = refine_response(initial_response, search_results)
else:
final_response = initial_response
return final_response
@trace_tool("web_search")
def web_search(query: str):
# Search implementation
return results
@trace_llm(model="gpt-4o")
def generate_response(query: str, context: list):
# LLM call
return response
@trace_llm(model="gpt-4o")
def evaluate_response(text: str):
# Another LLM call for reflection
return score
Pattern 3: Embeddings and Retrieval
Embedding and retrieval operations are always standalone by default:
@trace_embedding()
def embed_text(text: str):
"""Creates a standalone trace for embedding."""
response = openai.embeddings.create(
input=text,
model="text-embedding-3-small"
)
return response.data[0].embedding
@trace_retrieval("vector_search")
def search_docs(query: str):
"""Creates a standalone trace for retrieval."""
embedding = embed_text(query)
results = vector_db.similarity_search(embedding, k=5)
return results
Pattern 4: RAG Pipeline
Combining all patterns in a full RAG workflow:
@trace_agent(name="rag_assistant")
def rag_query(question: str):
"""Full RAG pipeline - all steps captured as spans."""
# Embedding step (creates span)
query_embedding = embed_query(question)
# Retrieval step (creates span)
docs = retrieve_docs(query_embedding)
# LLM step (creates span)
answer = generate_answer(question, docs)
return answer
@trace_embedding()
def embed_query(text: str):
# Embedding logic
return embedding
@trace_retrieval("doc_search")
def retrieve_docs(embedding: list):
# Vector search logic
return documents
@trace_llm(model="gpt-4o")
def generate_answer(question: str, context: list):
# LLM generation
return answer
Integration Examples
FastAPI Integration
from fastapi import FastAPI
from auditi import trace_agent, trace_tool, trace_llm
app = FastAPI()
@app.post("/chat")
async def chat_endpoint(message: str, user_id: str):
response = await process_chat(message, user_id)
return {"response": response}
@trace_agent(name="chat_agent")
async def process_chat(message: str, user_id: str):
"""Async agent - fully supported!"""
context = await fetch_user_context(user_id)
kb_results = await search_knowledge_base(message)
response = await call_llm(message, context, kb_results)
return response
@trace_tool("fetch_context")
async def fetch_user_context(user_id: str):
# Async tool call
return context
@trace_llm(model="gpt-4o")
async def call_llm(message: str, context: dict, docs: list):
# Async LLM call
return response
LangChain Integration
from langchain.agents import AgentExecutor, create_openai_functions_agent
from auditi import trace_agent, trace_tool
@trace_agent(name="langchain_agent")
def run_langchain_agent(query: str):
"""Wrap your LangChain execution."""
agent_executor = create_agent()
result = agent_executor.invoke({"input": query})
return result["output"]
@trace_tool("vector_search")
def vector_search(query: str):
"""Individual tools can be traced too."""
return vectorstore.similarity_search(query)
Custom Evaluators
Implement custom evaluation logic to assess trace quality:
from auditi import BaseEvaluator, EvaluationResult, TraceInput
class ResponseQualityEvaluator(BaseEvaluator):
def evaluate(self, trace: TraceInput) -> EvaluationResult:
"""Evaluate response quality based on custom criteria."""
# Access trace data
user_input = trace.user_input
assistant_output = trace.assistant_output
spans = trace.spans
# Your evaluation logic
score = self._calculate_quality_score(assistant_output)
# Return evaluation result
if score >= 0.8:
status = "pass"
reason = "High quality response"
elif score >= 0.6:
status = "pass"
reason = "Acceptable quality"
else:
status = "fail"
reason = "Low quality response - needs improvement"
return EvaluationResult(
status=status,
score=score,
reason=reason
)
def _calculate_quality_score(self, text: str) -> float:
# Your scoring logic here
return 0.85
# Use with trace_agent
@trace_agent(name="assistant", evaluator=ResponseQualityEvaluator())
def my_agent(message: str):
response = generate_response(message)
return response
Multi-Provider Support
Auditi automatically detects and handles multiple LLM providers:
# OpenAI
@trace_llm(model="gpt-4o")
def call_openai(prompt: str):
response = openai.chat.completions.create(...)
return response # Auto-extracts usage from response.usage
# Anthropic Claude
@trace_llm(model="claude-sonnet-4-5-20250929")
def call_anthropic(prompt: str):
response = anthropic.messages.create(...)
return response # Auto-extracts from response.usage
# Google Gemini
@trace_llm(model="gemini-2.0-flash-exp")
def call_google(prompt: str):
response = genai.generate_content(...)
return response # Auto-extracts from response.usage_metadata
Supported Providers:
- โ OpenAI (GPT-4, GPT-4o, GPT-3.5, etc.)
- โ Anthropic (Claude 3.5, Claude 3, Claude 2)
- โ Google (Gemini Pro, Gemini Flash)
- โ Auto-detection from model names and response structures
- โ Automatic cost calculation with up-to-date pricing
Configuration
Environment Variables
# Enable debug logging
export AUDITI_DEBUG=true
# Set API key
export AUDITI_API_KEY=your-api-key
# Set base URL
export AUDITI_BASE_URL=https://api.auditi.dev
Programmatic Configuration
import auditi
# Production setup
auditi.init(
api_key="your-api-key",
base_url="https://api.auditi.dev"
)
# Development setup (prints traces to console)
from auditi.transport import DebugTransport
auditi.init(
transport=DebugTransport() # Prints to console instead of sending
)
API Reference
Decorators
@trace_agent(name=None, user_id=None, evaluator=None)
Trace a top-level agent function. Creates a complete trace with user input, assistant output, and all spans.
Parameters:
name(str, optional): Custom name for the agentuser_id(str, optional): User identifierevaluator(BaseEvaluator, optional): Custom evaluator instance
Returns: The decorated function's return value becomes assistant_output
@trace_tool(name=None, standalone=False)
Trace a tool/function call within an agent.
Parameters:
name(str, optional): Custom name for the toolstandalone(bool): If True, creates a standalone trace when not inside@trace_agent
@trace_llm(name=None, model=None, standalone=False)
Trace an LLM call within an agent.
Parameters:
name(str, optional): Custom name for the LLM callmodel(str, optional): Model name (auto-detected from response if not provided)standalone(bool): If True, creates a standalone trace when not inside@trace_agent
@trace_embedding(name=None, model=None)
Trace an embedding operation. Always creates a standalone trace when not inside @trace_agent.
Parameters:
name(str, optional): Custom name for the embedding operationmodel(str, optional): Model name (auto-detected if not provided)
@trace_retrieval(name=None)
Trace a retrieval/search operation. Always creates a standalone trace when not inside @trace_agent.
Parameters:
name(str, optional): Custom name for the retrieval operation
Types
TraceInput
Complete trace data model.
Fields:
trace_id(str): Unique trace identifiername(str): Agent nameuser_input(str): User's messageassistant_output(str): Agent's responseuser_id(str, optional): User identifierconversation_id(str, optional): Conversation/session identifierspans(List[SpanInput]): List of spans (tools, LLM calls)input_tokens(int): Total input tokensoutput_tokens(int): Total output tokenstotal_tokens(int): Total tokenscost(float): Total cost in USDprocessing_time(float): Total processing time in secondsmetadata(dict, optional): Additional metadatatimestamp(datetime): Trace timestamp
SpanInput
Individual span within a trace.
Fields:
span_id(str): Unique span identifiername(str): Span namespan_type(str): Type: "tool", "llm", "embedding", "retrieval"inputs(dict): Input parametersoutputs(Any): Output valueinput_tokens(int, optional): Input tokens (for LLM spans)output_tokens(int, optional): Output tokens (for LLM spans)total_tokens(int, optional): Total tokenscost(float, optional): Cost in USDmodel(str, optional): Model nameprocessing_time(float, optional): Processing time in secondstimestamp(datetime): Span timestamp
EvaluationResult
Evaluation result data.
Fields:
status(str): "pass" or "fail"score(float, optional): Evaluation scorereason(str, optional): Explanationmetadata(dict, optional): Additional evaluation data
Transport
SyncHttpTransport(api_key, base_url)
Default synchronous HTTP transport.
Parameters:
api_key(str): API key for authenticationbase_url(str): Base URL of Auditi API
DebugTransport()
Debug transport that prints traces to console. Useful for local development.
Context Management
from auditi.context import (
get_current_trace,
set_current_trace,
get_current_span,
set_context,
get_context
)
# Get current trace (if inside @trace_agent)
trace = get_current_trace()
# Get current span (if inside @trace_tool/@trace_llm)
span = get_current_span()
# Set global context (available across all traces)
set_context({"environment": "production", "version": "1.0"})
Development
Setup
# Clone the repository
git clone https://github.com/deduu/auditi
cd auditi
# Install dev dependencies
pip install -e ".[dev]"
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=auditi --cov-report=html
# Run specific test file
pytest tests/test_decorators.py -v
# Run async tests
pytest tests/test_decorators.py -k async
Code Quality
# Format code
black auditi/
# Lint code
ruff auditi/
# Type check
mypy auditi/
Project Structure
auditi/
โโโ __init__.py # Package initialization
โโโ client.py # SDK client and initialization
โโโ context.py # Context management for traces/spans
โโโ decorators.py # Core decorators (@trace_agent, etc.)
โโโ evaluator.py # Base evaluator class
โโโ events.py # Event types for streaming
โโโ transport.py # Transport layer (HTTP, Debug)
โโโ providers/ # LLM provider abstractions
โ โโโ __init__.py
โ โโโ base.py # Base provider interface
โ โโโ openai.py # OpenAI provider
โ โโโ anthropic.py # Anthropic provider
โ โโโ google.py # Google provider
โ โโโ registry.py # Provider auto-detection
โโโ types/
โโโ __init__.py
โโโ api_types.py # Pydantic models for API types
Examples
The examples/ directory contains complete working examples:
01_basic_integration.py- Simple chatbot integration02_fastapi_integration.py- Production FastAPI integration03_langchain_integration.py- LangChain agent integration04_simple_llm_traces.py- Standalone LLM call tracing05_embedding_traces.py- Embedding and retrieval tracing
Run any example:
# Enable debug output
export AUDITI_DEBUG=true
# Run example
python examples/01_basic_integration.py
Troubleshooting
Traces Not Appearing
-
Check initialization:
import auditi auditi.init(api_key="your-key", base_url="https://api.auditi.dev")
-
Enable debug logging:
export AUDITI_DEBUG=true python your_script.py
-
Verify decorator order:
@trace_agentshould be the outermost decorator@trace_tooland@trace_llmshould be inside functions called by the agent
Missing Usage Metrics
Make sure your LLM call returns the full response object:
@trace_llm(model="gpt-4o")
def call_openai(prompt: str):
response = openai.chat.completions.create(...)
return response # โ
Return full response, not just .choices[0].message.content
Async Functions Not Working
Both sync and async functions are supported. Make sure to use await:
@trace_agent(name="async_agent")
async def my_agent(message: str):
result = await async_llm_call(message)
return result
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License - see LICENSE file for details.
Links
- GitHub: https://github.com/deduu/auditi
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file auditi-0.1.0.tar.gz.
File metadata
- Download URL: auditi-0.1.0.tar.gz
- Upload date:
- Size: 44.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f24511e8df4ac874a0c54cbaf56d78a064a992591cba943e101e436ae52048ce
|
|
| MD5 |
1f86497e74b5f556efd0148e73d21836
|
|
| BLAKE2b-256 |
21d120880143ab727371c53e798d6b4f0f723cd11127434faa0dbfad686e7d43
|
File details
Details for the file auditi-0.1.0-py3-none-any.whl.
File metadata
- Download URL: auditi-0.1.0-py3-none-any.whl
- Upload date:
- Size: 32.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
032edd47d11f038c8539e50560cd951e29a056d6da2f8548afba3dc8ebd01f93
|
|
| MD5 |
09e7bbb0c3a27e3812c8b6ff2594b309
|
|
| BLAKE2b-256 |
94c0d61d0dd2d346d0439211fafb8dfb4bf9bd35c0e8f125c33e55c19029b1f7
|