본문 바로가기
카테고리 없음

llm엔진은 내부가 어떻게 구성되어 있나? 그리고 rag 구축시 vectordb와 llm은 어떻게 연결되고 수정하여 저장하는가?

by 3604 2026. 3. 18.
728x90

 

LLM 엔진의 내부 구성과 RAG 시스템에서 Vector DB와의 연결 방식에 대해 설명해 드리겠습니다.

1. LLM 엔진의 내부 구성

핵심 아키텍처 레이어

plain
┌─────────────────────────────────────────────────────────┐
│                    Application Layer                      │
│         (Chat Interface, API, Plugins, etc.)           │
├─────────────────────────────────────────────────────────┤
│                   Inference Engine                        │
│    (Token Generation, Sampling, Decoding Strategy)     │
├─────────────────────────────────────────────────────────┤
│                    Model Core                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐ │
│  │   Tokenizer │  │  Transformer│  │  Attention      │ │
│  │   (BPE/SPM) │  │   Blocks    │  │  Mechanism      │ │
│  └─────────────┘  └─────────────┘  └─────────────────┘ │
├─────────────────────────────────────────────────────────┤
│                   Model Weights                           │
│    (Parameters: 7B/13B/70B+ stored in GPU/TPU Memory)   │
├─────────────────────────────────────────────────────────┤
│                    Hardware Layer                         │
│         (GPU/TPU/CPU Compute + High-bandwidth Memory)   │
└─────────────────────────────────────────────────────────┘

주요 구성 요소 상세

구성 요소 설명
Tokenizer 텍스트 → 토큰 ID 변환 (BPE, SentencePiece, TikToken 등)
Embedding Layer 토큰 ID → 고차원 벡터 (차원: 768~8192)
Transformer Blocks Multi-Head Attention + Feed-Forward Network 반복
Attention Mechanism Self-Attention, Cross-Attention, KV-Cache 관리
LM Head 최종 출력을 vocabulary 확률 분포로 변환
Sampling Engine Temperature, Top-p, Top-k 등으로 토큰 선택

2. RAG 시스템: Vector DB ↔ LLM 연결 구조

전체 아키텍처 플로우

plain
┌─────────────────────────────────────────────────────────────────┐
│                         User Query                               │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 1: Query Embedding (Same model used for document indexing) │
│  ┌─────────────┐    ┌─────────────────┐    ┌─────────────────┐ │
│  │   Query     │───▶│  Embedding      │───▶│  Dense Vector   │ │
│  │   Text      │    │  Model (384/768/│    │  (Query Vector) │ │
│  │             │    │  1024/1536 dim) │    │                 │ │
│  └─────────────┘    └─────────────────┘    └─────────────────┘ │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 2: Vector Search (Similarity Retrieval)                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                    Vector Database                       │    │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────────┐  │    │
│  │  │   HNSW      │  │   IVF/PQ    │  │   Metadata      │  │    │
│  │  │   Index     │  │   Index     │  │   Store         │  │    │
│  │  └─────────────┘  └─────────────┘  └─────────────────┘  │    │
│  │                                                           │    │
│  │  Operation: ANN Search (Approximate Nearest Neighbor)     │    │
│  │  Metric: Cosine Similarity / Euclidean / Dot Product        │    │
│  │  Return: Top-K similar vectors + metadata                 │    │
│  └─────────────────────────────────────────────────────────┘    │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 3: Context Assembly (Retrieved Documents)                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  Retrieved Chunks:                                        │    │
│  │  [Chunk A] "Relevant text segment 1..." (score: 0.92)    │    │
│  │  [Chunk B] "Relevant text segment 2..." (score: 0.87)    │    │
│  │  [Chunk C] "Relevant text segment 3..." (score: 0.81)    │    │
│  │                                                           │    │
│  │  Assembly Strategy:                                       │    │
│  │  • Reranking (Cross-encoder for precision)               │    │
│  │  • Context window fitting (respect token limit)          │    │
│  │  • Metadata injection (source, date, etc.)               │    │
│  └─────────────────────────────────────────────────────────┘    │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 4: Prompt Engineering (Augmented Input)                    │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │  System Prompt: "You are a helpful assistant. Use the   │    │
│  │  following context to answer accurately."                 │    │
│  │                                                           │    │
│  │  Context:                                                 │    │
│  │  ┌─────────────────────────────────────────────────┐      │    │
│  │  │ [Document 1] Title: ... Content: ...            │      │    │
│  │  │ [Document 2] Title: ... Content: ...            │      │    │
│  │  │ [Document 3] Title: ... Content: ...            │      │    │
│  │  └─────────────────────────────────────────────────┘      │    │
│  │                                                           │    │
│  │  User Question: {original_query}                          │    │
│  └─────────────────────────────────────────────────────────┘    │
└───────────────────────┬─────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  STEP 5: LLM Generation                                          │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                    LLM Engine                            │    │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐    │    │
│  │  │  Input  │─▶│Attention│─▶│  FFN    │─▶│ Output  │    │    │
│  │  │Embedding│  │ Layers  │  │ Layers  │  │  Head   │    │    │
│  │  │         │  │(Context+│  │         │  │         │    │    │
│  │  │         │  │ Query)  │  │         │  │         │    │    │
│  │  └─────────┘  └─────────┘  └─────────┘  └─────────┘    │    │
│  │                                                           │    │
│  │  Output: "Based on the provided documents..."            │    │
│  └─────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────┘

