LLM의 상위 20가지 AI 개념: 상세 설명과 예제
1. 개요
Java 개발자로서 LLM(ChatGPT, Gemini, Claude…)을 시스템에 통합하기 시작했다면, token, embedding, RAG, fine-tuning, hallucination… 같은 낯선 용어들을 자주 만나게 될 것입니다. 이 글은 LLM과 관련된 20가지 가장 중요한 AI 개념을 정리한 것으로, 각 개념마다 간단한 설명과 예제(대부분 Java/Spring AI)를 포함하고 있습니다. 이 글을 다 읽으면 OpenAI, Anthropic의 API 문서를 읽거나 기본적인 RAG 시스템을 설계할 수 있는 충분한 개념을 갖추게 될 것입니다.
2. Token과 Tokenization
LLM은 “문자”를 읽지 않고 token을 읽습니다. 이는 단어보다 작은 단위로, 한 단어, 단어의 일부, 또는 구두점일 수 있습니다. Tokenization은 텍스트를 이런 token들로 쪼개서 모델에 입력하기 전에 처리하는 단계입니다.
입력: "Spring Boot는 강력합니다"
Token: ["Spring", " Boot", "는", " 강", "력", "합니다"] (6개 token)
Token의 개수는 API 호출 비용(token별 청구)과 input/output의 길이 제한을 결정합니다.
주의: 아시아 언어는 같은 문장에 대해 영어보다 더 많은 token으로 분할되는 경향이 있으므로, 해당 언어 콘텐츠에 대한 API 호출 비용이 일반적으로 더 높습니다.
3. Embedding
Embedding은 텍스트를 실수 벡터(예: 1536차원)로 변환하는 과정으로, 의미가 가까운 두 텍스트는 벡터도 서로 가깝게 됩니다. 이것이 의미 기반 검색(semantic search)의 기초입니다.
EmbeddingModel embeddingModel = ...; // Spring AI에서 자동으로 구성하는 bean
EmbeddingResponse response = embeddingModel.embedForResponse(
List.of("고객이 주문 취소를 원함"));
float[] vector = response.getResult().getOutput();
System.out.println(vector.length); // 1536
embedForResponse는 embedding 모델을 호출하여 벡터를 반환합니다. “주문 취소”와 “cancel order”라는 두 문장은 언어가 다르더라도 벡터가 가까울 것입니다.
의미의 가까움을 비교하려면 cosine similarity를 사용합니다:
double cosineSimilarity(float[] a, float[] b) {
double dot = 0, normA = 0, normB = 0;
for (int i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
@Test
void similarVectorsShouldScoreHigh() {
float[] a = {1f, 0f, 1f};
float[] b = {1f, 0.1f, 0.9f};
assertThat(cosineSimilarity(a, b)).isGreaterThan(0.95);
}
1에 가까운 값은 두 벡터(그리고 따라서 두 문장)의 의미가 매우 가깝다는 것을 의미합니다.
4. Context Window
Context window는 한 번의 호출에서 모델이 “볼 수 있는” 최대 토큰 수로, prompt와 답변 부분을 모두 포함합니다. 이 한계를 초과하면 모델이 처음 부분을 자르거나 오류를 반환합니다.
GPT-4o: 128,000 tokens
Claude 3.5: 200,000 tokens
Gemini 1.5 Pro: 1,000,000 tokens
긴 대화 기록이 있는 chatbot 애플리케이션의 경우, context window가 가득 차기 전에 이전 기록을 주동적으로 자르거나 요약해야 합니다. 그렇지 않으면 명확한 경고 없이 초반 대화 정보가 손실될 수 있습니다.
5. Prompt와 Prompt Engineering
Prompt는 LLM에 어떤 작업을 할 것인지 요청하기 위해 보내는 텍스트입니다. Prompt engineering은 모델이 올바르고 원하는 형식으로 답변하도록 prompt를 설계하는 기법입니다.
먼저 Spring AI 의존성을 추가합니다:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
@Service
class OrderSummaryService {
private final ChatClient chatClient;
OrderSummaryService(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
String summarize(String orderNote) {
return chatClient.prompt()
.user("고객 요청을 한 문장으로 요약하세요: " + orderNote)
.call()
.content();
}
}
ChatClient는 HTTP를 직접 처리할 필요 없이 모델을 호출할 수 있게 해주는 Spring AI의 래퍼입니다. .user(...)는 prompt 내용을 설정하고, .call().content()는 결과 문자열을 반환합니다.
6. System Prompt vs User Prompt
System prompt는 전체 대화에서 모델의 역할과 규칙을 정의하는 “은연중의” 지침입니다. user prompt는 사용자의 구체적인 질문이나 요청입니다.
chatClient.prompt()
.system("당신은 신발 가게의 고객 지원 보조원입니다. 항상 간결하고 정중하게 답변하세요.")
.user("제 주문 #1023은 언제 배송되나요?")
.call()
.content();
System prompt는 한 번만 설정하고, user prompt는 각 요청에 따라 변합니다. 이 두 가지를 분리하면 각 질문에서 지침을 반복하지 않고도 모델의 “성격”을 제어할 수 있습니다.
7. Zero-shot, One-shot, Few-shot Learning
이는 모델을 fine-tuning할 필요 없이 원하는 형식으로 답변하는 방법을 배우도록 prompt에서 (또는 제공하지 않고) 예제를 제공하는 방식입니다.
Zero-shot: 예제 없음, 요구사항만 있음
Few-shot: 최종 질문 전에 2-5개의 입력 -> 출력 샘플 포함
String fewShotPrompt = """
리뷰 감정 분류(긍정/부정):
리뷰: "배송이 빠르고 품질이 좋음" -> 긍정
리뷰: "제품 결함, 배송 1주일 지연" -> 부정
리뷰: "%s" ->
""".formatted(userReview);
Few-shot은 일반적으로 특정 분류/형식 작업에서 zero-shot보다 더 안정적인 결과를 제공하지만, 각 호출마다 더 많은 token을 소비합니다.
8. Chain-of-Thought (CoT)
CoT는 모델이 최종 답변을 제시하기 전에 “단계별로 생각하도록” 요청하는 기법으로, 논리(수학, 로직)가 필요한 문제의 정확도를 향상시킵니다.
chatClient.prompt()
.user("""
주문에 3개 상품이 있고 가격이 120k, 85k, 45k이며 10% 할인이 적용됩니다.
단계별로 계산한 후 최종 금액을 제시하세요.
""")
.call()
.content();
“단계별로”라는 요청을 받으면 모델은 문제를 작은 계산들로 자동으로 분해하는 경향이 있어, 단순히 “총액이 얼마인가?“라고 물어보는 것보다 계산 오류 가능성이 감소합니다.
9. Temperature와 Top-p
Temperature와 top-p는 모델이 다음 단어를 선택할 때 “무작위성” 정도를 조정하는 두 개의 매개변수입니다.
낮은 temperature → 일관적이고 반복적인 답변; 높은 temperature → 더 창의적이지만 주제에서 벗어나기 쉬움.
ChatOptions options = OpenAiChatOptions.builder()
.withTemperature(0.2)
.withTopP(0.9)
.build();
temperature = 0.0 -> 적합: 데이터 추출, 정확한 답변
temperature = 0.8 -> 적합: 창의적 콘텐츠 작성, 브레인스토밍
주의: 재현 가능한 결과가 필요한 작업(예: 자동화된 테스트)의 경우, temperature = 0으로 설정하여 호출 간 변동성을 줄이세요.
10. Attention Mechanism
Attention은 모델이 한 단어를 처리할 때 문장의 다른 모든 단어를 “살펴보고” 어떤 단어가 가장 관련이 있는지 자동으로 가중치를 계산하는 메커니즘입니다.
이는 모델이 멀리 떨어진 문맥을 이해할 수 있는 이유입니다. 예를 들어 대명사 “그것이”가 어느 명사를 가리키는지 파악합니다.
문장: "주문이 고객 변심으로 인해 취소되었고, 환불 처리되었습니다."
Attention은 모델이 "그것이" -> "주문"을 연결하도록 도와주며, "고객"을 가리키지 않습니다.
API를 사용할 때 attention을 직접 코딩하지는 않지만, 이를 이해하면 모델이 때때로 너무 멀거나 긴 문장의 문맥을 “잊는” 이유를 설명할 수 있습니다.
11. Transformer Architecture
Transformer는 현재 거의 모든 LLM의 기반이 되는 신경망 아키텍처로, attention을 사용하여 구식 RNN처럼 순차적으로 처리하는 대신 전체 문장을 동시에(병렬로) 처리하므로 대규모 데이터에서 더 빠르게 훈련할 수 있습니다.
Input tokens -> Embedding -> [Attention + Feed-Forward] x N layers -> Output probabilities
Layer 수(N)와 매개변수 수는 모델의 “크기”를 결정합니다. GPT-4, Claude, Llama는 모두 다양한 layer 수와 훈련 방식을 가진 Transformer의 변형입니다.
12. Fine-tuning
Fine-tuning은 미리 훈련된(pretrained) 모델을 자신의 데이터로 추가 훈련하여 특정 작업에 특화되도록 하는 것입니다(예: 브랜드 톤으로 정확하게 답변).
{"messages": [
{"role": "user", "content": "주문 #203 배송되었나요?"},
{"role": "assistant", "content": "네, 주문 #203은 배송 중이며, 오늘 도착할 것으로 예상됩니다."}
]}
이 JSONL 파일은 fine-tuning을 위한 한 줄의 샘플 훈련 데이터입니다. 각 줄은 샘플 대화 쌍이며, 공급자의 fine-tuning API에 수천 개의 줄을 보냅니다.
사용하지 말아야 할 때: 모델이 단순한 규칙에 따라 답변하기만 하면 되는 경우, prompt engineering이나 RAG이 fine-tuning보다 훨씬 저렴하고 빠릅니다.
13. LoRA (Low-Rank Adaptation)
LoRA는 경제적인 fine-tuning 기법입니다. 기본 모델의 수십억 개 매개변수를 모두 업데이트하는 대신, LoRA는 작은 행렬만 훈련하여 layer에 “추가”하고 기본 모델은 유지합니다.
기본 모델: 70억 개 매개변수(고정, 변경 불가)
LoRA adapter: ~1000만-5000만 개 매개변수(훈련됨)
따라서 LoRA는 일반적인 GPU에서 큰 모델을 fine-tune할 수 있게 하며, 같은 기본 모델에서 여러 use case를 위해 다양한 adapter를 “탈착”할 수 있습니다.
14. Quantization
Quantization은 모델 매개변수의 수치 정확도를 줄입니다(예: float32에서 int8/int4로). 이는 크기를 줄이고 추론 속도를 높이지만, 약간의 정확도를 잃게 됩니다.
FP32: 70억 params x 4 bytes = ~28 GB RAM
INT4: 70억 params x 0.5 byte = ~3.5 GB RAM
Quantization이 있기 때문에 전용 GPU 서버가 필요한 대신 일반 노트북에서 70억 개 매개변수가 있는 LLM을 실행할 수 있습니다. 대신 답변 품질이 약간 저하됩니다.
15. RAG (Retrieval-Augmented Generation)
RAG는 LLM과 내부 데이터 검색(retrieval)을 결합하는 기법입니다. 답변하기 전에, 시스템이 가장 관련된 텍스트 조각(embedding을 통해)을 찾아 prompt에 “문맥”으로 추가하므로, 모델이 fine-tuning 없이 자신의 데이터를 기반으로 정확하게 답변할 수 있습니다.
List<Document> relevantDocs = vectorStore.similaritySearch(
SearchRequest.query("반품 정책").withTopK(3));
String context = relevantDocs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n---\n"));
String answer = chatClient.prompt()
.system("제공된 문맥을 기반으로만 답변하세요.")
.user("문맥:\n" + context + "\n\n질문: 반품은 몇 일 안에 처리되나요?")
.call()
.content();
similaritySearch는 질문과 가장 의미가 가까운 3개의 문서 조각을 찾아 prompt에 합쳐서 모델에 보냅니다. 따라서 답변이 실제 정책에 정확히 맞춰지며, pretrain 중에 모델이 배운 “일반적인” 지식이 아닙니다.
16. Vector Database
Vector database는 embedding과 메타데이터를 저장하고, 수백만 개의 벡터에서 빠른 “k 최근접 이웃”(k-NN) 검색을 지원하는 장소입니다. RAG를 대규모로 실행하기 위한 필수 구성 요소입니다(Pinecone, Milvus, PGVector…).
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
embedding VECTOR(1536)
);
SELECT content FROM documents
ORDER BY embedding <-> '[0.01, -0.02, ...]'
LIMIT 3;
연산자 <->(pgvector 확장에서 제공)는 질문 벡터와 저장된 벡터 간의 거리를 계산하여 가장 가까운 레코드를 반환합니다. 이것이 바로 15번 항목의 similaritySearch 단계입니다.
17. Function Calling / Tool Use
Function calling은 LLM이 필요할 때 애플리케이션에 특정 함수(가격 조회, 날씨 조회, DB 쿼리)를 호출하도록 요청할 수 있게 해주며, 자의적으로 데이터를 만들지 않습니다.
@Tool(description = "주문 번호로 주문 상태를 조회합니다")
String getOrderStatus(String orderId) {
return orderRepository.findStatusById(orderId);
}
chatClient.prompt()
.user("주문 #1023은 어떤 상태인가요?")
.tools(this)
.call()
.content();
질문을 보내면 모델이 자동으로 getOrderStatus 호출이 필요함을 인식하고, Spring AI가 실제 Java 함수를 실행하여 결과를 얻은 후 모델에 다시 제공하여 최종 답변을 작성하도록 합니다. 모델은 더 이상 주문 상태를 “추측”할 필요가 없습니다.
18. AI Agent
Agent는 LLM을 “두뇌”로 사용하여 자동으로 계획을 세우고, 여러 tool을 순서대로 호출하며, 결과를 관찰하고, 목표를 달성할 때까지 반복하는 시스템입니다. 한 번만 답변하는 chatbot과 다릅니다.
사용자: "주문 #1023을 확인하고, 3일 이상 지연되면 사과 이메일을 고객에게 보내세요."
Agent는 자동으로 다음을 실행합니다:
1. tool getOrderStatus("1023")을 호출합니다
2. 지연 일수를 계산합니다
3. 만약 > 3이면 -> tool sendEmail(...)을 호출합니다
4. 사용자에게 보고서를 반환합니다
Agent는 일반적으로 “생각 → 행동 → 관찰” 루프(ReAct 패턴)로 구축되며, 다단계 작업을 처리하기 위해 여러 function calling을 순차적으로 결합합니다.
19. Hallucination
Hallucination은 모델이 자신감 있게 답변하지만 그 정보가 잘못되었거나 완전히 지어낸 것입니다. 예를 들어 존재하지 않는 법령을 인용하거나 존재하지 않는 API를 잘못 기억하는 경우입니다.
사용자: "API `OrderService.cancelAndRefund()`는 어떻게 작동하나요?"
모델: "이 메서드는 24시간 내에 자동으로 환불합니다..." (하지만 이 메서드는 codebase에 존재하지 않습니다)
Hallucination을 줄이는 가장 일반적인 방법은 RAG(15번 항목)를 사용하여 모델이 실제 문서를 따르도록 하고, 문맥이 충분하지 않을 때 모델이 자신의 추론 대신 “모르겠습니다”라고 답변하도록 요청하는 것입니다.
20. Guardrails
Guardrails는 LLM 주변에 배치된 제어 계층의 집합입니다(input/output 필터링, 형식 검증, 민감한 내용 차단). 이는 최종 사용자에게 결과를 반환하기 전에 시스템이 안전하고 표준을 준수하도록 합니다.
String output = chatClient.prompt().user(userInput).call().content();
if (containsPersonalData(output) || !isValidJson(output)) {
throw new UnsafeModelOutputException("출력이 guardrail 기준을 충족하지 않습니다");
}
Guardrails는 input(prompt injection, 악성 콘텐츠 차단) 또는 output(JSON 형식 확인, 신용카드 번호 마스킹)에 위치할 수 있습니다. 모델이 데모 중에 “올바르게” 답변하는 것처럼 보이더라도 LLM을 실제 제품에 배포할 때 이 단계를 건너뛰면 안 됩니다.
21. RLHF (Reinforcement Learning from Human Feedback)
RLHF는 인간의 피드백을 기반으로 모델을 훈련하는 기법입니다. 인간이 모델의 여러 답변을 순위를 매기고, 이를 통해 “보상 모델”을 훈련하여 기본 모델을 계속 최적화하므로 더 유용하고 안전한 답변을 제공합니다.
단계 1: 모델이 같은 질문에 대해 3-4개의 답변을 생성합니다
단계 2: 인간이 순위를 매깁니다: 최고 -> 최악
단계 3: reward model을 훈련하여 인간처럼 "점수를 매기는" 방법을 배웁니다
단계 4: reward model을 사용하여 강화 학습을 통해 LLM을 fine-tune합니다
RLHF는 ChatGPT, Claude가 정중한 “톤”으로 답변하고 위험한 요청을 거절하는 이유입니다. 이는 순수하게 “다음 단어를 예측”하도록만 훈련된 기본 모델과 다릅니다.
22. 결론
위의 20개 개념은 LLM으로 진지한 작업을 하기 위한 최소 어휘 세트입니다. 낮은 수준(token, embedding, attention)부터 애플리케이션 수준(RAG, function calling, agent, guardrails)까지 포괄합니다.
LLM을 Spring Boot 시스템에 통합하기 위해 Transformer의 깊은 수학을 이해할 필요는 없지만, 이러한 개념들을 올바르게 이해하면 적절한 솔루션을 선택할 수 있습니다. 예를 들어 fine-tuning 대신 RAG를 언제 사용할지, 모델의 출력을 절대적으로 신뢰하는 대신 guardrail이 언제 필요한지 알 수 있습니다.