Ollama Chat

Ollama Chat

Ollama를 쓰면 다양한 대규모 언어 모델(LLM)을 로컬에서 실행하고 텍스트를 생성할 수 있어요. Spring AI는 OllamaChatModel API로 Ollama 채팅 완성 기능을 지원해요. 로컬에서 모델을 돌리기 때문에 클라우드 비용 없이 개발·테스트해볼 수 있다는 점이 매력적이에요.

출처: 공식문서

자동 설정 (Auto-configuration)

Spring AI의 자동 설정과 스타터 모듈의 아티팩트 이름이 크게 바뀌었어요. 자세한 내용은 업그레이드 노트를 확인해주세요.

Spring AI는 Ollama 채팅 통합을 위한 Spring Boot 자동 설정을 제공해요. Maven pom.xml이나 Gradle build.gradle에 다음 의존성을 추가하면 돼요.

  • Maven
  • Gradle
<dependency>
   <groupId>org.springframework.ai</groupId>
   <artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
dependencies {
    implementation 'org.springframework.ai:spring-ai-starter-model-ollama'
}

기본 속성 (Base Properties)

Ollama에 연결하기 위한 속성 프리픽스는 spring.ai.ollama예요.

기본 속성 | 속성 | 설명 | 기본값 | |---|---|---| | spring.ai.ollama.base-url | Ollama API 서버가 실행 중인 기본 URL | http://localhost:11434 | | 속성 | 설명 | 기본값 | |---|---|---| | spring.ai.ollama.init.pull-model-strategy | 시작 시 모델을 당겨올지, 어떻게 할지 | never | | spring.ai.ollama.init.timeout | 모델이 당겨질 때까지 기다리는 시간 | 5m | | spring.ai.ollama.init.max-retries | 모델 풀 작업의 최대 재시도 횟수 | 0 | | spring.ai.ollama.init.chat.include | 초기화 작업에 이 유형의 모델 포함 | true | | spring.ai.ollama.init.chat.additional-models | 기본 속성으로 구성된 모델 외에 초기화할 추가 모델 | [] |

채팅 속성 (Chat Properties)

채팅 자동 설정의 활성·비활성은 프리픽스 spring.ai.model.chat로 관리해요. 활성화하려면 spring.ai.model.chat=ollama(기본값), 비활성화하려면 spring.ai.model.chat=none을 쓰면 돼요.

Ollama 채팅 모델을 구성하는 프리픽스는 spring.ai.ollama.chat이에요. 여기에는 model, keep-alive, format 같은 Ollama 요청(고급) 파라미터와 Ollama 모델 options 속성이 포함돼요.

Ollama 채팅 모델의 고급 요청 파라미터를 볼게요.

