AI Engineer Portal
Your personal operating system for career transition.
Exercise
Build a type-safe configuration loader for AI services
Build a Type-Safe Configuration Loader for AI Services
AI services have more configuration surface than typical web backends: model names, temperature, token limits, provider API keys, retry counts, timeout values, rate limits, and feature flags. Passing these as raw environment variables or loose dicts means typos fail silently, missing required values are discovered at runtime, and the available configuration is not documented anywhere.
What to build
Implement a ServiceConfig Pydantic settings model and a load_config factory function:
ServiceConfig fields (all from environment variables with AI_ prefix):
provider: str— required, one of"openai","anthropic","local"model: str— required, minimum length 1api_key: str— required for non-local providers (validate this cross-field)max_tokens: int— default 1024, between 1 and 32768temperature: float— default 0.7, between 0.0 and 2.0timeout_s: float— default 30.0, minimum 1.0max_retries: int— default 3, between 0 and 10max_concurrent: int— default 5, between 1 and 50cache_ttl_seconds: int— default 3600, minimum 0
load_config(env: dict | None = None) -> ServiceConfig — loads config from the provided dict (or os.environ if None). Raises ConfigError (a custom exception subclassing ValueError) with a descriptive message if required fields are missing or invalid.
Why this matters
Configuration bugs in AI services show up in the worst possible way: the service starts fine, then fails on the first request because the API key is wrong, the timeout is too short, or the model name has a typo. Pydantic settings validation catches all of these at startup, not at request time.
Constraints
- Use Pydantic v2 field validators, not v1
@validator. - The
api_keyshould be required whenprovider != "local"— implement this as a@model_validator. ConfigErrorshould include a clear message listing what is wrong.
Python Refresh / medium / Step 12 of 16
Core runtime habits
Normalize the boundary first, keep return shapes stable, and make the middle of the function boring on purpose.
- - Returns one stable shape across branches
- - Makes failure handling obvious
- - Keeps the core logic readable in under a minute
- - Did I make the input and output shapes explicit?
- - Would a teammate know where validation happens?
- - Did I avoid silent mutation or vague branching?
Practice
Generate a variation
Generate a new exercise variation to deepen understanding or practice a related concept.
Attempt history
Recent submissions
Before you submit, decide what a strong answer should make obvious to the reviewer.
No attempts yet.