AIR

Example: automatic fallback

This example uses two small demo providers instead of real API keys, so it can be run directly to see fallback behavior without spending any provider quota. Swap in real providers (XAIProvider, GeminiProvider, GroqProvider, OpenRouterProvider) the same way as in multiple-providers.md; the fallback behavior is identical.

python
import asyncio
 
from air import AIR, ChatRequest, ChatResponse, Message, Role
from air.providers.base import Provider
from air.exceptions import RateLimitError
 
 
class FlakyProvider(Provider):
    name = "flaky"
 
    async def chat(self, request: ChatRequest) -> ChatResponse:
        raise RateLimitError("simulated rate limit", provider=self.name)
 
 
class BackupProvider(Provider):
    name = "backup"
 
    async def chat(self, request: ChatRequest) -> ChatResponse:
        last = request.messages[-1].content
        return ChatResponse(content=f"backup provider answering: {last}", provider=self.name, model="demo")
 
 
async def main():
    air = AIR()
    air.add_provider(FlakyProvider(), priority=1)
    air.add_provider(BackupProvider(), priority=2)
 
    response = await air.chat("Hello")
    print(response.content)
    print("answered by:", response.provider)
    print("events:")
    for line in response.events:
        print(" ", line)
 
 
if __name__ == "__main__":
    asyncio.run(main())

FlakyProvider always raises RateLimitError, which is one of the fallback eligible errors (see ../core/fallback.md). AIR tries it first (priority 1), catches the error, and moves on to BackupProvider (priority 2), which succeeds. response.provider is "backup", and response.events includes a line describing the switch.