LangSmith provides wrapper functions that add automatic tracing to LLM provider clients. Simply wrap your existing client and all API calls are traced with no code changes.
Available wrappers
OpenAI
Trace OpenAI API calls including chat completions, completions, and streaming.
from langsmith import wrappers
import openai
client = wrappers.wrap_openai(openai.Client())
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Hello!"}]
)
# Automatically traced
View OpenAI wrapper documentation →
Supports:
- Chat completions
- Text completions
- Streaming (sync and async)
- Tool/function calling
- Token usage tracking
- Azure OpenAI
Anthropic
Trace Anthropic Claude API calls including messages, streaming, and tool use.
from langsmith import wrappers
import anthropic
client = wrappers.wrap_anthropic(anthropic.Anthropic())
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}]
)
# Automatically traced
View Anthropic wrapper documentation →
Supports:
- Messages API
- Streaming (sync and async)
- Tool use
- Prompt caching
- Extended thinking (Claude 3.7)
- Token usage tracking
Google Gemini (Beta)
Trace Google Gemini API calls including text generation, multimodal inputs, and tool calling.
from langsmith import wrappers
from google import genai
client = wrappers.wrap_gemini(genai.Client(api_key="your-api-key"))
response = client.models.generate_content(
model="gemini-2.5-flash",
contents="Hello!",
)
# Automatically traced
View Gemini wrapper documentation →
Supports:
- Text generation
- Streaming (sync and async)
- Tool/function calling
- Multimodal inputs (text + images)
- Image generation
- Token usage tracking
- Thinking models
Common parameters
All wrappers support these common parameters:
client = wrappers.wrap_<provider>(
client,
project_name="my-project", # Override default project
tags=["production", "api"], # Add tags to all traces
metadata={"version": "1.0"}, # Add metadata to all traces
client_=custom_ls_client # Use custom LangSmith client
)
The provider’s client instance to wrap.
LangSmith project to log traces to. Overrides environment variable.
Tags applied to all traces from this wrapped client.
Metadata applied to all traces from this wrapped client.
Custom LangSmith client for tracing. Uses default if not provided.
What gets traced
For all wrappers, the following information is automatically captured:
Request details
- Model name
- Provider name
- Temperature, max_tokens, and other parameters
- Messages/prompts
- Tool/function definitions
Response details
- Generated text
- Token usage (input, output, cached)
- Stop reason
- Tool calls and responses
- Finish reason
- Request timestamp
- Response latency
- Provider-specific metadata
- Error information (if request fails)
Usage patterns
Basic wrapping
Wrap your client once at initialization:
from langsmith import wrappers
import openai
# Initialize and wrap once
client = wrappers.wrap_openai(openai.Client())
# Use throughout your application
def generate(prompt):
return client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}]
)
Nested tracing
Combine with @traceable for hierarchical traces:
from langsmith import traceable, wrappers
import openai
client = wrappers.wrap_openai(openai.Client())
@traceable
def research_question(question: str) -> str:
# Generate search queries
queries = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": f"Generate search queries for: {question}"}]
)
# Synthesize answer
answer = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": f"Answer: {question}"}]
)
return answer.choices[0].message.content
# Creates trace tree:
# research_question
# ├── chat completion (queries)
# └── chat completion (answer)
Multi-provider applications
Wrap multiple providers in the same application:
from langsmith import wrappers
import openai
import anthropic
openai_client = wrappers.wrap_openai(
openai.Client(),
tags=["openai"]
)
anthropic_client = wrappers.wrap_anthropic(
anthropic.Anthropic(),
tags=["anthropic"]
)
def compare_responses(prompt: str):
openai_resp = openai_client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}]
)
anthropic_resp = anthropic_client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
messages=[{"role": "user", "content": prompt}]
)
# Both traced with provider-specific tags
return openai_resp, anthropic_resp
Testing with request caching
Combine wrappers with @test for cached testing:
import pytest
from langsmith import test, wrappers
import openai
# Enable caching: export LANGSMITH_TEST_CACHE=tests/cassettes
client = wrappers.wrap_openai(openai.Client())
@test(cached_hosts=["api.openai.com"])
def test_generation():
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Say hello"}]
)
assert "hello" in response.choices[0].message.content.lower()
# First run: real API call (cached)
# Subsequent runs: instant replay from cache
Async support
All wrappers support both sync and async clients:
import asyncio
from langsmith import wrappers
import openai
import anthropic
# Async OpenAI
openai_async = wrappers.wrap_openai(openai.AsyncClient())
# Async Anthropic
anthropic_async = wrappers.wrap_anthropic(anthropic.AsyncAnthropic())
async def generate():
# Both work seamlessly
openai_resp = await openai_async.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Hello"}]
)
anthropic_resp = await anthropic_async.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}]
)
return openai_resp, anthropic_resp
asyncio.run(generate())
Environment configuration
Wrappers respect LangSmith environment variables:
# Enable tracing
export LANGCHAIN_TRACING_V2=true
# Set default project
export LANGCHAIN_PROJECT=my-project
# Set API key
export LANGSMITH_API_KEY=your-key
You can override these per-client:
client = wrappers.wrap_openai(
openai.Client(),
project_name="override-project" # Overrides LANGCHAIN_PROJECT
)
Best practices
-
Wrap once, use everywhere: Initialize wrapped clients once at application startup
# config.py
from langsmith import wrappers
import openai
openai_client = wrappers.wrap_openai(openai.Client())
-
Use tags for organization: Tag by provider, model, or use case
client = wrappers.wrap_openai(
openai.Client(),
tags=["production", "gpt-4", "customer-support"]
)
-
Add version metadata: Track model and application versions
client = wrappers.wrap_anthropic(
anthropic.Anthropic(),
metadata={"app_version": "2.0.0", "model_version": "claude-3-5"}
)
-
Combine with @traceable: Create meaningful trace hierarchies
@traceable(name="rag-pipeline")
def rag_pipeline(query):
docs = retrieve(query) # Traced
response = llm_client.chat.completions.create(...) # Traced
return response
-
Handle errors: Wrappers trace errors automatically
try:
response = client.chat.completions.create(...)
except openai.APIError as e:
# Error is captured in trace
logger.error(f"OpenAI API error: {e}")
Wrappers add minimal overhead:
- Sync calls: Less than 1ms overhead for tracing
- Async calls: Negligible overhead (non-blocking)
- Streaming: No impact on stream throughput
- Background upload: Traces sent asynchronously
Disable tracing in production if needed:
export LANGCHAIN_TRACING_V2=false
Or use local-only tracing:
from langsmith import tracing_context
with tracing_context(enabled="local"):
# Traces collected but not uploaded
response = client.chat.completions.create(...)