contexa-core

Model Providers

모델 프로바이더 시스템은 여러 런타임에 걸쳐 LLM 모델을 관리합니다. DynamicModelRegistryLlmRuntimeCatalog의 chat 바인딩과 구성된 TieredLLMProperties 계층에서 모델을 등록하며, DynamicModelSelectionStrategy는 각 요청에 대해 명시적 모델 힌트·티어 매핑·기본 ChatModel 폴백 순서로 런타임 모델을 해석합니다.

개요

Contexa는 여러 LLM 런타임을 동시에 지원합니다. 애플리케이션 시작 시 DynamicModelRegistry는 두 가지 경로로 디스크립터 맵을 채웁니다:

  1. LlmRuntimeCatalog chat 바인딩LlmRuntimeCatalog.getChatBindings()가 반환하는 모든 LlmRuntimeBinding이 등록됩니다. 카탈로그는 Contexa 런타임(예: contexa.llm.chat.ollama.*)과 Spring AI 자동 구성(Anthropic, OpenAI 등)으로 생성된 Spring AI ChatModel 빈으로부터 구성됩니다.
  2. TieredLLMProperties 계층spring.ai.security.layer1spring.ai.security.layer2에 구성된 기본·백업 모델이 해당 티어로 등록됩니다. 레지스트리는 resolveCanonicalModelId(...)를 사용하므로 동일 모델을 runtime ID, bean name, alias 어느 쪽으로도 조회할 수 있습니다.

바인딩이 없을 때 레지스트리는 모델 ID에서 provider 이름을 추론합니다. 인식되는 부분 문자열은 llama, qwen, gemma, mistral, phi, exaone, codellama, deepseek (→ ollama), claude (→ anthropic), gpt·o1·davinci (→ openai), gemini·vertex (→ gemini), bedrock (→ bedrock)입니다. 나머지는 spring으로 분류됩니다.

LlmRuntimeCatalog

탐색된 chat·embedding 런타임을 노출하는 인터페이스입니다. 레지스트리가 바인딩을 찾고 필요할 때 실제 ChatModel 인스턴스를 해석하는 데 사용합니다.

public interface LlmRuntimeCatalog
getChatBindings() List<LlmRuntimeBinding>
카탈로그가 알고 있는 모든 chat 런타임 바인딩을 반환합니다.
getEmbeddingBindings() List<LlmRuntimeBinding>
카탈로그가 알고 있는 모든 embedding 런타임 바인딩을 반환합니다.
findChatBinding(String selector) Optional<LlmRuntimeBinding>
runtime ID, bean name, model ID, 또는 등록된 alias로 chat 바인딩을 찾습니다.
findEmbeddingBinding(String selector) Optional<LlmRuntimeBinding>
같은 선택자로 embedding 바인딩을 찾습니다.
resolveChatModel(String selector) ChatModel
일치하는 바인딩에 대한 실제 Spring AI ChatModel을 반환합니다.
resolveEmbeddingModel(String selector) EmbeddingModel
일치하는 바인딩에 대한 실제 Spring AI EmbeddingModel을 반환합니다.
resolvePrimaryChatModel(String priorityConfig) Optional<ChatModel>
쉼표로 구분된 priority 설정 문자열을 사용해 기본 chat 모델을 해석합니다.
resolvePrimaryEmbeddingModel(String priorityConfig) Optional<EmbeddingModel>
priority 설정 문자열을 사용해 기본 embedding 모델을 해석합니다.
resolveSpringPrimaryChatModel() Optional<ChatModel>
컨텍스트에 존재할 경우 Spring AI primary ChatModel 빈을 반환합니다.
resolveSpringPrimaryEmbeddingModel() Optional<EmbeddingModel>
컨텍스트에 존재할 경우 Spring AI primary EmbeddingModel 빈을 반환합니다.

LlmRuntimeBinding

