LLM 프로바이더 모듈 개요
이 문서는 Elftia 내 LLM 프로바이더 서브시스템의 전체 아키텍처를 설명합니다. 이 서브시스템은 멀티 프로바이더 설정 관리, API 키 풀, 모델 검색, 요청 라우팅 및 Completion 호출 파이프라인을 담당합니다.
파일 위치
| 모듈 | 경로 |
|---|---|
| CompletionService | packages/desktop/app/main/services/capabilities/llm/completion/CompletionService.ts |
| ApiKeyPoolService | packages/desktop/app/main/services/capabilities/llm/completion/ApiKeyPoolService.ts |
| LLMConfigService | packages/desktop/app/main/services/capabilities/llm/config-service/LLMConfigService.ts |
| ProviderManager | packages/desktop/app/main/services/capabilities/llm/config-service/ProviderManager.ts |
| ModelDiscoveryManager | packages/desktop/app/main/services/capabilities/llm/config-service/ModelDiscoveryManager.ts |
| ConfigIOManager | packages/desktop/app/main/services/capabilities/llm/config-service/ConfigIOManager.ts |
| AgentModelsManager | packages/desktop/app/main/services/capabilities/llm/config-service/AgentModelsManager.ts |
| ThinkingResolver | packages/desktop/app/main/services/capabilities/llm/completion/ThinkingResolver.ts |
| StreamHandler | packages/desktop/app/main/services/capabilities/llm/completion/StreamHandler.ts |
| DirectApiHandler | packages/desktop/app/main/services/capabilities/llm/completion/DirectApiHandler.ts |
| ToolHandler | packages/desktop/app/main/services/capabilities/llm/completion/ToolHandler.ts |
| TransformerHandler | packages/desktop/app/main/services/capabilities/llm/completion/TransformerHandler.ts |
| ProviderSearchInjector | packages/desktop/app/main/services/capabilities/llm/completion/ProviderSearchInjector.ts |
| NativeSearchInjector | packages/desktop/app/main/services/capabilities/llm/completion/NativeSearchInjector.ts |
| URL Builder | packages/desktop/app/main/services/capabilities/llm/completion/url-builder.ts |
| Header Builder | packages/desktop/app/main/services/capabilities/llm/completion/header-builder.ts |
| Message Converter | packages/desktop/app/main/services/capabilities/llm/completion/message-converter.ts |
| Provider Presets | packages/desktop/app/shared/provider-presets.ts |
| IPC Routers | packages/desktop/app/main/services/routers/llm/ |
아키텍처 컨텍스트
graph TB
subgraph Frontend ["Frontend (Renderer)"]
UI[Provider Settings UI]
ChatUI[Chat Interface]
end
subgraph IPCLayer ["IPC Layer"]
PR[ProviderRouter]
AKR[ApiKeyRouter]
CR[CompletionRouter]
RCR[RouterConfigRouter]
TR[TransformerRouter]
MPR[ModelParametersRouter]
end
subgraph LLMConfigService ["LLMConfigService (Delegate Pattern)"]
PM[ProviderManager]
MDM[ModelDiscoveryManager]
CIOM[ConfigIOManager]
AMM[AgentModelsManager]
end
subgraph CompletionService ["CompletionService (Facade Pattern)"]
DAH[DirectApiHandler]
SH[StreamHandler]
TH[ToolHandler]
THR[TransformerHandler]
TR2[ThinkingResolver]
end
AKPS[ApiKeyPoolService]
subgraph ExternalAPIs ["External APIs"]
OpenAI[OpenAI API]
Anthropic[Anthropic API]
Gemini[Gemini API]
Azure[Azure OpenAI API]
Others[Other Providers...]
end
subgraph Storage ["Storage"]
SQLite[(SQLite)]
JSON[(llms-config.json)]
end
UI --> PR
UI --> AKR
ChatUI --> CR
PR --> PM
AKR --> AKPS
CR --> CompletionService
PM --> SQLite
PM --> JSON
MDM --> SQLite
MDM --> JSON
CompletionService --> AKPS
CompletionService --> LLMConfigService
DAH --> OpenAI
DAH --> Anthropic
DAH --> Gemini
DAH --> Azure
SH --> OpenAI
SH --> Anthropic
SH --> Gemini
SH --> Azure
데이터 구조
핵심 타입
// API format enum
type ApiFormat = 'openai' | 'anthropic' | 'google' | 'azure-openai' | 'openai-response';
// LLM provider
interface LLMProvider {
id: string; // Unique identifier
name: string; // Display name
apiFormat?: ApiFormat; // API format (preferred field)
chatApiFormat?: ApiFormat; // Legacy API format field
apiType?: string; // Legacy type field
api_base_url?: string; // API base URL
api_key: string; // Single key (legacy)
models: string[]; // Model ID list
modelConfigs?: ModelConfig[]; // Per-model detailed config
modelGroups?: ModelGroup[]; // Model groups
modelsEndpoint?: string; // Model discovery endpoint
enabled: boolean; // Whether enabled
transformer?: TransformerConfig; // Transformer chain config
icon?: string; // Icon
website?: string; // Official website
docsUrl?: string; // Documentation link
defaultSettings?: CompletionSettings; // Default completion parameters
codingPlan?: CodingPlanConfig; // Coding Plan config
isSystem?: boolean; // System built-in provider
presetId?: string; // Preset template ID
createdAt: string;
updatedAt: string;
}
// Completion request options
interface CompletionOptions {
providerId: string; // Provider ID
model: string; // Model ID
messages: SimpleChatMessage[]; // Message list
maxTokens?: number; // Max token count
temperature?: number; // Temperature
stream?: boolean; // Whether streaming
thinkLevel?: ThinkLevel; // Thinking level
nativeSearchAugmentation?: NativeSearchAugmentation; // Native search augmentation
sessionId?: string; // Session ID (for API Key Pool affinity)
}
// API key pool entry
interface ApiKeyEntry {
id: string; // Unique ID
providerId: string; // Owning provider
label?: string; // Display label
apiKey: string; // Key value
enabled: boolean; // Whether enabled
weight: number; // Weight (1-100)
}
데이터 흐름 개요
Completion 요청 파이프라인
sequenceDiagram
participant Frontend as Frontend
participant CS as CompletionService
participant LLC as LLMConfigService
participant AKP as ApiKeyPoolService
participant Handler as API Handler
participant API as Provider API
Frontend->>CS: complete() / completeStream()
CS->>LLC: resolveRoutedModel(providerId, model)
LLC-->>CS: actualProviderId + actualModel
CS->>LLC: getProvider(actualProviderId)
LLC-->>CS: provider config
CS->>CS: resolveApiKeyForRequest()
Note right of CS: Priority: codingPlan > pool > legacy
CS->>AKP: getKeyForSession(providerId, sessionId)
AKP-->>CS: resolved API key
CS->>CS: resolveApiFormat(provider)
CS->>Handler: callDirectHandler / callStreamHandler
Handler->>API: HTTP request
API-->>Handler: response / SSE stream
Handler-->>CS: CompletionResult
alt 429/529 error
CS->>AKP: reportError(providerId, sessionId, status)
AKP-->>CS: new key
CS->>Handler: retry with new key
end
CS->>AKP: reportSuccess(sessionId)
CS-->>Frontend: result
모듈 경계 및 책임
| 모듈 | 책임 | 비책임 영역 |
|---|---|---|
| CompletionService | 요청 파이프라인 오케스트레이션, 포맷 디스패치, 재시도, 비전 폴백 | 프로바이더 CRUD, 키 저장 |
| ApiKeyPoolService | 다중 키 로드 밸런싱, 세션 친화성, 쿨다운 백오프 | 키 영속화 (DB에 위임) |
| LLMConfigService | 프로바이더 설정 관리, 모델 검색, 라우팅, Transformer 체인 | API 호출 |
| ProviderManager | 프로바이더 CRUD, 템플릿/프리셋 시스템, SQLite 영속화 | 모델 검색, 라우팅 설정 |
| ModelDiscoveryManager | 모델 목록 검색, 캐싱 (SQLite + 파일) | 프로바이더 CRUD |
| ConfigIOManager | 설정 가져오기/내보내기, JSON 파일 I/O | 데이터베이스 작업 |
| AgentModelsManager | 라우팅 설정, Transformer 관리, 전역 파라미터 | 프로바이더 CRUD |
| ThinkingResolver | max_tokens 해석, 사고 예산 계산 | 요청 전송 |
| StreamHandler | SSE 스트림 처리 (OpenAI/Anthropic/Gemini) | 비스트리밍 요청 |
| DirectApiHandler | 비스트리밍 API 호출 | 스트리밍 요청 |
| ToolHandler | Agent 도구 호출 루프 | 일반 Completion |
| TransformerHandler | Transformer 체인 Completion | 직접 API 호출 |
IPC 통합 테이블
| IPC 채널 | 방향 | Router | 설명 |
|---|---|---|---|
llmConfig:getProviders | Renderer -> Main | ProviderRouter | 모든 프로바이더 조회 |
llmConfig:getProvider | Renderer -> Main | ProviderRouter | 단일 프로바이더 조회 |
llmConfig:addProvider | Renderer -> Main | ProviderRouter | 프로바이더 추가 |
llmConfig:updateProvider | Renderer -> Main | ProviderRouter | 프로바이더 업데이트 |
llmConfig:deleteProvider | Renderer -> Main | ProviderRouter | 프로바이더 삭제 |
llmConfig:toggleProvider | Renderer -> Main | ProviderRouter | 프로바이더 활성화/비활성화 |
llmConfig:discoverModels | Renderer -> Main | ProviderRouter | 모델 목록 검색 |
llmConfig:getProviderPresets | Renderer -> Main | ProviderRouter | 프리셋 템플릿 조회 |
llmConfig:addFromPreset | Renderer -> Main | ProviderRouter | 프리셋으로부터 프로바이더 추가 |
llmConfig:exportConfig | Renderer -> Main | ProviderRouter | 설정 내보내기 |
llmConfig:importConfig | Renderer -> Main | ProviderRouter | 설정 가져오기 |
llmConfig:getApiKeys | Renderer -> Main | ApiKeyRouter | 키 목록 조회 |
llmConfig:addApiKey | Renderer -> Main | ApiKeyRouter | 키 추가 |
llmConfig:updateApiKey | Renderer -> Main | ApiKeyRouter | 키 업데이트 |
llmConfig:deleteApiKey | Renderer -> Main | ApiKeyRouter | 키 삭제 |
llmConfig:toggleApiKey | Renderer -> Main | ApiKeyRouter | 키 활성화/비활성화 |
확장 포인트
- 새 API 포맷 추가:
url-builder.ts에 URL 빌더 함수를 추가하고,DirectApiHandler.ts/StreamHandler.ts에 핸들러 함수를 추가한 뒤CompletionService의 switch 문에 등록합니다 - 새 프로바이더 프리셋 추가:
provider-presets.ts의PROVIDER_PRESETS배열에 템플릿을 추가합니다 - 새 검색 설정 추가:
provider-presets.ts의PROVIDER_SEARCH_CONFIGS에 항목을 추가합니다 - 커스텀 Transformer:
AgentModelsManager를 통해 새 Transformer 체인을 등록합니다
관련 파일
| 파일 | 목적 |
|---|---|
packages/desktop/app/shared/llm-config.ts | LLM 설정 공유 타입 정의 |
packages/desktop/app/shared/completion-types.ts | Completion 타입 정의 |
packages/desktop/app/shared/thinking-config.ts | 사고 설정 및 예산 계산 |
packages/desktop/app/shared/provider-presets.ts | 프로바이더 프리셋 템플릿 및 검색 설정 |
packages/desktop/app/main/services/routers/llm/schemas.ts | IPC 요청 Zod 유효성 검사 스키마 |
packages/desktop/app/main/services/capabilities/llm/config-service/schemas.ts | 설정 서비스 내부 Zod 스키마 |
packages/desktop/app/main/services/infra/utils/sse-parser.ts | SSE 스트림 파싱 유틸리티 |
packages/desktop/app/main/workers/db/apiKeys.ts | API 키 데이터베이스 작업 |
packages/desktop/app/main/workers/DbClient.ts | 데이터베이스 클라이언트 |
packages/desktop/app/preload/index.ts | Preload API 노출 |