Documentation Index
Fetch the complete documentation index at: https://docs.zeroeval.com/llms.txt
Use this file to discover all available pages before exploring further.
The ZeroEval Python SDK automatically traces intruments the supported integrations, meaning the only thing to do is to initialize the SDK before importing the frameworks you want to trace.
OpenAI
import zeroeval as ze
ze.init()
import openai
client = openai.OpenAI()
# This call is automatically traced
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Hello!"}]
)
# Streaming is also automatically traced
stream = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Tell me a story"}],
stream=True
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
LangChain
import zeroeval as ze
ze.init()
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
# All components are automatically traced
model = ChatOpenAI()
prompt = ChatPromptTemplate.from_template("Tell me about {topic}")
chain = prompt | model
response = chain.invoke({"topic": "AI"})
LangGraph
import zeroeval as ze
ze.init()
from langgraph.graph import StateGraph, START, END
from langchain_core.messages import HumanMessage
# Define a multi-node graph
workflow = StateGraph(AgentState)
workflow.add_node("reasoning", reasoning_node)
workflow.add_node("agent", agent_node)
workflow.add_node("tools", tool_node)
workflow.add_conditional_edges(
"agent",
should_continue,
{"tools": "tools", "end": END}
)
app = workflow.compile()
# Full graph execution is automatically traced
result = app.invoke({"messages": [HumanMessage(content="Help me plan a trip")]})
# Streaming is also supported
for chunk in app.stream({"messages": [HumanMessage(content="Hello")]}):
print(chunk)
PydanticAI
PydanticAI agents are automatically traced, including multi-turn conversations. The SDK ensures that all LLM calls within an agent execution share the same trace, and consecutive conversation turns share the same trace ID when using shared message history.
import zeroeval as ze
ze.init()
from pydantic_ai import Agent
from pydantic import BaseModel
class Response(BaseModel):
message: str
sentiment: str
# Create an agent with structured output
agent = Agent(
model="openai:gpt-4o-mini",
output_type=Response,
system_prompt="You are a helpful assistant."
)
# Single execution - automatically traced
result = await agent.run("Hello!")
# Multi-turn conversation - all turns share the same trace
message_history = []
async with agent.iter("First message", message_history=message_history) as run:
async for node in run:
pass
message_history = run.result.all_messages()
# Second turn reuses the same trace_id
async with agent.iter("Follow-up message", message_history=message_history) as run:
async for node in run:
pass
message_history = run.result.all_messages()
When you pass the same message_history list across multiple agent runs, ZeroEval automatically groups all runs under a single trace. This provides a unified view of the entire conversation.
LiveKit
The SDK automatically creates traces for LiveKit agents, including events from the following plugins:
- Cartesia (TTS)
- Deepgram (STT)
- OpenAI (LLM)
import zeroeval as ze
ze.init()
from livekit import agents
from livekit.agents import AgentSession, Agent
from livekit.plugins import openai
async def entrypoint(ctx: agents.JobContext):
await ctx.connect()
# All agent sessions are automatically traced
session = AgentSession(
llm=openai.realtime.RealtimeModel(voice="coral")
)
await session.start(
room=ctx.room,
agent=Agent(instructions="You are a helpful voice AI assistant.")
)
# Agent interactions are automatically captured
await session.generate_reply(
instructions="Greet the user and offer your assistance."
)
if __name__ == "__main__":
agents.cli.run_app(agents.WorkerOptions(entrypoint_fnc=entrypoint))
Claude Agent SDK
Anthropic’s Python Claude Agent SDK (claude-agent-sdk) is automatically traced. Each agent turn becomes its own ZeroEval trace, and all turns in the same Claude conversation are grouped into one ZeroEval session via the claude_session_id attribute.
One-shot query
import zeroeval as ze
ze.init()
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
from claude_agent_sdk.types import AssistantMessage, TextBlock
async for message in query(
prompt="What are the three largest cities in Japan?",
options=ClaudeAgentOptions(
permission_mode="plan",
max_turns=3,
),
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)
elif isinstance(message, ResultMessage):
print(f"Cost: ${message.total_cost_usd:.4f}")
Multi-turn conversation
With ClaudeSDKClient, each query() call opens a new trace while all turns in the same conversation share a single session.
import zeroeval as ze
ze.init()
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions
from claude_agent_sdk.types import AssistantMessage, ResultMessage, TextBlock
async with ClaudeSDKClient(
options=ClaudeAgentOptions(permission_mode="plan", max_turns=3)
) as client:
await client.query("What is the population of Tokyo?")
async for msg in client.receive_response():
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
print(block.text)
await client.query("How does that compare to Osaka?")
async for msg in client.receive_response():
if isinstance(msg, AssistantMessage):
for block in msg.content:
if isinstance(block, TextBlock):
print(block.text)
ZeroEval automatically captures assistant output, tool use and tool result summaries, total cost, token usage, stop reason, permission decisions from can_use_tool callbacks, hook metadata, and partial stream event counts when include_partial_messages is enabled.
To disable the Claude Agent SDK integration, pass disabled_integrations=["claude_agent"] to ze.init() or set ZEROEVAL_DISABLED_INTEGRATIONS=claude_agent.
Only public Claude Agent SDK APIs are instrumented — private transport and protocol internals are not patched. The Claude CLI’s own OpenTelemetry output (beta) is separate from this integration; if you need both, enable CLAUDE_CODE_ENABLE_TELEMETRY=1 in ClaudeAgentOptions.env and point an OTLP collector at each backend independently.