단일 런타임 바인딩에 대한 불변 레코드입니다. 바인딩은 Contexa LLM 자동 구성이 생성하며 카탈로그와 레지스트리 모두가 소비합니다.

public final class LlmRuntimeBinding
속성타입설명
runtimeIdString이 바인딩에 할당된 Contexa 런타임 ID.
beanNameString실제 모델 빈의 Spring bean 이름.
providerString프로바이더 식별자(예: ollama, anthropic, openai).
modelIdString런타임이 보고한 정규 모델 ID(예: llama3.1:8b).
aliasesSet<String>같은 바인딩으로 해석되는 추가 선택자들.
typeLlmRuntimeTypeChat 또는 embedding 런타임 유형.
primaryboolean이 바인딩이 해당 유형의 Spring primary로 표시되어 있는지 여부.
sourceString바인딩의 출처(예: 자동 구성 클래스 또는 설정 키).

헬퍼 메서드

메서드반환설명
canonicalId()String바인딩의 선호 식별자를 반환합니다: modelIdruntimeIdbeanName 순.
matches(String selector)boolean선택자가 runtimeId, beanName, modelId, 또는 alias 중 하나와 일치하는지 반환합니다.

ModelDescriptor

모델의 정체성·기능·기본 옵션·현재 상태를 기술합니다.

@Data @Builder
public class ModelDescriptor
속성타입설명
modelIdString고유 모델 식별자(예: llama3.1:8b, claude-3-opus).
displayNameString사람이 읽기 쉬운 모델 이름.
providerString프로바이더 이름(ollama, anthropic, openai).
tierInteger모델에 할당된 구성 런타임 티어(1 또는 2). 할당되지 않으면 null.
versionString모델 버전 문자열.
capabilitiesModelCapabilitiesStreaming·Tool 호출·멀티모달·컨텍스트 윈도우·출력 예산을 기술하는 nested class.
optionsModelOptions기본 샘플링 옵션(temperature, topP, topK, repetitionPenalty)을 기술하는 nested class.
statusModelStatusAVAILABLE 또는 UNAVAILABLE.

ModelCapabilities (nested class)

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

ModelOptions (nested class)

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

헬퍼 메서드

supportsAdvancedFeatures() boolean
Capabilities가 tool calling·function calling·멀티모달 중 하나라도 선언할 때 true를 반환합니다.

DynamicModelRegistry

디스크립터를 관리하고 ChatModel 인스턴스를 캐시하는 중앙 레지스트리입니다. @PostConstruct 초기화 동안 카탈로그와 티어 설정에서 모델을 등록합니다.

public class DynamicModelRegistry

생성자 의존성

의존성설명
ApplicationContext초기화 시 사용되는 Spring application context 참조.
TieredLLMProperties구성된 티어 계층 구조(layer 1·layer 2, primary·backup 모델).
LlmRuntimeCatalogSpring AI 런타임 바인딩 카탈로그. Optional: 없을 경우 getModel(...)ModelSelectionException을 던집니다.

Public API

getModel(String modelId) ChatModel
주어진 ID의 ChatModel을 반환합니다. 정규 모델 ID를 해석하고 바인딩을 조회하여 카탈로그가 실제 모델을 해석하도록 요청하며 결과를 캐시합니다. ID나 카탈로그가 없으면 ModelSelectionException을 던집니다.
getAllModels() Collection<ModelDescriptor>
등록된 모든 모델 디스크립터의 복사본을 반환합니다.
getDescriptor(String modelId) ModelDescriptor
ChatModel을 인스턴스화하지 않고 모델 ID에 대한 등록된 디스크립터를 반환합니다.
getModelsByProvider(String provider) List<ModelDescriptor>
Provider 이름으로 필터링된 AVAILABLE 디스크립터를 반환합니다(대소문자 무시).
registerModel(ModelDescriptor descriptor) void
디스크립터를 등록하거나 기존 항목에 병합합니다. 수신 디스크립터가 값을 비워둘 때 기존 tier와 provider 값이 보존됩니다.
refreshModels() void
디스크립터·인스턴스 캐시·alias를 모두 지운 뒤 카탈로그 바인딩과 설정 계층을 다시 등록합니다.
updateModelStatus(String modelId, ModelStatus status) void
등록된 모델의 가용성 상태를 업데이트합니다.
shutdown() void
디스크립터·인스턴스 캐시·alias를 지우는 @PreDestroy 훅.