3. Vector DB 데이터 수정 및 저장 메커니즘

데이터 흐름 다이어그램

plain

 

┌─────────────────────────────────────────────────────────────────┐
│                    Data Ingestion Pipeline                       │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────────┐ │
│  │   Raw       │───▶│   Chunking  │───▶│   Embedding         │ │
│  │   Documents │    │   Strategy  │    │   Generation        │ │
│  │  (PDF/HTML/ │    │             │    │                     │ │
│  │   TXT/JSON) │    │ • Fixed size│    │ • Sentence-Transform│ │
│  │             │    │ • Semantic  │    │ • OpenAI text-      │ │
│  │             │    │ • Recursive │    │   embedding-3       │ │
│  │             │    │ • Sliding   │    │ • Custom models      │ │
│  └─────────────┘    │   window    │    │                     │ │
│                     └─────────────┘    └─────────────────────┘ │
│                                                   │              │
│                                                   ▼              │
│                              ┌────────────────────────────────┐ │
│                              │      Vector DB Write Path       │ │
│                              │  ┌──────────────────────────┐  │ │
│                              │  │  1. Vector Validation    │  │ │
│                              │  │     (dimension check)    │  │ │
│                              │  ├──────────────────────────┤  │ │
│                              │  │  2. Index Update           │  │ │
│                              │  │     • HNSW graph update  │  │ │
│                              │  │     • IVF cluster assign │  │ │
│                              │  ├──────────────────────────┤  │ │
│                              │  │  3. Metadata Persistence   │  │ │
│                              │  │     • ID mapping         │  │ │
│                              │  │     • Source tracking    │  │ │
│                              │  │     • Timestamp          │  │ │
│                              │  └──────────────────────────┘  │ │
│                              └────────────────────────────────┘ │
│                                                   │              │
│                                                   ▼              │
│                              ┌────────────────────────────────┐ │
│                              │    Storage Backend (Persistent)  │ │
│                              │  ┌────────────┐ ┌────────────┐ │ │
│                              │  │  Parquet/  │ │   WAL/     │ │ │
│                              │  │  Arrow     │ │   Journal  │ │ │
│                              │  │  (Vectors) │ │   (Logs)   │ │ │
│                              │  └────────────┘ └────────────┘ │ │
│                              └────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

주요 Vector DB별 수정 API

Vector DB 삽입 업데이트 삭제 특징
Pinecone upsert() upsert() (same ID) delete() 관리형, 실시간
Weaviate data_object.create() data_object.update() data_object.delete() GraphQL 지원
Chroma collection.add() collection.update() collection.delete() 로컬 임베디드
Milvus insert() upsert() delete() 분산형, 대규모
Qdrant upsert_points() 같은 API delete_points() Rust 기반, 고성능
pgvector INSERT UPDATE DELETE PostgreSQL 확장

