contexa-core

Model Provider

모델 프로바이더 시스템은 여러 백엔드에 걸쳐 LLM 모델을 관리합니다. DynamicModelRegistry는 Spring AI ChatModel 빈과 커스텀 ModelProvider 구현체를 자동 탐색하며, DynamicModelSelectionStrategy는 명시적 모델 힌트, 계층 매핑, 가용성, 구성된 폴백을 바탕으로 각 요청의 런타임 모델을 선택합니다.

개요

Contexa는 여러 LLM 프로바이더를 동시에 지원합니다. 시작 시 DynamicModelRegistry는 세 가지 메커니즘을 통해 사용 가능한 모든 모델을 탐색합니다:

  1. ModelProvider 빈 — Spring 컨텍스트에 등록된 커스텀 프로바이더 구현체.
  2. Spring AI ChatModel 빈contexa.llm.chat.ollama.*, spring.ai.anthropic.*, 또는 spring.ai.openai.* 설정에서 생성된 ChatModel 빈을 자동 감지합니다.
  3. TieredLLMProperties — 구성된 layer-1 / layer-2 계층에서 선언된 모델 ID.

레지스트리는 모델 클래스 이름에서 프로바이더를 자동 추론하고 (Ollama, Anthropic, OpenAI, Gemini, Mistral, Azure, Bedrock, HuggingFace) 초기화 시 헬스 체크를 수행합니다.

ModelProvider

커스텀 모델 프로바이더 구현을 위한 인터페이스입니다. Spring AI 자동 설정으로 다루지 않는 프로바이더를 지원하려면 이를 구현하세요.

public interface ModelProvider
getProviderName() String
고유 프로바이더 식별자를 반환합니다 (예: "ollama", "anthropic", "openai").
getDescription() String
프로바이더 구현의 사람이 읽을 수 있는 설명을 반환합니다.
getAvailableModels() List<ModelDescriptor>
이 프로바이더가 현재 노출하는 모든 모델을 반환합니다.
getModelDescriptor(String modelId) ModelDescriptor
프로바이더가 해석할 수 있는 특정 모델 ID의 디스크립터를 반환합니다.
createModel(ModelDescriptor descriptor, Map<String, Object> config) ChatModel
주어진 디스크립터에 대한 ChatModel 인스턴스를 생성합니다. config 맵은 런타임 오버라이드를 제공합니다.
supportsModel(String modelId) boolean
이 프로바이더가 주어진 모델 ID를 서비스할 수 있는지 여부를 반환합니다.
checkHealth(String modelId) HealthStatus
지정된 모델에 대한 헬스 체크를 수행하고 응답 시간 지표와 함께 결과를 반환합니다.
initialize(Map<String, Object> config) void
주어진 설정으로 프로바이더를 초기화합니다. 레지스트리 시작 시 한 번 호출됩니다.
shutdown() void
레지스트리 종료 시 프로바이더 리소스를 해제합니다.
isReady() boolean
프로바이더가 초기화되어 모델 접근과 헬스 체크를 수행할 준비가 되었는지 반환합니다.
refreshModels() void
레지스트리가 디스크립터를 다시 병합하기 전에 프로바이더 측 모델 캐시를 새로고침합니다.
getMetrics() Map<String, Object>
구현체가 노출하는 프로바이더 수준 메트릭을 반환합니다.
getPriority() int
프로바이더 우선순위를 반환합니다. 여러 프로바이더가 동일한 모델을 지원할 때 낮은 값이 우선됩니다. 기본값: 100.

ModelDescriptor

모델의 ID, 기능, 기본 옵션, 현재 상태를 설명합니다.

@Data @Builder
public class ModelDescriptor
속성타입설명
modelIdString고유 모델 식별자 (예: "llama3.1:8b", "claude-3-opus").
displayNameString사람이 읽을 수 있는 모델 이름.
providerString프로바이더 이름 (ollama, anthropic, openai).
tierInteger이 모델에 할당된 런타임 계층입니다 (1 또는 2). 미할당 시 null입니다.
versionString모델 버전 문자열.
capabilitiesModelCapabilities모델이 지원하는 기능 (Streaming, Tool 호출, 멀티모달, 컨텍스트 윈도우, 출력 예산).
optionsModelOptions기본 샘플링 옵션 (temperature, topP, topK, repetitionPenalty).
statusModelStatusAVAILABLE 또는 UNAVAILABLE.