ModelSelectionStrategy

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

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

DynamicModelSelectionStrategy

기본 선택 전략은 명시적 모델 우선 폴백 체인을 사용합니다. DynamicModelRegistry, TieredLLMProperties, 기본 ChatModel 빈으로 생성됩니다.

public class DynamicModelSelectionStrategy implements ModelSelectionStrategy
  1. 명시적 모델 요청 — 먼저 ExecutionContext.preferredModel을 시도합니다. 없으면 다음 순서로 메타데이터 키를 찾습니다: requestedModelId, preferredModel, runtimeModelId, modelId.
  2. 티어 해석 — 명시적 모델이 해석되지 않으면 다음 순서로 티어를 선택합니다: analysisLevel.getDefaultTier()securityTaskType.getDefaultTier()ExecutionContext.tier. 1을 초과하는 값은 구성된 layer 2로 정규화됩니다.
  3. Primary/backup 조회 — 전략은 TieredLLMProperties.getModelNameForTier(...)로 기본 모델을, getBackupModelNameForTier(...)로 백업 모델을 조회합니다.
  4. Primary ChatModel 폴백 — 모든 티어 후보가 실패하면 자동 구성된 기본 ChatModel 빈을 마지막 폴백으로 반환합니다.

해석 메타데이터

전략은 결과를 ExecutionContext.metadata에 기록합니다. 하위 코드와 어드바이저는 다음 키를 확인할 수 있습니다:

설명
requestedModelId요청된 명시적 모델 ID(제공된 경우).
requestedModelSourceKey요청 ID의 출처(예: executionContext.preferredModel 또는 executionContext.metadata.runtimeModelId).
selectedModelId최종적으로 선택된 모델 ID.
selectedModelProvider일치하는 ModelDescriptor에서 가져온 provider 이름(가능할 때).
runtimeModelId해당 키를 찾는 하위 소비자를 위한 selectedModelId의 복제본.
modelSelectionSource모델이 선택된 이유(예: explicit_model, analysis_level:NORMAL, security_task_type:FORENSIC_ANALYSIS, tier:2, primary_chat_model).
modelSelectionFallbackUsed백업 또는 기본 폴백이 사용되었을 때 true.
modelSelectionCandidates전략이 시도한 모델 ID의 정렬된 목록.
modelSelectionFailure모델을 선택할 수 없을 때의 실패 이유.

추가 메서드

getModelCapabilities(String modelName) Map<String, Object>
디스크립터의 modelId, provider, capabilities 블록, 컨텍스트 윈도우, maxTokens, streaming 플래그, tier, status를 요약한 맵을 반환합니다. 모델이 등록되어 있지 않으면 빈 맵을 반환합니다.

설정

계층형 모델 계층 구조

YAML
spring:
  ai:
    security:
      layer1:
        model: qwen2.5:7b
        backup:
          model: qwen2.5:7b
      layer2:
        model: gpt-4o-mini
        backup:
          model: llama3.1:8b
      tiered:
        layer1:
          timeout-ms: 30000
        layer2:
          timeout-ms: 60000

contexa:
  llm:
    chat:
      ollama:
        base-url: http://localhost:11434
        model: qwen2.5:7b

선택 순서: 명시적 모델 요청 → analysisLevelsecurityTaskType → 명시적 tier → 기본 ChatModel 폴백. 런타임은 구성된 layer 1과 2만 가지므로, 더 높은 시맨틱 티어는 layer 2로 정규화됩니다.