Issue: Refactor AI Service & Backend to Support Multiple LLM Providers
Title
refactor(ai): introduce multi-provider LLM architecture with configurable provider/model selection per feature
Description
Currently, the AI Service only supports Groq as the LLM provider and the backend only stores a single Groq API key.
Refactor the AI infrastructure to support multiple LLM providers through a unified abstraction layer, allowing each AI feature to use a different provider and model.
The system should be extensible so that adding a new provider in the future requires minimal changes.
Motivation
Different LLM providers excel at different tasks.
Examples:
- OpenAI → CV Tailoring
- Claude → Cover Letter / Email generation
- Gemini → Long context analysis
- Groq → Fast inference
- Future providers (DeepSeek, Mistral, xAI, etc.)
Instead of hardcoding Groq everywhere, the application should allow selecting the provider/model per feature.
Goals
- Support multiple LLM providers
- Store multiple API keys
- Allow selecting provider & model for each AI feature
- Make provider implementations interchangeable
- Keep feature code provider-agnostic
Supported Providers (Initial)
- Groq
- OpenAI
- Claude (Anthropic)
- Gemini (Google)
Future providers should be easy to plug in.
Current Architecture
Frontend
↓
Backend
↓
AI Service
↓
Groq API
Desired Architecture
Frontend
↓
Backend
↓
AI Service
↓
LLM Router
↓
┌──────────────┬─────────────┬──────────────┬──────────────┐
│ Groq │ OpenAI │ Claude │ Gemini │
└──────────────┴─────────────┴──────────────┴──────────────┘
Feature code should never directly know which provider is being used.
Functional Requirements
1. Provider Abstraction
Create a common interface for all providers.
Example:
interface LLMProvider {
chat(request): Promise<ChatResponse>;
getAvailableModels(): Promise<Model[]>;
}
Each provider implements this interface.
Examples:
- GroqProvider
- OpenAIProvider
- ClaudeProvider
- GeminiProvider
2. LLM Router
Introduce a router/factory responsible for:
- Reading configuration
- Selecting provider
- Selecting model
- Executing request
Example:
router.generate({
feature: "cvTailoring",
...
})
Router internally resolves:
Feature
↓
Provider
↓
Model
3. Provider Configuration
Store API credentials for every supported provider.
Example configuration:
{
"groq": {
"apiKey": "..."
},
"openai": {
"apiKey": "..."
},
"claude": {
"apiKey": "..."
},
"gemini": {
"apiKey": "..."
}
}
Missing API keys should disable that provider without affecting others.
4. Feature-Level Provider Selection
Each AI feature should have configurable:
Initial configurable features:
- CV Tailoring
- Mail Creator
- Interview Insights Analyzer
- Job Search (future)
Example:
{
"cvTailoring": {
"provider": "openai",
"model": "gpt-5"
},
"mailCreator": {
"provider": "claude",
"model": "claude-sonnet-4"
},
"interviewInsights": {
"provider": "gemini",
"model": "gemini-2.5-pro"
}
}
No feature should hardcode provider names.
5. Backend Settings API
Extend the settings endpoints to support:
API Keys
- Groq API Key
- OpenAI API Key
- Claude API Key
- Gemini API Key
AI Feature Configuration
For every feature:
6. Settings UI
Refactor the settings page.
API Keys Section
Groq API Key
OpenAI API Key
Claude API Key
Gemini API Key
AI Configuration
For each feature:
CV Tailoring
Provider:
▼ OpenAI
Model:
▼ GPT-5
Mail Creator
Provider:
▼ Claude
Model:
▼ Claude Sonnet 4
etc.
Model lists should update dynamically based on the selected provider (where supported).
7. Model Discovery
Where supported by the provider:
- Fetch available models dynamically.
Otherwise:
- Use predefined model lists.
8. Error Handling
Handle cases where:
- API key missing
- Invalid API key
- Provider unavailable
- Model unavailable
- Timeout
- Rate limit
- Unsupported provider
Errors should be provider-independent at the feature layer.
9. Extensibility
Adding a new provider should only require:
- New provider implementation
- Provider registration
- Optional UI updates (if needed)
No feature logic should require modification.
Non-Goals
- Prompt optimization
- Provider benchmarking
- Automatic provider fallback
- Load balancing between providers
- Cost optimization
- Streaming responses (unless already supported)
These can be addressed in future issues.
Suggested Project Structure
ai-service/
providers/
groq/
openai/
claude/
gemini/
interfaces/
llm-provider.ts
router/
llm-router.ts
config/
provider-config.ts
features/
cv-tailoring/
mail-creator/
interview-insights/
Acceptance Criteria
Issue: Refactor AI Service & Backend to Support Multiple LLM Providers
Title
refactor(ai): introduce multi-provider LLM architecture with configurable provider/model selection per feature
Description
Currently, the AI Service only supports Groq as the LLM provider and the backend only stores a single Groq API key.
Refactor the AI infrastructure to support multiple LLM providers through a unified abstraction layer, allowing each AI feature to use a different provider and model.
The system should be extensible so that adding a new provider in the future requires minimal changes.
Motivation
Different LLM providers excel at different tasks.
Examples:
Instead of hardcoding Groq everywhere, the application should allow selecting the provider/model per feature.
Goals
Supported Providers (Initial)
Future providers should be easy to plug in.
Current Architecture
Desired Architecture
Feature code should never directly know which provider is being used.
Functional Requirements
1. Provider Abstraction
Create a common interface for all providers.
Example:
Each provider implements this interface.
Examples:
2. LLM Router
Introduce a router/factory responsible for:
Example:
Router internally resolves:
3. Provider Configuration
Store API credentials for every supported provider.
Example configuration:
{ "groq": { "apiKey": "..." }, "openai": { "apiKey": "..." }, "claude": { "apiKey": "..." }, "gemini": { "apiKey": "..." } }Missing API keys should disable that provider without affecting others.
4. Feature-Level Provider Selection
Each AI feature should have configurable:
Initial configurable features:
Example:
{ "cvTailoring": { "provider": "openai", "model": "gpt-5" }, "mailCreator": { "provider": "claude", "model": "claude-sonnet-4" }, "interviewInsights": { "provider": "gemini", "model": "gemini-2.5-pro" } }No feature should hardcode provider names.
5. Backend Settings API
Extend the settings endpoints to support:
API Keys
AI Feature Configuration
For every feature:
6. Settings UI
Refactor the settings page.
API Keys Section
AI Configuration
For each feature:
etc.
Model lists should update dynamically based on the selected provider (where supported).
7. Model Discovery
Where supported by the provider:
Otherwise:
8. Error Handling
Handle cases where:
Errors should be provider-independent at the feature layer.
9. Extensibility
Adding a new provider should only require:
No feature logic should require modification.
Non-Goals
These can be addressed in future issues.
Suggested Project Structure
Acceptance Criteria