Skip to main content

v-router

A unified LLM interface that provides automatic fallback between different LLM providers. Route your AI requests seamlessly across Anthropic, OpenAI, Google, and Azure with intelligent failover strategies and a consistent API.

✨ Features

  • 🚀 Automatic Fallback: Seamless switching between models and providers when failures occur
  • 📚 Unified API: Same interface works across all major LLM providers
  • ⚡ Smart Routing: Intelligent model selection based on availability and configuration
  • 🔧 Function Calling: Unified tool calling interface across all providers
  • 🖼️ Multimodal Support: Send images and PDFs with automatic format conversion
  • 🎯 Consistent Responses: Standardized response format regardless of provider
  • ⚙️ Flexible Configuration: Fine-tune parameters, backup models, and provider priorities

📦 Installation

pip install v-router

Or with development dependencies:

uv sync --all-extras

🚀 Quick Start

Basic Conversation

from v_router import Client, LLM
from v_router import HumanMessage, AIMessage, SystemMessage

# Initialize client
client = Client(
    llm_config=LLM(
        model_name="claude-3-sonnet-20240229",
        provider="anthropic",
        max_tokens=500
    )
)

# Basic conversation
response = await client.messages.create(
    messages=[
        SystemMessage("You are a helpful assistant"),
        HumanMessage("What's the capital of France?")
    ]
)

print(response.content)  # "The capital of France is Paris."

Response Format

All providers return a consistent AIMessage format:

# The response object
print(response.content)        # "The capital of France is Paris." (or ["Part 1", "Part 2"] for multi-part)
print(response.model)          # "claude-3-sonnet-20240229"
print(response.provider)       # "anthropic"
print(response.usage.input_tokens)   # 25
print(response.usage.output_tokens)  # 8

Multi-turn Conversations

# Start a conversation
messages = [
    SystemMessage("You are a helpful math tutor"),
    HumanMessage("What's 15% of 80?")
]

response = await client.messages.create(messages=messages)
print(response.content)  # "To find 15% of 80..."

# Continue the conversation - just append the response
messages.append(response)  # AIMessage is automatically handled
messages.append(HumanMessage("Can you show me another way to calculate it?"))

response2 = await client.messages.create(messages=messages)
print(response2.content)  # "Sure! Another way to calculate 15% of 80..."

🔧 Function Calling (Tool Use)

from v_router import Client, LLM, HumanMessage, ToolMessage
from v_router.classes.tools import ToolCall, Tools
from pydantic import BaseModel, Field

# Define your tool
class Calculator(BaseModel):
    expression: str = Field(..., description="Mathematical expression to evaluate")

calculator_tool = ToolCall(
    name="calculator",
    description="Evaluate mathematical expressions",
    input_schema=Calculator.model_json_schema()
)

# Create client with tools
client = Client(
    llm_config=LLM(
        model_name="gpt-4",
        provider="openai",
        tools=Tools(tools=[calculator_tool])
    )
)

# Ask a question that requires the tool
messages = [HumanMessage("What's 392 * 47?")]
response = await client.messages.create(messages=messages)

# Check if the model wants to use a tool
if response.tool_calls:
    tool_call = response.tool_calls[0]
    print(f"Tool: {tool_call.name}")           # "calculator"
    print(f"Arguments: {tool_call.args}")      # {"expression": "392 * 47"}
    
    # Execute the tool (your implementation)
    result = eval(tool_call.args["expression"])  # 18,424
    
    # Send tool result back
    messages.append(response)  # Add the AIMessage with tool_calls
    messages.append(
        ToolMessage(
            content=str(result),
            tool_call_id=tool_call.id
        )
    )
    
    # Get final response
    final_response = await client.messages.create(messages=messages)
    print(final_response.content)  # "392 * 47 = 18,424"

🖼️ Multimodal Messages

Sending Images

from v_router import Client, LLM, HumanMessage
from v_router.classes.messages import TextContent, ImageContent
import base64

client = Client(
    llm_config=LLM(
        model_name="gpt-4o",
        provider="openai"
    )
)