속성 설명 기본값
spring.ai.ollama.chat.enabled (제거됨, 더는 유효하지 않음) Ollama 채팅 모델 활성화 true
spring.ai.model.chat Ollama 채팅 모델 활성화 ollama
spring.ai.ollama.chat.model 사용할 지원 모델 이름 mistral
spring.ai.ollama.chat.format 응답을 반환할 형식. "json"(모든 JSON 구조) 또는 JSON Schema 객체(강제 구조) 허용 -
spring.ai.ollama.chat.keep_alive 요청 후 모델이 메모리에 로드된 채 유지되는 시간 5m
spring.ai.ollama.chat.think 모델이 최종 답변 전에 추론 trace를 출력할지 제어 -
속성 설명 기본값
--- --- ---
spring.ai.ollama.chat.numa NUMA 사용 여부 false
spring.ai.ollama.chat.num-ctx 다음 토큰 생성에 사용되는 컨텍스트 창 크기 2048
spring.ai.ollama.chat.num-batch 프롬프트 처리 최대 배치 크기 512
spring.ai.ollama.chat.num-gpu GPU로 보낼 레이어 수. macOS에서는 metal 지원을 위해 기본 1, 0은 비활성화. 1은 NumGPU를 동적으로 설정해야 함을 의미 -1
spring.ai.ollama.chat.main-gpu 다중 GPU 사용 시 모든 GPU에 계산을 분할하기에 오버헤드가 아깝지 않은 작은 텐서에 사용할 GPU 제어. 해당 GPU는 임시 결과용 스크래치 버퍼를 위해 약간 더 많은 VRAM 사용 0
spring.ai.ollama.chat.low-vram - false
spring.ai.ollama.chat.f16-kv - true
spring.ai.ollama.chat.logits-all 마지막 토큰이 아니라 모든 토큰의 logits 반환. 완성이 logprobs를 반환하려면 true여야 함 -
spring.ai.ollama.chat.vocab-only 가중치가 아닌 어휘만 로드 -
spring.ai.ollama.chat.use-mmap 기본적으로 모델은 메모리에 매핑되어 필요에 따라 필요한 부분만 로드. 모델이 총 RAM보다 크거나 메모리가 부족하면 mmap 사용이 pageout 위험을 높일 수 있음. mmap 비활성화는 로드가 느려지지만 mlock을 안 쓰면 pageout을 줄일 수 있음. 모델이 총 RAM보다 크면 mmap을 끄면 모델이 아예 로드되지 않음 null
spring.ai.ollama.chat.use-mlock 메모리 매핑 시 모델을 메모리에 잠가 swap되지 않게 함. 성능은 좋아지지만 더 많은 RAM을 요구해 로드 시간이 느려질 수 있음 false
spring.ai.ollama.chat.num-thread 계산 중 사용할 스레드 수. 기본적으로 Ollama가 최적 성능을 위해 감지. 물리 CPU 코어 수(논리 코어 수 아님)로 설정 권장. 0 = 런타임이 결정 0
spring.ai.ollama.chat.num-keep - 4
spring.ai.ollama.chat.seed 생성에 사용할 난수 시드. 특정 숫자로 설정하면 같은 프롬프트에 같은 텍스트 생성 -1
spring.ai.ollama.chat.num-predict 텍스트 생성 시 예측할 최대 토큰 수. (-1 = 무한 생성, -2 = 컨텍스트 채우기) -1
spring.ai.ollama.chat.top-k 의미 없는 텍스트 생성 확률을 줄임. 높은 값(예: 100)은 더 다양한 답변, 낮은 값(예: 10)은 더 보수적 40
spring.ai.ollama.chat.top-p top-k와 함께 동작. 높은 값(예: 0.95)은 더 다양한 텍스트, 낮은 값(예: 0.5)은 더 집중적·보수적 텍스트 0.9
spring.ai.ollama.chat.min-p top_p의 대안으로 품질과 다양성의 균형 지향. p는 가장 가능성 높은 토큰의 확률에 상대적으로 토큰이 고려되는 최소 확률. p=0.05이고 가장 가능성 높은 토큰 확률이 0.9면 0.045 미만 logits는 필터링 0.0
spring.ai.ollama.chat.tfs-z Tail-free sampling은 덜 가능성 있는 토큰의 영향력을 줄임. 높은 값(예: 2.0)은 영향력을 더 줄이고 1.0은 비활성화 1.0
spring.ai.ollama.chat.typical-p - 1.0
spring.ai.ollama.chat.repeat-last-n 반복 방지를 위해 모델이 얼마나 뒤를 보는지 설정. (기본: 64, 0 = 비활성화, -1 = num_ctx) 64
spring.ai.ollama.chat.temperature 모델의 온도. 높일수록 더 창의적으로 답변 0.8
spring.ai.ollama.chat.repeat-penalty 반복을 얼마나 강하게 페널티할지. 높은 값(예: 1.5)은 반복을 더 강하게 페널티, 낮은 값(예: 0.9)은 더 관대 1.1
spring.ai.ollama.chat.presence-penalty - 0.0
spring.ai.ollama.chat.frequency-penalty - 0.0
spring.ai.ollama.chat.mirostat perplexity 제어를 위한 Mirostat sampling 활성화. (기본: 0, 0 = 비활성화, 1 = Mirostat, 2 = Mirostat 2.0) 0
spring.ai.ollama.chat.mirostat-tau 출력의 응집력과 다양성의 균형 제어. 낮은 값은 더 집중적·응집력 있는 텍스트 5.0
spring.ai.ollama.chat.mirostat-eta 생성된 텍스트의 피드백에 알고리즘이 얼마나 빨리 반응하는지 영향. 낮은 학습률은 더 느린 조정, 높은 학습률은 더 반응적 0.1
spring.ai.ollama.chat.penalize-newline - true
spring.ai.ollama.chat.stop 사용할 중지 시퀀스. 이 패턴이 만나면 LLM이 생성 중지. modelfile에서 여러 중지 파라미터를 지정해 여러 중지 패턴 설정 가능 -
spring.ai.ollama.chat.tool-callbacks ChatModel에 등록할 Tool 콜백 -

spring.ai.ollama.chat 프리픽스가 붙은 모든 속성은 Prompt 호출에 요청별 runtime 옵션을 추가해 런타임에 덮어쓸 수 있어요.

런타임 옵션

OllamaChatOptions.java 클래스는 사용할 모델, temperature, thinking mode 같은 모델 구성을 제공해요.

OllamaOptions 클래스는 더 이상 사용되지 않아요(Deprecated). 채팅 모델에는 OllamaChatOptions를, 임베딩 모델에는 OllamaEmbeddingOptions를 사용하세요. 새 클래스들은 타입 안전하고 모델별로 특화된 구성 옵션을 제공해요.