4. 코드 예시: RAG 파이프라인 구현

Python 구현 예시 (LangChain + Chroma)

Python
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA

# 1. 임베딩 모델 초기화
embedding_model = OpenAIEmbeddings(model="text-embedding-3-large")

# 2. Vector DB 생성/연결
vectorstore = Chroma(
    collection_name="my_knowledge",
    embedding_function=embedding_model,
    persist_directory="./chroma_db"  # 로컬 저장 경로
)

# 3. 문서 추가 (자동 임베딩 + 저장)
texts = ["문서 내용 1...", "문서 내용 2...", "문서 내용 3..."]
metadatas = [{"source": "doc1.pdf"}, {"source": "doc2.pdf"}]
ids = ["chunk_001", "chunk_002", "chunk_003"]

vectorstore.add_texts(
    texts=texts,
    metadatas=metadatas,
    ids=ids
)

# 4. 문서 업데이트 (동일 ID로 upsert)
vectorstore.update_document(
    document_id="chunk_001",
    document="수정된 새로운 내용..."
)

# 5. 검색-증강-생성 체인 구성
llm = ChatOpenAI(model="gpt-4", temperature=0)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",  # 또는 "map_reduce", "refine"
    retriever=vectorstore.as_retriever(
        search_type="similarity",
        search_kwargs={"k": 5}  # Top-5 검색
    ),
    return_source_documents=True
)

# 6. 실행
result = qa_chain({"query": "사용자 질문?"})
print(result["result"])
print(result["source_documents"])  # 출처 문서 확인

고급 RAG 패턴: Self-Query + Rerank

Python
from langchain.retrievers import SelfQueryRetriever
from langchain.chains.query_constructor.base import AttributeInfo

# 메타데이터 필터링 자동화
metadata_field_info = [
    AttributeInfo(
        name="source",
        description="문서 출처 파일명",
        type="string",
    ),
    AttributeInfo(
        name="date",
        description="문서 생성 날짜",
        type="string",
    ),
]

self_query_retriever = SelfQueryRetriever.from_llm(
    llm=llm,
    vectorstore=vectorstore,
    document_contents="기술 문서 내용",
    metadata_field_info=metadata_field_info,
)

# Reranking (Cross-encoder로 정밀도 향상)
from sentence_transformers import CrossEncoder
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')

# 검색 → 재정렬 → 상위 3개 선택
docs = self_query_retriever.get_relevant_documents(query)
pairs = [[query, doc.page_content] for doc in docs]
scores = reranker.predict(pairs)
top_docs = [doc for _, doc in sorted(zip(scores, docs), reverse=True)[:3]]

5. 핵심 연결 포인트 요약

단계 Vector DB 역할 LLM 역할 데이터 흐름
Indexing 벡터 + 메타데이터 저장 임베딩 모델 제공 Doc → Embedding → Vector DB
Retrieval 유사도 검색 실행 - Query Vector → ANN Search → Chunks
Augmentation 검색 결과 제공 컨텍스트 조립 Chunks + Query → Prompt
Generation - 답변 생성 Prompt → LLM → Response
이 구조를 통해 LLM은 학습하지 않은 최신 정보나 사설 문서를 Vector DB에서 검색하여 활용할 수 있으며, 문서가 업데이트되면 Vector DB만 갱신하면 즉시 반영됩니다.
 
 
 
 
 
[참고] Tokenizer란
 

Tokenizer는 LLM의 입력 게이트 역할을 하는 핵심 구성 요소입니다. 자연어 텍스트를 모델이 이해할 수 있는 숫자 형태(토큰 ID)로 변환하는 인코더입니다.


Tokenizer의 핵심 역할

plain
Copy
┌─────────────────────────────────────────────────────────────┐
│  자연어 텍스트  ──▶  Tokenizer  ──▶  토큰 ID 시퀀스  ──▶  LLM  │
│                                                             │
│  "Hello world"    [15496, 995]      Embedding Layer       │
│  "안녕하세요"      [12345, 6789]      ↓                     │
│                                    Transformer 처리        │
└─────────────────────────────────────────────────────────────┘

