# How to Configure API Keys and Models for the ADR Detector

> Configure API keys and models for the ADR detector by setting environment variables and customizing the config_detector.yaml file for LLM control.

- Repository: [Uber Open Source/ADR](https://github.com/uber/ADR)
- Tags: how-to-guide
- Published: 2026-08-06

---

**Set `OPENAI_API_KEY` (and optionally `ANTHROPIC_API_KEY`) as environment variables, then customize model parameters in [`config_detector.yaml`](https://github.com/uber/ADR/blob/main/config_detector.yaml) to control which LLMs handle triage and reasoning.**

The **ADR detector** from Uber's open-source repository relies on two configuration layers: API credentials for cloud LLM providers, and a YAML file that defines which models run during different detection phases. This guide walks through both steps using the actual source code structure.

---

## Setting Up API Keys

The detector expects credentials via environment variables. According to the source code in [`Detection/openai_config.py`](https://github.com/uber/ADR/blob/main/Detection/openai_config.py), the helper function `get_openai_client()` reads directly from `os.environ`:

```python
def get_openai_client() -> OpenAI:
    """Return a configured OpenAI client using the OPENAI_API_KEY env var."""
    return OpenAI(api_key=os.environ["OPENAI_API_KEY"])

```

### Required Environment Variables

- `OPENAI_API_KEY` — **mandatory** for all OpenAI models
- `ANTHROPIC_API_KEY` — optional, needed only if you configure Claude models in [`config_detector.yaml`](https://github.com/uber/ADR/blob/main/config_detector.yaml)

### Example .env File

```text
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ANTHROPIC_API_KEY=sk-ant-api03-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

```

### Export Before Running

```bash
export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...

python -m Detection.main_detector

```

If `OPENAI_API_KEY` is missing, the code raises a `KeyError` on startup. The OpenAI client itself validates the key format, so errors surface immediately.

---

## Configuring Models in config_detector.yaml

All LLM selection, pricing, and generation parameters live in [`Detection/config_detector.yaml`](https://github.com/uber/ADR/blob/main/Detection/config_detector.yaml). The detector reads this file at startup and passes values to `create_chat_completion()` in [`openai_config.py`](https://github.com/uber/ADR/blob/main/openai_config.py):

```python
def create_chat_completion(model: str = 'gpt-4o', messages: Optional[list] = None, **kwargs):
    client = get_openai_client()
    return client.chat.completions.create(model=model, messages=messages, **kwargs)

```

### Key Configuration Sections

| Section | Purpose | Controls |
|---------|---------|----------|
| `llamafirewall` | Jailbreak detection on input messages | Model, cost rates |
| `adr_framework.triage_llm` | Fast, high-recall initial screening | Model, temperature, token limits, cost |
| `adr_framework.reasoning_agent` | Deep, high-precision analysis | Model, timeout, max turns, cost |

### Customizing the Triage LLM

To switch to `gpt-4o-mini` with updated pricing:

```yaml
adr_framework:
  triage_llm:
    model: "gpt-4o-mini"
    cost_per_1m_input: 0.10
    cost_per_1m_output: 0.30
    temperature: 0
    max_tokens: 800

```

### Customizing the Reasoning Agent

To use Claude 3.5 Sonnet for deeper analysis:

```yaml
adr_framework:
  reasoning_agent:
    model: "claude-3-5-sonnet-20240620"
    cost_per_1m_input: 2.00
    cost_per_1m_output: 12.00
    max_turns: 50
    timeout: 300
    max_tokens: 12000

```

**Note:** Claude models require `ANTHROPIC_API_KEY` to be set, even though [`openai_config.py`](https://github.com/uber/ADR/blob/main/openai_config.py) currently wraps the OpenAI-compatible client interface.

---

## Cost Tracking and Calculation

The detector uses configured rates to compute actual spend. The utility function in [`openai_config.py`](https://github.com/uber/ADR/blob/main/openai_config.py):

```python
cost = calculate_cost(
    cost_per_1m_input=cfg['cost_per_1m_input'],
    cost_per_1m_output=cfg['cost_per_1m_output'],
    input_tokens=used_input,
    output_tokens=used_output,
)

```

This enables accurate budget tracking across runs. Unit tests in [`Detection/tests/test_openai_config.py`](https://github.com/uber/ADR/blob/main/Detection/tests/test_openai_config.py) verify the calculation logic.

---

## Running the Detector with Custom Configuration

### Python API Usage

```python
import os
import yaml
from Detection.openai_config import get_openai_client, create_chat_completion

# Verify environment

assert "OPENAI_API_KEY" in os.environ, "Set OPENAI_API_KEY first"

# Load configuration

with open('Detection/config_detector.yaml') as f:
    cfg = yaml.safe_load(f)

# Use triage configuration

triage = cfg['adr_framework']['triage_llm']
response = create_chat_completion(
    model=triage['model'],
    messages=[{'role': 'user', 'content': 'Analyze this code change.'}],
    max_tokens=triage['max_tokens'],
    temperature=triage['temperature'],
)

```

### Command Line Execution

```bash

# Verify keys

echo $OPENAI_API_KEY

# Run with default config location

python -m Detection.main_detector

# Or specify custom config path

python -m Detection.main_detector --config ./my_custom_config.yaml

```

---

## Key Files Reference

| File | Role |
|------|------|
| [`Detection/openai_config.py`](https://github.com/uber/ADR/blob/main/Detection/openai_config.py) | OpenAI client factory, completion wrapper, cost calculator |
| [`Detection/config_detector.yaml`](https://github.com/uber/ADR/blob/main/Detection/config_detector.yaml) | Central model and pricing configuration |
| [`Detection/main_detector.py`](https://github.com/uber/ADR/blob/main/Detection/main_detector.py) | Entry point that orchestrates triage and reasoning agents |
| [`Detection/tests/test_openai_config.py`](https://github.com/uber/ADR/blob/main/Detection/tests/test_openai_config.py) | Unit tests for cost calculation and client helpers |

---

## Summary

- **Export `OPENAI_API_KEY`** as an environment variable; add `ANTHROPIC_API_KEY` only if using Claude models
- **Edit [`config_detector.yaml`](https://github.com/uber/ADR/blob/main/config_detector.yaml)** to select models, set cost rates, and tune generation parameters for both triage and reasoning phases
- **The detector reads YAML at startup** and passes values through [`openai_config.py`](https://github.com/uber/ADR/blob/main/openai_config.py) helpers
- **Cost tracking is automatic** based on configured per‑million‑token rates

---

## Frequently Asked Questions

### What happens if I forget to set OPENAI_API_KEY?

The detector fails immediately with a `KeyError` when `get_openai_client()` attempts to read `os.environ["OPENAI_API_KEY"]`. There is no fallback or default key.

### Can I use Azure OpenAI instead of OpenAI's API?

The current [`openai_config.py`](https://github.com/uber/ADR/blob/main/openai_config.py) instantiates the standard `OpenAI` client. Azure OpenAI requires the `AzureOpenAI` client class with additional parameters (`api_version`, `azure_endpoint`). You would need to modify `get_openai_client()` or add a new factory function to support Azure.

### How do I switch from GPT-4o to Claude for reasoning?

Update `adr_framework.reasoning_agent.model` in [`config_detector.yaml`](https://github.com/uber/ADR/blob/main/config_detector.yaml) to a Claude model string (e.g., `"claude-3-5-sonnet-20240620"`), ensure `ANTHROPIC_API_KEY` is exported, and verify your client supports Anthropic's API. The current implementation expects an OpenAI-compatible interface.

### Where are the cost rates used?

The rates defined in `cost_per_1m_input` and `cost_per_1m_output` feed into `calculate_cost()` in [`openai_config.py`](https://github.com/uber/ADR/blob/main/openai_config.py), which computes actual USD spend based on token usage from each API call.