시작 시 기본 옵션은 OllamaChatModel(api, options) 생성자나 spring.ai.ollama.chat.* 속성으로 구성해요. 런타임에는 Prompt 호출에 요청별 옵션을 추가해 기본값을 덮어쓸 수 있어요. 특정 요청의 기본 모델과 temperature를 덮어쓰는 예시예요.

ChatResponse response = chatModel.call(
    new Prompt(
        "Generate the names of 5 famous pirates.",
        OllamaChatOptions.builder()
            .model(OllamaModel.LLAMA3_1)
            .temperature(0.4)
            .build()
    ));

모델 자동 당겨오기 (Auto-pulling Models)

Spring AI Ollama는 Ollama 인스턴스에 모델이 없으면 자동으로 당겨올 수 있어요. 이 기능은 개발·테스트는 물론 새 환경에 애플리케이션을 배포할 때 특히 유용해요.

모델 당겨오기에는 세 가지 전략이 있어요.

  • always (PullModelStrategy.ALWAYS에 정의): 이미 사용 가능해도 항상 모델을 당겨와요. 모델의 최신 버전을 사용하고 싶을 때 유용.
  • when_missing (PullModelStrategy.WHEN_MISSING에 정의): 모델이 없을 때만 당겨와요. 모델의 이전 버전을 사용하게 될 수 있어요.
  • never (PullModelStrategy.NEVER에 정의): 자동으로 모델을 당겨오지 않아요.

모델 다운로드 중 지연이 발생할 수 있으므로 자동 당겨오기는 프로덕션 환경에서 권장되지 않아요. 대신 필요한 모델을 미리 평가하고 미리 다운로드해두는 걸 고려하세요.

샘플 컨트롤러

새 Spring Boot 프로젝트를 만들어 spring-ai-starter-model-ollama 의존성을 추가한 뒤, application.properties에 Ollama 설정과 채팅 모델을 구성해요. 채팅 모델을 주입해 텍스트 생성을 처리하는 @Controller 예시를 만들 수 있어요.

@RestController
public class ChatController {

    @GetMapping("/ai/generate")
    public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", chatModel.call(message));
    }

    @GetMapping("/ai/generateStream")
	public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        Prompt prompt = new Prompt(new UserMessage(message));
        return this.chatModel.stream(prompt);
    }

}

수동 설정

Spring Boot 자동 설정을 쓰고 싶지 않다면 애플리케이션에서 OllamaChatModel을 수동으로 구성할 수 있어요. OllamaChatModelChatModelStreamingChatModel을 구현하고, Ollama 서비스에 연결하기 위해 저수준 OllamaApi 클라이언트를 사용해요.

Maven pom.xml이나 Gradle build.gradlespring-ai-ollama 의존성을 추가해요.

  • Maven
  • Gradle
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-ollama</artifactId>
</dependency>
dependencies {
    implementation 'org.springframework.ai:spring-ai-ollama'
}

spring-ai-ollama 의존성은 OllamaEmbeddingModel에도 접근을 제공해요. OllamaEmbeddingModel에 대한 자세한 내용은 Ollama Embedding Model 섹션을 참고해요.

다음으로 OllamaChatModel 인스턴스를 만들어 텍스트 생성 요청에 사용해요.

var ollamaApi = OllamaApi.builder().build();

var chatModel = OllamaChatModel.builder()
                    .ollamaApi(ollamaApi)
                    .options(
                        OllamaChatOptions.builder()
                            .model(OllamaModel.MISTRAL)
                            .temperature(0.9)
                            .build())
                    .build();

ChatResponse response = this.chatModel.call(
    new Prompt("Generate the names of 5 famous pirates."));

// Or with streaming responses
Flux<ChatResponse> response = this.chatModel.stream(
    new Prompt("Generate the names of 5 famous pirates."));

OllamaChatOptions는 모든 채팅 요청의 구성 정보를 제공해요.

저수준 OllamaApi 클라이언트

OllamaApi는 저수준 API라 직접 사용은 권장하지 않아요. OllamaChatModel을 대신 사용하세요.

API를 프로그래밍 방식으로 사용하는 간단한 예시를 볼게요.

OllamaApi ollamaApi = new OllamaApi("YOUR_HOST:YOUR_PORT");

// Sync request
var request = ChatRequest.builder("orca-mini")
    .stream(false) // not streaming
    .messages(List.of(
            Message.builder(Role.SYSTEM)
                .content("You are a geography teacher. You are talking to a student.")
                .build(),
            Message.builder(Role.USER)
                .content("What is the capital of Bulgaria and what is the size? "
                        + "What is the national anthem?")
                .build()))
    .options(OllamaChatOptions.builder().temperature(0.9).build())
    .build();

ChatResponse response = this.ollamaApi.chat(this.request);

더 알아보기