동작 원리: 3단계 파이프라인

1. 정규화 (Normalization)

Python
Copy
# 입력 텍스트 전처리
"Hello!" → "hello"  # 소문자화, 특수문자 처리
"  여러   공백  " → "여러 공백"  # 공백 정규화

2. 토큰화 (Tokenization)

텍스트를 서브워드 단위로 분할합니다:
알고리즘 방식 예시
BPE (Byte-Pair Encoding) 빈도 기반 병합 low  low, lower  low + er
WordPiece 확률 기반 병합 playing  play + ##ing
SentencePiece 공백 독립 처리 _Hello  _ + He + ll + o
Unigram 확률 모델 기반 후보 중 최적 선택
TikToken (GPT-4) BPE 최적화 바이트 기반 정규 BPE
실제 분할 예시:
plain
Input:  "Tokenization"
BPE:     ["Token", "ization"]           # 2 토큰
TikToken: ["Token", "iz", "ation"]       # 3 토큰

3. 인덱싱 (Indexing)

분할된 토큰을 고유 정수 ID로 매핑:
Python
vocab = {
    "Token": 15496,
    "ization": 328,
    "iz": 892,
    "ation": 441,
    "<|endoftext|>": 50256  # 특수 토큰
}

주요 Tokenizer 비교

모델 Tokenizer 어휘 크기 특징
GPT-2/3 BPE 50,257 바이트 기반, 영어 최적화
GPT-4 TikToken (cl100k_base) 100,256 다국어 개선, 효율적
BERT WordPiece 30,522 양방향, ## 접두사
T5 SentencePiece 32,000 공백 보존, _ 표시
LLaMA 2 BPE (SentencePiece 기반) 32,000 다국어 확장
LLaMA 3 TikToken 유사 128,256 15개 언어 최적화
Claude BPE 변형 미공개 안전 토큰 포함
KoGPT BPE + 한국어 52,000 한국어 형태소 고려

토큰화 실제 예시

Python
import tiktoken

# GPT-4 Tokenizer
enc = tiktoken.encoding_for_model("gpt-4")

text = "Tokenizer는 텍스트를 숫자로 변환합니다."
tokens = enc.encode(text)
print(f"토큰 IDs: {tokens}")
print(f"토큰 수: {len(tokens)}")

# 디코딩 확인
decoded = [enc.decode_single_token_bytes(t) for t in tokens]
print(f"토큰 분할: {decoded}")
출력:
plain
토큰 IDs: [31347, 119, 243, 108, 255, 245, 102, 11, 251, 114, ...]
토큰 수: 14
토큰 분할: [b'Token', b'izer', b'\xeb\x8a\x94', b' \xed\x85\x8d', ...]

중요 개념: 토큰 vs 문자

구분 설명 예시
문자 글자 단위 "가" = 1 문자
토큰 의미 단위 "Tokenization" = 3~4 토큰
바이트 최소 단위 "가" = 3 바이트 (UTF-8)
주의: 영어는 1단어 ≈ 1.3토큰, 한국어/중국어는 1글자 ≈ 2~3토큰 (비효율적)

특수 토큰 (Special Tokens)

plain
<|endoftext|>     : 문서 종료 (GPT)
[CLS]             : 분류 시작 (BERT)
[SEP]             : 문장 구분 (BERT)
[MASK]            : 마스킹 위치 (BERT)
[PAD]             : 시퀀스 패딩
<s>, </s>         : 문장 시작/끝 (T5, LLaMA)
<|im_start|>      : 대화 시작 (ChatML)
<|tool_call|>     : 도구 호출 (함수 호출)

Tokenizer 선택의 영향

측면 영향
어휘 크기 클수록 희귀어 처리 ↑, 메모리 ↑
토큰 길이 짧을수록 처리 속도 ↑, 의미 손실 ↑
언어 커버리지 다국어 토큰화 효율성 차이
비용 API 과금 = 토큰 수 기준
핵심: Tokenizer는 LLM의 "입력 알파벳"을 정의합니다. 같은 모델이라도 Tokenizer가 다르면 완전히 다른 입력이 됩니다.
728x90