All Providers
A multi-provider showcase that calls OpenAI (gpt-4o-mini), Anthropic (claude-sonnet-4-5), and LiteLLM/Groq (llama-3.3-70b-versatile) within a single trace. Each provider runs as a dedicated child agent, and the orchestrator compares all responses with a @reasoning decorator. Demonstrates how to unify diverse LLM providers under a single observability trace with provider-specific tagging and cross-provider quality comparison.
This example requires OPENAI_API_KEY, ANTHROPIC_API_KEY, WAXELL_API_KEY, and WAXELL_API_URL. Use --dry-run to run without any API keys.
Architecture
Key Code
Provider execution order decision
The orchestrator decides whether to prioritize speed (Groq first), quality (OpenAI/Anthropic first), or round-robin based on query complexity.
@waxell.decision(name="choose_provider_order", options=["fastest_first", "quality_first", "round_robin"])
async def choose_provider_order(query: str, num_providers: int) -> dict:
word_count = len(query.split())
if word_count < 10:
return {
"chosen": "fastest_first",
"reasoning": f"Short query ({word_count} words) -- prioritize low-latency providers",
"confidence": 0.88,
}
elif word_count > 25:
return {
"chosen": "quality_first",
"reasoning": f"Complex query ({word_count} words) -- prioritize quality providers",
"confidence": 0.85,
}
return {
"chosen": "round_robin",
"reasoning": f"Medium query ({word_count} words) -- balanced comparison",
"confidence": 0.75,
}
Per-provider child agents with auto-instrumented calls
Each provider uses its native SDK. OpenAI and Anthropic are auto-instrumented; LiteLLM uses the @tool(llm) wrapper.
@waxell.observe(agent_name="openai-agent", workflow_name="openai-generation")
async def run_openai(query: str, openai_client, waxell_ctx=None):
waxell.tag("provider", "openai")
response = await openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "system", "content": "You are a tech analyst."}, {"role": "user", "content": query}],
)
waxell.score("response_quality", 0.88)
return {"provider": "OpenAI", "content": response.choices[0].message.content}
@waxell.observe(agent_name="anthropic-agent", workflow_name="anthropic-generation")
async def run_anthropic(query: str, anthropic_client, waxell_ctx=None):
waxell.tag("provider", "anthropic")
response = await anthropic_client.messages.create(
model="claude-sonnet-4-5-20250929", max_tokens=500,
messages=[{"role": "user", "content": query}],
)
waxell.score("response_quality", 0.91)
return {"provider": "Anthropic", "content": response.content[0].text}
What this demonstrates
@waxell.observe-- parent orchestrator with 3 child agents (one per provider)@waxell.step_dec-- query preprocessing@waxell.decision-- provider execution order selection@waxell.tool(llm)-- LiteLLM wrapper for Groq calls@waxell.reasoning_dec-- cross-provider response comparisonwaxell.tag()-- per-provider taggingwaxell.score()-- per-provider quality and multi-provider coverage scoreswaxell.metadata()-- model and token metadata per provider- Auto-instrumented -- OpenAI and Anthropic calls traced automatically
- Single trace -- all 3 providers unified under one session
Run it
cd dev/waxell-dev
python -m app.demos.all_providers_agent --dry-run