지금까지 Spring AI로 Gemini와 OpenAI 같은 클라우드 API를 연동해봤다.
ChatClient 하나로 다양한 모델을 추상화해서 쓸 수 있다는 것도 확인했다.
그런데 이런 의문이 생길 수 있다.
이번 글에서는 이 세 가지 문제를 한 번에 해결하는 방법인 로컬 LLM 실행을 다룬다.
핵심 도구는 Ollama고, Spring AI와 어떻게 연결하는지까지 살펴본다.
클라우드 API 방식은 편하다. API 키 하나만 있으면 GPT-4, Claude 같은 최고 성능의 모델을 바로 쓸 수 있다.
하지만 이 방식에는 구조적인 단점이 있다.
Spring Boot
│
│ HTTPS (외부 인터넷)
▼
OpenAI / Anthropic 서버
모든 데이터가 외부로 나간다. 의료 기록, 금융 거래 내역, 사내 기밀 문서 같은 민감한 정보를 다루는 시스템이라면 이건 심각한 문제다.
게다가 사용량이 늘어날수록 비용도 선형이 아니라 폭발적으로 증가한다.
로컬 모델 방식은 구조가 다르다.
Spring Boot
│
│ localhost:11434
▼
Ollama (내 컴퓨터)
└── qwen2.5:3b (AI 모델)
데이터가 밖으로 나가지 않는다. 초기 설정 이후에는 추가 비용도 없다.
인터넷이 없는 환경에서도 동작한다.
| 항목 | 클라우드 API | 로컬 모델 (Ollama) |
|---|---|---|
| 비용 | 토큰당 과금 | 초기 설정 이후 무료 |
| 데이터 보안 | 외부 서버 전송 | 로컬 저장 |
| 인터넷 의존 | 필수 | 불필요 |
| 응답 속도 | 네트워크 지연 발생 | 로컬 통신 (빠름) |
| 모델 성능 | 초거대 모델 사용 가능 | 하드웨어에 따라 제한 |
| 하드웨어 요구 | 없음 | RAM 8GB 이상 권장 |
두 방식은 경쟁 관계가 아니라 보완 관계다.
보안이 중요하거나 고빈도 호출이 필요한 서비스는 로컬 모델, 최고 성능이 필요하거나 초기 출시를 빠르게 해야 한다면 클라우드 API가 적합하다.
Ollama는 한 줄로 이렇게 정의할 수 있다.
"AI 모델계의 Docker"
Docker가 컨테이너 이미지를 패키징해서 어디서든 동일하게 실행시켜주듯,
Ollama는 AI 모델을 패키징해서 내 로컬 환경에서 동일하게 실행할 수 있게 해준다.
Docker Ollama
───────────── ──────────────────
이미지 AI 모델 (qwen2.5:3b)
컨테이너 런타임 Ollama 런타임
포트 노출 localhost:11434
Docker로 설치하는 방법은 간단하다.
# Ollama 컨테이너 실행
docker run -d \
-v ollama:/root/.ollama \
-p 11434:11434 \
--name ollama \
ollama/ollama
# 모델 다운로드 및 실행
docker exec -it ollama ollama run qwen2.5:3b
실행 후 브라우저에서 http://localhost:11434에 접속했을 때 "Ollama is running"이 뜨면 준비 완료다.
Ollama에서 제공하는 모델은 다양하다. 이번 실습에서는 Qwen2.5를 사용했다.
Alibaba Cloud가 만든 모델로, 한국어 처리 능력이 뛰어나고 4b(40억 파라미터) 크기는 일반 개발용 노트북에서도 무리 없이 돌아간다.
| 모델 | RAM 요구량 | 속도 | 품질 | 추천 용도 |
|---|---|---|---|---|
| qwen2.5:0.5b | 2GB | 매우 빠름 | 낮음 | 단순 분류, 테스트 |
| qwen2.5:3b | 8GB | 빠름 | 좋음 | 균형 잡힌 일반 용도 |
| qwen2.5:7b | 16GB | 보통 | 매우 좋음 | 복잡한 로직, RAG |
하드웨어 사양에 따라 모델을 선택하면 된다. RAM이 16GB 이상이라면 7b를, 그렇지 않다면 3b가 현실적인 선택이다.
이제 핵심이다. Spring AI에서 Ollama를 연결하는 방법은 Gemini나 OpenAI와 구조가 동일하다.
dependencies {
// Ollama 연동 스타터
implementation 'org.springframework.ai:spring-ai-ollama-spring-boot-starter'
}
starter를 추가하는 순간, Spring Boot Auto Configuration이 동작해서 ChatClient Bean을 자동으로 등록한다.
우리가 직접 @Component를 붙이거나 Bean 설정을 작성할 필요가 없다.
spring:
ai:
ollama:
base-url: http://localhost:11434 # Ollama 서버 주소
chat:
options:
model: qwen2.5:3b
temperature: 0.7
top-k: 40
top-p: 0.9
num-predict: 10000
repeat-penalty: 1.1
클라우드 API와의 차이점은 하나다. api-key 대신 base-url을 설정한다.
로컬에서 돌아가는 서버이므로 인증 키가 필요 없고, 대신 어디에 서버가 있는지만 알려주면 된다.
@Service
@RequiredArgsConstructor
public class OllamaService {
private final ChatClient chatClient; // Auto Configuration이 주입해준 Bean
public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}
public String chatWithOptions(String systemPrompt, String message, Double temperature) {
return chatClient.prompt()
.system(systemPrompt)
.user(message)
.options(OllamaOptions.builder()
.temperature(temperature)
.build())
.call()
.content();
}
}
주목할 점은 ChatClient를 사용하는 코드가 Gemini를 쓰던 것과 완전히 동일하다는 것이다.
모델이 바뀌었지만 비즈니스 로직은 한 줄도 수정하지 않았다.
이것이 가능한 이유는 1단계에서 배운 추상화 때문이다.
ChatClient라는 인터페이스에 의존하기 때문에, 구체적인 구현체(Gemini, Ollama)가 무엇인지 알 필요가 없다.
개발자 코드 Spring AI 실제 모델
────────────── ────────────── ──────────────
ChatClient.prompt() → ChatClient (인터페이스) → Gemini
→ Ollama
→ OpenAI
yaml 설정만 바꾸면 모델이 교체된다. 코드는 그대로다.
모델의 답변 품질은 파라미터로 조절할 수 있다. 세 가지를 이해하면 대부분의 상황에 대응할 수 있다.
가장 기본적인 파라미터다. 0부터 1 사이의 값으로 답변의 창의성 정도를 조절한다.
코드 생성이나 사실 기반 답변은 낮은 temperature, 아이디어 제안이나 창작은 높은 temperature가 적합하다.
다음 단어 후보를 확률 상위 k개로 고정해서 제한하는 방식이다.
전체 어휘: 50,000개
top-k = 40 설정
→ 확률 상위 40개만 후보로 인정
→ 나머지 49,960개는 무조건 제외
후보군 크기가 항상 고정되어 있어서 예측 가능하다는 특징이 있다.
누적 확률이 p에 도달할 때까지의 단어들만 후보로 삼는 방식이다.
확률 분포: "맑아"(70%), "흐려"(20%), "더워"(5%), "춥고"(3%) ...
top-p = 0.9 설정
→ 70% + 20% = 90% 도달
→ "맑아", "흐려" 2개만 후보
top-k와 달리 후보 개수가 문맥에 따라 동적으로 변한다는 것이 핵심이다.
문맥이 명확할수록 후보가 줄고, 애매할수록 후보가 늘어난다.
결과적으로 더 자연스러운 답변을 생성하는 경향이 있다.
| 파라미터 | 역할 | 특징 |
|---|---|---|
| temperature | 창의성 정도 조절 | 0 = 정확, 1 = 창의적 |
| top-k | 후보 개수 고정 제한 | 항상 동일한 개수 |
| top-p | 누적 확률 기반 제한 | 문맥에 따라 동적 조절 |
실무에서는 세 파라미터를 함께 사용한다. 일반적인 챗봇이라면 temperature: 0.7, top-k: 40, top-p: 0.9 조합이 무난한 출발점이다.
로컬 LLM은 클라우드 API의 대안이 아니라 상황에 따른 선택지다.
보안이 중요하거나 비용이 부담되는 상황이라면 Ollama + Spring AI 조합이 실용적인 해답이 된다.
Spring AI의 추상화 덕분에 클라우드 API를 쓰던 코드를 그대로 유지하면서 모델만 교체할 수 있다.
이것이 Spring AI가 제공하는 가장 큰 가치다.