@dataclass(init=False)classFallbackModel(Model):"""A model that uses one or more fallback models upon failure. Apart from `__init__`, all methods are private or match those of the base class. """models:list[Model]_model_name:str=field(repr=False)_fallback_on:Callable[[Exception],bool]def__init__(self,default_model:Model|KnownModelName,*fallback_models:Model|KnownModelName,fallback_on:Callable[[Exception],bool]|tuple[type[Exception],...]=(ModelHTTPError,),):"""Initialize a fallback model instance. Args: default_model: The name or instance of the default model to use. fallback_models: The names or instances of the fallback models to use upon failure. fallback_on: A callable or tuple of exceptions that should trigger a fallback. """self.models=[infer_model(default_model),*[infer_model(m)forminfallback_models]]ifisinstance(fallback_on,tuple):self._fallback_on=_default_fallback_condition_factory(fallback_on)else:self._fallback_on=fallback_onasyncdefrequest(self,messages:list[ModelMessage],model_settings:ModelSettings|None,model_request_parameters:ModelRequestParameters,)->tuple[ModelResponse,Usage]:"""Try each model in sequence until one succeeds. In case of failure, raise a FallbackExceptionGroup with all exceptions. """exceptions:list[Exception]=[]formodelinself.models:try:response,usage=awaitmodel.request(messages,model_settings,model_request_parameters)exceptExceptionasexc:ifself._fallback_on(exc):exceptions.append(exc)continueraiseexcself._set_span_attributes(model)returnresponse,usageraiseFallbackExceptionGroup('All models from FallbackModel failed',exceptions)@asynccontextmanagerasyncdefrequest_stream(self,messages:list[ModelMessage],model_settings:ModelSettings|None,model_request_parameters:ModelRequestParameters,)->AsyncIterator[StreamedResponse]:"""Try each model in sequence until one succeeds."""exceptions:list[Exception]=[]formodelinself.models:asyncwithAsyncExitStack()asstack:try:response=awaitstack.enter_async_context(model.request_stream(messages,model_settings,model_request_parameters))exceptExceptionasexc:ifself._fallback_on(exc):exceptions.append(exc)continueraiseexcself._set_span_attributes(model)yieldresponsereturnraiseFallbackExceptionGroup('All models from FallbackModel failed',exceptions)def_set_span_attributes(self,model:Model):withsuppress(Exception):span=get_current_span()ifspan.is_recording():attributes=getattr(span,'attributes',{})ifattributes.get('gen_ai.request.model')==self.model_name:span.set_attributes(InstrumentedModel.model_attributes(model))@propertydefmodel_name(self)->str:"""The model name."""returnf'fallback:{",".join(model.model_nameformodelinself.models)}'@propertydefsystem(self)->str:returnf'fallback:{",".join(model.systemformodelinself.models)}'@propertydefbase_url(self)->str|None:returnself.models[0].base_url
Source code in pydantic_ai_slim/pydantic_ai/models/fallback.py
33343536373839404142434445464748495051
def__init__(self,default_model:Model|KnownModelName,*fallback_models:Model|KnownModelName,fallback_on:Callable[[Exception],bool]|tuple[type[Exception],...]=(ModelHTTPError,),):"""Initialize a fallback model instance. Args: default_model: The name or instance of the default model to use. fallback_models: The names or instances of the fallback models to use upon failure. fallback_on: A callable or tuple of exceptions that should trigger a fallback. """self.models=[infer_model(default_model),*[infer_model(m)forminfallback_models]]ifisinstance(fallback_on,tuple):self._fallback_on=_default_fallback_condition_factory(fallback_on)else:self._fallback_on=fallback_on
asyncdefrequest(self,messages:list[ModelMessage],model_settings:ModelSettings|None,model_request_parameters:ModelRequestParameters,)->tuple[ModelResponse,Usage]:"""Try each model in sequence until one succeeds. In case of failure, raise a FallbackExceptionGroup with all exceptions. """exceptions:list[Exception]=[]formodelinself.models:try:response,usage=awaitmodel.request(messages,model_settings,model_request_parameters)exceptExceptionasexc:ifself._fallback_on(exc):exceptions.append(exc)continueraiseexcself._set_span_attributes(model)returnresponse,usageraiseFallbackExceptionGroup('All models from FallbackModel failed',exceptions)
@asynccontextmanagerasyncdefrequest_stream(self,messages:list[ModelMessage],model_settings:ModelSettings|None,model_request_parameters:ModelRequestParameters,)->AsyncIterator[StreamedResponse]:"""Try each model in sequence until one succeeds."""exceptions:list[Exception]=[]formodelinself.models:asyncwithAsyncExitStack()asstack:try:response=awaitstack.enter_async_context(model.request_stream(messages,model_settings,model_request_parameters))exceptExceptionasexc:ifself._fallback_on(exc):exceptions.append(exc)continueraiseexcself._set_span_attributes(model)yieldresponsereturnraiseFallbackExceptionGroup('All models from FallbackModel failed',exceptions)