# Method 1: Direct file path (auto-converted to base64)
response = await client.messages.create(
    messages=[
        HumanMessage("image.jpg"),  # Just pass the file path
        HumanMessage("What's in this image?")
    ]
)

# Method 2: Explicit multimodal content
with open("chart.png", "rb") as f:
    image_data = base64.b64encode(f.read()).decode("utf-8")

response = await client.messages.create(
    messages=[
        HumanMessage([
            TextContent(text="Analyze this chart and tell me the trend:"),
            ImageContent(data=image_data, media_type="image/png")
        ])
    ]
)

print(response.content)  # "The chart shows an upward trend..."

Working with Documents (PDFs)

from v_router.classes.messages import DocumentContent

# PDFs work similarly to images
with open("report.pdf", "rb") as f:
    pdf_data = base64.b64encode(f.read()).decode("utf-8")

response = await client.messages.create(
    messages=[
        HumanMessage([
            TextContent(text="Summarize this report:"),
            DocumentContent(
                data=pdf_data,
                media_type="application/pdf"
            )
        ])
    ]
)

# Or just use the file path
response = await client.messages.create(
    messages=[
        HumanMessage("report.pdf"),  # Auto-converted
        HumanMessage("What are the key findings?")
    ]
)

🚀 Automatic Fallback

Configure backup models to ensure reliability:

from v_router import Client, LLM, BackupModel

llm_config = LLM(
    model_name="claude-3-opus-20240229",  # Primary model
    provider="anthropic",
    backup_models=[
        BackupModel(
            model=LLM(model_name="gpt-4", provider="openai"),
            priority=1  # First fallback
        ),
        BackupModel(
            model=LLM(model_name="gemini-1.5-pro", provider="google"),
            priority=2  # Second fallback
        )
    ]
)

client = Client(llm_config)

# If Claude fails, automatically tries GPT-4, then Gemini
response = await client.messages.create(
    messages=[HumanMessage("Hello!")]
)

print(f"Response from: {response.provider}")  # Shows which provider succeeded

🔄 Cross-Provider Switching

Enable automatic cross-provider fallback for the same model:

llm_config = LLM(
    model_name="claude-3-sonnet-20240229",
    provider="vertexai",  # Try Vertex AI first
    try_other_providers=True  # Fall back to direct Anthropic if needed
)

# If Vertex AI fails, automatically tries the same model on Anthropic
response = await client.messages.create(
    messages=[HumanMessage("Hello!")]
)

🎯 Provider-Specific Parameters

v-router supports provider-specific features through flexible parameters:

# Anthropic - Thinking mode
response = await client.messages.create(
    messages=[HumanMessage("Solve this complex problem: ...")],
    timeout=600,
    thinking={
        "type": "enabled",
        "budget_tokens": 10000
    }
)

# OpenAI - JSON mode
response = await client.messages.create(
    messages=[HumanMessage("Return a JSON object with name and age")],
    response_format={"type": "json_object"},
    seed=12345
)

# Google - Safety settings
response = await client.messages.create(
    messages=[HumanMessage("Tell me about...")],
    safety_settings=[{
        "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
        "threshold": "BLOCK_ONLY_HIGH"
    }]
)

🌐 Supported Providers

Provider Models Features
Anthropic Claude 3 (Opus, Sonnet, Haiku), Claude 4 (Opus, Sonnet) Function calling, Images, PDFs
OpenAI GPT-4, GPT-4 Turbo, GPT-4o, GPT-3.5 Function calling, Images
Google Gemini Pro, Gemini 1.5 (Pro, Flash), Gemini 2.0 Flash Function calling, Images, PDFs
Azure OpenAI GPT-4, GPT-4 Turbo, GPT-4o, GPT-3.5 Function calling, Images
Vertex AI Claude 3/4 & Gemini models via Google Cloud Function calling, Images, PDFs

⚙️ Configuration

Environment Variables

Set up authentication for your providers:

# Anthropic
export ANTHROPIC_API_KEY="your-key-here"

# OpenAI
export OPENAI_API_KEY="your-key-here"