ModelCapabilities

필드타입기본값
streamingbooleantrue
toolCallingbooleanfalse
functionCallingbooleanfalse
multiModalbooleanfalse
maxTokensint4096
contextWindowint4096
maxOutputTokensint4096

ModelOptions

필드타입기본값
temperatureDouble0.7
topPDouble0.9
topKIntegernull
repetitionPenaltyDouble1.0

DynamicModelRegistry

모든 LLM 모델을 탐색, 관리, 접근하는 중앙 레지스트리입니다. 애플리케이션 시작 시 자동 초기화됩니다.

public class DynamicModelRegistry
getModel(String modelId) ChatModel
주어진 ID의 ChatModel을 반환합니다. 아직 로드되지 않은 경우 인스턴스를 생성하고 캐시합니다. 찾지 못하면 ModelSelectionException을 던집니다.
getAllModels() Collection<ModelDescriptor>
등록된 모든 모델 디스크립터를 반환합니다.
getDescriptor(String modelId) ModelDescriptor
ChatModel 인스턴스를 만들지 않고, 모델 ID에 대한 등록된 디스크립터를 반환합니다.
getModelsByProvider(String provider) List<ModelDescriptor>
프로바이더 이름으로 필터링된 AVAILABLE 모델 디스크립터를 반환합니다.
registerModel(ModelDescriptor descriptor) void
모델 디스크립터를 등록하거나 병합합니다. 설정에서 정의된 티어가 프로바이더에서 정의된 티어보다 우선합니다.
refreshModels() void
모든 프로바이더에 모델 목록 새로고침을 요청하고 새로 발견된 모델을 등록합니다.
updateModelStatus(String modelId, ModelStatus status) void
등록된 모델의 가용성 상태를 업데이트합니다.
shutdown() void
애플리케이션 종료 시 등록된 프로바이더의 shutdown()을 호출합니다.

ModelSelectionStrategy

모델 선택 로직을 위한 인터페이스입니다. DynamicModelSelectionStrategy가 기본 구현체입니다.

public interface ModelSelectionStrategy
selectModel(ExecutionContext context) ChatModel
주어진 실행 컨텍스트에 가장 적합한 모델을 선택합니다. 사용 가능한 모델이 없으면 null을 반환합니다.
getSupportedModels() Set<String>
선택 가능한 모든 모델 ID의 집합을 반환합니다.
isModelAvailable(String modelName) boolean
특정 모델이 현재 사용 가능한지 확인합니다.

DynamicModelSelectionStrategy

기본 선택 전략은 명시적 모델 우선 폴백 체인을 사용합니다:

public class DynamicModelSelectionStrategy implements ModelSelectionStrategy
  1. 명시적 모델 요청ExecutionContext.preferredModel 또는 메타데이터의 requestedModelId, preferredModel, runtimeModelId, modelId 키를 먼저 확인합니다.
  2. 티어 해석 — 명시적 모델이 없으면 analysisLevel, securityTaskType, ExecutionContext.tier 순서로 의미적 티어를 해석합니다. 1보다 큰 값은 구성된 layer 2로 정규화됩니다.
  3. 주/백업 모델 조회 — 해석된 티어에 대해 TieredLLMProperties의 주 모델을 먼저 시도하고, 필요하면 백업 모델로 폴백합니다.
  4. 기본 ChatModel 폴백 — 티어 기반 선택까지 실패하면 자동 구성된 기본 ChatModel 빈을 마지막 폴백으로 사용합니다.

설정

계층형 모델 구조

YAML
contexa:
  llm:
    layer1:
      model: tinyllama:latest
      backup:
        model: qwen2.5:0.5b
    layer2:
      model: llama3.1:8b
      backup:
        model: exaone3.5:7.8b

모델 선택 우선순위: 선택은 먼저 ExecutionContext.preferredModel과 메타데이터의 명시적 모델 키를 확인하고, 그 다음 analysisLevelsecurityTaskTypeExecutionContext.tier 순으로 티어를 해석합니다. 이후 TieredLLMProperties의 주/백업 모델을 시도하고, 마지막으로 기본 ChatModel 빈으로 폴백합니다.