# How the `initialize_llm_provider` Factory Function Works in InterviewStreet's Hiring-Agent

> Discover how the initialize_llm_provider factory function in InterviewStreet's Hiring Agent dynamically creates Ollama or Gemini instances, ensuring seamless operation with automatic fallback.

- Repository: [HackerRank/hiring-agent](https://github.com/interviewstreet/hiring-agent)
- Tags: internals
- Published: 2026-07-08

---

**The `initialize_llm_provider` function is a factory that creates either an `OllamaProvider` or `GeminiProvider` instance based on the requested `model_name`, automatically falling back to Ollama when the Gemini API key is unavailable.**

The `initialize_llm_provider` factory function in the [interviewstreet/hiring-agent](https://github.com/interviewstreet/hiring-agent) repository provides a unified entry point for selecting Large Language Model backends. Located in [`llm_utils.py`](https://github.com/interviewstreet/hiring-agent/blob/main/llm_utils.py), this function eliminates hardcoded provider dependencies by dynamically instantiating the correct adapter based on model configuration and credential availability.

## Step-by-Step Execution Flow

The factory follows a defensive initialization pattern that prioritizes availability while respecting explicit model preferences. The implementation spans lines 40‑63 of [`llm_utils.py`](https://github.com/interviewstreet/hiring-agent/blob/main/llm_utils.py).

### Default to Ollama

The function begins by creating a fallback provider:

```python
provider = OllamaProvider()

```

This instantiation at line 51 ensures that a valid provider exists before any configuration checks occur. If subsequent steps fail, the system retains a functional local LLM backend rather than returning `None`.

### Model-to-Provider Mapping

Next, the function resolves which provider the requested model belongs to using a dictionary lookup:

```python
model_provider = MODEL_PROVIDER_MAPPING.get(model_name, ModelProvider.OLLAMA)

```

This references `MODEL_PROVIDER_MAPPING` defined in [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py), which translates specific model names (such as `"gemini-1.5-flash"`) into `ModelProvider` enum values (`GEMINI` or `OLLAMA`).

### Gemini API Key Validation

When the mapping indicates a Gemini model, the factory validates credentials before switching:

```python
if model_provider == ModelProvider.GEMINI:
    if not GEMINI_API_KEY:
        logger.warning("⚠️ Gemini API key not found. Falling back to Ollama.")

```

The `GEMINI_API_KEY` constant is also imported from [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py). If this key is falsy or empty, the function logs a warning and retains the default `OllamaProvider` created in step one.

### Provider Instantiation and Logging

If the API key exists, the factory switches to Gemini and logs the transition:

```python
logger.info(f"🔄 Using Google Gemini API provider with model {model_name}")
provider = GeminiProvider(api_key=GEMINI_API_KEY)

```

For Ollama models, or when Gemini is unavailable, an informational log confirms the selection:

```python
logger.info(f"🔄 Using Ollama provider with model {model_name}")

```

The function returns the configured provider at lines 62‑63.

## Provider Interface and Protocol

Both `OllamaProvider` and `GeminiProvider` implement the `LLMProvider` protocol defined in [`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py). This protocol requires a `chat` method with a consistent signature, allowing the rest of the codebase to interact with either backend interchangeably without import-time dependencies on specific LLM services.

According to the source code in [`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py) (lines 13‑26), the protocol ensures that consumers can call `provider.chat(model=..., messages=..., options=...)` regardless of which concrete class backs the implementation.

## Usage Examples

### Direct Factory Usage

You can instantiate providers directly for custom scripts:

```python
from llm_utils import initialize_llm_provider

# Select a Gemini model

model_name = "gemini-1.5-flash"
provider = initialize_llm_provider(model_name)

# The interface is identical regardless of provider

response = provider.chat(
    model=model_name,
    messages=[{"role": "user", "content": "Explain the Factory pattern"}],
    options={"temperature": 0.7}
)

```

### Integration in Document Processors

The factory integrates into processing classes throughout the codebase. In [`pdf.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pdf.py), the `PDFProcessor` class uses the factory during initialization:

```python
class PDFProcessor:
    def __init__(self):
        self._initialize_llm_provider()

    def _initialize_llm_provider(self):
        self.provider = initialize_llm_provider(DEFAULT_MODEL)

```

This same pattern appears in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) and [`evaluator.py`](https://github.com/interviewstreet/hiring-agent/blob/main/evaluator.py), ensuring consistent provider behavior across PDF processing, GitHub analysis, and candidate evaluation modules.

## Summary

- **Defensive defaults**: The factory always creates an `OllamaProvider` first, ensuring a fallback exists before checking configuration.
- **Configuration-driven**: Provider selection relies on `MODEL_PROVIDER_MAPPING` from [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py) to determine which backend supports the requested model.
- **Credential-aware**: When targeting Gemini, the function checks for `GEMINI_API_KEY` and logs appropriate warnings before falling back to the default.
- **Interface-unified**: Both providers implement the `LLMProvider` protocol from [`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py), exposing a standardized `chat` method.
- **Centralized logging**: Each code path generates informative logs indicating which provider was selected and why.

## Frequently Asked Questions

### What happens if the Gemini API key is missing?

If `GEMINI_API_KEY` is not set in [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py), the factory logs a warning message ("⚠️ Gemini API key not found. Falling back to Ollama.") and returns the default `OllamaProvider` instance created at line 51. The application continues functioning using the local Ollama backend rather than raising an exception or returning `None`.

### Where is the provider selection logic defined?

The core selection logic resides in [`llm_utils.py`](https://github.com/interviewstreet/hiring-agent/blob/main/llm_utils.py) (lines 40‑63). However, the mapping of model names to providers lives in `MODEL_PROVIDER_MAPPING` within [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py), and the provider classes themselves—along with the `LLMProvider` protocol—are defined in [`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py).

### Can I add support for additional LLM providers?

Yes. You would need to: add a new value to the `ModelProvider` enum in [`models.py`](https://github.com/interviewstreet/hiring-agent/blob/main/models.py); create a new provider class implementing the `LLMProvider` protocol; update `MODEL_PROVIDER_MAPPING` in [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py) to associate models with your new provider; and extend the conditional logic in `initialize_llm_provider` (around line 54) to instantiate your provider when its corresponding configuration key is present.

### Why does the factory default to Ollama instead of raising an error for unknown models?

Defaulting to `OllamaProvider` ensures high availability in local development environments where Gemini credentials might not be configured. This defensive pattern prevents runtime failures when `MODEL_PROVIDER_MAPPING` lacks an entry for a specific model name, gracefully treating unknown models as Ollama-compatible rather than crashing the application.