# Google AI Studio
export GOOGLE_API_KEY="your-key-here"

# Google Cloud (for Vertex AI)
export GOOGLE_APPLICATION_CREDENTIALS="path/to/service-account.json"
export GCP_PROJECT_ID="your-project-id"
export GCP_LOCATION="us-central1"

# Azure OpenAI
export AZURE_OPENAI_API_KEY="your-key-here"
export AZURE_OPENAI_ENDPOINT="your-endpoint"

# LangFuse (optional - for tracing)
export LANGFUSE_HOST="your-langfuse-host"
export LANGFUSE_PUBLIC_KEY="your-public-key"
export LANGFUSE_SECRET_KEY="your-secret-key"

📊 LangFuse Tracing Support

v-router includes built-in support for LangFuse tracing:

📊 LLM Request
├── 🔴 Primary Model (claude-3-opus on anthropic) - FAILED
│   ├── Error: Rate limit exceeded
│   └── Duration: 150ms
└── ✅ Backup Model (gpt-4 on openai) - SUCCESS
    ├── Input tokens: 45
    ├── Output tokens: 128
    ├── Duration: 2.3s
    └── Cost: $0.0043

Enable by setting the LANGFUSE_HOST environment variable. No code changes required.

Model Configuration

v-router uses models.yml to map model names across providers:

# These all work automatically:
LLM(model_name="claude-3-sonnet", provider="anthropic")      # → claude-3-sonnet-20240229
LLM(model_name="claude-3-sonnet", provider="vertexai")       # → claude-3-sonnet@20240229
LLM(model_name="gpt-4", provider="openai")                   # → gpt-4
LLM(model_name="gemini-1.5-pro", provider="google")          # → gemini-1.5-pro-latest

📖 Documentation

Complete documentation is available online:

📚 Full Documentation

Jupyter Notebooks

Explore the examples/ directory for interactive examples:

🛠️ Development

Setup

# Install with development dependencies
uv sync --all-extras

# Install pre-commit hooks
uv run pre-commit install

Testing

# Run all tests
uv run pytest

# Run specific test file
uv run pytest tests/models/test_llm.py

# Run with verbose output
uv run pytest -v

Code Quality

# Check code style
uv run ruff check .

# Auto-fix issues
uv run ruff check --fix .

# Format code
uv run ruff format .

🏗️ Architecture

v-router follows a clean provider pattern:

  • Client: Main entry point with unified API
  • Router: Handles request routing and fallback logic
  • Providers: Individual provider implementations
  • Models: Unified request/response models

📄 License

This project is licensed under the MIT License.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📞 Support


v-router - Making LLM integration simple, reliable, and unified across all providers.

Metadata

Release files for v-router 0.0.27

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

Source distribution (sdist)

Source distribution for v-router 0.0.27
File Size Uploaded
v_router-0.0.27.tar.gz 1.2 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for v-router 0.0.27
File Interpreter ABI Platform
v_router-0.0.27-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / v_router-0.0.27.tar.gz

Download URL v_router-0.0.27.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
5998a5c3134c30ce2d683a2a99a3138bad9afc106e98bc87118c7439f9151466
BLAKE2b-256 checksum
How to use checksums
c6c9e305ca8a5952b1a9e7fe7cde54f272bc9ff1c72121c491e505593a547e36
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.7.13

Release files / v_router-0.0.27-py3-none-any.whl

Download URL v_router-0.0.27-py3-none-any.whl
Size 30.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
157102d160e79cc415105847381677499fc3f308f629cb260668e2f3144021c4
BLAKE2b-256 checksum
How to use checksums
81069f5f22a9f6e0a5e6cbf2bab47edc7194abad020f8342a95bced74aa0022f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.7.13

Release history Release notifications | RSS feed

This release

0.0.27 This release

2 release files

0.0.25

2 release files

0.0.24

2 release files

0.0.23

2 release files

0.0.22

2 release files

0.0.21

2 release files

0.0.20

2 release files

0.0.9

2 release files

0.0.8

2 release files

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